1. 程式人生 > >Kubernetes使用者指南(三)--在生產環境中使用Pod來工作、管理部署

Kubernetes使用者指南(三)--在生產環境中使用Pod來工作、管理部署

一、在生產環境中使用Pod來工作 本節將介紹一些在生產環境中執行應用非常有用的功能。 1、持久化儲存 容器的檔案系統只有當容器正常執行時有效,一旦容器奔潰或者重啟,所有對檔案系統的修改將會丟失,從一個原始的檔案系統重新開始。 所以為了實現更多的持久化資訊,在檔案系統之外你需要一個volume,volume對有狀態的應用來說是非常重要的,例如鍵值對儲存和資料庫等。 例如,Redis是一個鍵值對的儲存庫,在guestbook這個例子中使用過。 我們可以通過一下的配置新增一個volume來儲存需要持久化的資料: apiVersion: v1
kind: ReplicationController

metadata:
  name: redis
spec:
  template:
    metadata:
      labels:
        app: redis
        tier: backend
    spec:
      # Provision a fresh volume for the pod
      volumes:
        name: data
          emptyDir: {}
      containers:
      name: redis
        image: kubernetes/redis:v1
        ports:

        containerPort: 6379
        # Mount the volume into the pod
        volumeMounts:
        mountPath: /redis-master-data           name: data   # must match the name of the volume, above emptyDir這列的生命週期是隨著pod的生命週期的,比任何一個容器的生命週期都要長,所以當容器奔潰或者重啟的時候,這些持久化資料依然存在。 除了emptyDir提供的本地磁碟儲存之外,k8s還提供了很多不同的網路儲存方案,包括GCE的PD和EC2的EBS,這些是儲存關鍵資料的首先方案並且會自動處理一些細節,例如在節點上mount和unmout裝置。 從這裡看配置volume的全部資訊: 2、分配證書
為了和其他的應用、資料和和伺服器進行互相驗證,很多應用都需要證書,例如密碼、OAuth tokens和TLS keys等。 將這些證書儲存在容器的映象或者環境變數中是不理想的,因為這些證書可以被任何容器從映象、配置檔案、主機檔案系統或者主機的Docker守護程序中複製出來。 為了方便容器之間互動敏感的證書,k8s提供了一個名為secrets的機制。 Secret也是k8s中的一個資源,一組map型別的資料,例如,一個簡單的包含使用者名稱和密碼的Secret可以這樣定義: apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: dmFsdWUtMg0K
  username: dmFsdWUtMQ0K
和其他的資源一樣,Secret也可以通過create命令來例項化,也可以通過get命令來檢視: $ kubectl create -f ./secret.yaml
secrets/mysecret
kubectl get secrets
NAME                  TYPE                                  DATA

mysecret              Opaque                                2
你需要在Pod或者Pod Template中引用這個Secret才能使用它,secret列使你可以在容器中將它像記憶體目錄一樣進行掛載。 apiVersion: v1
kind: ReplicationController
metadata:
  name: redis
spec:
  template:
    metadata:
      labels:
        app: redis
        tier: backend
    spec:
      volumes:
        name: data
          emptyDir: {}
        name: supersecret
          secret:
            secretName: mysecret
      containers:
      name: redis
        image: kubernetes/redis:v1
        ports:
        containerPort: 6379
        # Mount the volume into the pod
        volumeMounts:
        mountPath: /redis-master-data
          name: data   # must match the name of the volume, above
        mountPath: /var/run/secrets/super           name: supersecret 點選這些檢視更加詳細的資訊: 3、通過私有的映象倉庫進行校驗 首先,穿件一個.dockercfg檔案,例如執行docker login <registry.domain>。 之後將.dockercfg的執行結果輸入到一個Secret資源中,示例如下: $ docker login
Username: janedoe
Password: ●●●●●●●●●●●

WARNING: login credentials saved in /Users/jdoe/.dockercfg.
Login Succeeded

echo $(cat ~/.dockercfg)


cat ~/.dockercfg | base64
eyAiaHR0cHM6Ly9pbmRleC5kb2NrZXIuaW8vdjEvIjogeyAiYXV0aCI6ICJabUZyWlhCaGMzTjNiM0prTVRJSyIsICJlbWFpbCI6ICJqZG9lQGV4YW1wbGUuY29tIiB9IH0K

cat > /tmp/image-pull-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
data:
  .dockercfg: eyAiaHR0cHM6Ly9pbmRleC5kb2NrZXIuaW8vdjEvIjogeyAiYXV0aCI6ICJabUZyWlhCaGMzTjNiM0prTVRJSyIsICJlbWFpbCI6ICJqZG9lQGV4YW1wbGUuY29tIiB9IH0K

