Docker基础知识 (20) - Kubernetes(三) | 在 K8s 集群上部署 Nginx


Kubernetes,也被称为 K8s 或 Kube,是谷歌推出的业界最受欢迎的容器管理/运维工具(容器编排器)。它是一套自动化容器管理/运维的开源平台,包括部署、调度和节点集群的扩展等。

Kubernetes 的详细介绍,请参考 "系统架构与设计(6)- Kubernetes(K8s)"。

Kubernetes: https://kubernetes.io/
Kubernetes GitHub: https://github.com/kubernetes

本文在 K8s 集群上部署 Nginx 服务,如何部署一个 K8s 集群可以参考 “Docker基础知识 (19) - Kubernetes(二) | 部署 K8s 集群(一主一从)”。


1. 部署环境

    虚拟机: Virtual Box 6.1.30(Windows 版)
    操作系统: Linux CentOS 7.9 64位
    Docker 版本:20.10.7
    Docker Compose 版本:2.6.1
    Kubernetes 版本:1.23.0

    工作目录:/home/k8s
    Linux 用户:非 root 权限用户 (用户名自定义,这里以 xxx 表示),属于 docker 用户组


    1) 主机列表

        主机名          IP            角色       操作系统
        k8s-master  192.168.0.10    master      CentOS 7.9
        k8s-node01  192.168.0.11    node        CentOS 7.9

 

    2) 部署和调度

        部署的工作都是在 master (192.168.0.10) 主机上进行,K8s 会自动调度到 node 节点。

        默认情况下,master 节点不参与调度,且在 master 节点上有一个污点 NoSchedule(表示 K8s 将不会将 Pod 调度到具有该污点的 Node 上),即如果没有 node 节点处于工作状态时,新部署的 Pod 将一直处于 Pending 状态。

        让 master 节点参与调度的步骤:

            # 查看 node
            $ kubectl get nodes

            # 查看污点(taints)
            $ kubectl describe node k8s-master | grep Taints 

                Taints:  node-role.kubernetes.io/master:NoSchedule

            # 删除污点
            $ kubectl taint nodes k8s-master node-role.kubernetes.io/master-

            # 把 master 标记为 worker。如果想删除标记,运行命令时把 = 换成 -
            $ kubectl label nodes k8s-master node-role.kubernetes.io/worker=

   给 master 节点添加污点(master 节点不参与调度),运行如下命令:

    $ kubectl taint nodes k8s-master node-role.kubernetes.io/master:NoSchedule


    3) 工作目录结构

         以下目录结构处于 master 节点 /home/k8s 目录下:

            k8s
             |- init.default.yaml
             |- kube-flannel.yml
             |- nginx-test
                    |- namespace.yaml
                    |- nginx-deployment.yaml
                    |- nginx-service.yaml
                    |- nginx 
                        |- conf.d
                        |   |- nginx.conf
                        |   
                        |- html 
                        |   |- test.html 
                        |
                        |- log 

 

2. 创建命名空间 (namespace)

    1) 命名空间 (namespace)

        Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群,这些虚拟集群被称为命名空间。

        命名空间 (namespace) 是 k8s 集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的命名空间。

        命名空间适用于存在很多跨多个团队或项目的用户的场景,对于只有少数项目人员的集群则不需要使用 namespace。

        在创建 pod 时可以指定 pod 到 namespace,如果没有指定 namespace,则会默认使用 default 这个 namespace。

    2) 创建 namespace.yaml 文件

        $ cd  /home/k8s/nginx-test      # 手动创建 nginx-test 目录  
        $ vim namespace.yaml

            apiVersion: v1
            kind: Namespace
            metadata:
                name: nginx-test
                labels:
                    name: nginx-test

        配置说明:

            kind:Namespace 表示该 yaml 文件要创建命名空间;
            metadata: 表示命名空间的元信息;
            metadata.name: 是命名空间的名称;
            metadata.labels: 是命名空间的标签;

    3) 执行创建命令

        $ kubectl apply -f namespace.yaml

            namespace/nginx-test created

        # 查看命名空间列表
        $ kubectl get namespaces

            NAME              STATUS   AGE
            default           Active   3h5m
            kube-node-lease   Active   3h5m
            kube-public       Active   3h5m
            kube-system       Active   3h5m
            nginx-test        Active   23s


        # 查看命名空间详情
        $ kubectl describe namespace nginx-test

            Name:         nginx-test
            Labels:       kubernetes.io/metadata.name=nginx-test
                          name=nginx-test
            Annotations:  <none>
            Status:       Active

            No resource quota.

            No LimitRange resource.


