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

將專案遷移到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)

分享創造快樂