如何在K8S平臺部署微服務

Deploying Micro-services on Kubernetes

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

  1. 5分鐘搭建 K8S 集羣node

  2. 部署 CNI 網絡linux

  3. 部署監控服務git

  4. 部署網關github

  5. 部署日誌服務golang

  6. 部署一個應用web

5分鐘搭建 K8S 集羣

第一次徹底手動搭建集羣大約花了一週時間,主要的問題是在於docker

  1. K8S的組件多,每一個程序的參數有很多,哪些是關鍵的參數須要花時間搞清楚。json

  2. 萬惡的牆,代理訪問外網比較慢ubuntu

  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 的界面

圖片描述

Grafana

kubectl create -f grafana.deploy.yaml

打開 http://front-end-ip:30200 就能看到 grafana 的界面.

  1. 還須要添加一個 Data Source. 選擇 Promethues, 地址填上:
    http://promethues:9090, 由於有kube-dns,因此這樣就能訪問 pod 中的 service 圖片描述

  2. 添加模板,內容爲 grafana.config.k8s.json, 這個模板是針對 k8s 集羣的儀表模板,添加時選擇對應的 Data Source,而後就能看到效果。 圖片描述圖片描述

網關

相似上面的步驟,配置文件在 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 看下,會發現服務已經被發現;

圖片描述
圖片描述

再測試一下經過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.

http://web-rat.com/posts/2016...

相關文章
相關標籤/搜索