Kubernetes(5) Stateless Pod Controller -> ReplicaSet, DaemonSet, Deployment

1 Pod 控制器入门

ReplicaSet and Deployment (stateless) 可以管理无状态用户资源。Deployment是 ReplicaSet的 high level 版本实现,且封装了一些附加的常用功能。在实战中往往推荐使用Deployment而不是ReplicaSet。见 https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/

DaemonSet (stateless) : 可以确保Pod能平均分布在每一个定义好的节点上启动,这种类型的控制器可以用作管理一些服务如: Beats 这样收集节点日志的服务

Jobs, CronJob: 一次性,或定期完成特定工作

StatefulSets, Operator -> 特殊用于 stateful 应用

 

2 ReplicaSet

ReplicaSet中有三个重要配置即:

  • replicas: 需要运行的副本数,可以设置为0,默认为1
  • selector: 按照标签j键值筛选匹配上的Pod 结果。标签的键值必须匹配才能控制到相应ReplicaSet,如果选择结果没有匹配,则返回空对象。 详见: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors .
  • template: 模块用于定义Pod,包括Pod的名字,Pod拥有的label以及Pod中运行的应用 详见: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template  

一个例子用于展示如何创建 ReplicaSet,其中 spec.selector.matchLabels 决定哪个 Pod 会被选中如标签含有-> app: rs-demo-app 与 release: canary  

spec.template.metadata.labels 定义了Pod 的标签.

使用如下模板生成2 副本的 ReplicaSet:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo-app
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: rs-demo-app
      release: canary
  template:
    metadata:
      name: rs-demo-app-pod
      labels:
        app: rs-demo-app
        release: canary
        enviroment: qa
    spec:
      containers:
        - name: rs-demo-app-container
          image: ikubernetes/myapp:v1
          ports:
          - name: http
            containerPort: 80
          livenessProbe:
            httpGet:
              port: http
              path: /index.html
            initialDelaySeconds: 1
            periodSeconds: 3

命令行演示:

[root@k8smaster controllers]# kubectl create -f replicaset-demo.yaml
replicaset.apps/rs-demo-app created
[root@k8smaster controllers]# kubectl get rs
NAME               DESIRED   CURRENT   READY   AGE
nginx-79976cbb47   3         3         3       4d
nginx-f4bd648c7    0         0         0       4d
rs-demo-app        2         2         2       12s
[root@k8smaster controllers]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-79976cbb47-8dqnk   1/1     Running   1          4d
nginx-79976cbb47-p247g   1/1     Running   1          4d
nginx-79976cbb47-ppbqv   1/1     Running   1          4d
rs-demo-app-c2crz        1/1     Running   0          26s
rs-demo-app-xzddj        1/1     Running   0          26s


[root@k8smaster controllers]# kubectl describe rs
-demo-app-c2crz error: the server doesn't have a resource type "rs-demo-app-c2crz"

[root@k8smaster controllers]# kubectl describe po rs-demo-app-c2crz Name: rs-demo-app-c2crz Namespace: default Priority: 0 PriorityClassName: <none> Node: k8snode2/172.16.0.13 Start Time: Mon, 07 Jan 2019 22:44:25 +0100 Labels: app=rs-demo-app enviroment=qa release=canary Annotations: <none> Status: Running IP: 10.244.2.17 Controlled By: ReplicaSet/rs-demo-app Containers: rs-demo-app-container: Container ID: docker://b82932a65bf6f02ccbb05ef6d39d2c27f42e90cc9a0e4a21924928133e29f9fa Image: ikubernetes/myapp:v1 Image ID: docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513 Port: 80/TCP Host Port: 0/TCP State: Running Started: Mon, 07 Jan 2019 22:44:26 +0100 Ready: True Restart Count: 0 Liveness: http-get http://:http/index.html delay=1s timeout=1s period=3s #success=1 #failure=3 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-rxs5t (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-rxs5t: Type: Secret (a volume populated by a Secret) SecretName: default-token-rxs5t Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 104s default-scheduler Successfully assigned default/rs-demo-app-c2crz to k8snode2 Normal Pulled 88s kubelet, k8snode2 Container image "ikubernetes/myapp:v1" already present on machine Normal Created 88s kubelet, k8snode2 Created container Normal Started 87s kubelet, k8snode2 Started container

 

3 手动给 ReplicaSet 扩容

