灰度發布在實際生產部署中是經常被使用的方式,常規的方法是手動從前端LB(負載均衡)上將后端服務器摘掉,然后,停服務,最后上傳代碼,完成軟連接更新。在使用CI/CD工具時,這個過程變得自動化了,我們只需要通過Jenkins這個功能強大的開源持續集成和部署工具,就可以聯合Gitlab 或 Gogs 來實現自動拉取代碼,並根據自己編寫的pipeline腳本,實現自動連接到LB上摘掉后端Server,並自動連接到后端Server上,上傳代碼,並重啟服務,最后通過郵件通知管理員整個過程的結果報告。但今天,K8s的更讓我們看到了一種更便捷高效的灰度發布的實現方法,下面就來說說:
由於本人能力有限,對k8s的理解尚淺,原理部分在后續研究透徹后,在來詳細說明,本編僅供初學者參考
首先需要制作此次實驗的基礎鏡像:
1. Dockerfile的編寫:
mkdir dockerfile && cd dockerfile
vim Dockerfile #注意: Dockerfile的文件名首字母要大寫
FROM alpine:latest
MAINTAINER "ZCF <zcf@zczf.com>"
ENV NGX_DOC_ROOT="/var/lib/nginx/html" HOSTNAME="" IP="" PORT="" INDEX_PAGE=""
RUN apk --no-cache add nginx && mkdir -p ${NGX_DOC_ROOT}/shop /run/nginx
COPY chk.html ${NGX_DOC_ROOT}
COPY entrypoint.sh /bin
CMD ["/usr/sbin/nginx","-g","daemon off;"] #定義啟動nginx服務為前端啟動, -g:是global段,中修改daemon off;
ENTRYPOINT ["/bin/entrypoint.sh"] #將CMD的命令,作為參數傳遞給/bin/entrypoint.sh 腳本.
#准備Dockerfile配套的基礎文件:
1) 啟動容器時,執行的腳本文件: entrypoint.sh
vim entrypoint.sh
#!/bin/sh
echo "<h1>WELCOME TO ${HOSTNAME:-www.zcf.com} WEB SITE | `date` | `hostname` | `hostname -i` | -${YOU_INFO:-v1}- | </h1>" > ${NGX_DOC_ROOT}/index.html
cat > /etc/nginx/conf.d/default.conf <<EOF
server {
server_name ${HOSTNAME:-www.zcf.com};
listen ${IP:-0.0.0.0}:${PORT:-80};
root ${NGX_DOC_ROOT};
location / {
index ${INDEX_PAGE} index.html index.htm;
}
location = /404.html {
internal;
}
}
EOF
exec "$@" #它就是來接受CMD傳入的參數的.
2 ) 給entrypoint.sh 添加執行權限
chown +x entrypoint.sh
3) 后期做健康檢查時,使用的html文件:
echo OK > chk.html
2. 開始制作docker鏡像文件:
docker build --tag myapp:v1 ./
3. 將制作好的鏡像文件,打上標簽,並上傳到harbor上。
docker login harbor.zcf.com -u admin -p 123456 #登錄harbor
docker tag myapp:v1 harbor.zcf.com/k8s/myapp:v1 #先打上harbor倉庫路徑
docker push harbor.zcf.com/k8s/myapp:v1 #再上傳鏡像到harbor上。
4. 為了方便延時恢復發布的效果,我們還需要在制作一個鏡像
docker run -d --name ngx1 -e YOU_INFO="DIY-HelloWorld-v2" harbor.zcf.com/k8s/myapp:v1
#說明: -e 是指定要傳遞給容器的環境變量, 因為我提前在myapp中啟動腳本entrypoint.sh中使用的了YOU_INFO這個環境變量,
# 因此,這里我可以直接給容器傳遞這個變量,來實現修改nginx首頁的效果.
docker commit --pause ngx1 #將ngx1暫停,並將當前容器狀態,導出為一個新鏡像。
docker kill ngx1 && docker rm -fv ngx1 #制作完鏡像,就直接刪除測試ngx1容器.
root@k8s-n1:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 85355d4af36c 6 seconds ago 7.02MB #這個就上剛制作的新鏡像.
#給剛制作好的鏡像打上標簽:harbor.zcf.com/k8s/myapp:v2,便於上傳到harbor上。
docker tag 85355d4af36c harbor.zcf.com/k8s/myapp:v2
#測試運行鏡像,若沒有問題,就可以上傳到本地harbor上了。
docker run -p 83:80 --rm -d --name ngx1 harbor.zcf.com/k8s/myapp:v2
root@k8s-n1:~# curl http://192.168.111.80:83/ #測試鏡像是否修改了nginx的首頁為YOU_INFO的內容.
<h1>WERCOME TO www.zcf.com WEB SITE | Fri Jul 19 02:31:13 UTC 2019 | ec4f08f831de | 172.17.0.2 | -DIY-HelloWorld-v2- | </h1>
docker kill ngx1 #刪除ngx1容器.
docker push harbor.zcf.com/k8s/myapp:v2 #最后,上傳新鏡像到harbor上.
5. 現在已經有了,myapp:v1 和 myapp:v2 那就可以開始K8s的灰度發布測試了。
#先創建三個pod,一個Client,兩個Nginx
#1. 先創建 Client
kubectl run client --image=harbor.zcf.com/k8s/alpine:v1 --replicas=1
#注意: alpine:是一個最小化的Linux系統,很多開源鏡像站都可以下載到.
kubectl get pods -o wide #查看Pod的創建詳情.
#2. 創建Nginx
kubectl run nginx --image=harbor.zcf.com/k8s/myapp:v1 --port=80 --replicas=2
kubectl get deployment -w #watch着監控k8s幫我們創建2個pod的過程.
kubectl get pod -o wide
#3. 登錄Client,測試訪問Nginx
root@k8s-m1:/etc/ansible# kubectl get pod
NAME READY STATUS RESTARTS AGE
client-f5cdb799f-2wsmr 1/1 Running 2 16h
nginx-6d6d8b685-7t7xj 1/1 Running 0 99m
nginx-6d6d8b685-xpx5r 1/1 Running 0 99m
kubectl exec -it client-f5cdb799f-2wsmr sh
/ # ip addr
/ # for i in `seq 1000`; do wget -O - -q http://nginx/ ; sleep 1; done
/ # #說明: 若你的kube-dns沒有部署成功,這里的nginx可換成Service的IP.
/ # # kubectl get svc |grep nginx #這個就是Nginx的Service的集群IP.
#4. 以上測試可看到,已經能夠實現負載均衡的效果了。
接着,開始進行灰度發布測試
#更新myapp的鏡像為myapp:v2
kubectl set image --help
kubectl set image deployment myapp myapp=harbor.zcf.com/k8s/myapp:v2 #升級myapp的鏡像為myapp:v2
#上面執行命令時,就可以看着,另一個終端中Client的訪問變化情況,你可以發現,訪問逐漸從 v1 變成 DIY-HelloWorld-v2了。
#5.測試動態調整nginx Pod的數量
kubectl scale --replicas=5 deployment nginx #修改nginx的Pod副本數量為5個.
kubectl get pods
#接着在到Client所在的終端上,查看變化,你會發現,主機名和IP部分開始有更多變化了。
#6. 查看nginx鏡像升級狀態,是否成功
kubectl rollout status deployment nginx
#7. 再查看myapp的鏡像是否已經升級為最新的了
kubectl describe pods nginx-xxx-xx
#8. 將myapp回滾到之前的版本,即v1版本
kubectl rollout undo --help
kubectl rollout undo deployment nginx
6. 測試K8s集群外部訪問nginx
#修改 myapp service的類型,讓它能被集群外部的客戶端訪問.
kubectl edit svc myapp
#type: ClusterIP 把它修改為 type:NodePort
#查看svc的更新信息:
kubectl get svc #這里就可以看到,myap service的端口將動態增加一個. 如:80:30020/TCP,注意:30020是隨機分配的。
#它的范圍是,你在使用kubeasz部署時,設置 NODE_PORT_RANGE="30000-60000"中隨機選的.
#接着就可以在集群外部的客戶端去訪問myapp了
http://Master或Node的物理IP:30020/
#好了,以上測試結果,我就不截圖了,想看到結果的道友們要多多動手測試,然后多多總結,多多思考,就可以看到,並且明白了。