3. 创建 Deployment

    1) Deployment 简介

​        Deployment 是一个定义及管理多副本应用(即多个副本 Pod)的新一代对象,与 Replication Controller 相比,它提供了更加完善的功能,使用起来更加简单方便。

        在 k8s 中 Deployment 对象管理 Pod 对象的方法,被叫作 "控制器" 模式(controller pattern),Deployment 扮演的是 Pod 的 "控制器" 角色。

        Deployment 通过管理 ReplicaSet 来间接管理 Pod,即:Deployment 管理 ReplicaSet,ReplicaSet 管理 Pod。所以 Deployment 比 ReplicaSet 的功能更强大。

        如果 Pod 出现故障,对应的服务也会挂掉,所以 Kubernetes 提供了一个 Deployment 的概念 ,目的是让 Kubernetes 去管理一组 Pod 的副本,也就是副本集,这样就能够保证一定数量的副本一直可用,不会因为某一个 Pod 挂掉导致整个服务挂掉。

        Deployment 还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。

    2) 创建 nginx.conf 文件

        $ cd  /home/k8s/nginx-test/nginx/conf.d   # 手动创建 nginx/conf.d 各级子目录
        $ vim nginx.conf

            server {
                listen  80 default_server;
                server_name localhost;
            
                location / {
                    root   /usr/share/nginx/html;
                    index index.php index.html index.htm;
                    autoindex off;
                }
            }


    3) 创建 test.html 文件

        $ cd  /home/k8s/nginx-test/nginx/html   # 手动创建 nginx/html 各级子目录
        $ vim test.html

            <p>K8s Nginx - HTML page</p>

    4) 创建 nginx-deployment.yaml 文件

        $ cd /home/k8s/nginx-test
        $ vim nginx-deployment.yaml

            apiVersion: apps/v1
            kind: Deployment
            metadata:
              name: nginx-deployment
              namespace: nginx-test
            spec:
              replicas: 1
              selector:
                matchLabels:
                  app: nginx-pod
              template:
                metadata:
                  labels:
                    app: nginx-pod
                spec:
                  containers:
                  - name: nginx-1-21
                    image: nginx:1.21
                    ports:
                    - containerPort: 80
                    volumeMounts:
                    - name: conf
                      mountPath: /etc/nginx/conf.d
                    - name: log
                      mountPath: /var/log/nginx
                    - name: html
                      mountPath: /usr/share/nginx/html
                  volumes:
                  - name: conf
                    hostPath:
                      path: /home/k8s/nginx-test/nginx/conf.d
                      type: Directory
                  - name: log
                    hostPath:
                      path: /home/k8s/nginx-test/nginx/log
                      type: Directory
                  - name: html
                    hostPath:
                      path: /home/k8s/nginx-test/nginx/html
                      type: Directory

            配置说明:

                kind: Deployment 表示该 yaml 文件要创建 Deployment 发布;
                metadata: 表示这个 deployment 的元信息;
                metadata.name: 是 deployment 的名称 nginx-deployment;
                metadata.labels: 是 deployment 的标签;
                metadata.namespace: 是 deployment 所在的命名空间;

                spec: 表示 deployment 的详细参数配置说明;
                spec.replicas: 是启动几个 pod 节点(副本);
                spec.template.spec: 是 deployment 选择模块的详细说明;
                spec.template.spec.containers:表示容器,此处是 nginx 的 docker 镜像,容器的端口设置 containerPort: 80, volumeMounts 表示绑定的文件和目录;
                spec.template.spec.volumes:表示选择的容器挂载的宿主机的文件和目录 conf, logs 和 html;

            注:手动创建 /home/k8s/nginx-test/nginx/log 目录。


        # 执行创建命令
        $ kubectl apply -f nginx-deployment.yaml

            deployment.apps/nginx-deployment created

        # 查询 pods
        $ kubectl get pods -n nginx-test -o wide

            NAME                              READY STATUS   ...  AGE    IP           NODE
            nginx-deployment-56786d8495-rxr9c 1/1   Running       3m32s  10.244.0.10  k8s-master


        # 集群内访问 nginx(Pod 的虚拟 IP,外部无法访问)  
        $ curl http://10.244.0.10/test.html

            <p>K8s Nginx - HTML page</p>

    5) 操作 Deployment

        # 查询命名空间 nginx-test 下的 deployment
        $ kubectl get deploy -n nginx-test

            NAME               READY   UP-TO-DATE   AVAILABLE   AGE
            nginx-deployment   1/1     1            1           144m


        # 查询 deployment 详情
        $ kubectl describe deploy nginx-deployment -n nginx-test

            Name:                   nginx-deployment
            Namespace:              nginx-test
            CreationTimestamp:      Wed, 16 Nov 2022 17:44:39 -0500
            Labels:                 <none>
            Annotations:            deployment.kubernetes.io/revision: 1
            Selector:               app=nginx-pod
            Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
            ...


        # 动态修改 deployment 的副本数量
        $ kubectl scale deploy nginx-deployment --replicas=2 -n nginx-test

            deployment.apps/nginx-deployment scaled
        
        # 重启 deployment
        $ kubectl rollout restart deploy nginx-deployment -n nginx-test

            deployment.apps/nginx-deployment restarted

        # 删除一个 deployment
        $ kubectl delete deploy nginx-deployment -n nginx-test

    6) 操作 ReplicaSet

        # 查询命名空间 nginx-test 下的 ReplicaSet
        $ kubectl get rs -n nginx-test

            NAME                         DESIRED   CURRENT   READY   AGE
            nginx-deployment-fc98c7b77   2         2         0       34m


    7) 操作 Pod

        # 查询命名空间 nginx-test 下的 pod
        $ kubectl get pods -n nginx-test

            NAME                                READY   STATUS    RESTARTS   AGE
            nginx-deployment-6487bc588b-nnpw8   1/1     Running   0          5m10s
            nginx-deployment-6487bc588b-sfxh9   1/1     Running   0          5m12s


        # 查询 pod 详情
        $ kubectl describe pod nginx-deployment-6487bc588b-nnpw8 -n nginx-test

            Name:         nginx-deployment-6487bc588b-nnpw8
            Namespace:    nginx-test
            Priority:     0
            Node:         k8s-master/192.168.0.10
            Start Time:   Wed, 16 Nov 2022 20:14:42 -0500
            Labels:       app=nginx-pod
                        pod-template-hash=6487bc588b
            ...

 

        # 查看 pod 日志
        $ kubectl logs nginx-deployment-6487bc588b-nnpw8 -n nginx-test


        # 删除 pod
        $ kubectl delete pod nginx-deployment-6487bc588b-nnpw8 -n nginx-test

        # 强制删除 pod
        $ kubectl delete pod nginx-deployment-6487bc588b-nnpw8 -n nginx-test --force --grace-period=0


