Go微服務架構實戰 中篇:5. k8s基於ingress和service實現金絲雀釋出和藍綠髮布
Go微服務架構實戰-【公粽號:堆疊future】
1. 微服務架構上篇
1. grpc技術介紹
2. grpc+protobuf+閘道器實戰
3. etcd技術介紹
4. 基於etcd的服務發現與註冊
5. 基於etcd的分散式鎖實戰
2. 微服務架構中篇
5. 基於ingress和service實現灰度釋出
關於灰度釋出有好幾種方式,比如藍綠髮布,滾動釋出以及金絲雀釋出。基於它們的表現形式不同,可以在不同場景下做到靈活應用。
細分的話基於Request Header的流量切分,基於Cookie的流量切分以及基於服務權重的流量切分都是灰度釋出的具體表現,那我們這篇文章重點來聊聊藍綠髮布和金絲雀釋出。
先大概介紹下這三種釋出:
藍綠髮布:藍綠部署是不停老版本,部署新版本然後進行測試,確認OK,將流量切到新版本,然後老版本同時也升級到新版本。
也就是說老版本(綠)在提供服務的時候,新版本上線(藍),把流量全部切到新版本之後,如果驗證通過就直接將老版本資源釋放掉(下線機器等資源).
這種方式風險太大,一旦新版本有問題,回退之後切到原來老版本上,那麼資料庫裡面的資料有可能因為這次灰度變髒了,怎麼處理這些資料需要較強的運維能力和解決問題能力。
所以藍綠髮布不太適合高併發的場景中,比較適合後臺這樣的系統釋出。
滾動釋出:摘除一個釋出一個,當然前提是你有多個這樣的服務。那如果是一個呢?那我們為了不停機提供服務,首先得先起一個服務,然後把新進來的流量都打到剛才起的服務上,然後等摘除的服務把它原本處理的流量處理完成之後就可以選擇下線了。
這種方式是比較建議的一種部署方式,也是k8s比較推薦的。這個上篇文章已經講過實操,這裡就不再演示了。
金絲雀釋出:不用解釋太多,看這個故事就知道了。
礦井中的金絲雀 17世紀,英國礦井工人發現,金絲雀對瓦斯這種氣體十分敏感。空氣中哪怕有極其微量的瓦斯,金絲雀也會停止歌唱;而當瓦斯含量超過一定限度時,雖然魯鈍的人類毫無察覺,金絲雀卻早已毒發身亡。當時在採礦裝置相對簡陋的條件下,工人們每次下井都會帶上一隻金絲雀作為“瓦斯檢測指標”,以便在危險狀況下緊急撤離。
故事結束之後我們總結下經驗:新老服務都線上,只不過新上的服務可能是一個,等新的服務沒有問題之後,把剩餘的服務全部升級到新的服務。
這種釋出也是灰度的一種,也是比較推薦的。
接下來看下藍綠髮布和金絲雀釋出實操。
1. 藍綠髮布
- 準備好兩個版本的Deployment
deploy.yaml(v1.0.0)
apiVersion:apps/v1
kind:Deployment
metadata:
name:k8sdemo-deploy
labels:
app:k8sdemo
version:1.0.0#pod版本
spec:
replicas:1
selector:
matchLabels:
app:k8sdemo
version:1.0.0
template:
metadata:
labels:
app:k8sdemo
version:1.0.0
spec:
containers:
-name:k8sdemo
image:k8s-grpc-demo:v2
imagePullPolicy:Never
deploy1.yaml(v1.0.1)
apiVersion:apps/v1
kind:Deployment
metadata:
name:k8sdemo-deploy-old
labels:
app:k8sdemo
version:1.0.1#pod版本
spec:
replicas:1
selector:
matchLabels:
app:k8sdemo
version:1.0.1
template:
metadata:
labels:
app:k8sdemo
version:1.0.1
spec:
containers:
-name:k8sdemo
image:k8s-grpc-demo:v6
imagePullPolicy:Never
service.yaml
apiVersion:v1
kind:Service
metadata:
name:k8sdemo-svc
spec:
ports:
-name:k8sdemo-svc
port:8000
targetPort:60001
selector:
app:k8sdemo
version:1.0.0#關聯pod的版本
type:NodePort
ingress.yaml
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:k8sdemo-ingress-prefix
annotations:
kubernetes.io/ingress.class:"nginx"
spec:
rules:
-host:hi.k8sdemo.com
http:
paths:
-path:"/hello"
pathType:ImplementationSpecific
backend:
service:
name:k8sdemo-svc#關聯service
port:
number:8000
直接kubectl apply -f .
就都建立好了。
我們首先訪問下老的服務:
docker@minikube:~$curl-XPOSThttp://hi.k8sdemo.com:31721/hello-d'{"name":"fromGW"}'
{"message":"HellofromGWfrom172.17.0.3:50009"}
沒問題之後我們最後升級釋出新的版本:在service.yaml中只需修改version=1.0.1就可以了。
apiVersion:v1
kind:Service
metadata:
name:k8sdemo-svc
spec:
ports:
-name:k8sdemo-svc
port:8000
targetPort:60001
selector:
app:k8sdemo
version:1.0.1#這裡從1.0.0到1.0.1
type:NodePort
再次kubectl apply -f service.yaml
。
我們訪問看下:
docker@minikube:~$curl-XPOSThttp://hi.k8sdemo.com:31721/hello-d'{"name":"fromGW"}'
{"message":"[gray]HellofromGWfrom172.17.0.7:50009"}
可以看到這次返回的內容就是我們新增加或者修改的內容,因為它帶有[gray]標識‼️
最後我們就可以把老的服務下線:
kubectldeletedeployk8sdemo-deploy
這樣就完成了服務的藍綠部署。
2. 金絲雀釋出
還是上面幾個yaml檔案,只不過策略上有點區別,就是老的v1.0.0多起幾個pod,比如這裡我們擴容到3個pod;我們新的服務就一個v1.0.1的pod。
大家可以看下:
接下來為了測試,service.yaml需要把version標籤去掉,因為這次我們允許新的服務也提供線上服務(新老共存)。service.yaml:
apiVersion:v1
kind:Service
metadata:
name:k8sdemo-svc
spec:
ports:
-name:k8sdemo-svc
port:8000
targetPort:60001
selector:
app:k8sdemo
type:NodePort
我們訪問看下:
docker@minikube:~$whiletrue;docurl-XPOSThttp://hi.k8sdemo.com:31721/hello-d'{"name":"fromGW"}';done
{
"message":"HellofromGWfrom172.17.0.3:50009"
}
{
"message":"HellofromGWfrom172.17.0.8:50009"
}
{
"message":"HellofromGWfrom172.17.0.8:50009"
}
{
"message":"[gray]HellofromGWfrom172.17.0.7:50009"
}
我們看到是RR輪循的方式把流量負載均衡到各個pod中。最後我們也看到[gray]出現在我們的列印中。
當我們驗證沒有問題之後我們就可以把流量全部切換到新的版本中,只需要修改service.yaml加上新的版本號即可,然後通過kubectl scale
擴容到和老的服務一樣的數量。
這種就是按照1:3的流量做灰度的。這在規模比較小的時候可以使用,當規模達到成千上萬的時候,不建議這麼做了。
寫到這裡我不禁感嘆:技術的發展就是把人變得懶惰一點,原本部署很複雜的事情,但是你兩行命令就搞定了,剩下的時間幹什麼呢?喝杯咖啡打發掉還能怎樣?
3. 小結
基於k8s的ingress和service實現的灰度釋出方案到這裡就結束了,因為k8s對細粒度的灰度支援不太友好,所以我們需要藉助第三方元件幫助我們完成,比如雲廠商提供的ingress以及istio
提供的ingress,像這樣的ingress就可以做到真正的全方位的灰度釋出。
公粽號:堆疊future
使很多處於迷茫階段的coder能從這裡找到光明,堆疊創世,功在當代,利在千秋