UZABASE Tech Blog

〜迷ったら挑戦する道を選ぶ〜 株式会社ユーザベースの技術チームブログです。

Kubernetes + Istioでblue-green deploymentを実現する

こんにちは、SPEEDAのSREチームの阿南です。最近Kubernetes界隈が盛り上がっていますね。ここ一年で、各企業での利用事例やKubernetesを解説している書籍等もかなり増え、活用の仕方も徐々に確立されて来ているのではないでしょうか。一方Istioについては、色々できそうということはわかったんだけど、利用事例も少ないためどう使えばいいかわからない、本番運用しているという企業もまだあまり聞かないし導入に踏み切れない、という方も多いかと思います。弊社ではまだ2つのnamespaceのみですが、Istioで運用を開始しております。今回は、Istioで実現できることはなんとなく知っているが、具体的な設定方法がよくわからない方向けにblue-green deployの設定を参考に説明してみたいと思います。

Istioの通信について知りたい方はこちら

環境

GKE 1.9.7-gke.11 ,Istio1.0.2 を利用しています。

IstioのRouting Rule

IstioのRouting Ruleには大きく4つのリソースがあります。

resource 説明
Gateway HTTP/TCPのリクエストを受付. どのHost or Portのアクセスを許可するかのルールを記載。 Ingress / Egress のルールを適用できる
VirtualService ルールにマッチしたリクエストをKubernetesのサービスにルーティングする. weightやheaderの情報を利用した振り分けを定義でき、Istioの設定の要とも言える
DestinationRule trafficの振り分けルールを設定. (例: round robin, least connection 等)
ServiceEntry 外部サービスを登録. 例えば、Kubernetes(Istio)の外側にあるDBの接続先等

この4つが適用された通信のイメージを手書きして見ました。まず、クラスター外部から内部への通信です。

f:id:tanan55:20181118130152p:plain

Gatewayを通ったリクエストがVirtualServiceのルールに基づいて各サービスにルーティングされます。その際に、DestinationRuleに基づき最終的にリクエストが送られるpodが決まります。(DestinationRuleでsubsetが設定されていない場合は、RoundRobinで均等に分散される)

続いて、クラスター内部から外部への通信です。

f:id:tanan55:20181118132321p:plain

コンテナから外向きに通信が発生した後、ServiceEntryのルールに基づきRequestを許可するかどうか判断します。ルール次第で、Egressgatewayを通る場合とそうでない場合の2種類があります。個人的には、まだEgressgatewayを使ってないので、外部のエンドポイントを登録する際はServiceEntryに毎回登録しています。

blue-green deploymentの設定

まずは、Kubernetes のPodをサービスとして稼働させるためのリソースを作成します。

  • namespace

gist.github.com

Namespaceを作成する際に istio-injection: enabled を設定しておきます。この設定で自動的にistio-proxyがサイドカーコンテナとして起動するようになります。

  • deployment

gist.github.com

Deploymentでは、 version: blueversion: green の2つnginxを稼働させます。Istioの設定を行う際に、このlabelを元にBlue-Greenができるように設定します。

  • service

gist.github.com

serviceでは、port: 40001で待ち受け、app: nginxtargetPort: 80番へフォワードします。

続いて、Istioのリソースです。Istioのリソースについては、istioをインストールした際にCRDに登録されていますので、kubectl コマンドを利用して設定の反映が可能です。

  • gateway

gist.github.com

gatewayには許容するHostを指定します。正規表現も可能です。 今回は sample.hoge.com を登録します。

  • virtualservice

gist.github.com

gatewayのルールにマッチした通信が、virtualserviceのルールに基づいてkubernetesのServiceへルーティングされます。ポイントとして、headerに x-version: blue とあれば、subset: blue のdestinationruleが適用されるようにしています。このほかの通信については全てgreenにアクセスされます。この設定を利用してblue-greenの切り替え前にblue環境のテストに利用が可能です。

  • destinationrule

gist.github.com