给ReplicaSet 扩容可以用 kubectl api 直接编辑。比如这里我们使用了 kubectl edit rs 然后将 spec.replicas 从2 上调至 3, 这样会自动启动一个新的副本。

[root@k8smaster controllers]# kubectl edit rs rs-demo-app
replicaset.extensions/rs-demo-app edited # then change spec.replicas from 2 to 3

[root@k8smaster controllers]# kubectl get pod --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   LABELS
nginx-79976cbb47-8dqnk   1/1     Running   1          4d    pod-template-hash=3553276603,run=nginx
nginx-79976cbb47-p247g   1/1     Running   1          4d    pod-template-hash=3553276603,run=nginx
nginx-79976cbb47-ppbqv   1/1     Running   1          4d    pod-template-hash=3553276603,run=nginx
rs-demo-app-c2crz        1/1     Running   0          14m   app=rs-demo-app,enviroment=qa,release=canary
rs-demo-app-lkh5j        1/1     Running   0          9s    app=rs-demo-app,enviroment=qa,release=canary
rs-demo-app-xzddj        1/1     Running   0          14m   app=rs-demo-app,enviroment=qa,release=canary

* 同理也可以通过修改 image 字段来更新应用的版本号,后面的文章会逐渐介绍这以功能

 

4 Deployments

Deployments 是加强版的 ReplicatSet 且拥有ReplicaSet的所有功能。也就是说,Deployment 可以用于执行一系列 ReplicaSet 组合操作如:Rollingupdate, 各种类型发布 (blue/green, canary etc.).

下面列举了 Deployment 的应用场景:

下面的例子展示了部署Deployment 且配置两个replica 副本:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
        - name: myapp-container
          image: ikubernetes/myapp.v1
          ports:
            - name: http
              containerPort: 80

部署命令:

kubectl apply -f deployments-demo.yaml

检查部署情况:

[root@k8smaster controllers]# kubectl get deploy -o wide
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS        IMAGES                 SELECTOR
myapp-deploy   2         2         2            0           5m    myapp-container   ikubernetes/myapp.v1   app=myapp,release=canary

[root@k8smaster controllers]# kubectl get rs
-o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-deploy-8546d69b76 2 2 0 5m myapp-container ikubernetes/myapp.v1 app=myapp,pod-template-hash=4102825632,release=canary

[root@k8smaster controllers]# kubectl get po -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE
myapp-deploy-f5f97bb54-2tlh6   1/1     Running   0          18s   10.244.2.23   k8snode2
myapp-deploy-f5f97bb54-65ffd   1/1     Running   0          18s   10.244.1.37   k8snode1

 

* 部署成功后发现,经过我们只写了部署脚本,但是同时自动生成了ReplicaSet对象,这也充分证明Deployment是ReplicaSet的升级版

* 名字: myapp-deploy-8546d69b76 来源于Deployment名字加 Pod 自动生成的 hash-code 

5 Deployments 扩容

可以用修改模板然后靠 apply 命令完成自动扩容,比如修改模板中的 replicas 参数从 2 到 3 然后部署:

kubectl apply -f deployment-demo.yaml

与ReplicaSet不同 用户可以重复使用这个命令来进行 Update操作,且不需要删除现有的 ReplicaSet,这个操作已经封装在 Deployment中了。

