3.1 控制器——ReplicaSet

3. 控制器(Controller)

3.1 副本集(ReplicaSet)

定義:副本集(ReplicaSet)的目的是爲了保證一組穩定的Pod副本在任意給定時刻都在運行。因此,它通常用於保證特定數量的相同Pod的可用性。

 副本集使用一些字段進行定義,這些字段包含了一個選擇器(指定如何識別可以獲取的pods)、一個數字(表示應該維持多少個副本)、一個Pod模板(pod template,指定了新的Pod的創建標準)。然後,復副本集將根據需要進行創建或刪除pods以達到所需的數量,從而實現其目的。當副本集需要創建新的Pod時,就會使用Pod模板。

 副本集和Pod之間的鏈接是通過Pod的metadata.ownerReferences字段,該字段指定了當前對象是屬於哪個資源的,正是通過這個鏈接,副本集才知道它所維護的pods的狀態,並據此進行計劃。一個副本集主要是通過使用選擇器辨識新的Pod,如果一個Pod沒有OwnerReference(所屬資源)或者OwnerReference(所屬資源)不是一個控制器,它一旦和副本集的選擇器匹配上了,它將會被副本集立即獲取。

 副本集(ReplicaSet)保證了特定數量的Pod副本在任意狀態都是處於運行狀態。然而,Deployment是一個相對比較高層次的概念,它負責管理副本集(ReplicaSet)以及提供對pods的聲明性更新以及許多其他有用的功能。相對於直接使用副本集(ReplicaSets),更加推薦使用Deployments來操作,除非需要自定義更新業務流程、或者根本不需要更新。因爲實際上可能從不需要操作副本集對象,所以從這個角度也是推薦使用Deployments來替換,在spec部分來定義應用。下面是直接創建副本集的一個實例:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # 下面是定義副本集的部分
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3

下面的命令將上述的清單保存到frontend.yaml並將其提交給K8S集羣,它會創建定義的副本集(ReplicaSet)和它所管理的Pod:

kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml

注意yaml文件的縮進,很容易出錯的,將上述的鏡像改成我自己打包的鏡像,或者在worker node上拉鏡像再改名(我這裏是後者):

docker pull registry.cn-shanghai.aliyuncs.com/hhu/gb-frontend:v3
docker tag registry.cn-shanghai.aliyuncs.com/hhu/gb-frontend:v3 gcr.io/google_samples/gb-frontend:v3
docker rmi registry.cn-shanghai.aliyuncs.com/hhu/gb-frontend:v3

查看當前部署的副本集(ReplicaSets):

kubectl get rs
# 本地結果
NAME                  DESIRED   CURRENT   READY   AGE
frontend              3         3         3       5m24s
curl-66959f6557       1         1         1       15d
jenkins-7958858b5d    1         1         1       11d
my-nginx-64fc468bd4   0         0         0       15d

可以看到剛剛創建的frontend(上述的鏡像和配置文件國內是拉不下來的),也可以檢查副本集(Replicaset)的狀態:

# 查看frontend的狀態
kubectl describe rs/frontend

# 結果
Name:         frontend
Namespace:    default
Selector:     tier=frontend
Labels:       app=guestbook
              tier=frontend
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",...
Replicas:     3 current / 3 desired
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  tier=frontend
  Containers:
   php-redis:
    Image:        gcr.io/google_samples/gb-frontend:v3
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age    From                   Message
  ----    ------            ----   ----                   -------
  Normal  SuccessfulCreate  4m26s  replicaset-controller  Created pod: frontend-chgz5
  Normal  SuccessfulCreate  4m26s  replicaset-controller  Created pod: frontend-lmqv7
  Normal  SuccessfulCreate  4m26s  replicaset-controller  Created pod: frontend-4mklc

查看Pod(有3個frontend的Pod):

# 查看Pod
kubectl get Pods

# 結果
NAME                       READY   STATUS    RESTARTS   AGE
curl-66959f6557-pn49b      1/1     Running   2          15d
frontend-4mklc             1/1     Running   0          5m4s
frontend-chgz5             1/1     Running   0          5m4s
frontend-lmqv7             1/1     Running   0          5m4s
jenkins-7958858b5d-27qlx   1/1     Running   1          11d

當然還可以驗證這些Pod的owner reference是設置到了frontend副本集(ReplicaSet),可以通過獲取某個運行的Pod的yaml文件查看:

# 查看frontend-4mklc的pod的yaml文件
kubectl get pods frontend-4mklc -o yaml

# 部分輸出
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2019-04-28T06:27:56Z"
  generateName: frontend-
  labels:
    tier: frontend
  name: frontend-4mklc
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: frontend
    uid: c2d0bc7c-697e-11e9-a84a-000c292a92cd
  resourceVersion: "3146592"
  selfLink: /api/v1/namespaces/default/pods/frontend-4mklc
  uid: c2e03103-697e-11e9-a84a-000c292a92cd