subsetがblueであれば、version: blue のラベルを付与し、subsetがgreenであれば、 version: green のラベルを付与します。これによって、どのPodにアクセスが振り分けられるかが決まります。以上で、設定が完了です。設定を確認するには下記のコマンドを実行します。

$ kubectl get gateway
$ kubectl get virtualservice
$ kubectl get destinationrule

今回構築した環境のイメージは下記の通りです。

f:id:tanan55:20181118230108p:plain

では、実際にアクセスしてみます。今回は、nginxコンテナに出力されたログを見ることにより、どちらのPodにアクセスされたかを確認します。 下記のコマンドでコンテナのログをtailしておきます。

$ kubectl logs -f -n sample-ns $(kubectl get pod -n sample-ns | grep blue | cut -d' ' -f1) -c nginx
$ kubectl logs -f -n sample-ns $(kubectl get pod -n sample-ns | grep green | cut -d' ' -f1) -c nginx

まずは、headerにx-versionを記載せずアクセスします。

$ kubectl get svc istio-ingressgateway -n istio-system
// EXTERNAL-IP を確認
$ curl -XGET -H 'Host: sample.hoge.com' http://<EXTERNAL-IP>/

f:id:tanan55:20181119223402p:plain

最初にアクセスした際は、全てのリクエストがblueのPodにしかリクエストが送られません。

ここで、headerにx-version: green を付けてアクセスします。

$ curl -XGET -H 'Host: sample.hoge.com' -H 'x-version: green' http://<EXTERNAL-IP>/

f:id:tanan55:20181119223549p:plain

特別なheaderをつけることで、特定のリクエストのみを新規にリリースしたgreenに送ることができます。greenが正常なことを確認できたら、blueとgreenを切り替えます。切り替えの方法は、先ほど設定したvirtualserviceのsubsetのblue-greenを逆転させるだけです。

gist.github.com

上記のyamlを適用後、アクセスすると、blueとgreenが入れ替わり、Blue-Green Deploymentが出来ます。

Istioを使い始めてこれはいい!と思ったポイントとしては、本番環境と全く同じ環境でテストができるということです。検証環境と本番環境で差分があってリリースがうまく行かないというのはよくあることだと思いますが、Istioを使うことで、テストができている状態のPodにアクセスを切り替えることが簡単に実現できます。さらにこれを応用して、特定の割合を振り分けたり、社内ユーザのみに新しい環境にアクセスしたりといったことをPodに変更を加えることなく実現できるようになります。 今回は紹介していませんが、gateway や istio-proxy で telemetryを収集でき、grafana / jaeger 等でリクエストのトレースやレスポンス速度を簡単に可視化できるのでこの辺りをフルスタックで揃えているIstioには最初感動しました。ただし、ハマりどころの多さ(本当に多い)や安定性といった面ではまだまだ成熟していない(バグ結構ある)ので、まずは影響の少ないnamespaceから、かつ、メイン機能となるルーティング周りからIstioを使い始めて、運用ノウハウを貯めていくのがいいかなと個人的には思っています。

仲間募集!!

ユーザベースのSPEEDA SREチームは、 「No Challenge, No SRE, No SPEEDA」 を掲げて業務に取り組んでいます。

「挑戦しなければ、SREではないし、SREがなければ、SPEEDAもない」という意識の元、ユーザベースのミッションである 「経済情報で、世界をかえる」 の実現に向けて、日々邁進しています。

IstioやKubernetes以外にも様々なことにチャレンジしてますので少しでも興味を持ってくださった方はこちらまで!

Istioを使いこなすために知っておくこと

こんにちは、SPEEDAのSREチームの阿南です。最近Kubernetes界隈が盛り上がっていますね。ここ一年で、各企業での利用事例やKubernetesを解説している書籍等もかなり増え、活用の仕方も徐々に確立されて来ているのではないでしょうか。一方Istioについては、色々できそうということはわかったんだけど、利用事例も少ないためどう使えばいいかわからない、本番運用しているという企業もまだあまり聞かないし導入に踏み切れない、という方も多いかと思います。弊社ではまだ2つのnamespaceのみですが、Istioで運用を開始しております。今回は、Istioで実現できることはなんとなく知っているが、内部の通信の仕組みやどのようなコンポーネントがあるのかを追っていきたいと思います。その上でBlue-Green Deploymentを実現するための設定方法についても次回記事で触れていきます。

