微服務開發有道之把項目遷移到Kubernetes上的5個小技巧

咱們將在本文中提供5個訣竅幫你將項目遷移到Kubernetes上,這些訣竅來源於過去12個月中OpenFaas社區的經驗。下文的內容與Kubernetes 1.8兼容,而且已經應用於OpenFaaS - Serverless Functions Made Simple的實踐中。

免責聲明node

由於Kubernetes 的API更新的特別頻繁,請參考官方文檔得到最新信息。

1. 將全部的內容都放進Docker

第一步操做是給以獨立進程方式運行的每一個組件建立一個Dockerfile,這看起來是顯而易見的。若是你已經這麼作了,那麼你已經快人一步了。

可是若是你尚未開始這麼作,那麼請確保你的每個組件都在使用多階段構建。一個多階段的構建要用到兩個Docker鏡像: 一個是構建時;一個是運行時。舉例來講,基礎的鏡像多是一個Go SDK用來編譯二進制文件,最後階段則是一個相似Alpine Linux的最小的Linux鏡像。咱們將二進制文件拷貝到最終階段的鏡像中,安裝相似CA證書這樣的軟件包,而後設置入口(entry-point)。這樣你最後獲得的鏡像體積很小並且不會包括不須要的軟件包。

這裏給出一個例子: Go寫的OpenFaaS API gateway 組件的多階段構建。你會注意到它裏面包含的一些其它實踐:linux

  • 使用一個非root用戶的運行時
  • 將構建時的階段命名爲相似build
  • 指定構建的基礎架構,好比linux
  • 使用版本作標籤,好比3.6。 若是你使用latest,那會致使不可預知的狀況。


例子以下:git

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"]

注意:github

若是你想要使用OpenShift(一個Kubernetes的發行版),那麼你必須保證你全部的Docker鏡像都是以非root用戶運行的。

1.1 得到Kubernetes

你須要在你的筆記本或者開發機上裝好Kubernetes。 能夠閱讀我寫的一篇博文,描述了在Mac上運行Docker和Kubernetes的全部經常使用選項。

若是你以前已經用過Docker了,那麼你可能已經熟悉容器這個詞了。在Kubernetes的詞彙表裏面你會不多直接操做容器,取而代之的是抽象爲Pod的概念。

一個Pod是一個到多個容器組成的一個組,裏面的這些容器被集中的調度和部署並經過環回接口127.0.0.1互相訪問。

這裏給出一個例子,說明Pod抽象的用處:比方說你有一個傳統的應用,自己沒有TLS/SSL支持。它能夠與一個配置了TLS的Nginx或者其它Web服務器部署到一個Pod中。這麼作的優勢是能夠將多個容器部署到一塊兒來擴展它的功能而不會帶來破壞性改變。golang

2. 建立YAML文件

在你有了Dockerfile和鏡像以後,下一步你就須要開始寫Kubernetes格式的YAML文件了。集羣會讀取這些文件來部署應用而後維持你項目的狀態。

這與Docker自己的Compose files是不一樣的,剛開始你可能會以爲困難。個人建議是到文檔裏面找一些例子或者其它的項目試着模仿跟隨它們的樣式和方法。好消息就是隨着經驗增加你會以爲愈來愈容易。

每個Docker鏡像都須要在Deployment對象裏面定義,指定須要運行的容器和它須要的資源。一個Deployment會建立和維持Pod來運行你的代碼,若是Pod已經存在它會爲你重起。

若是你想要經過HTTP/TCP來訪問,那麼須要爲每個組件建立一個Service對象。

你能夠將多個Kubernetes定義寫到一個文件裏面,而後資源之間經過---和一個新行來分隔。可是更加廣泛的作法是將定義寫到多個文件裏面去,每一個文件表明集羣中的一個API對象。

例如:docker

  • gateway-svc.yml //表明一個service服務
  • gateway-dep //表明一個deployment


若是全部的文件都在一個目錄下,那麼你能夠經過一條命令來應用它們全部文件:api

kubectl apply -f ./yaml/


當你須要運行在其它的操做系統或者架構(相似Raspberry Pi)時,咱們推薦將文件放到一個新的目錄裏面,相似yaml_arm的目錄名。安全

Deployment的例子

這裏給出一個Deployment的例子,用來部署 NATS Streaming(一個輕量級的分發工做的流平臺):服務器

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的例子:OpenFaaSKakfaMinio

讓編輯更簡單

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

更多文檔查看:https://kubernetes.io/docs/tas ... gmap/

4. 使用安全的Secret

爲了保證你密碼,API Key,token等的私密性和安全性,你須要使用Kubernetes的secret管理機制。

若是你已經熟悉了ConfigMaps的使用,那麼有一個好消息,secret的使用方式基本同樣:

  • 在集羣中定義secret
  • 經過mount加載進一個Deployment/Pod中


當你須要從一個私有的Docker鏡像倉庫拉鏡像下來時,你可能會用到的其它的secret類型。這被稱之爲ImagePullSecret, 更多信息參見這裏

關於如何建立和管理secret在官方文檔裏面有更多信息:https://kubernetes.io/docs/con ... cret/

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/tas ... obes/

總結

在這篇文章中,咱們列出了一些當要把項目遷移到Kubernetes上要作的一些核心工做。這包括:

  • 建立好的Docker鏡像
  • 書寫好的Kubernetes清單(YAML文件)
  • 使用ConfigMap來將配置和代碼解耦
  • 使用Secret來保護API Key這樣的隱私數據
  • 使用liveness 和readiness探針來實現彈性和自愈

接下來你能夠閱讀我寫的Docker Swarm vs Kubernetes的比較和快速搭建一個集羣的指南:

比較Docker Kubernetes和Swarm, 得的一個從CLI到網絡到組件的工具概覽。

若是你想要在一個VM或者雲主機上運行Kubernetes, 這多是將一個開發集羣跑起來最快速的方式了。

Java架構師學習公衆號!

一個專一分享架構乾貨的微信公衆號

相關文章
相關標籤/搜索