• k8s入门篇资源管理


    Kubernetes入门

    一、为什么需要Kubernetes

    1.1 传统的容器编排痛点

    容器技术虽然解决了应用和基础设施异构的问题,让应用可以做到一次构建,多次部署,但在复杂的微服务场景,单靠 Docker 技术还不够,它仍然有以下问题没有解决:

    • 集成和编排微服务模块
    • 提供按需自动扩容,缩容能力
    • 故障自愈
    • 集群内的通信

     

    1.2 Kubernetes 能解决的问题

    • 按需的垂直扩容,新的服务器(node)能够轻易的增加或删除
    • 按需的水平扩容,容器实例能够轻松扩容,缩容
    • 副本控制器,你不用担心副本的状态
    • 服务发现和路由
    • 自动部署和回滚,如果应用状态错误,可以实现自动回滚

     

    1.3 什么时候使用 Kubernetes?

    • 应用是微服务架构
    • 开发者需要快速部署自己的新功能到测试环境进行验证
    • 降低硬件资源成本,提高使用率

     

    1.4 什么时候不适合使用 Kubernetes

    • 应用是轻量级的单体应用,没有高并发的需求
    • 团队文化不适应变革

    二、Kubernetes的发展

    • 2014年6月 谷歌云计算专家Eric Brewer在旧金山的发布会为这款新的开源工具揭牌。
    • 2015年7月22日K8S迭代到 v 1.0并在OSCON大会上正式对外公布。为了建立容器编排领域的标准和规范,Google、RedHat 等开源基础设施领域玩家们,在 2015 年共同牵头发起了名为 CNCF(Cloud Native Computing Foundation)的基金会。Kubernetes 成为 CNCF 最核心的项目。

       发起成员:AT&T, Box, Cisco, Cloud Foundry Foundation, CoreOS, Cycle Computing, Docker, eBay, Goldman Sachs, Google, Huawei, IBM, Intel, Joyent, Kismatic, Mesosphere, Red Hat, Switch SUPERNAP, Twitter, Univa, VMware and Weaveworks。

    • 2018年,超过 1700 开发者成为 Kubernetes 项目社区贡献者,全球有 500 多场沙龙。国内出现大量基于 Kubernetes 的创业公司。
    • 2020 年,Kubernetes 项目已经成为贡献者仅次于 Linux 项目的第二大开源项目。成为了业界容器编排的事实标准,各大厂商纷纷宣布支持 Kubernetes 作为容器编排的方案。

    三、kubernetes组成

    3.1 Master节点

    • Kube-APIServer:集群的控制中枢,各个模块之间信息交互都需要经过Kube-APIServer,同时它也是集群管理、资源配额、整个集群安全机制的入口。【信息交互,大脑】
    • Controller-Manager:集群的状态管理器,保证Pod或其他资源达到期望值,也是需要和APIServer进行通信,在需要的时候创建、更新或删除它所管理的资源。【资源管理,控制】
    • Scheduler:集群的调度中心,它会根据指定的一系列条件,选择一个或一批最佳的节点,然后部署我们的Pod。【资源分配,调度】
    • Etcd:键值数据库,保存一些集群的信息,一般生产环境中建议部署三个以上节点(奇数个)。【数据存储,存储】

    3.2 Node工作节点

       Worker、node节点、minion节点

    • Kubelet:负责监听节点上Pod的状态,同时负责上报节点和节点上面Pod的状态,负责与Master节点通信,并管理节点上面的Pod。
    • Kube-proxy:负责Pod之间的通信和负载均衡,将指定的流量分发到后端正确的机器上。

        查看Kube-proxy工作模式:curl 127.0.0.1:10249/proxyMode

         Ipvs:监听Master节点增加和删除service以及endpoint的消息,调用Netlink接口创建相应的IPVS规则。通过IPVS规则,将流量转发至相应的Pod上。

         Iptables:监听Master节点增加和删除service以及endpoint的消息,对于每一个Service,他都会创建一个iptables规则,将service的clusterIP代理到后端对应的Pod。

    3.3 其他组件

    • Calico:符合CNI标准的网络插件,给每个Pod生成一个唯一的IP地址,并且把每个节点当做一个路由器。最新Cilium插件,可关注
    • CoreDNS:用于Kubernetes集群内部Service的解析,可以让Pod把Service名称解析成IP地址,然后通过Service的IP地址进行连接到对应的应用上。
    • Docker:容器引擎,负责对容器的管理。

     

    四、Pod

    4.1 Pod是什么

    Pod是Kubernetes中最小的单元,它由一组、一个或多个容器组成,每个Pod还包含了一个Pause容器,Pause容器是Pod的父容器,主要负责僵尸进程的回收管理,通过Pause容器可以使同一个Pod里面的多个容器共享存储、网络、PID、IPC等。

    4.2 Pod定义

    apiVersion: v1 # 必选,API的版本号
    kind: Pod       # 必选,类型Pod
    metadata:       # 必选,元数据
      name: nginx   # 必选,符合RFC 1035规范的Pod名称
      namespace: default # 可选,Pod所在的命名空间,不指定默认为default,可以使用-n 指定namespace 
      labels:       # 可选,标签选择器,一般用于过滤和区分Pod
        app: nginx
        role: frontend # 可以写多个
      annotations:  # 可选,注释列表,可以写多个
        app: nginx  #格式要求不是很严格
    spec:   # 必选,用于定义容器的详细信息
      initContainers: # 初始化容器,在容器启动之前执行的一些初始化操作
      - command:
        - sh
        - -c
        - echo "I am InitContainer for init some configuration"
        image: busybox
        imagePullPolicy: IfNotPresent
        name: init-container
      containers:   # 必选,容器列表
      - name: nginx # 必选,符合RFC 1035规范的容器名称
        image: nginx:latest    # 必选,容器所用的镜像的地址
        imagePullPolicy: Always     # 可选,镜像拉取策略
        command: # 可选,容器启动执行的命令
        - nginx 
        - -g
        - "daemon off;"
        workingDir: /usr/share/nginx/html       # 可选,容器的工作目录
        volumeMounts:   # 可选,存储卷配置,可以配置多个
        - name: webroot # 存储卷名称
          mountPath: /usr/share/nginx/html # 挂载目录
          readOnly: true        # 只读
        ports:  # 可选,容器需要暴露的端口号列表
        - name: http    # 端口名称
          containerPort: 80     # 端口号
          protocol: TCP # 端口协议,默认TCP
        env:    # 可选,环境变量配置列表
        - name: TZ      # 变量名
          value: Asia/Shanghai # 变量的值
        - name: LANG
          value: en_US.utf8
        resources:      # 可选,资源限制和资源请求限制
          limits:       # 最大限制设置
            cpu: 1000m
            memory: 1024Mi
          requests:     # 启动所需的资源
            cpu: 100m
            memory: 512Mi
    #    startupProbe: # 可选,检测容器内进程是否完成启动。注意三种检查方式同时只能使用一种。
    #      httpGet:      # httpGet检测方式,生产环境建议使用httpGet实现接口级健康检查,健康检查由应用程序提供。
    #            path: /api/successStart # 检查路径
    #            port: 80
        readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。
          httpGet:      # httpGet检测方式,生产环境建议使用httpGet实现接口级健康检查,健康检查由应用程序提供。
                path: / # 检查路径
                port: 80        # 监控端口
        livenessProbe:  # 可选,健康检查
          #exec:        # 执行容器命令检测方式
                #command: 
                #- cat
                #- /health
        #httpGet:       # httpGet检测方式
        #   path: /_health # 检查路径
        #   port: 8080
        #   httpHeaders: # 检查的请求头
        #   - name: end-user
        #     value: Jason 
          tcpSocket:    # 端口检测方式
                port: 80
          initialDelaySeconds: 60       # 初始化时间
          timeoutSeconds: 2     # 超时时间
          periodSeconds: 5      # 检测间隔
          successThreshold: 1 # 检查成功为2次表示就绪
          failureThreshold: 2 # 检测失败1次表示未就绪
        lifecycle:
          postStart: # 容器创建完成后执行的指令, 可以是exec httpGet TCPSocket
            exec:
              command:
              - sh
              - -c
              - 'mkdir /data/ '
          preStop:
            httpGet:      
                  path: /
                  port: 80
          #  exec:
          #    command:
          #    - sh
          #    - -c
          #    - sleep 9
      restartPolicy: Always   # 可选,默认为Always
      #nodeSelector: # 可选,指定Node节点
      #      region: subnet7
      imagePullSecrets:     # 可选,拉取镜像使用的secret,可以配置多个
      - name: default-dockercfg-86258
      hostNetwork: false    # 可选,是否为主机模式,如是,会占用主机端口
      volumes:      # 共享存储卷列表
      - name: webroot # 名称,与上述对应
        emptyDir: {}    # 挂载目录
            #hostPath:              # 挂载本机目录
            #  path: /etc/hosts
    
    

     

    4.3  零宕机必备之Pod探针

    • StartupProbe:k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动。如果配置了startupProbe,就会先禁止其他的探测,直到它成功为止,成功后将不在进行探测。【判断容器内的程序是否正常提供服务】
    • LivenessProbe:用于探测容器是否运行,如果探测失败,kubelet会根据配置的重启策略进行相应的处理。若没有配置该探针,默认就是success。【判断容器是否运行】
    • ReadinessProbe:一般用于探测容器内的程序是否健康,它的返回值如果为success,那么久代表这个容器已经完成启动,并且程序已经是可以接受流量的状态。【判断容器内的程序是否健康】

    4.3.1 Pod探针的检测方式

    • ExecAction:在容器内执行一个命令,如果返回值为0,则认为容器健康。
    • TCPSocketAction:通过TCP连接检查容器内的端口是否是通的,如果是通的就认为容器健康。
    • HTTPGetAction:通过应用程序暴露的API地址来检查程序是否是正常的,如果状态码为200~400之间,则认为容器健康。

    4.3.2 探针使用场景

    • LivenessProbe探针

             如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活态探针; kubelet 将根据 Pod 的 restartPolicy 自动执行修复操作。

            如果你希望容器在探测失败时被杀死并重新启动,那么请指定一个存活态探针, 并指定 restartPolicy 为 "Always" 或 "OnFailure"。

    • ReadinessProbe探针

             如果要仅在探测成功时才开始向 Pod 发送请求流量,请指定就绪态探针。 在这种情况下,就绪态探针可能与存活态探针相同,但是规约中的就绪态探针的存在意味着 Pod 将在启动阶段不接收任何数据,并且只有在探针探测成功后才开始接收数据。

             如果你希望容器能够自行进入维护状态,也可以指定一个就绪态探针, 检查某个特定于就绪态的因此不同于存活态探测的端点。

            如果你的应用程序对后端服务有严格的依赖性,你可以同时实现存活态和就绪态探针。 当应用程序本身是健康的,存活态探针检测通过后,就绪态探针会额外检查每个所需的后端服务是否可用。 这可以帮助你避免将流量导向只能返回错误信息的 Pod。

            如果你的容器需要在启动期间加载大型数据、配置文件或执行迁移, 你可以使用启动探针。 然而,如果你想区分已经失败的应用和仍在处理其启动数据的应用,你可能更倾向于使用就绪探针。

    • StartupProbe探针

       对于所包含的容器需要较长时间才能启动就绪的 Pod 而言,启动探针是有用的。 你不再需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定, 对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长。

      如果你的容器启动时间通常超出 initialDelaySeconds + failureThreshold × periodSeconds 总值,你应该设置一个启动探测,对存活态探针所使用的同一端点执行检查。 periodSeconds 的默认值是 10 秒。你应该将其 failureThreshold 设置得足够高, 以

      便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值。 这一设置有助于减少死锁状况的发生。

     4.3.3 探针参数

    #      initialDelaySeconds: 60       # 初始化时间

    #      timeoutSeconds: 2     # 超时时间

    #      periodSeconds: 5      # 检测间隔

    #      successThreshold: 1 # 检查成功为1次表示就绪

    #      failureThreshold: 2 # 检测失败2次表示未就绪

    探针整体设计思路:

    由于有些程序可能启动时间比较长,所以新增了StartupProbe探针。一旦启用了StartupProbe探针,其他2个就禁用了,等StartupProbe探针检测完成后,再进行容器存活和容器ready检测。

    4.4 pod的退出流程

    pod退出的流程,当用户执行删除pod操作时:

    1、pod的状态变为terminating

    2、endpoint中删除改pod的ip

    3、执行prestop命令,进行pod退出前的一些清理操作

    优雅退出默认时间:30s

    terminationGracePeriodSeconds: 30

    如果我们希望更长,可以进行配置;或者命令行  kubectl delete pod nginx --grace-period=40

    4.5 pod实践

    定义一个pod

    apiVersion: v1 # 必选,API的版本号
    kind: Pod       # 必选,类型Pod
    metadata:       # 必选,元数据
      name: nginx   # 必选,符合RFC 1035规范的Pod名称
      namespace: default # 可选,Pod所在的命名空间,不指定默认为default,可以使用-n 指定namespace 
      labels:       # 可选,标签选择器,一般用于过滤和区分Pod
        app: nginx
        role: frontend # 可以写多个
      annotations:  # 可选,注释列表,可以写多个
        app: nginx
    spec:   # 必选,用于定义容器的详细信息
      containers:   # 必选,容器列表
      - name: nginx # 必选,符合RFC 1035规范的容器名称
        image: nginx:1.15.2    # 必选,容器所用的镜像的地址
        imagePullPolicy: IfNotPresent     # 可选,镜像拉取策略, IfNotPresent: 如果宿主机有这个镜像,那就不需要拉取了. Always: 总是拉取, Never: 不管是否存储都不拉去
        command: # 可选,容器启动执行的命令 ENTRYPOINT, arg --> cmd
        - nginx 
        - -g
        - "daemon off;"
        workingDir: /usr/share/nginx/html       # 可选,容器的工作目录
        ports:  # 可选,容器需要暴露的端口号列表
        - name: http    # 端口名称
          containerPort: 80     # 端口号
          protocol: TCP # 端口协议,默认TCP
        env:    # 可选,环境变量配置列表
        - name: TZ      # 变量名
          value: Asia/Shanghai # 变量的值
        - name: LANG
          value: en_US.utf8
          #exec:        # 执行容器命令检测方式
                #command: 
                #- cat
                #- /health
        startupProbe:
          tcpSocket:
            port: 80
    

     创建pod

    [root@k8s-master01 ~]# kubectl apply -f nginx-pod.yaml 
    pod/nginx created

     查看pod

    [root@k8s-master01 ~]# kubectl get pod
    NAME    READY   STATUS    RESTARTS   AGE
    nginx   1/1     Running   0          32s
    

      

    查看pod实时动态

    kubectl get pod -w
    

      

    五、RC和RS

    Replication Controller(复制控制器,RC)和ReplicaSet(复制集,RS)是两种简单部署Pod的方式。因为在生产环境中,主要使用更高级的Deployment等方式进行Pod的管理和部署,所以本节只对Replication Controller和Replica Set的部署方式进行简单介绍。

    5.1 Replication Controller

    Replication Controller(简称RC)可确保Pod副本数达到期望值,也就是RC定义的数量。换句话说,Replication Controller可确保一个Pod或一组同类Pod总是可用。

    如果存在的Pod大于设定的值,则Replication Controller将终止额外的Pod。如果太小,Replication Controller将启动更多的Pod用于保证达到期望值。与手动创建Pod不同的是,用Replication Controller维护的Pod在失败、删除或终止时会自动替换。因此即使应用程序只需要一个Pod,也应该使用Replication Controller或其他方式管理。Replication Controller类似于进程管理程序,但是Replication Controller不是监视单个节点上的各个进程,而是监视多个节点上的多个Pod。

    定义一个Replication Controller的示例如下。

    apiVersion: v1
    kind: ReplicationController
    metadata:
      name: nginx
    spec:
      replicas: 3
      selector:
        app: nginx
      template:
        metadata:
          name: nginx
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
    

      

    5.2 ReplicaSet

    ReplicaSet是支持基于集合的标签选择器的下一代Replication Controller,它主要用作Deployment协调创建、删除和更新Pod,和Replication Controller唯一的区别是,ReplicaSet支持标签选择器。在实际应用中,虽然ReplicaSet可以单独使用,但是一般建议使用Deployment来自动管理ReplicaSet,除非自定义的Pod不需要更新或有其他编排等。

    定义一个ReplicaSet的示例如下:

    apiVersion: apps/v1
    kind: ReplicaSet
    metadata:
      name: frontend
      labels:
        app: guestbook
        tier: frontend
    spec:
      # modify replicas according to your case
      replicas: 3
      selector:
        matchLabels:
          tier: frontend
        matchExpressions:
          - {key: tier, operator: In, values: [frontend]}
      template:
        metadata:
          labels:
            app: guestbook
            tier: frontend
        spec:
          containers:
          - name: php-redis
            image: gcr.io/google_samples/gb-frontend:v3
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            env:
            - name: GET_HOSTS_FROM
              value: dns
              # If your cluster config does not include a dns service, then to
              # instead access environment variables to find service host
              # info, comment out the 'value: dns' line above, and uncomment the
              # line below.
              # value: env
            ports:
            - containerPort: 80
    

      Replication Controller和ReplicaSet的创建删除和Pod并无太大区别,Replication Controller目前几乎已经不在生产环境中使用,ReplicaSet也很少单独被使用,都是使用更高级的资源Deployment、DaemonSet、StatefulSet进行管理Pod。

    六、Deployment

    用于部署无状态的服务,这个最常用的控制器。一般用于管理维护企业内部无状态的微服务,比如configserver、zuul、springboot。他可以管理多个副本的Pod实现无缝迁移、自动扩容缩容、自动灾难恢复、一键回滚等功能。

     

    6.1 创建一个Deployment

    手动创建:

    kubectl create deployment nginx --image=nginx:1.15.2
    

      

    从文件创建:

    # cat nginx-deploy.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        deployment.kubernetes.io/revision: "1"
      creationTimestamp: "2020-09-19T02:41:11Z"
      generation: 1
      labels:
        app: nginx
      name: nginx
      namespace: default
    spec:
      progressDeadlineSeconds: 600
      replicas: 2 #副本数
      revisionHistoryLimit: 10 # 历史记录保留的个数
      selector:
        matchLabels:
          app: nginx
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx:1.15.2
            imagePullPolicy: IfNotPresent
            name: nginx
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    

     
    从文件创建:

    kubelet apply -f nginx-deploy.yaml
    

      

    查看deployment

    [root@k8s-master01 ~/k8s]# kubectl get deploy -o wide
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
    nginx   2/2     2            2           3m42s   nginx        nginx:1.15.2   app=nginx
    
    • NAME: Deployment名称
    • READY:Pod的状态,已经Ready的个数
    • UP-TO-DATE:已经达到期望状态的被更新的副本数
    • AVAILABLE:已经可以用的副本数
    • AGE:显示应用程序运行的时间
    • CONTAINERS:容器名称
    • IMAGES:容器的镜像
    • SELECTOR:管理的Pod的标签

      

    可以直接通过修改replicas数量来动态调整pod的数量,pod创建后,不可动态修改labels,需要删掉pod后,重建pod才行。

    6.2 Deployment的更新

    更改deployment的镜像并记录:

    kubectl set image deploy nginx nginx=nginx:1.15.3 –record
    

      

    查看更新过程:

    # kubectl rollout status deploy nginx
    deployment "nginx" successfully rolled out
    [root@k8s-master01 ~]# kubectl rollout status deploy nginx
    Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated...
    Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated...
    Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated...
    Waiting for deployment "nginx" rollout to finish: 1 old replicas are pending termination...
    Waiting for deployment "nginx" rollout to finish: 1 old replicas are pending termination...
    deployment "nginx" successfully rolled out
    

      

    或者使用describe查看:

    # kubectl describe deploy nginx  
    Normal  ScalingReplicaSet  25m                  deployment-controller  Scaled up replica set nginx-66bbc9fdc5 to 1
      Normal  ScalingReplicaSet  18m (x2 over 23m)    deployment-controller  Scaled up replica set nginx-66bbc9fdc5 to 2
      Normal  ScalingReplicaSet  7m7s                 deployment-controller  Scaled up replica set nginx-5dfc8689c6 to 1
      Normal  ScalingReplicaSet  6m28s (x2 over 23m)  deployment-controller  Scaled down replica set nginx-66bbc9fdc5 to 1
      Normal  ScalingReplicaSet  6m27s                deployment-controller  Scaled up replica set nginx-5dfc8689c6 to 2
      Normal  ScalingReplicaSet  5m58s                deployment-controller  Scaled down replica set nginx-66bbc9fdc5 to 0
      Normal  ScalingReplicaSet  4m19s                deployment-controller  Scaled up replica set nginx-6cdd5dd489 to 1
      Normal  ScalingReplicaSet  3m44s                deployment-controller  Scaled down replica set nginx-5dfc8689c6 to 1
      Normal  ScalingReplicaSet  3m44s                deployment-controller  Scaled up replica set nginx-6cdd5dd489 to 2
      Normal  ScalingReplicaSet  3m6s                 deployment-controller  Scaled down replica set nginx-5dfc8689c6 to 0
    

      

     

    6.3  Deployment的回滚

    # 执行更新操作

    模拟操作一个不存在或者错误的镜像:

    [root@k8s-master01 ~]# kubectl set image deploy nginx nginx=nginx:787977da --record
    deployment.apps/nginx image updated
    [root@k8s-master01 ~]# kubectl get po 
    NAME                     READY   STATUS              RESTARTS   AGE
    nginx-6cdd5dd489-lv28z   1/1     Running             0          7m12s
    nginx-6cdd5dd489-nqqz7   1/1     Running             0          6m37s
    nginx-7d79b96f68-x7t67   0/1     ContainerCreating   0          19s
    

      

    查看历史版本

    [root@k8s-master01 ~]# kubectl rollout history deploy nginx
    deployment.apps/nginx 
    REVISION  CHANGE-CAUSE
    1         <none>
    2         kubectl set image deploy nginx nginx=nginx:1.15.3 --record=true
    3         kubectl set image deploy nginx nginx=nginx:1.15.4 --record=true
    4         kubectl set image deploy nginx nginx=nginx:787977da --record=true
    

      

    回滚到上一个版本

    [root@k8s-master01 ~]# kubectl rollout undo deploy nginx 
    deployment.apps/nginx rolled back
    

      

    查看回滚结果

    [root@k8s-master01 ~]# kubectl get po
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-6cdd5dd489-lv28z   1/1     Running   0          9m8s
    nginx-6cdd5dd489-nqqz7   1/1     Running   0          8m33s
    [root@k8s-master01 ~]# kubectl get deploy nginx -oyaml | grep nginx
        kubernetes.io/change-cause: kubectl set image deploy nginx nginx=nginx:1.15.4
        app: nginx
                  k:{"name":"nginx"}:
                  k:{"name":"nginx"}:
      name: nginx
      selfLink: /apis/apps/v1/namespaces/default/deployments/nginx
          app: nginx
            app: nginx
          - image: nginx:1.15.4
            name: nginx
        message: ReplicaSet "nginx-6cdd5dd489" has successfully progressed.
    

      

    进行多次更新

    [root@k8s-master01 ~]# kubectl set image deploy nginx nginx=nginx:787977da --record
    deployment.apps/nginx image updated
    [root@k8s-master01 ~]# kubectl set image deploy nginx nginx=nginx:787977dadaa --record
    deployment.apps/nginx image updated
    [root@k8s-master01 ~]# kubectl set image deploy nginx nginx=nginx:787977xxxxxdadaa --record
    deployment.apps/nginx image updated
    [root@k8s-master01 ~]# kubectl set image deploy nginx nginx=nginx:787977dadxxxxxdadaa --record
    deployment.apps/nginx image updated
    [root@k8s-master01 ~]# # 查看历史记录
    [root@k8s-master01 ~]# kubectl  rollout history deploy nginx
    deployment.apps/nginx 
    REVISION  CHANGE-CAUSE
    1         <none>
    2         kubectl set image deploy nginx nginx=nginx:1.15.3 --record=true
    5         kubectl set image deploy nginx nginx=nginx:1.15.4 --record=true
    6         kubectl set image deploy nginx nginx=nginx:787977da --record=true
    7         kubectl set image deploy nginx nginx=nginx:787977dadaa --record=true
    8         kubectl set image deploy nginx nginx=nginx:787977xxxxxdadaa --record=true
    9         kubectl set image deploy nginx nginx=nginx:787977dadxxxxxdadaa --record=true
    

      

    查看指定版本的详细信息

    [root@k8s-master01 ~]# kubectl rollout history deploy nginx --revision=5
    deployment.apps/nginx with revision #5
    Pod Template:
      Labels:	app=nginx
    	pod-template-hash=6cdd5dd489
      Annotations:	kubernetes.io/change-cause: kubectl set image deploy nginx nginx=nginx:1.15.4 --record=true
      Containers:
       nginx:
        Image:	nginx:1.15.4
        Port:	<none>
        Host Port:	<none>
        Environment:	<none>
        Mounts:	<none>
      Volumes:	<none>
    

      

    回滚到任意指定版本

    [root@k8s-master01 ~]# kubectl rollout undo deploy nginx --to-revision=5
    deployment.apps/nginx rolled back
    

      

    查看deploy状态

    [root@k8s-master01 ~]# kubectl get deploy -oyaml
    

      

    6.4  Deployment的暂停

    Deployment 暂停功能

    [root@k8s-master01 ~]# kubectl rollout pause deployment nginx 
    deployment.apps/nginx paused
    

      

    暂停后多次配置

    第一次配置

    修改deploy镜像

    [root@k8s-master01 ~]# kubectl set image deploy nginx nginx=nginx:1.15.3 --record
    deployment.apps/nginx image updated
    

    第二次配置  

    暂停后添加内存CPU配置

    [root@k8s-master01 ~]# kubectl set resources deploy nginx -c nginx --limits=cpu=200m,memory=128Mi --requests=cpu=10m,memory=16Mi
    deployment.apps/nginx resource requirements updated
    [root@k8s-master01 ~]# kubectl get deploy nginx -oyaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        deployment.kubernetes.io/revision: "11"
        kubernetes.io/change-cause: kubectl set image deploy nginx nginx=nginx:1.15.3
          --record=true
      creationTimestamp: "2020-09-19T02:41:11Z"
      generation: 18
      labels:
        app: nginx
      name: nginx
      namespace: default
      resourceVersion: "2660534"
      selfLink: /apis/apps/v1/namespaces/default/deployments/nginx
      uid: 1d9253a5-a36c-48cc-aefe-56f95967db66
    spec:
      paused: true
      progressDeadlineSeconds: 600
      replicas: 2
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: nginx
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx:1.15.3
            imagePullPolicy: IfNotPresent
            name: nginx
            resources:
              limits:
                cpu: 200m
                memory: 128Mi
              requests:
                cpu: 10m
                memory: 16Mi
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    status:
      availableReplicas: 2
      conditions:
      - lastTransitionTime: "2020-09-19T03:26:50Z"
        lastUpdateTime: "2020-09-19T03:26:50Z"
        message: Deployment has minimum availability.
        reason: MinimumReplicasAvailable
        status: "True"
        type: Available
      - lastTransitionTime: "2020-09-19T03:30:15Z"
        lastUpdateTime: "2020-09-19T03:30:15Z"
        message: Deployment is paused
        reason: DeploymentPaused
        status: Unknown
        type: Progressing
      observedGeneration: 18
      readyReplicas: 2
      replicas: 2
    

      

    查看pod是否被更新

    [root@k8s-master01 ~]# kubectl get po
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-6cdd5dd489-lv28z   1/1     Running   0          30m
    nginx-6cdd5dd489-nqqz7   1/1     Running   0          30m
    

      

    6.5  Deployment的恢复

    [root@k8s-master01 ~]# kubectl rollout resume deploy nginx 
    deployment.apps/nginx resumed
    [root@k8s-master01 ~]# kubectl get rs
    NAME               DESIRED   CURRENT   READY   AGE
    nginx-5475c49ffb   0         0         0       21m
    nginx-5dfc8689c6   0         0         0       33m
    nginx-66bbc9fdc5   0         0         0       52m
    nginx-68db656dd8   1         1         0       15s
    nginx-6cdd5dd489   2         2         2       31m
    nginx-799b8478d4   0         0         0       21m
    nginx-7d79b96f68   0         0         0       24m
    nginx-f974656f7    0         0         0       21m
    

      

    6.6  Deployment的扩缩容

    kubectl scale --replicas=1 deploy nginx
    

      扩缩容不会增加rs,因为他只是增加或减少某个rs下的pod数量。

    6.7  Deployment的配置项

    • .spec.revisionHistoryLimit:设置保留RS旧的revision的个数,设置为0的话,不保留历史数据
    • .spec.minReadySeconds:可选参数,指定新创建的Pod在没有任何容器崩溃的情况下视为Ready最小的秒数,默认为0,即一旦被创建就视为可用。

    滚动更新的策略:

    .spec.strategy.type:更新deployment的方式,默认是RollingUpdate

    • RollingUpdate:滚动更新,可以指定maxSurge和maxUnavailable

         maxUnavailable:指定在回滚或更新时最大不可用的Pod的数量,可选字段,默认25%,可以设置成数字或百分比,如果该值为0,那么maxSurge就不能0。

        maxSurge:可以超过期望值的最大Pod数,可选字段,默认为25%,可以设置成数字或百分比,如果该值为0,那么maxUnavailable不能为0

        假如副本4个,如果最大不可用设置成0,最大期望也是0,那就没法滚动了。最大不可用至少为1,最大期望值可以是0或者以上的值,才能进行滚动;

        同理,最大期望如果设置成0,则最大不可用至少必须设置1,才能进行滚动。

    •  Recreate:重建,先删除旧的Pod,再创建新的Pod

    七、StatefulSet

    StatefulSet(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余Spring Boot应用可以直接通过Eureka的Headless Service即可进行注册。

    Eureka的statefulset的资源名称是eureka,eureka-0 eureka-1 eureka-2
    
    Service:headless service,没有ClusterIP eureka-svc
    
    Eureka-0.eureka-svc.NAMESPACE_NAME  
    eureka-1.eureka-svc.NAMESPACE_NAME
    eureka-N-1.eureka-svc......
    

      

      

    7.1  StatefulSet的基本概念

    StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。

    和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod。不同的是,StatefulSet为每个Pod维护了一个粘性标识。这些Pod是根据相同的规范创建的,但是不可互换,每个Pod都有一个持久的标识符,在重新调度时也会保留,一般格式为StatefulSetName-Number。比如定义一个名字是Redis-Sentinel的StatefulSet,指定创建三个Pod,那么创建出来的Pod名字就为Redis-Sentinel-0、Redis-Sentinel-1、Redis-Sentinel-2。而StatefulSet创建的Pod一般使用Headless Service(无头服务)进行通信,和普通的Service的区别在于Headless Service没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为:

    statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local。

    说明:

    • serviceName为Headless Service的名字,创建StatefulSet时,必须指定Headless Service名称;
    • 0..N-1为Pod所在的序号,从0开始到N-1;
    • statefulSetName为StatefulSet的名字;
    • namespace为服务所在的命名空间;
    • .cluster.local为Cluster Domain(集群域)。

    假如公司某个项目需要在Kubernetes中部署一个主从模式的Redis,此时使用StatefulSet部署就极为合适,因为StatefulSet启动时,只有当前一个容器完全启动时,后一个容器才会被调度,并且每个容器的标识符是固定的,那么就可以通过标识符来断定当前Pod的角色。

    比如用一个名为redis-ms的StatefulSet部署主从架构的Redis,第一个容器启动时,它的标识符为redis-ms-0,并且Pod内主机名也为redis-ms-0,此时就可以根据主机名来判断,当主机名为redis-ms-0的容器作为Redis的主节点,其余从节点,那么Slave连接Master主机配置就可以使用不会更改的Master的Headless Service,此时Redis从节点(Slave)配置文件如下:

    port 6379
    
    slaveof redis-ms-0.redis-ms.public-service.svc.cluster.local 6379
    
    tcp-backlog 511
    
    timeout 0
    
    tcp-keepalive 0
    
    ……
    

      

    其中redis-ms-0.redis-ms.public-service.svc.cluster.local是Redis Master的Headless Service,在同一命名空间下只需要写redis-ms-0.redis-ms即可,后面的public-service.svc.cluster.local可以省略

    7.2   StatefulSet注意事项

    一般StatefulSet用于有以下一个或者多个需求的应用程序:

    • 需要稳定的独一无二的网络标识符。
    • 需要持久化数据。
    • 需要有序的、优雅的部署和扩展。
    • 需要有序的自动滚动更新。

    StatefulSet注意事项

    • 如果应用程序不需要任何稳定的标识符或者有序的部署、删除或者扩展,应该使用无状态的控制器部署应用程序,比如Deployment或者ReplicaSet。
    • StatefulSet是Kubernetes 1.9版本之前的beta资源,在1.5版本之前的任何Kubernetes版本都没有。
    • Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配置,当然也可以不配置存储。
    • 为了确保数据安全,删除和缩放StatefulSet不会删除与StatefulSet关联的卷,可以手动选择性地删除PVC和PV(关于PV和PVC请参考2.2.12节)。
    • StatefulSet目前使用Headless Service(无头服务)负责Pod的网络身份和通信,需要提前创建此服务。
    • 删除一个StatefulSet时,不保证对Pod的终止,要在StatefulSet中实现Pod的有序和正常终止,可以在删除之前将StatefulSet的副本缩减为0。

    7.3 创建一个StatefulSet

    [root@k8s-master01 ~/k8s]# cat nginx-sts.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      serviceName: "nginx"
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.15.2
            ports:
            - containerPort: 80
              name: web
    

      

    创建statefulset

    [root@k8s-master01 ~/k8s]# kubectl apply -f nginx-sts.yaml 
    service/nginx created
    statefulset.apps/web created
    

      

    查看statefulset的svc

    web-1                    1/1     Running   0          10s
    [root@k8s-master01 ~/k8s]# kubectl get svc
    NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   192.168.0.1   <none>        443/TCP   21d
    nginx        ClusterIP   None          <none>        80/TCP    18s
    

      新创建的statefulset的svc是一个无头服务,也就是他没有ep,直接可以通过svc进行访问服务,这样就少了一层代理。

    我们直接通过服务访问后端pod,启动一个busybox:

    cat<<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: busybox
      namespace: default
    spec:
      containers:
      - name: busybox
        image: busybox:1.28
        command:
          - sleep
          - "3600"
        imagePullPolicy: IfNotPresent
      restartPolicy: Always
    EOF
    

      

    对服务进程访问

    [root@k8s-master01 ~/k8s]# kubectl get pods -owide
    NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
    busybox                  1/1     Running   0          38s     172.17.125.14    k8s-node01     <none>           <none>
    nginx                    1/1     Running   0          120m    172.25.244.200   k8s-master01   <none>           <none>
    nginx-5dfc8689c6-bdxk7   1/1     Running   0          65m     172.27.14.195    k8s-node02     <none>           <none>
    web-0                    1/1     Running   0          3m53s   172.25.92.71     k8s-master02   <none>           <none>
    web-1                    1/1     Running   0          3m52s   172.17.125.13    k8s-node01     <none>           <none>
    [root@k8s-master01 ~/k8s]# kubectl exec -it busybox sh
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
    / # ping web-0.nginx.default
    PING web-0.nginx.default (172.25.92.71): 56 data bytes
    64 bytes from 172.25.92.71: seq=0 ttl=62 time=0.244 ms
    

      可以看到,我们通过statefulset-name-0.svc-name.namespace.svc.cluster.local进行服务访问。

    7.4 statefulset特征

    1、启动的时候,一定是web-0启动成功后,才会启动web-1;同样,删除的时候,是从最后一个开始删,删除最后一个后,再删除倒数第二个。

    7.5 statfulset更新

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      annotations:
      name: web
      namespace: default
    spec:
      replicas: 2
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: nginx
      serviceName: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx:1.15.2
            imagePullPolicy: IfNotPresent
            name: nginx
            ports:
            - containerPort: 80
              name: web
              protocol: TCP
            resources: 
              limits:
                cpu: 1000m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 10Mi
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
      updateStrategy:
        rollingUpdate:
          partition: 0
        type: RollingUpdate
    

      更新策略:滚动更新

    7.6 statfulset灰度发布

     partition参数设置
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      annotations:
      name: web
      namespace: default
    spec:
      replicas: 5
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: nginx
      serviceName: nginx
      template:
        metadata:
          labels:
            app: nginx
            type: statefulset
        spec:
          containers:
          - image: nginx:1.15.2
            imagePullPolicy: IfNotPresent
            name: nginx
            ports:
            - containerPort: 80
              name: web
              protocol: TCP
            resources: 
              limits:
                cpu: 1000m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 10Mi
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
      updateStrategy:
        rollingUpdate:
          partition: 3  # 从第三个pod开始更新
        type: RollingUpdate
    

      

    7.7 statfulset删除和级联删除

     级联删除:删除statefulset的同时删除pod(默认)

    kubectl delete sts web
    

      

    非级联删除:删除statefulset的同时不删除pod

    kubectl delete sts web --cascade=false
    

      这样删除会出现孤儿pod,即pod无法管理了,删除pod后就没了。

    7.8 statfulset更新和回滚

    statefulset更新:

    kubectl set image sts web nginx=nginx:1.15.1 --record=true
    

      

    statefulset回滚:

    #查看历史版本
    kubectl rollout history sts web
    #回滚到上一个版本
    kubectl rollout undo sts web
    

      

     statefulset回滚到任意指定版本:

    #查看历史版本
    kubectl rollout history sts web
    
    #查看当前镜像
    kubectl get pods -l type=statefulset -o yaml|grep image
    
    #回滚到指定版本
    kubectl rollout undo sts web --to-revision=14
    
    #查看当前镜像
    kubectl get pods -l type=statefulset -o yaml|grep image
    

      

    九、DaemoSet

    9.1 DaemonSet是什么?

    DaemonSet:守护进程集,缩写为ds,在所有节点或者是匹配的节点上都部署一个Pod。

    使用DaemonSet的场景

    • 运行集群存储的daemon,比如ceph或者glusterd
    • 节点的CNI网络插件,calico
    • 节点日志的收集:fluentd或者是filebeat
    • 节点的监控:node exporter
    • 服务暴露:部署一个ingress nginx

    9.2 定义一个DaemonSet

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      annotations:
      name: web
      namespace: default
    spec:
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          nodeSelector:
            ds: "true" 
          containers:
          - image: nginx:1.15.2
            imagePullPolicy: IfNotPresent
            name: nginx
            ports:
            - containerPort: 80
              name: web
              protocol: TCP
            resources: 
              limits:
                cpu: 1000m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 10Mi
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    

      其中:nodeSelector用于节点选择。

    kubectl label node k8s-node01 ds=true
    

      

    节点打上标签后就会在上面创建对应的pod。

     

    9.3 DaemonSet更新和回滚

     Daemonset更新

      Daemonset回滚

    9.4 DaemonSet更新策略

    #滚动更新 
    updateStrategy:
          rollingUpdate:
            maxSurge: 0
            maxUnavailable: 1
          type: RollingUpdate 
    
    
    #即使删除
     updateStrategy:
          rollingUpdate:
            maxSurge: 0
            maxUnavailable: 1
          type: OnDelete
    

      建议使用OnDelete方式,删除某个pod后,进行更新,查看没问题后,全部更新。【灰度更新方式】

    十、HPA(水平pod扩缩容)

     

    10.1 HPA实践

    DaemonSet无法自动扩缩容,他的初衷就是每个node部署一个。

    1、创建deloyment

    kubectl create deployment nginx-server-hpa  --image=nginx:1.15.2 --port=80 --dry-run=client -o yaml>hpa-deloy.yaml
    

      

    2、增加reources

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-server-hpa
      name: nginx-server-hpa
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx-server-hpa
      strategy: {}
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx-server-hpa
        spec:
          containers:
          - image: nginx:1.15.2
            name: nginx
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 10m
    status: {}
    

      

    3、暴露服务

    [root@k8s-master01 ~/k8s]# kubectl expose deployment nginx-server-hpa --port=80
    service/nginx-server-hpa exposed
    

      

    4、查看服务并访问

    [root@k8s-master01 ~/k8s]# kubectl get svc
    NAME               TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
    kubernetes         ClusterIP   192.168.0.1       <none>        443/TCP   24d
    nginx              ClusterIP   None              <none>        80/TCP    2d13h
    nginx-server-hpa   ClusterIP   192.168.166.198   <none>        80/TCP    5s
    

      

     5、创建hpa

    [root@k8s-master01 ~/k8s]# kubectl autoscale deployment nginx-server-hpa --cpu-percent=10 --min=1 --max=10
    horizontalpodautoscaler.autoscaling/nginx-server-hpa autoscaled
    

      

    查看hpa

    [root@k8s-master01 ~/k8s]# kubectl get hpa
    NAME               REFERENCE                     TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
    nginx-server-hpa   Deployment/nginx-server-hpa   <unknown>/10%   1         10        0          6s
    

      

    再次查看

    [root@k8s-master01 ~/k8s]# kubectl get hpa
    NAME               REFERENCE                     TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    nginx-server-hpa   Deployment/nginx-server-hpa   0%/10%    1         10        1          78s
    

      

     

    10.2 HPA注意事项

    注意事项:
    1、必须安装metrics-server或其他自定义metrics-server
    2、必须配置requests参数
    3、不能扩容无法缩放的对象,比如DaemonSet
    4、要考虑压力的根本原因,假如是后端的瓶颈,我们扩容front,是没有作用的。
          此时,需要后端提供压力接口才能进行扩缩容。
    

      

     十一、服务发布

    11.1 label和selector

    Label:对k8s中各种资源进行分类、分组,添加一个具有特别属性的一个标签。

    Selector:通过一个过滤的语法进行查找到对应标签的资源

    11.2 label操作

    #创建标签
     kubectl label pods nginx unhealthy=true
    
    #修改标签
    kubectl label --overwrite pods nginx status=unhealthy
    
    #删除标签
    kubectl label pods nginx app-
    
    #过滤资源
     kubectl get pods -l 'app in (nginx,nginx-server-hpa)' -owide --show-labels
    
     kubectl get pods -l 'app in (nginx,nginx-server-hpa)',controller-revision-hash!=web-cdd4c789b -owide --show-labels
    

      

    11.3 service

    在k8s中,service用于东西流量的实现,而南北流量则是通过ingress实现。

    11.3.1 service定义

    Service可以简单的理解为逻辑上的一组Pod。一种可以访问Pod的策略,而且其他Pod可以通过这个Service访问到这个Service代理的Pod。相对于Pod而言,它会有一个固定的名称,一旦创建就固定不变。

    service创建后,同时会创建一个同名的EP(endpoint),也就是podIP:port的记录,记录了service调度到后端的信息。

    11.3.2 创建一个service

    # cat nginx-svc.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: nginx-svc
      name: nginx-svc
    spec:
      ports:
      - name: http # Service端口的名称
        port: 80 # Service自己的端口, servicea --> serviceb http://serviceb,  http://serviceb:8080 
        protocol: TCP # UDP TCP SCTP default: TCP
        targetPort: 80 # 后端应用的端口
      - name: https
        port: 443
        protocol: TCP
        targetPort: 443
      selector:
        app: nginx
      sessionAffinity: None
      type: ClusterIP
    

      

    11.3.3 为什么要有service?

    访问服务时,我们可以通过svc直接访问后端的pod,因为pod经常创建和删除,为了保证服务一直连接,而不关心后端pod,所以引进了svc。

    service  ==> endpoint  ==> pod

     

    11.3.4 使用Service代理k8s外部应用

    使用场景:

    • 希望在生产环境中使用某个固定的名称而非IP地址进行访问外部的中间件服务
    • 希望Service指向另一个Namespace中或其他集群中的服务
    • 某个项目正在迁移至k8s集群,但是一部分服务仍然在集群外部,此时可以使用service代理至k8s集群外部的服务

     通过service反代外部服务,我们可以统一配置文件,即使从外部迁移到容器内部,也不需要修改配置文件,只需要修改EP的地址!非常方便。

    # cat nginx-svc-external.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: nginx-svc-external
      name: nginx-svc-external
    spec:
      ports:
      - name: http # Service端口的名称
        port: 80 # Service自己的端口, servicea --> serviceb http://serviceb,  http://serviceb:8080 
        protocol: TCP # UDP TCP SCTP default: TCP
        targetPort: 8081 # 后端应用的端口
      sessionAffinity: None
      type: ClusterIP
    
    #创建好了svc后,ep不会自动创建,需要我们手动创建一个ep,指向后端代理的服务。我们这里使用baidu的地址来测试。
    # cat nginx-ep-external.yaml 
    apiVersion: v1
    kind: Endpoints
    metadata:
      labels:
        app: nginx-svc-external
      name: nginx-svc-external
      namespace: default
    subsets:
    - addresses:
      - ip: 140.205.94.189 
      ports:
      - name: http
        port: 8081
        protocol: TCP
    

      

    测试:

    11.3.5 使用Service代理域名

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: nginx-externalname
      name: nginx-externalname
    spec:
      type: ExternalName
      externalName: www.baidu.com
    

      注意:说明: ExternalName 服务接受 IPv4 地址字符串,但作为包含数字的 DNS 名称,而不是 IP 地址。实测下来,这里使用IP地址不行

    11.3.6 service的常见类型

    • ClusterIP:在集群内部使用,也是默认值。
    • ExternalName:通过返回定义的CNAME别名。一定要使用域名!
    • NodePort:在所有安装了kube-proxy的节点上打开一个端口,此端口可以代理至后端Pod,然后集群外部可以使用节点的IP地址和NodePort的端口号访问到集群Pod的服务。NodePort端口范围默认是30000-32767。
    • LoadBalancer:使用云提供商的负载均衡器公开服务。

    11.4 Ingress

    11.4.1 Ingress安装

    通俗来讲,ingress和之前提到的Service、Deployment,也是一个k8s的资源类型,ingress用于实现用域名的方式访问k8s内部应用。

    首先安装helm管理工具:https://helm.sh/docs/intro/install/

    使用helm安装ingress:https://kubernetes.github.io/ingress-nginx/deploy/#using-helm

    添加ingress的helm仓库(课程讲解的版本已经上传至百度网盘)

    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

    下载ingress的helm包至本地

    helm pull ingress-nginx/ingress-nginx

    tar xf ingress-nginx-3.6.0.tgz
    
    cd ingress-nginx
    
    vim values.yaml
    

     

    更改对应的配置

    • a) Controller和admissionWebhook的镜像地址,需要将公网镜像同步至公司内网镜像仓库(和课程不一致的版本,需要自行同步gcr镜像的,可以百度查一下使用阿里云同步gcr的镜像,也可以参考这个连接https://blog.csdn.net/weixin_39961559/article/details/80739352,或者参考这个连接: https://blog.csdn.net/sinat_35543900/article/details/103290782)
    • b) hostNetwork设置为true
    • c)  dnsPolicy设置为 ClusterFirstWithHostNet
    • d)  NodeSelector添加ingress: "true"部署至指定节点
    • e)  类型更改为kind: DaemonSet

    部署ingress

    给需要部署ingress的节点上打标签

    kubectl label node k8s-master03 ingress=true
    
    kubectl create ns ingress-nginx
    
    helm install ingress-nginx -n ingress-nginx .
    

      

    1. 将ingress controller部署至Node节点(ingress controller不能部署在master节点,需要安装视频中的步骤将ingress controller部署至Node节点,生产环境最少三个ingress controller,并且最好是独立的节点)

    kubectl label node k8s-node01 ingress=true

    kubectl label node k8s-master03 ingress-

    11.4.2 Ingress入门使用

    apiVersion: networking.k8s.io/v1beta1 # networking.k8s.io/v1 / extensions/v1beta1 
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.class: "nginx"
      name: example
    spec:
      rules: # 一个Ingress可以配置多个rules
      - host: foo.bar.com # 域名配置,可以不写,匹配*, *.bar.com
        http:
          paths: # 相当于nginx的location配合,同一个host可以配置多个path / /abc
          - backend:
              serviceName: nginx-svc
              servicePort: 80
            path: /
      - host: foo2.bar.com # 域名配置,可以不写,匹配*, *.bar.com
        http:
          paths: # 相当于nginx的location配合,同一个host可以配置多个path / /abc
          - backend:
              serviceName: nginx-externalname
              servicePort: 80
            path: /test
    

      

    说明:

    • 配置了2个主机,一个后端服务是nginx-svc,另一个后端服务是nginx-externalname
    • 确保后端服务都是可用的
    • 本地测试,在本机上写hosts,hosts为ingress的主机ip
    #ingress-nginx所在机器的ip
    10.10.2.129 foo.bar.com 10.10.2.129 foo2.bar.com

      

    验证:

    集群级别的资源,没有命名空间隔离。

    classrole

    classrolebinding

    storageclass

    ingressclass


  • 相关阅读:
    使用Optioanl优雅的处理空值
    综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列
    Nginx 相关介绍
    在Intellij IDEA中使用Debug
    关于Spring的BeanUtils
    MySQL 索引总结
    java中值传递和引用传递
    SQL易错锦集
    Java和SQL取两个字符间的值
    好文章收藏--五分钟理解一致性哈希算法(consistent hashing)
  • 原文地址:https://www.cnblogs.com/skyflask/p/16787704.html
Copyright © 2020-2023  润新知