1 为什么有这样的设计

  1. 假设你需要固定数量的pod 运行,如果某个 Pod 失效或被删除,你想要自动创建新的 Pod 来替代,从而保持应用程序的高可用性
  2. 假如你想要滚动更新, 想平滑地更新应用程序的副本. 需要它可以控制旧 Pod 和新 Pod 的并行运行数量,以及更新的速率,从而避免应用程序的中断或过载

2 ReplicationController

Warning

已经不推荐用, 推荐使用 ReplicaSet

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

3 ReplicaSet(RS)

Tip
  • RS确保任何时间都有指定数量的 Pod 副本在运行
  • 一般不会单独去用的

官方文档

3.1 创建

kubectl explain rs # ReplicaSet可以简写为rs
# 我们发现 rs 内部有个模板属性,看下里面的,其实就是pod的属性
# pod 模板对象
kubectl explain rs.spec.template

kubectl api-resources |grep ReplicaSet
rs-nginx.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-nginx
spec:
1  replicas: 2
2  selector:
     matchLabels:
       app: rs-pod
3  template:
    metadata:
      labels:
4        app: rs-pod
    spec:
5      restartPolicy: Always
      containers:
      - name: c-nginx
        image: nginx:1.14.2
        ports:
        - name: http
          containerPort: 80
1
创建几个pod资源,2个都是按照下面设置的模板template来创建的,如果没有设置,默认就是1
2
使用什么样的标签 来选择 pod呢,符合这样的标签的pod 都会被rs所管理
3
定义pod的模板
4
这里定义的标签一定要和 上面selector定义的matchlabels一样
5
Always 唯一允许的取值,也是默认值
k create -f rs-nginx.yaml
k get rs -o wide
NAME       DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
rs-nginx   2         2         2       34s   c-nginx      nginx:1.14.2   app=rs-pod
k get po
rs-nginx-hn2jl       1/1     Running   0          7m21s
rs-nginx-xqznf       1/1     Running   0          7m21s
# ReplicaSet 的信息被pod设置在 metadata 的 ownerReferences 字段中
k get po rs-nginx-hn2jl -o yaml|grep ownerReferences -A 8 -B 10
# 我们删除其中一个pod 来看看
k delete pod rs-nginx-hn2jl
k get po # 发现 又重新创建了一个pod

3.2 脱离模板的pod

Tip

如果我们创建了符合rs 标签选择器的pod ,会如何呢?

  • 先创建rs ,后创建脱离模板的pod
pod-nginx-single-match-rs.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: rs-pod
  name: pod-nginx-single-match-rs
  namespace: default
spec:
  containers:
  - image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    name: c-nginx
    ports:
    - containerPort: 80
      name: http
      protocol: TCP
# 实时监控pod的创建情况
# 我们会发现 创建后会开始删除
k get po -w
Note

由于这些 Pod 没有控制器作为其属主引用(ownerReferences 属性),并且 其标签与 ReplicaSet 的选择算符匹配,它们会立即被该 ReplicaSet 获取, 但是该pod 会立即被 ReplicaSet 终止,因为 它们的存在会使得 ReplicaSet 中 Pod 个数超出其期望值

  • 先创建符合rs的pod, 再创建rs

会被rs 管理, rs根据你符合条件的pod数量,再看是否需要创建rs中模板的pod.

3.3 删除

# 只删除rs, 不删除pod
k delete --cascade=orphan -f rs-nginx.yaml

4 Deployment (deploy)

Tip
  • 一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力
  • 你负责描述 Deployment 中的 目标状态,而 Deployment 控制器(Controller)以受控速率更改实际状态, 使其变为期望状态
  • 无状态资源管理,最常用的控制器, 继承了rs,通过控制 replicaSet来控制管理pod
  • 什么叫无状态? 无状态指的是对于请求方的每个请求,接收方都当这次请求是第一次请求

官方文档

4.1 创建

k get deploy
# 这样可以导出 配置文件, 做些修改
k create deploy deploy-nginx \
  --image=nginx:1.14.2 \
  --dry-run=client -o yaml > deploy-nginx.yaml 
deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: pod-deploy-nginx
  template:
    metadata:
      labels:
        app: pod-deploy-nginx
    spec:
      containers:
      - name: c-deploy-nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
