天天看點

如何在K8S平台部署微服務

本文将介紹如何使用 kubernetes 部署微服務,包括 服務發現,監控,路由,日志。用實際的例子來示範自動化流程。主要分為以下幾個部分:

  1. 5分鐘搭建 K8S 叢集
  2. 部署 CNI 網絡
  3. 部署監控服務
  4. 部署網關
  5. 部署日志服務
  6. 部署一個應用

第一次完全手動搭建叢集大約花了一周時間,主要的問題是在于

  1. K8S的元件多,每個程式的參數有不少,哪些是關鍵的參數需要花時間搞清楚。
  2. 萬惡的牆,代理通路外網比較慢
  3. CNI網絡問題,主要是 CNI 網段和雲上的區域網路網段沖突了,基礎知識缺失導緻
  4. K8S 的證書和驗證方式不清楚

本文相關代碼位于

github

, 歡迎star。

手動部署可以參考我之前的

博文

,即便是完全熟悉部署流程,不寫腳本的情況下,如果純手動 setup 或者 tear down 一個叢集,都是比較耗時間的。直到發現了這個工具 kubeadm, 世界美好了。

這個工具對作業系統有限制, ubuntu 16.04 或 centos 7 以上。其實當初也看到了這個工具, 不過 因為系統限制,并且kubeadm還在alpha版本,又想手動撸一遍部署過程,是以沒直接采用。 不過 kubeadm 不建議在生産環境中使用,在 官方文檔中的 limitation 中有詳細解釋.

文檔

中第一點就說了, kubeadm部署的是 single master,意味着不是高可用,謹慎使用。 但是作為示範執行個體再合适不過。

小插曲: 因為最近釋出的 k8s 1.6 的 kubeadm 有一個bug,導緻用以下步驟安裝會有問題,為此社群裡有人提了一個patch, 步驟有些多,我寫在本文最後了。

kubeadm v1.6.1 已經修複了bug。

開始部署步驟:

  • 在 Digital Ocean 中開三台機器, centos 7,建議2C2G,按小時計費用不了多少錢,用完就銷毀。 如果還沒有新增賬號,并且覺得本文對你有幫助,可以用我的 referral link 注冊,可以得到 10美金, 連結 . 發現一個更便宜的vps, vultr , 還是SSD
  • 登入三台機器,安裝必要元件.
yum clean yum update -y cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://yum.kubernetes.io/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF setenforce 0 yum install -y docker kubelet kubeadm kubectl kubernetes-cni systemctl enable docker && systemctl start docker systemctl enable kubelet && systemctl start kubelet 
# 補充幾點 # 1. 因為1.6開始K8S開啟了 RBAC 驗證,需要在啟動 kubelet 的參數中添加 --authentication-token-webhook vim vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 添加 --authentication-token-webhook 
# 2. 如果是 centos, 還需要添加 --cgroup-driver=systemd # 3. v1.6開始,apiserver禁用了 insecure-port, 需要拷貝 /var/kubernetes/ 下的 admin config, 作為驗證配置.            
  • 選擇一台作為master, 運作
kubeadm init

# 輸出
Your Kubernetes master has initialized successfully!

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
 http://kubernetes.io/docs/admin/addons/

You can now join any number of machines by running the following on each node:

kubeadm join --token=e344fa.e007ce406eb41f07 104.236.166.119           
完成後會看到提示: `kubeadm join --token=311971.7260777a25d70ac8 104.236.166.119`           
  1. 在其他兩台機器上分别運作以上提示的指令
  2. 在 master 上檢視狀态,

    kubectl get nodes

    , 如果看到一共有2個node,一個master, 則表示叢集建立成功。

部署CNI網絡

kubeadm 自動部署了一個插件,就是 kube-dns, 用于服務發現,但是到這裡你會發現 kube-dns 這個服務沒有啟動成功,因為我們還沒有部署CNI網絡。

kubectl get pods --all-namespaces | grep dns           

這裡有比較多的選擇,我使用了 calico,因為性能比較好,支援一鍵部署。 這裡有一篇對比容器網絡的文章,優缺點介紹比較全面,

Battlefield: Calico, Flannel, Weave and Docker Overlay Network

配置檔案在cni目錄下,或者可以直接在master運作:

# for v1.6.0
kubectl apply -f http://docs.projectcalico.org/v2.1/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml           

再次檢視 dns 服務是否運作成功吧。

# 按需安裝 git 和 dig
yum install -y bind-utils git            

監控

在部署之前,我們需要對兩台node标記角色,k8s是通過label來自定義各個資源的類型的。

首先确定兩台node的name, 通過

kubectl get nodes

來檢視,之後挑選其中一台作為前端機器(frontend).

kubectl label node centos-2gb-sfo1-03 role=frontend           

這裡把centos-2gb-sfo2-node1換成你的 node name

Prometheus

應用 monitor 目錄下的兩個配置檔案,如下

kubectl create -f prometheus.config.yaml kubectl create -f prometheus.deploy.yaml           

接下來打開

http://front-end-ip:30900

就能看到 prometheus 的界面

如何在K8S平台部署微服務

Grafana

kubectl create -f grafana.deploy.yaml           

打開

http://front-end-ip:30200

就能看到 grafana 的界面.

  1. 還需要添加一個 Data Source. 選擇 Promethues, 位址填上: http://promethues:9090, 因為有kube-dns,是以這樣就能通路 pod 中的 service
    如何在K8S平台部署微服務
  2. 添加模闆,内容為 grafana.config.k8s.json, 這個模闆是針對 k8s 叢集的儀表模闆,添加時選擇對應的 Data Source,然後就能看到效果。
    如何在K8S平台部署微服務

網關

