歡迎光臨
每天分享高質量文章

將專案遷移到Kubernetes上的5個訣竅

我們將在本文中提供5個訣竅幫你將專案遷移到Kubernetes上,這些訣竅來源於過去12個月中OpenFaas社群的經驗。下文的內容與Kubernetes 1.8相容,並且已經應用於OpenFaaS – Serverless Functions Made Simple[1]的實踐中。
免責宣告:因為Kubernetes 的API更新的特別頻繁,請參考官方檔案獲得最新資訊。
1. 將所有的內容都放進Docker

第一步操作是給以獨立行程方式執行的每個元件建立一個Dockerfile,這看起來是顯而易見的。如果你已經這麼做了,那麼你已經快人一步了。
但是如果你還沒有開始這麼做,那麼請確保你的每一個元件都在使用多階段構建。一個多階段的構建要用到兩個Docker映象: 一個是構建時;一個是執行時。舉例來說,基礎的映象可能是一個Go SDK用來編譯二進位制檔案,最後階段則是一個類似Alpine Linux的最小的Linux映象。我們將二進位制檔案複製到最終階段的映象中,安裝類似CA證書這樣的軟體包,然後設定入口(entry-point)。這樣你最後得到的映象體積很小而且不會包括不需要的軟體包。
這裡給出一個例子: Go寫的OpenFaaS API gateway 元件的多階段構建。你會註意到它裡麵包含的一些其它實踐:
  • 使用一個非root使用者的執行時

  • 將構建時的階段命名為類似build

  • 指定構建的基礎架構,比如linux

  • 使用版本做標簽,比如3.6。 如果你使用latest,那會導致不可預知的情況。

例子如下:
FROM golang:1.9.4 as build
WORKDIR /go/src/github.com/openfaas/faas/gateway
COPY .   .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o gateway .
FROM alpine:3.6
RUN addgroup -S app \
   && adduser -S -g app app
WORKDIR /home/app
EXPOSE 8080
ENV http_proxy      ""
ENV https_proxy     ""
COPY --from=build /go/src/github.com/openfaas/faas/gateway/gateway    .
COPY assets     assets
RUN chown -R app:app ./
USER app
CMD ["./gateway"]
註意:如果你想要使用OpenShift(一個Kubernetes的發行版),那麼你必須保證你所有的Docker映象都是以非root使用者執行的。
1.1 獲得Kubernetes
你需要在你的筆記本或者開發機上裝好Kubernetes。 可以閱讀我寫的一篇博文[2],描述了在Mac上執行Docker和Kubernetes的所有常用選項。
如果你之前已經用過Docker了,那麼你可能已經熟悉容器這個詞了。在Kubernetes的詞彙表裡面你會很少直接操作容器,取而代之的是抽象為Pod的概念。
一個Pod是一個到多個容器組成的一個組,裡面的這些容器被集中的排程和部署並透過環回介面127.0.0.1互相訪問。
這裡給出一個例子,說明Pod抽象的用處:比方說你有一個傳統的應用,本身沒有TLS/SSL支援。它可以與一個配置了TLS的Nginx或者其它Web伺服器部署到一個Pod中。這麼做的優點是可以將多個容器部署到一起來擴充套件它的功能而不會帶來破壞性改變。

2. 建立YAML檔案

在你有了Dockerfile和映象之後,下一步你就需要開始寫Kubernetes格式的YAML檔案了。叢集會讀取這些檔案來部署應用然後維持你專案的狀態。
這與Docker本身的Compose files是不同的,剛開始你可能會覺得困難。我的建議是到檔案裡面找一些例子或者其它的專案試著模仿跟隨它們的樣式和方法。好訊息就是隨著經驗增長你會覺得越來越容易。
每一個Docker映象都需要在Deployment物件裡面定義,指定需要執行的容器和它需要的資源。一個Deployment會建立和維持Pod來執行你的程式碼,如果Pod已經存在它會為你重起。
如果你想要透過HTTP/TCP來訪問,那麼需要為每一個元件建立一個Service物件。
你可以將多個Kubernetes定義寫到一個檔案裡面,然後資源之間透過—和一個新行來分隔。但是更加普遍的做法是將定義寫到多個檔案裡面去,每個檔案代表叢集中的一個API物件。
例如:
  • gateway-svc.yml //代表一個service服務

  • gateway-dep //代表一個deployment