[root@k8smaster controllers]# kubectl describe deploy myapp-deploy
Name:                   myapp-deploy
Namespace:              default
CreationTimestamp:      Tue, 08 Jan 2019 06:02:20 +0100
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 1
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"myapp-deploy","namespace":"default"},"spec":{"replicas":2...
Selector:               app=myapp,release=canary
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=myapp
           release=canary
  Containers:
   myapp-container:
    Image:        ikubernetes/myapp:v1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   myapp-deploy-f5f97bb54 (2/2 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  7m36s  deployment-controller  Scaled up replica set myapp-deploy-f5f97bb54 to 2

* if you change the template and deploy it again, kubernetes will remark the change information in Annotations -> like if you set replicas from 2 to 3...

* StrategyType by default is RollingUpdate and RollingUpdateStrategy: 25% max unavailable, 25% max surge

 

6 Deployments Update

现在我们修改模板的 replicas 从 2 到3, app version 从ikubernetes/myapp:v1 到 ikubernetes/myapp:v2 ,之后让这个修改生效,观察 Deployment的变动.

另开一个窗口 用 -w 命令观察 Pod 被终止和重启的过程:

[root@k8smaster ~]# kubectl get pod -l app=myapp -w
NAME                           READY   STATUS    RESTARTS   AGE
myapp-deploy-f5f97bb54-2tlh6   1/1     Running   0          18m
myapp-deploy-f5f97bb54-65ffd   1/1     Running   0          18m

回之前的窗口执行部署命令:

[root@k8smaster controllers]# kubectl apply -f deployments-demo.yaml 
deployment.apps/myapp-deploy configured

我们可以看到新窗口的变化:

[root@k8smaster ~]# kubectl get pod -l app=myapp -w
NAME                           READY   STATUS    RESTARTS   AGE
myapp-deploy-f5f97bb54-2tlh6   1/1     Running   0          18m
myapp-deploy-f5f97bb54-65ffd   1/1     Running   0          18m
myapp-deploy-f5f97bb54-7lhmz   0/1   Pending   0     0s
myapp-deploy-f5f97bb54-7lhmz   0/1   Pending   0     0s
myapp-deploy-f5f97bb54-7lhmz   0/1   ContainerCreating   0     0s
myapp-deploy-f5f97bb54-7lhmz   1/1   Running   0     2s
myapp-deploy-5c574dbf-trf5k   0/1   Pending   0     0s
myapp-deploy-5c574dbf-trf5k   0/1   Pending   0     0s
myapp-deploy-5c574dbf-trf5k   0/1   ContainerCreating   0     0s
myapp-deploy-5c574dbf-trf5k   1/1   Running   0     5s
myapp-deploy-f5f97bb54-7lhmz   1/1   Terminating   0     7m12s
myapp-deploy-5c574dbf-p7jpw   0/1   Pending   0     0s
myapp-deploy-5c574dbf-p7jpw   0/1   Pending   0     0s
myapp-deploy-5c574dbf-p7jpw   0/1   ContainerCreating   0     0s
myapp-deploy-f5f97bb54-7lhmz   0/1   Terminating   0     7m14s
myapp-deploy-f5f97bb54-7lhmz   0/1   Terminating   0     7m15s
myapp-deploy-f5f97bb54-7lhmz   0/1   Terminating   0     7m15s
myapp-deploy-5c574dbf-p7jpw   1/1   Running   0     4s
myapp-deploy-f5f97bb54-2tlh6   1/1   Terminating   0     28m
myapp-deploy-5c574dbf-j25bz   0/1   Pending   0     0s
myapp-deploy-5c574dbf-j25bz   0/1   Pending   0     0s
myapp-deploy-5c574dbf-j25bz   0/1   ContainerCreating   0     0s
myapp-deploy-f5f97bb54-2tlh6   0/1   Terminating   0     28m
myapp-deploy-5c574dbf-j25bz   1/1   Running   0     1s
myapp-deploy-f5f97bb54-65ffd   1/1   Terminating   0     28m
myapp-deploy-f5f97bb54-65ffd   0/1   Terminating   0     28m
myapp-deploy-f5f97bb54-2tlh6   0/1   Terminating   0     28m
myapp-deploy-f5f97bb54-2tlh6   0/1   Terminating   0     28m
myapp-deploy-f5f97bb54-65ffd   0/1   Terminating   0     28m
myapp-deploy-f5f97bb54-65ffd   0/1   Terminating   0     28m

通过上面信息可以看到 Deployment 会自动创建一个新 Pod 然后干掉一个旧的

Update结束后会达到如下状态:

[root@k8smaster ~]# kubectl get rs -o wide
NAME                     DESIRED   CURRENT   READY   AGE   CONTAINERS        IMAGES                 SELECTOR
myapp-deploy-5c574dbf    3         3         3       50m   myapp-container   ikubernetes/myapp:v2   app=myapp,pod-template-hash=17130869,release=canary
myapp-deploy-f5f97bb54   0         0         0       1h    myapp-container   ikubernetes/myapp:v1   app=myapp,pod-template-hash=919536610,release=canary

[root@k8smaster
~]# kubectl get deploy -o wide NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp-deploy 3 3 3 3 1h myapp-container ikubernetes/myapp:v2 app=myapp,release=canary

* ReplicaSet myapp-deploy-f5f97bb54 下面没有任何 Pods 新部署的ReplicaSet  myapp-deploy-5c574dbf 升级到了新的版本

* 旧 ReplicaSet 依然会被显示,在特定情况下可以使用 Rollback 返回到上一个版本

 

用户也可以通过使用 kubectl rollout history deploy <deployment name> 检查版本信息:

[root@k8smaster ~]# kubectl rollout history deploy myapp-deploy
deployment.extensions/myapp-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

使用 kubectl rollout undo 可以做回滚操作,默认会返回上一版本:

[root@k8smaster ~]# kubectl get rs -o wide
NAME                     DESIRED   CURRENT   READY   AGE   CONTAINERS        IMAGES                 SELECTOR
myapp-deploy-5c574dbf    0         0         0       1h    myapp-container   ikubernetes/myapp:v2   app=myapp,pod-template-hash=17130869,release=canary
myapp-deploy-f5f97bb54   3         3         3       1h    myapp-container   ikubernetes/myapp:v1   app=myapp,pod-template-hash=919536610,release=canary

[root@k8smaster
~]# kubectl get deploy -o wide NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp-deploy 3 3 3 3 1h myapp-container ikubernetes/myapp:v1 app=myapp,release=canary

现在我们回滚到 v2 使用命令 kubectl apply -f deployments-demo.yam...

 

7 Deployments Patch

也可以使用另一种方法升级或者扩容 Deploymets -> kubectl patch + json<content>

比如现在增加副本数从 3 到 5:

[root@k8smaster ~]# kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
deployment.extensions/myapp-deploy patched

[root@k8smaster
~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE myapp-deploy-5c574dbf-5q6vm 1/1 Running 0 14m 10.244.1.42 k8snode1 myapp-deploy-5c574dbf-7t9qw 1/1 Running 0 8s 10.244.2.29 k8snode2 myapp-deploy-5c574dbf-p9mfb 1/1 Running 0 14m 10.244.1.41 k8snode1 myapp-deploy-5c574dbf-ssxkc 1/1 Running 0 8s 10.244.1.43 k8snode1 myapp-deploy-5c574dbf-tcbhz 1/1 Running 0 14m 10.244.2.28 k8snode2

 

8 用Deployment部署 Canary Release

1. 编写新的部署模板

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
        - name: myapp-container
          image: ikubernetes/myapp:v2
          ports:
            - name: http
              containerPort: 80
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

2. 将镜像版本从 v2 变为 v3

3. pause Deployments:

# start rollout
kubectl apply -f deployment-demo.yaml

# pause after the first update been performed
kubectl rollout pause deployment myapp-deploy

# till here kubernetes will update one from Deployments-Pod

 4. 恢复 Rollout Update

没有"pause" k8s将会按顺序删除一个Pod 然后添加一个新的 Pod 用于Update
但是现在有了 Pause 我们停止在当前状态下,该状态经过观察一共有 6 个Pod
生产环境中这个方法可以用于测试,比如在10个小时之后如果Update的版本工作顺利,则可以继续进行发布,使用以下命令:
kubectl rollout resume deployment myapp-deploy
这个命令会更新剩下的 Pods 到新的版本。最后可以使用后边的命令来检查当前的更新状态
kubectl get rs -o wide

9 Rollback
你可以使用 kubectl rollout undo 回滚到上一个版本
kubectl rollout undo deployment myapp-deploy
或者回滚至特定版本,你可以用以下命令来展示版本历史
kubectl rollout history deployment myapp-deploy
记住版本号,然后用这个版本号回滚至之前的状态
kubectl rollout undo deployment myapp-deploy --to-revision=1

10 DaemonSet

DeamonSet 保证所有或者被特定标记的节点上必定运行特定Pod 资源。当新节点加入集群时,Pod 也会相应添加进来。在节点被移除时,Pod 也会被相应地回收。在删除DaemonSet时,Pod 会随之被删除。

用下面模板创建 DaemonSet on Kubernetes Cluster

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: myapp-ds
  namespace: default
spec:
  selector:
    matchLabels:
      app: filebeat
      release: stable
  template:
    metadata:
      labels:
        app: filebeat
        release: stable
    spec:
      containers:
        - name: filebeat
          image: ikubernetes/filebeat:v5.6.5-alpine
          env:
            - name: REDIS_HOST
              value: redis.default.svc.cluster.local
            - name: REDIS_LOG_LEVEL
              value: info

 

 

 

 

 



posted on 2019-01-23 18:32  mad_baix  阅读(416)  评论(0编辑  收藏  举报

导航