類似上面的步驟,配置檔案在 gateway 目錄下,運作

kubectl create -f traefik.yaml           

這樣在

http://front-end-ip:30088

能看到 網關的 dashboard。

traefik 可以監聽 etcd 中注冊的 ingress 的變化,根據 ingress 資源來自動配置路由, 下面會有具體的示例。最後的效果是, 後端服務的配置檔案中定義他自己的 服務domain 和 prefix, traefik會自動添加這個路由, 這樣就可以通過gateway來通路後端服務了。

日志收集

官方有推薦的Log系統: cAdvisor 和 Heapster.

我比較偏愛 ELK, 主要是生态比較好。有兩種方式應用:

  1. 第一種是每個Pod都多加一個 sidecar - Filebeat, 在每個後端服務配置檔案中指定本地log的路徑(利用 k8s 的 emptyDir 這個volume),在filebeat的配置中指定這個路徑,實作日志收集
  2. 還有一種是Filebeat作為 DaemonSet 運作在每台機器,利用 k8s 的 hostPath 這個volume, 這樣每台機器隻有一個 filebeat 運作,監聽一個指定目錄;後端服務約定好log都寫入這個目錄的子目錄中,這樣也能達到收集效果。

我比較推薦第二種方式,工作量稍微小一些。

第一個服務

終于到了這個緊張刺激的環節。

源檔案在 hello-app 目錄下,一個簡單的 http service, 主要包含兩個路由:

  1. /metrics 傳回 prometheus 抓取的資料格式
  2. / 其他Path,傳回一個随機id和URI

log 日志輸入 /tmp/hello-log/hello-app.log;

想要達到的效果是:

  1. 配置檔案中配好路由,自動注冊到 gateway
  2. promethues 自動發現服務,抓取 http://hello:8080/metrics 的監控資料
  3. 日志能夠自動收集

app 的配置檔案位于 hello-app 目錄下, 運作:

kubectl create -f hello.yaml           

接着去 gateway 和 prometheus 的 dashboard 看下,會發現服務已經被發現;

如何在K8S平台部署微服務

再測試一下通過gateway是否能通路到 hello-app 這個服務:

curl http://front-end-ip:30087/v1/hello -H 'Host: www.hello.local' #結果為: ID:5577006791947779410 path:/hello           

編譯安裝 kubeadm

  1. 下載下傳 kubernetes 項目, checkout v1.6.0, 必須是這個tag
  2. cherry-pick 89557110ed4693a7d23e515e738ced266e099365

  3. KUBE_BUILD_PLATFORMS=linux/amd64 hack/make-rules/build.sh cmd/kubeadm

  4. 把生成的 _output 檔案打包,放入伺服器上
  5. 按照本文第一部分的步驟 yum 安裝 docker, kubelet
  6. 編輯檔案

    /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

    添加 參數

    --cgroup-driver=systemd

  7. sudo systemctl daemon-reload && sudo systemctl restart kubelet.service

  8. kubeadm init

    能完成,但是 node 狀态是 not-ready,因為 cni 沒有配置.
  9. 複制

    /etc/kubernetes/admin.conf

    檔案到

    ~/.kube/config

    然後 執行

    kubectl get nodes

    才可以,因為新版的apiserver啟動時,把 insecure-port 禁用了,8080端口不再可用.

Alpine Linux

這次還遇到一個問題, alpine的docker鏡像使用不順利,ubuntu, centos下編譯的檔案在 alpine 下無法運作, 記得之前還運作成功過,這次得仔細找找原因。

如何打包出最小鏡像

靜态編譯

CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o hello hello-app/*.go

the -a flag means to rebuild all the packages we’re using, which means all the imports will be rebuilt with cgo disabled.

https://github.com/golang/go/...

建議使用 bash 作為 base image, 畢竟還有一些操作例如 mkdir, mv , cp 等需要執行。

如何檢視 二進制檔案 的 動态依賴?

# ldd hello linux-vdso.so.1 => (0x00007ffde7df8000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff931ae5000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff93171e000) /lib64/ld-linux-x86-64.so.2 (0x00005637b0ae4000) 

# readelf -d hello Dynamic section at offset 0x697100 contains 19 entries: Tag Type Name/Value 0x0000000000000004 (HASH) 0xa959e0 0x0000000000000006 (SYMTAB) 0xa95e60 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000005 (STRTAB) 0xa95c40 0x000000000000000a (STRSZ) 518 (bytes) 0x0000000000000007 (RELA) 0xa95650 0x0000000000000008 (RELASZ) 24 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x0000000000000003 (PLTGOT) 0xa97000 0x0000000000000015 (DEBUG) 0x0 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0] // 動态依賴庫 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] // 動态依賴庫 0x000000006ffffffe (VERNEED) 0xa95960 0x000000006fffffff (VERNEEDNUM) 2 0x000000006ffffff0 (VERSYM) 0xa95920 0x0000000000000014 (PLTREL) RELA 0x0000000000000002 (PLTRELSZ) 648 (bytes) 0x0000000000000017 (JMPREL) 0xa95680 0x0000000000000000 (NULL) 0x0           

Alpine 編譯

alpine linux 使用 musl libc,而 ubuntu, centos 使用的是 glibc, 是以在 ubuntu,centos下編譯的檔案一般不能直接使用在 alpine 環境。

# export WORKDIR=/go/src/hello-app 
# docker run --rm -v $GOPATH/src:/go/src -v "$PWD":${WORKDIR} -w ${WORKDIR} golang:1.8-alpine go build -o hello-alpine hello-app/main.go            

注意,編譯的依賴package 被映射入了 /go/src 中; -w 表示 working directory.

本文轉自中文社群-

如何在K8S平台部署微服務

繼續閱讀