EOF

kubectl create -f ./image-pull-secret.yaml
secrets/myregistrykey
現在,你就可以建立通過imagePullSecrets引用secret的Pod: apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    name: myregistrykey
4、輔助容器 Pods提供了集中執行多個容器的能力,它們可以在主機上被用來做應用的垂直整合。 但是Pods設計的原始動機是為協助主應用程式提供幫助,典型的例子有data pullers、data pushers和proxies。 這些代表性的容器經常通過檔案系統和其他容器進行互動,將相同的卷掛載到不同的容器中就可以做到這一點。 這種模式的一個例子是使用git來進行程式碼管理的的web服務: apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
      name: www-data
        emptyDir: {}
      containers:
      name: nginx
        image: nginx
        # This container reads from the www-data volume
        volumeMounts:
        mountPath: /srv/www
          name: www-data
          readOnly: true
      name: git-monitor
        image: myrepo/git-monitor
        env:
        name: GIT_REPO
         
        # This container writes to the www-data volume
        volumeMounts:
        mountPath: /data
          name: www-data
更多的使用例子在: 5、資源分配 k8s的Scheduler只會在擁有足夠的CPU和記憶體的節點上佈置應用,但是要做到這一點,Scheduler就必須知道它們需要多少資源。 如果指定的CPU資源太少,當有很多容器被啟動在同一個節點上的時候就會出現CPU匱缺。 同樣的,當沒有足夠的記憶體在請求的時候,容器將會因為不可預料的記憶體溢位而掛掉,尤其是需要大記憶體的應用。 如果沒有明確指定資源需求,名義上,資源分配的數量是預設的(這個預設值是通過預設Namespace下的LimitRange應用的,可以通過kubectl describe limitrange limits來檢視)。 你可以通過以下的方式明確地指定資源的需求量: apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      name: nginx
        image: nginx
        ports:
        containerPort: 80
        resources:
          limits:
            # cpu units are cores
            cpu: 500m
            # memory units are bytes
            memory: 64Mi
          requests:
            # cpu units are cores
            cpu: 500m
            # memory units are bytes
            memory: 64Mi
容器請求的資源超出規定的限制之後會出現記憶體溢位的錯誤而掛掉,所以指定的值略高於預期準備指定的值會普遍提高可靠性。 通過規定資源的需求量,保證了Pod在需要的時候可以有足夠的資源來使用。 更多資源限制和資源需求量的設定請看: 如果你不確定多少資源需要分配,剛開始你可以不指定多少資源分配直接啟動應用,之後通過 來觀察和確定出合適的值。 6、活躍度和狀態資訊檢查(又名健康狀態檢查) 許多應用運行了很長一段時間後有可能會因為很多原因最後變為不可用的,除了重啟之外無法恢復還原。 k8s提供了 用來檢查和補救以上的情況。 可以使用HTTP進行常規的應用檢查,定義如下: apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      name: nginx
        image: nginx
        ports:
        containerPort: 80
        livenessProbe:
          httpGet:
            # Path to probe; should be cheap, but representative of typical behavior
            path: /index.html
            port: 80
          initialDelaySeconds: 30
          timeoutSeconds: 1
至於其他的時間,應用可能只是暫時無法提供服務,並且會進行自我恢復。 這個時候,你肯定不願去直接關掉應用,但是也不要給他傳送請求,因為它不會馬上回復你甚至根本不響應。 一個典型的場景是當應用初始化的時候載入大量資料或者配置檔案。 k8s提供了Readiness probes來檢查和緩解這種情況,Readiness probes的配置和Liveness probes大致是相同的,只是使用readinessProbe欄位。 Pod中的容器將會通過k8s服務來報告它們現在是否準備就緒。 更多詳細請看: 7、生命週期中的鉤子和終止注意 節點和應用可能在任何時間點失敗掛掉,但是對於乾淨地關閉,對很多應用來說都是有益的。 例如當故意關掉應用的時候,完成正在處理中的請求。 k8s提供了兩種通知來實現:
  • k8s將會給應用傳送SIGTERM訊號,可以用來正確、優雅地關閉應用。當應用沒有提前終止的時候,SIGKILL將會發送一個配置好的時間數(預設為30秒,通過spec.terminationGracePeriodSeconds配置)。