4. 创建 Service

    上文 Deployment 创建的一组 Pod 提供具有高可用性的 Nginx 服务。

    虽然每个 Pod 都会分配一个单独的 Pod 虚拟 IP,但有如下两个问题:

        (1) Pod 虚拟 IP 会随着 Pod 的重建产生变化;
        (2) Pod 虚拟 IP 仅仅是集群内可见,外部无法访问;

    kubernetes 设计了 Service 来解决以上问题,Service 可以看作是一组同类 Pod 对外的访问接口,基于 Service,应用可以方便地实现服务发现和负载均衡。

    1) 创建 nginx-service.yaml 文件

        $ cd  /home/k8s/nginx-test
        $ vim nginx-service.yaml

            apiVersion: v1
            kind: Service
            metadata:
                labels:
                    app: nginx-pod
                name: nginx-service
                namespace: nginx-test
            spec:
                ports:
                - port: 9080
                  name: nginx-service-80
                  protocol: TCP
                  targetPort: 80
                  nodePort: 30080
                selector:
                    app: nginx-pod
                type: NodePort


            配置说明:

                kind: Service 表示 yaml 文件创建的是一个 Service;
                metadata: 表示这个 Service 的元信息;
                metadata.name: 是 Service 的名称 nginx-service;
                metadata.labels: 是 Service 的标签;
                metadata.namespace: 是 Service 的命名空间,此处选择的是第一步创建的命名空间 nginx;

                sepc: 是 Service 的详细配置说明;
                sepc.type: NodePort 表示外部可以访问,ClusterIP 表示集群内访问;
                sepc.selector: 表示这个 Service 是将带标签的哪些 pods 做为一个集合对外通过服务;
                sepc.ports.port: 是 Service 绑定端口 9080 ;
                sepc.ports.name: nginx-service-80 表示 Service 服务的名称;
                sepc.ports.protocol: TCP 表示 Service 转发请求到容器的协议是 TCP,我们部署的 http 的 nginx 服务,因此选择协议为TCP;
                sepc.ports.targetPort: 80 表示 Service 转发外部请求到容器的目标端口 80,即 deployment 的 pod 容器对外开放的容器端口 80;
                sepc.ports.nodePort: 30080 表示 Service 对外开放的节点端口;

        # 执行创建 Service 命令
        $ kubectl apply -f nginx-service.yaml

        # 查询服务列表
        $ kubectl get services -n nginx-test

            NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
            nginx-service   NodePort   10.104.204.25   <none>        9080:30080/TCP   16s


        浏览器外部访问 http://192.168.0.10:30080/test.html,显示结果如下:

            K8s Nginx - HTML page

    2) 操作 Service

        # 查询 Service 详情
        $ kubectl describe service nginx-service -n nginx-test

            Name:                     nginx-service
            Namespace:                nginx-test
            Labels:                   app=nginx-pod
            Annotations:              <none>
            Selector:                 app=nginx-pod
            Type:                     NodePort
            IP Family Policy:         SingleStack
            IP Families:              IPv4
            IP:                       10.104.204.25
            IPs:                      10.104.204.25
            Port:                     nginx-service-80  9080/TCP
            TargetPort:               80/TCP
            NodePort:                 nginx-service-80  30080/TCP
            Endpoints:                10.244.0.12:80,10.244.0.13:80
            Session Affinity:         None
            External Traffic Policy:  Cluster
            Events:                   <none>


        # 删除 service 服务
        $ kubectl delete services nginx-service -n nginx-test

            service "nginx-service" deleted

 