如果所有的檔案都在一個目錄下,那麼你可以透過一條命令來應用它們所有檔案:
kubectl apply -f ./yaml/
當你需要執行在其它的作業系統或者架構(類似Raspberry Pi)時,我們推薦將檔案放到一個新的目錄裡面,類似yaml_arm的目錄名。
Deployment的例子
這裡給出一個Deployment的例子,用來部署NATS Streaming[3](一個輕量級的分發工作的流平臺):
apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: nats
 namespace: openfaas
spec:
 replicas: 1
 template:
   metadata:
     labels:
       app: nats
   spec:
     containers:
     - name:  nats
       image: nats-streaming:0.6.0
       imagePullPolicy: Always
       ports:
       - containerPort: 4222
         protocol: TCP
       - containerPort: 8222
         protocol: TCP
       command: ["/nats-streaming-server"]
       args:
         - --store
         - memory
         - --cluster_id
         - faas-cluster
一個deployment也可以宣告在啟動時給service(服務)建立多個副本或者實體。
Service 定義

apiVersion: v1
kind: Service
metadata:
 name: nats
 namespace: openfaas
 labels:
   app: nats
spec:
 type: ClusterIP
 ports:
   - port: 4222
     protocol: TCP
     targetPort: 4222
 selector:
   app: nats
Service提供了一種機制可以在你的Deployment的多個副本之間對請求做負載均衡。在之前的例子中我們只有單副本的NATS Streaming,但是如果我們有多個副本,它們每個都有獨立的IP地址,追蹤它們就會變成問題。使用Service的優點是它可以有一個靜態IP地址和DNS入口,透過它們可以隨時訪問到任意一個副本。
Service不是直接對映到Deployment的,它對映到label(標簽)上。在上面的例子中Service會尋找app=nats的標簽。標簽可以在執行時狀態下從Deployment(或者其它API物件)上增加或者刪除,這樣在你的叢集中重定向流量就相當容易。這些可以方便的啟用A/B測試或者滾動釋出。
學習Kubernetes相關YAML語法的最好方式是檢視官方檔案裡面相關的API物件的章節,你可以從中找到YAML或者kubectl使用的例子。
更多API物件的檔案請檢視:https://kubernetes.io/docs/concepts/。
2.1 Helm
Helm說它自己是Kubernetes的包管理器。 從我的觀點來看它主要提供了兩個主要功能:
分發你的應用(在一個Chart裡面)
一旦你已經準備好分發你專案的yaml檔案時,你可以將它們打包提交到Helm倉庫中。這樣其它人就可以找到你的應用,透過一條命令就可以安裝。Chart本身可以有版本控制,也可以指定依賴與其它的Chart。
這裡有三個Chart的例子:OpenFaaS[4]、Kakfa[5]和Minio[6]。

讓編輯更簡單
Helm支援Go語言的內嵌模板,你可以將通用的配置專案放到一個檔案裡面。所以如果你釋出了一組新的Docker映象需要做更新,你只需要在一個地方做修改。你也可以寫條件判斷陳述句,這樣將flag和helm命令一起使用可以在部署時啟用不同的配置項和feature。
在正常的Yaml檔案裡面我們這樣定義容器映象:
image: functions/gateway:0.7.5
使用Helm模板我們這樣做:
image: {{ .Values.images.gateway }}
然後在一個單獨的檔案中我們可以定義imags.gateway的值。Helm能讓我們做的另一件事情是使用條件判斷——當要支援多個架構或者feature時非常有用。
下麵再給一個例子展現如何選擇應用ClusterIP或者NodePort,這是暴露叢集中某個服務的兩種不同方式。NodePort會將服務暴露到叢集以外,所以你可能需要控制什麼時候要這個功能。
如果我們使用常規的YAML檔案,那意味著我們需要兩組配置檔案:
spec:
 type: {{ .Values.serviceType }}
 ports:
   - port: 8080
     protocol: TCP
     targetPort: 8080
     {{- if contains "NodePort" .Values.serviceType }}
     nodePort: 31112
     {{- end }}
在這個例子裡面“.serviceType”可以是ClusterIP或者NodePort,下麵的陳述句說明在條件滿足時將nodePort元素加入到YAML中。

3. 使用ConfigMaps

在Kubernetes中你可以透過ConfigMap將配置檔案載入到叢集中。ConfigMap比“bind mounting”的方式要好因為配置檔案的資料會被覆制到整個叢集中,保證了魯棒性。如果資料是透過bind mount方式從一臺主機上掛載的,那麼你必須要事先把資料放置到這臺主機中,並且同步好。這兩種方式都要比把配置檔案直接打進映象的方式好,因為那樣更新配置檔案很不方便。
一個ConfigMap可以透過kubectl或者YAML檔案按需呼叫。一旦叢集中建好了一個ConfigMap,那麼它就可以被新增進容器或者Pod中。
下麵是一個為Prometheus定義的ConfigMap的例子:
kind: ConfigMap
apiVersion: v1
metadata:
 labels:
   app: prometheus
 name: prometheus-config
 namespace: openfaas