pre-stop hook的配置方式和probes大致相同,但是沒有timing-related引數,例如: apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      name: nginx
        image: nginx
        ports:
        containerPort: 80
        lifecycle:
          preStop:
            exec:
              # SIGTERM triggers a quick exit; gracefully terminate instead               command: ["/usr/sbin/nginx","-s","quit"] 8、終止資訊 實現一個高可用的機制是必要的,尤其是對於一些十分活躍的應用。 快速DEBUG是十分重要的,k8s當出現致命的錯誤時可以快速debug,並且在kubectl或者UI中顯示,除了一般的日誌收集。 一個容器掛掉之後通過terminationMessagePath配置“寫下它的遺言”這是有可能的,就像列印錯誤、異常和堆疊資訊一樣。 預設的路勁為/dev/termination-log。 以下是一個小例子: apiVersion: v1
kind: Pod
metadata:
  name: pod-w-message
spec:
  containers:
  name: messager
    image: "ubuntu:14.04"
    command: ["/bin/sh","-c"]     args: ["sleep 60 && /bin/echo Sleep expired > /dev/termination-log"] 這些訊息的最後部分會使用其他的規定來單獨儲存: $ kubectl create -f ./pod.yaml
pods/pod-w-message
sleep 70
kubectl get pods/pod-w-message -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
Sleep expired
kubectl get pods/pod-w-message -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.exitCode}}{{end}}"
0
二、管理部署 現在你已經並通過Service與外界相連線。 那麼現在可以準備怎麼辦呢? k8s提供了一系列的工具幫助你管理應用的部署,包括擴充套件和更新。 除了這些,我們將會在 和 中討論更多的細節。 1、組織資源的配置 很多應用要求建立許多資源,例如RC和SVC。 可以將這些資源在同一個檔案中分組來簡化對他們的管理(在YAML檔案中通過 --- 來分隔)。 如下面的例子: apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
spec:
  type: LoadBalancer
  ports:
  port: 80
  selector:
    app: nginx
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      name: nginx
        image: nginx
        ports:
        containerPort: 80