5. 维护 node 节点

    K8s v1.2 加入了 cordon、drain、uncordon 三个命令用户实现节点的维护,有了这三个命令,在维护 node 节点时,就不必把要维护的 node 节点退出集群。维护 node 节点的步骤如下:

        # 查看节点
        $ kubectl get nodes

            NAME         STATUS   ROLES                  AGE    VERSION
            k8s-master   Ready    control-plane,master   140m   v1.23.0
            k8s-node01   Ready    <none>                 18m    v1.23.0

        # 设置 k8s-node01 节点不可调度
        $ kubectl cordon k8s-node01

        # 驱逐/清空节点上的 Pod
        $ kubectl drain k8s-node01 --force --ignore-daemonsets

        # 维护工作
        ...

        # 复节点可调度
        $ kubectl uncordon k8s-node01


6. 注意要点

    以上的部署工作都是在 master (k8s-master,192.168.0.10) 主机上进行,工作目录在 /home/k8s,测试运行 nginx 服务时要注意以下两种情况:

    1) master 节点不参与调度

        这种情况下 node 节点(k8s-node01,192.168.0.11)必须处于 Ready 状态,运行如下命令查询:

            $ kubectl get nodes

                NAME         STATUS   ROLES                  AGE    VERSION
                k8s-master   Ready    control-plane,master   140m   v1.23.0
                k8s-node01   Ready    <none>                 18m    v1.23.0

        当 node 节点处于 Ready 状态时,集群应该会很快把 Pod 调度到 node 节点运行。此时 nginx 无法正常运行,因为 nginx 找不到 /home/k8s/nginx-test/nginx 目录及其子目录 (node 节点上没有这个目录),需要把 master 下的 /home/k8s/nginx-test/nginx 目录完全复制到 node 下的 /home/k8s/nginx-test/nginx 目录。

    2) master 节点参与调度

        这种情况下如果 node 节点处于 Ready 状态,也需要复制 master 的 /home/k8s/nginx-test/nginx 目录。 

        如果 node 节点处于 NotReady 状态,可以不复制 master 的 /home/k8s/nginx-test/nginx 目录,因为 Pod 只会在 master 上运行。

 

posted @ 2022-11-17 21:55  垄山小站  阅读(1438)  评论(5编辑  收藏  举报