创建
k create -f deploy-nginx.yaml
k get deploy 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
deploy-nginx   3/3     3            3           15s
# 每个deploy 都会有一个rs控制器,来实际创建pod
k get rs
NAME                      DESIRED   CURRENT   READY   AGE
deploy-nginx-77d87b4b6c   3         3         3       2m34s 

4.2 更新

如何更新
  1. 假设我们deploy 管理着3个pod ,3个nginx pod 让用户访问, 负载均衡
  2. 现在我们要更新里面nginx 的版本
  3. 问题
    1. 因为只有好像只能有3个, 不能超过, 所以更新的时候先删除一个pod?
    2. 但是如果这个时候因为删除一个pod导致用户访问满载… 就有问题了
  4. 解决
    1. deploy 支持临时添加pod, 支持在滚动更新前,设置最多多几个(比如原来是3个,现在可以是4个),和最多少几个(比如原先3个,现在至少需要2个pod运行)
看一下创建的deploy的更新策略
# 我们yaml没有指定, 这里显示的就是默认的.
k get deployments.apps  deploy-nginx  -o yaml |grep strategy -A 5
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate

kubectl explain deploy.spec.strategy
更新策略
属性 值/子属性 描述
type Recreate
  • 这个策略就是先删除,再重建,设置这个值后 rollingUpdate属性无效了
RollingUpdate
  • 滚动更新,再去设置 设置 rollingUpdate属性
RollingUpdate maxSurge
  • 在更新期间,最多可以多几个可用
  • 比如原先3个,设置1,则表示最多可以有4个pod保持运
  • 原先3个,设置25%,就是能多4*25%也是1,如果不足1,当成1,也是表示最多可以有4个pod运行
maxUnavailable
  • 在更新期间,最多有几个不可用原先是5
  • 这里设置1,则表示至少需要有4个pod保持运行
# 直接修改 deploy 中pod使用的image
# --record 记录 会在 kubectl rollout history deployment demo-nginx 命令中显示,
# 会在 CHANGE-CAUSE 里显示 你的命令,否则显示none
# --record will be removed in the future ,未来会被移除
# pod-deploy-nginx 是模板中pod的名字 , nginx:1.9.1 是新的镜像名
kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.9.1 --record=true
#  annotations 里有kubernetes.io/change-cause 会显示为最新变更的原因
# 如果上面不加 --record 就不会记录新的,会显示旧的
k get deployments.apps deploy-nginx -o yaml|grep annotations -A 5 #(1)
  annotations:
    deployment.kubernetes.io/revision: "4"
    kubernetes.io/change-cause: kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.9.1
  --record=true
# 或使用edit
kubectl edit deploy deploy-nginx
# 或
kubectl apply -f deploy-nginx.yaml --record=true
k get rs -w
  # 为了 方便看,我将新的rs 名字下面显示为 deploy-nginx-new
  NAME                      DESIRED   CURRENT   READY   AGE
  deploy-nginx-77d87b4b6c   3         3         3       7m38s
  deploy-nginx--------new   1         0         0       0s
  deploy-nginx--------new   1         1         0       0s
  deploy-nginx--------new   1         1         1       85s
  deploy-nginx-77d87b4b6c   2         3         3       9m52s
  deploy-nginx--------new   2         1         1       85s
  deploy-nginx-77d87b4b6c   2         2         2       9m52s
  deploy-nginx--------new   2         2         1       85s
  deploy-nginx--------new   2         2         2       2m47s
  deploy-nginx-77d87b4b6c   1         2         2       11m
  deploy-nginx--------new   3         2         2       2m47s
  deploy-nginx-77d87b4b6c   1         1         1       11m
  deploy-nginx--------new   3         3         2       2m47s
  deploy-nginx--------new   3         3         3       2m48s
  deploy-nginx-77d87b4b6c   0         1         1       11m
  deploy-nginx-77d87b4b6c   0         0         0       11m
  1. 创建了一个新的rs, 新rs创建一个pod, 旧的rs 缩容,减少一个pod
  2. 继续以上操作, 最终新的rs 创建了3个, 旧的缩容为0