多個資源的建立方式和之前的建立單個資源一樣: $ kubectl create -f ./nginx-app.yaml
services/my-nginx-svc
replicationcontrollers/my-nginx
這些資源將會按照檔案中的順序來建立。 所以,第一個定義SVC是最好的,因為這樣一來Scheduler就可以使這個RC建立的Pods都通過SVC來連線。 kubectl create命令也接受多個-f引數: $ kubectl create -f ./nginx-svc.yaml -f ./nginx-rc.yaml
也可以指定一個目錄而不僅僅是一個檔案: $ kubectl create -f ./nginx/
kubectl將會讀取所有後綴名為.yaml、.yml、.json的檔案。 這是一個推薦的做法,來把一個微服務或者應用中相關的資源在一個檔案中順序定義,並且在一個目錄中將這些和你的應用相關的檔案分組。 如果每層中的應用都通過DNS互相連線繫結,那麼你就可以十分簡單地部署所有元件。 一個URL也可以作為配置檔案的源,例如直接使用簽入git中的配置檔案來部署: 2、Kubectl中的批量操作 kubectl並不只是僅僅能夠執行批量建立資源的操作。 它也可以將資源的名字從配置檔案中抽取出來,用來進行一些其他的操作,特別是要刪除你建立的相同的資源的時候: $ kubectl delete -f ./nginx/
replicationcontrollers/my-nginx
services/my-nginx-svc
在這裡例子中,只有兩個資源被刪除了,同樣的效果在命令列中也可以通過資源的名稱很容易地操作: $ kubectl delete replicationcontrollers/my-nginx services/my-nginx-svc
對於資源數量很大的情況,另外一種是可以使用Labels來過濾資源。 Selector通過-l引數來使用: $ kubectl delete all -lapp=nginx
replicationcontrollers/my-nginx services/my-nginx-svc 因為kubectl會使用相同的語法將其接受的資源名稱再次輸出,所以通過$()或者xarg可以很容易地進行連續的操作: $ kubectl get $(kubectl create -f ./nginx/ | grep my-nginx)
CONTROLLER   CONTAINER(S)   IMAGE(S)   SELECTOR    REPLICAS
my-nginx     nginx          nginx      app=nginx   2
NAME           LABELS      SELECTOR    IP(S)          PORT(S)
my-nginx-svc   app=nginx   app=nginx   10.0.152.174   80/TCP
3、有效地使用Labels 目前為止我們使用的例子中,資源最多有一個Label。 下面介紹在資源集合之間使用多個Labels來進行區分。 例如,不同的應用使用了不同的label,app等於不同的值,但是一個多層的應用,例如guestbook example 需要額外地區分不同層,那麼前端可以攜帶以下標籤: labels:     app: guestbook     tier: frontend 而Redis主節點和從節點使用不同的tier標籤,同時甚至有可能會有一個role標籤: labels:     app: guestbook     tier: backend     role: master labels:     app: guestbook     tier: backend     role: slave Labels允許我們可以將資源劃分成任意級別,然後根據這些劃分尺度進行互動: $ kubectl create -f ./guestbook-fe.yaml -f ./redis-master.yaml -f ./redis-slave.yaml
replicationcontrollers/guestbook-fe
replicationcontrollers/guestbook-redis-master
replicationcontrollers/guestbook-redis-slave
kubectl get pods -Lapp -Ltier -Lrole
NAME                           READY     STATUS    RESTARTS   AGE       APP         TIER       ROLE
guestbook-fe-4nlpb             1/1       Running   0          1m        guestbook   frontend   <n/a>
guestbook-fe-ght6d             1/1       Running   0          1m        guestbook   frontend   <n/a>
guestbook-fe-jpy62             1/1       Running   0          1m        guestbook   frontend   <n/a>
guestbook-redis-master-5pg3b   1/1       Running   0          1m        guestbook   backend    master
guestbook-redis-slave-2q2yf    1/1       Running   0          1m        guestbook   backend    slave
guestbook-redis-slave-qgazl    1/1       Running   0          1m        guestbook   backend    slave
my-nginx-divi2                 1/1       Running   0          29m       nginx       <n/a>      <n/a>
my-nginx-o0ef1                 1/1       Running   0          29m       nginx       <n/a>      <n/a>
kubectl get pods -lapp=guestbook,role=slave
NAME                          READY     STATUS    RESTARTS   AGE
guestbook-redis-slave-2q2yf   1/1       Running   0          3m
guestbook-redis-slave-qgazl   1/1       Running   0          3m
4、多種部署 另外一個會使用到多標籤的場景是:分別部署一個元件的不同版本、不同配置。 將應用的新版本和舊版一同部署是十分正常的,這樣一來,在舊版本淘汰之前,新版應用可以接管舊版本的一些功能使用。 例如,一個新版的guestbook前端可以攜帶以下的標籤: labels:     app: guestbook     tier: frontend     track: canary 同時,穩定版本的track標籤有不同的值,這樣一來,兩個RC控制的Pods集合就不會發生重疊: labels:     app: guestbook     tier: frontend     track: stable 通過選擇它們Labels的子集,省略track這個Label,前端的Service可以跨越兩組replicas: selector:  app: guestbook  tier: frontend 5、更新Labels 有時候,在建立新的資源之前,已存在的Pods或者其他資源需要重置Label。 這可以通過kubectl label來做到,例如: $ kubectl label pods -lapp=nginx tier=fe
NAME                READY     STATUS    RESTARTS   AGE
my-nginx-v4-9gw19   1/1       Running   0          14m
NAME                READY     STATUS    RESTARTS   AGE
my-nginx-v4-hayza   1/1       Running   0          13m
NAME                READY     STATUS    RESTARTS   AGE
my-nginx-v4-mde6m   1/1       Running   0          17m
NAME                READY     STATUS    RESTARTS   AGE
my-nginx-v4-sh6m8   1/1       Running   0          18m
NAME                READY     STATUS    RESTARTS   AGE
my-nginx-v4-wfof4   1/1       Running   0          16m
kubectl get pods -lapp=nginx -Ltier
NAME                READY     STATUS    RESTARTS   AGE       TIER
my-nginx-v4-9gw19   1/1       Running   0          15m       fe
my-nginx-v4-hayza   1/1       Running   0          14m       fe
my-nginx-v4-mde6m   1/1       Running   0          18m       fe
my-nginx-v4-sh6m8   1/1       Running   0          19m       fe
my-nginx-v4-wfof4   1/1       Running   0          16m       fe
6、擴縮你的應用 當你的應用負載增加或者縮小了,通過kubectl可以十分簡單地進行擴縮。 例如,將nginx replicas的Pod數量由2增長到3: $ kubectl scale rc my-nginx --replicas=3
scaled
kubectl get pods -lapp=nginx
NAME             READY     STATUS    RESTARTS   AGE
my-nginx-1jgkf   1/1       Running   0          3m
my-nginx-divi2   1/1       Running   0          1h
my-nginx-o0ef1   1/1       Running   0          1h
7、保證服務不中斷的情況下更新你的應用 有時候,你需要更新你已經部署的應用,在上面的部署例子中,是通過一個新的Image或者Image tag來更新。 kubectl不同的更新操作方式,適用於各種不同的場景。 在保證服務不中斷的情況下,為了更新應用,kubectl提供了一個叫做“rolling update”的操作,它是一次更新一個Pod,而不是在同一時間將所有服務停掉。 請檢視 和 來獲得更多資訊。 假設你執行著1.7.9版本的nginx: apiVersion: v1