k8s入门篇-资源管理

作者:@skyflask
转载本文请注明出处:https://www.cnblogs.com/skyflask/p/16787704.html


目录

Kubernetes入门
一、为什么需要Kubernetes
1.1 传统的容器编排痛点
1.2 Kubernetes 能解决的问题
1.3 什么时候使用 Kubernetes?
1.4 什么时候不适合使用 Kubernetes
二、Kubernetes的发展
三、kubernetes组成
3.1 Master节点
3.2 Node工作节点
3.3 其他组件
四、Pod
4.1 Pod是什么
4.2 Pod定义
4.3  零宕机必备之Pod探针
4.4 pod的退出流程
4.5 pod实践
五、RC和RS
5.1 Replication Controller
5.2 ReplicaSet
六、Deployment
6.1 创建一个Deployment
6.2 Deployment的更新
6.3  Deployment的回滚
6.4  Deployment的暂停
6.5  Deployment的恢复
6.6  Deployment的扩缩容
6.7  Deployment的配置项
七、StatefulSet
7.1  StatefulSet的基本概念
7.2   StatefulSet注意事项
7.3 创建一个StatefulSet
7.4 statefulset特征
7.5 statfulset更新
7.6 statfulset灰度发布
7.7 statfulset删除和级联删除
7.8 statfulset更新和回滚
九、DaemoSet
9.1 DaemonSet是什么?
9.2 定义一个DaemonSet
9.3 DaemonSet更新和回滚
9.4 DaemonSet更新策略
十、HPA(水平pod扩缩容)
10.1 HPA实践
10.2 HPA注意事项
 十一、服务发布
11.1 label和selector
11.2 label操作
11.3 service
11.4 Ingress

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定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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

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

 查看pod

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

  

查看pod实时动态

1
kubectl get pod -w<br>kubectl

  

五、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的示例如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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

手动创建:

1
kubectl create deployment nginx --image=nginx:1.15.2

  

从文件创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 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

 
从文件创建:

1
kubelet apply -f nginx-deploy.yaml

  

查看deployment

1
2
3
[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的镜像并记录:

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

  

查看更新过程:

1
2
3
4
5
6
7
8
9
# 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查看:

1
2
3
4
5
6
7
8
9
10
11
# 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的回滚

# 执行更新操作

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

1
2
3
4
5
6
7
[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

  

查看历史版本

1
2
3
4
5
6
7
[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

  

回滚到上一个版本

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

  

查看回滚结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[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.

  

进行多次更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[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

  

查看指定版本的详细信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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>

  

回滚到任意指定版本

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

  

查看deploy状态

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

  

 

6.4  Deployment的暂停

Deployment 暂停功能

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

  

暂停后多次配置

第一次配置

修改deploy镜像

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

 

第二次配置  

暂停后添加内存CPU配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
[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是否被更新

1
2
3
4
[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的恢复

1
2
3
4
5
6
7
8
9
10
11
12
[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的扩缩容

1
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即可进行注册。

1
2
3
4
5
6
7
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)配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[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

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

  

查看statefulset的svc

1
2
3
4
5
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

  

对服务进程访问

1
2
3
4
5
6
7
8
9
10
11
12
[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更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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灰度发布

1
partition参数设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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(默认)

1
kubectl delete sts web

  

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

1
kubectl delete sts web --cascade=false

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

 

7.8 statfulset更新和回滚

statefulset更新:

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

  

 

statefulset回滚:

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

  

 

 

 statefulset回滚到任意指定版本:

1
2
3
4
5
6
7
8
9
10
11
#查看历史版本
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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用于节点选择。

1
kubectl label node k8s-node01 ds=true

  

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

 

 

 

9.3 DaemonSet更新和回滚

 Daemonset更新

 

 

  Daemonset回滚

 

 

9.4 DaemonSet更新策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#滚动更新
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

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

  

2、增加reources

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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、暴露服务

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

  

4、查看服务并访问

1
2
3
4
5
[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

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

  

查看hpa

1
2
3
[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

  

再次查看

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

  

 十一、服务发布

11.1 label和selector

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

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

 

11.2 label操作

1
2
3
4
5
6
7
8
9
10
11
12
13
#创建标签
 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 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的地址!非常方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 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代理域名

1
2
3
4
5
6
7
8
9
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

 

1
2
3
4
5
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的节点上打标签

1
2
3
4
5
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入门使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
1
2
#ingress-nginx所在机器的ip<br>10.10.2.129 foo.bar.com
10.10.2.129 foo2.bar.com

  

验证:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

classrole

classrolebinding

storageclass

ingressclass


posted @   skyflask  阅读(78)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示