この記事で扱うこと

  • Istioを構成するコンポーネントについて
  • Istioの通信の流れ

Istioを構成するコンポーネント

Istioのコンポーネントについては、IstioのDocumentationに下記の図が紹介されています。

f:id:tanan55:20181125110511p:plain

図の上側はdata planeで、サービスのPodにサイドカーコンテナ(Envoy) が起動し、Podへのリクエストを中継しています。 図の下側はcontrol planeで、Pilot, Mixer, Citadel が稼働します。Pilotは各サイドカーコンテナにConfigを反映し、Mixerはtelemetry収集やPolicy check(アクセスコントロールや流量の制御等)を担います。Citadelは証明書の管理を担当します。

では、実際にIstioをデプロイしてみて確認してみます。

f:id:tanan55:20181008191459p:plain

デプロイの方法については省略しますが、コマンド一つで大量のPodが起動してきますので、一見面食らいますが、順に整理していきます。(grafana, prometheus, servicegraph, tracingについては実際のサービス通信とは関係が薄いため、省略します)

pod 役割
istio-citadel 証明書の発行、管理を実施
istio-egressgateway Istioの内部から外部へ通信するためのgateway
istio-galley ユーザが定義したIstio設定のvalidationを実施
istio-ingressgateway Istioの外部から内部へ通信するためのgateway
istio-pilot ユーザが定義したIstio設定を反映
istio-policy Mixerの一部. istio-proxyに来たrequestをチェック
istio-telemetry Mixerの一部. 各podからテレメトリを収集
istio-sidecar-injector Podが起動する際に、リクエストをhookしてサイドカーを auto Injectする

上記のコンポーネントでIstioの外からどのようにサービスのPodまでリクエストが到達しているのかを図で表現してみました。

f:id:tanan55:20181125114804p:plain

上図の番号順に処理内容を解説します。

  • リクエストが来る前にEnvoyをサイドカーコンテナとしてInjectしておく。(⓪)
  • ingress-gatewayへリクエストが到達。ここで、hostやpathベースで、どのサービスPodにリクエストをforwardするか決める。(①)
  • istio-proxyへリクエストが到達。実際には、サービスPodへのリクエストをPreroutingしている。例えば、サービスコンテナが80番で稼働していた場合、80番に来たリクエストを15001(Envoyポート)に流す。(②)
  • istio-proxyからistio-policyにアクセスし、Policyのチェックを実施。例えば、流量の制御(最大同時アクセス数100等)で条件にひっかかった場合は、サービスのコンテナに到達する前にその時点でリクエストが返される。(③)
  • Policyでチェックを通ったリクエストがサービスコンテナに到達。(④)

この辺りは、実際に通信の流れを理解するまでに時間がかかりました(今も勉強中です)。ご自身で確認したい方は、実際にistio-proxyのコンテナでshellを起動して、tcpdump, netstat等を取ってみると理解が進むと思います。istio-proxyにはデフォルトでこの辺りのコマンドがインストールされているので、スムーズに調査ができます。
今回、実際に通信をみていった結果、想像以上に色々なことをしてるなという印象でした。特に、PolicyチェックのためにMixerにアクセスしている点は結構重要で、istio-policyのPodがダウンするとサービスの通信もダウンしてしまいます。本番運用する際は、この辺りのConfigurationも注意して見ていきましょう。ちなみに、Istioは必要なコンポーネントに絞ってインストールが可能なので、最初はistio-policyなしで運用するのも十分ありだと思います。