data:
 prometheus.yml: |
   scrape_configs:
     - job_name: 'prometheus'
       scrape_interval: 5s
       static_configs:
         - targets: ['localhost:9090']
你可以將它載入進一個Deployment或者Pod中:
        volumeMounts:
       - mountPath: /etc/prometheus/prometheus.yml
         name: prometheus-config
         subPath: prometheus.yml
     volumes:
       - name: prometheus-config
         configMap:
           name: prometheus-config
           items:
             - key: prometheus.yml
               path: prometheus.yml
               mode: 0644
檢視完整例子:ConfigMap Prometheus config[7]。
更多檔案檢視:https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/。

4. 使用安全的Secret

為了保證你密碼,API Key,token等的私密性和安全性,你需要使用Kubernetes的secret管理機制。
如果你已經熟悉了ConfigMaps的使用,那麼有一個好訊息,secret的使用方式基本一樣:
  • 在叢集中定義secret

  • 透過mount載入進一個Deployment/Pod中

當你需要從一個私有的Docker映象倉庫拉映象下來時,你可能會用到的其它的secret型別。這被稱之為ImagePullSecret, 更多資訊參見這裡[8]。
關於如何建立和管理secret在官方檔案裡面有更多資訊:https://kubernetes.io/docs/concepts/configuration/secret/。

5. 實現健康檢查health-checks

Kubernetes透過liveness和readiness的檢查來實現健康檢查。我們需要利用這些機制來確保我們叢集的自愈和失效保護。它們的工作方式:透過一個探針(probe)來在Pod裡面執行一個命令或者呼叫一個預先定義好的HTTP入口。
Liveness
一個liveness檢查可以檢視程式是否在執行。針對OpenFaaS functions我們會在function啟動時建立一個/tmp/.lock的鎖檔案。如果我們發現非健康狀態,我們會將這個檔案刪除,Kubernetes就會給我們重新排程這個function。
另外一種常用方式是增加一個新的HTTP路由類似/_/healthz。使用/_/是一種傳統做法因為這樣不會跟已經存在的其它路由衝突。
Readiness
如果你在Kubernetes裡面啟用了readiness檢查,那麼它只會給透過測試條件的容器轉發流量。
readiness檢查可以是定期的執行,這與health-check不同。一個容器即使在高負載下也可以是健康的——只是這種情況我們定義為“Not ready”這樣Kubernetes就會停止給它轉發流量直到它恢復。
官方檔案有更多關於這方面的資訊:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/。

總結

在這篇文章中,我們列出了一些當要把專案遷移到Kubernetes上要做的一些核心工作。這包括:
  • 建立好的Docker映象

  • 書寫好的Kubernetes清單(YAML檔案)

  • 使用ConfigMap來將配置和程式碼解耦

  • 使用Secret來保護API Key這樣的隱私資料

  • 使用liveness 和readiness探針來實現彈性和自愈

如果你想要在一個VM或者雲主機上執行Kubernetes, 這可能是將一個開發叢集跑起來最快速的方式了。
相關連結:
  1. https://www.openfaas.com/

  2. https://blog.alexellis.io/docker-for-mac-with-kubernetes/

  3. https://github.com/nats-io/nats-streaming-server

  4. https://github.com/openfaas/faas-netes/tree/master/chart/openfaas

  5. https://github.com/kubernetes/charts/tree/master/incubator/kafka

  6. https://github.com/kubernetes/charts/tree/master/stable/minio

  7. https://github.com/openfaas/faas-netes/blob/master/yaml/prometheus.yml

  8. https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

原文連結:https://blog.alexellis.io/move-your-project-to-kubernetes/
Kubernetes入門與進階實戰培訓

本次培訓內容包括:Docker基礎、容器技術、Docker映象、資料共享與持久化、Docker三駕馬車、Docker實踐、Kubernetes基礎、Pod基礎與進階、常用物件操作、服務發現、Helm、Kubernetes核心元件原理分析、Kubernetes服務質量保證、排程詳解與應用場景、網路、基於Kubernetes的CI/CD、基於Kubernetes的配置管理等,點選瞭解具體培訓內容

5月11日正式上課,點選閱讀原文連結即可報名。
贊(0)

分享創造快樂