k get deploy  -w
  NAME           READY   UP-TO-DATE   AVAILABLE   AGE
  deploy-nginx   3/3     3            3           20m
  deploy-nginx   3/3     0            3           20m
  deploy-nginx   3/3     1            3           20m
  deploy-nginx   4/3     1            4           20m
  deploy-nginx   3/3     1            3           20m
  deploy-nginx   3/3     2            3           20m
  deploy-nginx   4/3     2            4           20m
  deploy-nginx   3/3     2            3           20m
  deploy-nginx   3/3     3            3           20m
  deploy-nginx   4/3     3            4           20m
  deploy-nginx   3/3     3            3           20m


# 也可以看到相关的信息, 通过控制rs的replicas的数量
# 新rs先创建一个pod,是因为 一开始replicas=1
k describe deploy deploy-nginx
# 上线的状态如何,是否更新成功
k rollout status deploy deploy-nginx
状态 描述
DESIRED 用户期望的 Pod 副本个数 (spec.replicas 的值)
CURRENT 当前处于 Running 状态的 Pod 的个数, pull image时期就属于running状态
READY pod已经启动可以提供服务的状态
UP-TO-DATE
  • 当前处于最新版本的 Pod 的个数
  • 所谓最新版本指的是Pod的Spec部分与Deployment里 Pod 模板里定义的完全一
AVAILABLE
  • 当前已经可用的Pod 的个数
  • Running 状态,又是最新版本,并且已经处于 Ready(健康检查正确)状态的 Pod
  • 应用可供用户使用的副本数

4.3 回滚

Tip

前面更新那里我们会看到,更新成功后, 旧的rs 不会被删除. 有什么用呢?

# 我们再看看 
k describe deployments.apps deploy-nginx  | grep  annotation -iA 3
  Annotations:            deployment.kubernetes.io/revision: 9
                          kubernetes.io/change-cause: kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.9.1 --record=true

# 查看deploy-nginx 的上线历史, 显示的相关信息对应上面的版本号和 change-cause
k  rollout history deployment deploy-nginx
  1         kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.9.1 --record=true
  2         kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.14.1 --record=true

# 表示默认保留10个历史记录 可以用于回滚, 可以在创建deploy时指定
# 0 的话,表示不保留
k get deployments.apps deploy-nginx  -o yaml  | grep revisionHistoryLimit
  revisionHistoryLimit: 10 

#我们再做一次更新, 没有record,
kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:latest
k  rollout history deployment deploy-nginx
  REVISION  CHANGE-CAUSE
  1         kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.9.1 --record=true
  2         kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.14.2 --record=true
  3        kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:1.14.2 --record=true # 这里还是用的旧的.

# 前面说到 --record 会废弃, 那么实际上就是给deploy 添加一个annotation
# 我们可以手动添加你这个更新的原因. 仅作为注释.
k annotate deploy deploy-nginx  kubernetes.io/change-cause='kubectl set image deploy deploy-nginx pod-deploy-nginx=nginx:latest'

# 会先是3个rs. 都保留着 用来回滚用的.
# rs 的配置里面image用的之前的nginx 版本.
k get rs

# 查看某个版本的详情
k rollout history deployment deploy-nginx --revision=1
# 回滚到上一个版本
k rollout undo deploy deploy-nginx
k get rs # 对应的rs就会创建pod了.
# 回滚到指定版本
k rollout undo deploy deploy-nginx  --to-revision=2

4.4 扩容

k scale deployment deploy-nginx --replicas=4

4.5 暂停和恢复

Tip
  • 如果你是用命令修改, 需要多次操作,比如一次修改了image,一次修改了cpu什么的. 你不希望修改后就马上重建pod,则可以先暂停, 当然你直接edit 一次全部修改就得了
  • 这个就是你自动化操作的时候可能就有用了. 我们一般会在cicd里使用诸如 kubectl set …

kubectl rollout pause deploy deploy-nginx

..... 做了修改后

kubectl rollout resume deploy deploy-nginx

5 statefulset(sts)

Tip
  • 前面我们说到的pod控制器都是无状态的,关注的是群体(群体里的个体都是一样的,所以把整个群体当成一个个体)
  • statefulset 关注个体
  • StatefulSet(有状态集)常用于部署有状态的且需要有序启动的应用程序

StatefulSet 的核心功能,就是通过某种方式记录这些状态,然后在 Pod 被重新创 建时,能够为新 Pod 恢复这些状态.

6 daemonSet (ds)

7 job

8 cronjob

Back to top