今後Istioがどの程度、使われ広まっていくかはまだわかりませんが、Service Meshに必要な概念や機能を勉強するには良いソフトウェアだと思いますので、皆さんもぜひ一度触れてみてください。次回の記事では、通信の流れやコンポーネントを理解した上で、Istioを使ったBlue-Green Deploymentの方法をみていきます。

Kubernetes + Istioでblue-green deploymentを実現する

仲間募集!!

ユーザベースのSPEEDA SREチームは、 「No Challenge, No SRE, No SPEEDA」 を掲げて業務に取り組んでいます。

「挑戦しなければ、SREではないし、SREがなければ、SPEEDAもない」という意識の元、ユーザベースのミッションである 「経済情報で、世界をかえる」 の実現に向けて、日々邁進しています。

少しでも興味を持ってくださった方はこちらまで!

Vue.jsとFirebaseとGASとiPadで会議室表示板を作った

こんにちは、コーポレートエンジニアリングチームという新チーム所属のたけうち(@chimerast)です。ユーザベース社内ではレアポケモンと呼ばれています。

数ヶ月前、メンバーも数百人を超え、アメリカのQuartz社がユーザベースグループに加わったりして、業務改善を主として行う管理部門付けのエンジニアチームが欲しいという話になり、新しいチームが作られました。名前はなんでも良かったのですが、世の中的に流行っているのとエンジニア採用に効きそうなので、コーポレートエンジニアリングチームという名前になっています。

コーポレートエンジニアリングチームという名前がついてはいるものの、ユーザベース社の場合はその業務範囲は幅広く、業務改善、情報セキュリティ、内部統制、情報システム、全社リスク管理等々、管理部門でITが絡めば大体担当になります。

あと、普通の情シスチームでも面白くないので、

いいのがない、作ればいいじゃん、ホトトギス
使いにくい、作ればいいじゃん、ホトトギス
お金が無い、作ればいいじゃん、ホトトギス

の精神で、バックオフィス業務全般(経理・財務・法務・人事・労務・総務)や監査もわかり、システム開発できる情シスを目指しています。

業務改善軸で数ヶ月前に作ったもの: 会議室表示板

会議室が誰が使っているのか、いつからいつまで使うのかが一目見てわかるものを作りました。iPad用のシステムですが、iOSアプリではなくウェブアプリです。Google Calendarの会議室予約と連動します。

f:id:chimerast:20180724113649j:plain:w280f:id:chimerast:20180724113659j:plain:w280

作った経緯

ユーザベース社は今年2018年7月に六本木にオフィスが引っ越しました。

ピッカピカの新オフィスで、会議室も恵比寿オフィスの時の4部屋から9部屋に倍増、会議室からの眺めもよいという非常に良い環境でテンションも上がります。そして、そこには壁への埋め込み式のiPadが。創業期の狭い8畳ぐらいのオフィスから、数回のオフィス引越しを経て、ついに弊社オフィスにも近代化の波が押し寄せてきたのかとわくわくしたものです。

が、そこまでは良かったものの、オフィス引越チームが選定していた会議室表示システムを入れてみたところ、

  • iPadの画面をタッチしても反応が悪い・遅い、謎のスワイプさせるUI
  • 会議室名についている色に合わせて画面背景の色だけでも変更したいのにできない
  • 現在行っているミーティングの予定しか見れず、次に自分が使う会議室なのか分からない

という状況で使いにくい。社員は会議室を探してうろうろしているし、なにより自分が会議室を使おうとしたときにイライラするという状態でした。

サービスを提供している会社さんには悪いとは思いつつも、普通のiPadだしウェブアプリとして作ればそんなに時間がかからず作れるだろうと思い、強権発動して作って入れ替える事にしました。

これくらいの用途であれば、ウェブアプリとして作ってもサクサク動きます。また、作るのもデプロイするのもiOSアプリと比べると圧倒的に楽です。 一晩夜なべしたらできました。

f:id:chimerast:20181120020512p:plain:w280f:id:chimerast:20181120020518p:plain:w280

作り方および使った技術

Vue.js+TypeScript、Firebase、Google App Scriptを使って作りました。