spec:
  containers:
  - image: gcr.io/google_samples/gb-frontend:v3
    imagePullPolicy: IfNotPresent
    name: php-redis
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-gb6cw
      readOnly: true
...

【採集非模板Pod】

 當創建裸倉(bare Pod)並沒有問題,強烈推薦確保裸倉不要有和任何副本集(ReplicaSet)標籤選擇器匹配的,因爲副本集(ReplicaSet)不限制模板指定哪些Pod屬於該副本集——它可以以規定的方式獲取其他的Pod,以之前的前端副本集爲例,Pod在下面的清單中指定:

apiVersion: v1
kind: Pod
metadata:
  name: pod1
  labels:
    tier: frontend
spec:
  containers:
  - name: hello1
    image: registry.cn-shanghai.aliyuncs.com/hhu/hello-app:2.0

---

apiVersion: v1
kind: Pod
metadata:
  name: pod2
  labels:
    tier: frontend
spec:
  containers:
  - name: hello2
    image: registry.cn-shanghai.aliyuncs.com/hhu/hello-app:1.0

上述的Pod沒有控制器作爲它們的owner reference、沒有匹配的前端副本集,假設在前端副本集已經部署了、並這個副本集已經被設置爲它的初始化Pod的副本,然後創建了Pod,已經將這個Pod設置爲初始Pod副本去填充必要的副本數量:kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml,新的Pod將會通過副本集(ReplicaSet)獲取,然後然後立即終止,因爲副本集會超過其所需的計數。注意這裏的順序是創建副本集–>再通過副本集創建Pod,如果先創建Pod(kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml),再創建副本集(kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml),此時通過kubectl get Pods只會發現只有一個Pod。

【副本集RepicaSet清單】

 副本集也是K8S中的API對象,一個ReplicaSet需要apiVersionkind以及metadata字段,對於ReplicaSet,kind永遠都僅僅是ReplicaSet,副本集也需要.spec

 Pod模板,.spec.template字段是Pod模板,它也需要標籤,在之前的frontend.yaml栗子中,有一個標籤tier: frontend,注意不要和其他控制器的標籤選擇器重疊,以免它們使用這個Pod,對於Pod模板的重啓策略(restart policy字段.spec.template.spec.restartPolicy)只能指定爲Always(這也是默認值)。

 Pod 標籤選擇器,即.spec.selector,用於辨識Pod,在之前的frontend.yaml栗子中,選擇器位:

matchLabels:
	tier: frontend

在副本集(ReplicaSet)中,.spec.template.metadata.labels必須和spec.selector,否則會直接被API拒絕請求。注意:2個ReplicaSet指定相同的.spec.selector、但指定的.spec.template.metadata.labels.spec.template.spec字段不同,每個ReplicaSet會忽略其他ReplicaSet創建的pod。

副本:可以通過.spec.replicas設置多少個Pod應該並行運行,然後由副本集控制添加、刪除Pod以滿足這個數字,如果不指定,默認爲1

【副本集的操作】

 ReplicaSet常見的行爲有:

1.刪除副本集以及由其創建的Pod

必須將下面的-d選項中的propagationPolicy設置爲Background或者Foreground

kubectl proxy --port=8080
curl -X DELETE  'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"

2.僅僅刪除副本集

必須將下面的propagationPolicy設置爲Orphan

kubectl proxy --port=8080
curl -X DELETE  'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"

原始的副本集刪除後,可以創建新的副本替換它並接管它之前創建的Pod,只要新的副本集中的.spec.selector和之前的一樣就行,但新的副本集不會做出任何努力使現有的pod匹配新的、不同的pod模板。如果要升級Pod到新的,需要使用 rolling update。

3.將Pod從副本集中隔離

這裏是需要修改Pod上的標籤即可,以這種方式從副本集中隔離開來的Pod會自動被新的Pod替換。

4.對副本集進行伸縮

通過更新.spec.replicas可以輕鬆對副本集進行伸縮,ReplicaSet Controller將確保這個數量的Pod副本。

5.作爲水平Pod自動定標器目標的副本集

副本集也可以是水平Pod自動分頻器( Horizontal Pod Autoscalers-HPA)的目標,即副本集可以由hpa自動縮放,下面是栗子:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: frontend-scaler
spec:
  scaleTargetRef:
    kind: ReplicaSet
    name: frontend
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

保存上述清單到hpa-rs.yaml並提交到K8S集羣就會創建定義的HPA,它將根據複製的Pod的CPU使用情況自動縮放目標副本集kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml,還可以使用kubectl autoscale完成同樣的事:kubectl autoscale rs frontend --max=10(這種方式更簡單)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章