KubernetesでBlue-Green Deploymentしてみる
今回はサービスを本番で運用していくときに欲しくなるBlue-Green DeploymentをKubernetesでやってみます。
TL;DR
- Serviceのselectorを更新するやり方だと10分程度BlueとGreenがまざる
- Istioを使用すれば瞬時に100%のトラフィックを切り分けられるのでBlue-Green Deploymentができる
環境
- GKE 1.9.7-gke.0
2種類のAPI
BlueとGreenを見分けるために、自身の色を返すAPIを用意します。
package main import ( "fmt" "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "blue-api") } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":80", nil) }
そして、このAPIが稼働するDeploymentがこれです。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: blue-api spec: replicas: 1 template: metadata: labels: app: color-api version: blue spec: containers: - name: blue-api image: asia.gcr.io/hoge/color-api:blue ports: - containerPort: 80 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: green-api spec: replicas: 1 template: metadata: labels: app: color-api version: green spec: containers: - name: green-api image: asia.gcr.io/hoge/color-api:green ports: - containerPort: 80
ServiceでB/Gしてみる
KubernetesはServiceでアクセスするPodを見つけているので、そこの設定を書き換えればB/Gできそうです。
apiVersion: v1 kind: Service metadata: name: service-color-api spec: selector: app: color-api version: green # version: blue type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 name: http
versionをblueとgreenで変えてみた結果、このようになりました。
ちょっとわかりづらいですね。
点線の時間で切り替えを行い、Blue(上)からGreen(下)にトラフィックが切り替わるようにServiceを書き換えました。
Serviceの設定を更新したらすべてのトラフィックがGreenに行ってほしいところですが、10分ほど両方のPodにアクセスが行ってしまっています。
これではAPIのバージョニングができていないと不整合がおきてしまい正しく動かない恐れがあります。
なにか設定が漏れているのかもしれません。
原因を知っていれば教えてほしいです...
余談ですが、切り替えた直後に前の色のPodを削除することで、瞬時に全てのトラフィックを新しい色に流すことができます。
瞬時に100%のトラフィックを切り替えたいので別のアプローチとしてサービスメッシュのIstioを導入してみます。
IstioでB/Gする
まずはIstioの導入をします。
公式ドキュメントのステップ2まででIstioの導入は完了です。
Istioで経路の制御をするので、ServiceはBlueにもGreenにも通信ができるようにしておきます。
apiVersion: v1 kind: Service metadata: name: service-color-api labels: app: color-api spec: selector: app: color-api type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 name: http
Istioを使用する場合はIstio用のIngressを通さないと経路制御などができないので、少し設定に変更を入れます。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: color-ingress annotations: kubernetes.io/ingress.class: "istio" spec: backend: serviceName: service-color-api servicePort: 80
最後に本命の経路制御の設定をいれます。
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: color-api spec: destination: name: service-color-api precedence: 1 route: - labels: version: green
今回もselectorを書き換えることで制御できます。
定期的なアクセスがある状態で切り替えるとこのようになりました。
取得できるメトリクスがCPU利用率しかなかったので、あまりいいグラフにはなっていませんが、切り替えた直後からすべてのトラフィックが新しいほうに流れています。
Prometheusを導入後に今度はアクセス数をグラフ化して追記したいとおもいます。
まとめ
サービスメッシュを入れるとトラフィックの正確な制御ができます。
しかし、制御のためのプロキシも追加されてしまうため、余計なリソースを使うことにもなってしまいます。
デメリットも存在しますが、Istioを入れてしまえばB/Gだけでなくカナリアリリースもできるようになるので、
リリースを正確に行うためにIstioを導入するのもありかもしれません。