細かい所は難しいものではないので、はしょります。流れとしては下記になります。

  1. 会議室カレンダーの追加や変更イベントをGoogle App Scriptのトリガーで捕捉できるように設定する
  2. Google App ScriptからCloud Firestoreにカレンダーの追加・変更を登録する
  3. iPad上のウェブアプリからFirestoreのonSnapshot()を呼び出して、リアルタイムにFirestore上の変更を監視する

f:id:chimerast:20181120022515p:plain:w400

GASからFirestoreへの登録にはこちらのGAS用ライブラリを使わせてもらってます。 https://github.com/grahamearley/FirestoreGoogleAppsScript

全体のソースコードは残念ながら現時点では公開していないです。

ウェブアプリをiPadホーム画面に登録する方法

Safariの共有メニューから「ホーム画面に追加」というボタンを押せば、普通のWebサイトをアプリっぽく登録できます。後述しますが、いろいろHTMLに細工をするとほぼネイティブアプリっぽく見えるようになります。

f:id:chimerast:20181120020448p:plain:w280f:id:chimerast:20181120020458p:plain:w280

ネイティブアプリっぽく見せる細かいテクニック

iPadでそのままウェブアプリを表示すると、ブラウザだなーと一目見て分かってしまうので、いくつかHTMLに細工をしています。

上部の時計やバッテリー表示部分の帯を透過させる & 全画面つかえるようにする

iOS標準の状態だと、ウェブアプリを起動すると黒い帯が表示されてしまいます。また全画面にもならないです。

f:id:chimerast:20181120020523p:plain:w280

そのままだとかっこ悪いので、下記のHTMLをHEADタグ内におまじないとして追加するといい感じになります。

<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

f:id:chimerast:20181120020512p:plain:w280

ドラッグ操作をキャンセルする

iOSのブラウザの標準動作では、指でドラッグするとテキスト選択ができてしまいます。これができてしまうと一瞬でブラウザだとばれてしまい、見た目が悪いので、ontouchmoveのデフォルト操作を無効化します。

<body ontouchmove="event.preventDefault()">

タッチしたときに素早く反応するようにする

.rt-left(@touchstart="inuse = !inuse; return false" :style="{ backgroundColor: room.color }")

普通のPC用ブラウザでマウスクリックしたときのイベントとして利用する onclickonmousedownでも一応動くのですが、タップしても反応が悪かったり、微妙に遅れたりします。

元々入っていたシステムでもタッチ操作の反応が悪かったので、周りのアクリル板の静電気が悪さしてるのかなと思って、帯電防止スプレーを吹きかけてみたりしたのですが直らず、結局素直にスマホ用のontouchstartを使うことで今までの微妙な動作は何だったのかと思うぐらいキビキビ動くようになりました。

最近Safariのアップデートが進んで、onclickonmousedownもタップ操作で十分違和感なく動くようになったと思い込んでいたのですが、勘違いだったようです。素直にスマホ用のイベントを使いましょう。

その他iPadを使った社内システム向けテクニック

ホームボタンを押しても操作できないようにする

iOS標準のアクセスガイド機能を使います。暗証番号を入れないとホーム画面に戻れなくなります。

https://support.apple.com/ja-jp/HT202612

常につけっぱなしにする & 画面が暗くならないようにする

常につけっぱなしにするには、「設定」→「画面表示と明るさ」から、自動ロックを「なし」に設定すればOKです。

これだけだと明るさMAXにしておいても、周りの明るさによって微妙に暗くなったりします。これを避けるためには、「設定」→「一般」→「アクセシビリティ」→「ディスプレイ調整」→「明るさの自動調整」をオフにします。その上で明るさをMAXにします。

最後に

コーポレートエンジニアリングチームでは、業務改善と内部統制・情報セキュリティが表裏一体だということを熱く語れる人を募集中です!

また、12/4(火)に、この辺について熱く語れる人を集めて、情報交換するためのLT大会を開催します。もしご興味があればご参加ください!