この記事はドワンゴ Advent Calendar 2017 8日目の記事です。
昨日は @binzume さんの【Android】minSdkVersion = 4 でアプリ開発する縛りプレイ【バッドノウハウ】でした。
仕事ではiOSを書いていて、iOSはOSのアップデート率がとても高く、古いOSをサポートし続ける理由が少なく、古い端末に悩まされるということは(あまり)ありません。時々はありますが・・。Androidは古いOSの対応が大変そうだなといつも横目で見ています。そんななかこの縛りプレイは業務に役立つかは不明ですが、とても面白い試みだと思いました。
この記事ではサービスメッシュについて書こうと思います。
僕は業務ではN予備校のiOSエンジニアをしています。ただ、サービス開発全般的に興味があり、インフラからフロントまでなんでも学ぶ気持ちを持っています。最近注目している技術はコンテナとそれを管理するKubernetesで、サービスメッシュはKubernetesの先にある技術だと思っているため、今回は勉強も兼ねてアドベントカレンダーに書く内容をこれに決めました。
Conduitを使ってみる
最近のサービス開発ではマイクロサービスが賑わっています。2年前のアドベントカレンダーで僕はCloud Naviteなアプリケーションについて書きましたが、2年も経つとCloud Nativeが指す意味も明確になってきています。Pivotalが発表した Cloud-Native Maturity Model では、Cloud Nativeなアプリケーションについて、マイクロサービスアーキテクチャが使われていることをあげています。1
マイクロサービスはサービス同士が互いに通信を行うため、今までのサービス管理にはなかった問題が発生します。一番単純な例ではホスト名をサービスに与え、DNS等で名前解決を行いHTTPで通信をします。この方法でサービス同士の通信は可能になりますが、不便な点がいくつもあります。
- このサービスにアクセスしたいけど・・・どうやったらアクセスできるんだろう
- どのサービスとどのサービスがどれくらい通信しているんだろう
- リクエストは失敗していないのかな、失敗したらリトライしたいな・・・
- でも無限にリトライはしたくないな、そして指数的にリトライしたいけど・・その処理どこが持つんだろ
- サービス間の認証ってどうなってるんだっけ?
- 本デプロイの前に5%くらいのリクエストを新しいサービスに流して問題ないか確かめたいなぁ・・
このようにマイクロサービスアーキテクチャでアプリケーションを作っていくと、本来実現したかった機能ではない問題を考える必要がでてきます。これらはモノリシックなアプリケーションでは(多くの場合)無視できた問題ですが、マイクロサービスではこのあたりをしっかりと管理しないとサービス間の依存がわからなくなったり、無限にリクエストを飛ばし続けるサービスがバグにより生まれてしまった時にサービス全体に影響してしまったりします。
これらの問題を解決するため、サービスのロジックに影響せずにサービスの管理や監視等の処理を受け持つプロダクトがあり、それらの一つはサービスメッシュと呼ばれています。サービスメッシュの具体的なプロダクトとしては、IstioやLinkerd、そして、先日発表されたばかりのConduitがあります。
Conduitについて
ConduitはLinkerdの開発や運用の経験を経て作られたKubernetes用のサービスメッシュです。Linkerdを作った人が開発をしているため、そこで得られた経験や知見が生かされ作られています。
開発元のConduitを発表した記事によると、とても軽いが強力なKubernetes用のサービスメッシュとして2作られています。
まだ発表されたばかりなので機能が十分にあるわけではないですが、Kubernetesさえあれば簡単に試すことができます。
Conduitはどのようにサービスメッシュを実現するか
Conduitはサービスメッシュを管理するコンテナと、各サービスのPodにデプロイするコンテナによって成り立っています。各Pod内にデプロイされるコンテナはサイドカーと呼ばれています。Conduitではこのサイドカーコンテナは軽量なプロキシとして動作し、サービス同士の通信をプロキシし、同時にメトリクスの収集も行います。
各サービス間の通信はサイドカーのConduitが用意したプロキシコンテナを通し行われることになります。
KubernetesにConduitを適用する
Getting Startedに沿ってConduitをインストールしてみます。ConduitのGetting StartedではConduitのインストールから、COnduitが用意したマイクロサービスのデモアプリのデプロイまでを行うことができます。
デプロイにはKubernetesが必要なので、minikubeやGKE等でkubectl
コマンドが使える状態のKubernetesを準備しておきましょう。
1. 自分のマシンにConduitをインストールする
以下のコマンドでConduitをインストールできます
curl https://run.conduit.io/install | sh
上記コマンド実行後に~/.conduit/bin/conduit
に実行可能ファイルが配置されるので、zshrcやbashrcに
export PATH="/Users/{your-name}/.conduit/bin:$PATH"```
などと記述しパスを通しておきましょう。
2. ConduitをKubernetesに適用する
Conduitの動作に必要なプログラムは全てコンテナ化されていて、KubernetesのDeploymentやService等で定義されています。以下のコマンドを適用することでこれらをインストールすることが可能です。
conduit install | kubectl apply -f -
実際にどのようなコンテナが使われるかを知りたいときは、 conduit install
と入力することでKubernetesのアプリ定義ymlを確認することができます。
また、上記コマンド適用後はKubernetes上にデプロイされているため、kubectlコマンドでどのようなコンテナが動いているか確認することができます。Conduitの制御用コンテナはconduit
namespaceで動作するため、以下のように確認できます。
kouki_dan% kubectl get deployment -n conduit
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
controller 1 1 1 1 3h
prometheus 1 1 1 1 3h
web 1 1 1 1 3h
NAMEから想像すると、
- Conduit全体を管理するために
controller
- サービス間通信のメトリクスを保持しておくために
prometheus
- Web UIを提供するための
web
の3つのDeploymentが存在するのでしょうか。こちらはあとで見ていこうと思います。
3. dashboardを見てみる
Kubernetesを普段から使っている人はkubernetes-dashboardを見たことがあると思います。これはクラスタ内のNodeやPod、ServiceやDeployment等、Kubernetes上の情報を確認できるUIを提供しています。
Conduitもサービスメッシュ用のUIを提供しており、このコマンドを打つことで確認できます
conduit dashboard
このコマンドを入力すると自動的にブラウザが開き、Conduitのdashboardが開かれるはずなのですが、僕の環境では動きませんでした。その場合は手動で開く必要があります。たいていの人はこのURLがConduitのURLになるはずです。
http://127.0.0.1:8001/api/v1/namespaces/conduit/services/web:http/proxy/
ブラウザでdashboardを見ると、このような画面が表示されるはずです
リクエストの頻度や成功頻度、等を見ることができます。
この時点ではまだアプリをデプロイしていないため有用な情報は表示されていないと思います。次のステップに進みデモアプリをデプロイしてみましょう.
4. デモアプリをデプロイしてみる
Conduitが作ったデモアプリをデプロイしてみましょう。デプロイ用のymlと、デプロイされるアプリのコンテナが準備されています。
curl https://raw.githubusercontent.com/runconduit/conduit-examples/master/emojivoto/emojivoto.yml | conduit inject - --skip-inbound-ports=80 | kubectl apply -f -
Kubernetesにデプロイするためのymlに、conduit inject
を適用することでConduitの実行に必要なサイドカーコンテナを追加したymlに変換します。それをkubectl applyに渡すことでConduit経由でサービス間通信を行うことができるPodをデプロイすることができます。
デモアプリ以外をデプロイする場合でもDeploymentを定義したymlにconduit injectを使うことでConduitを使ったサービスをデプロイすることが可能です。
どのようなymlが生成されるか興味がある方はパイプで繋いでいるコマンドを一つずつ実行してみてください。
- サービス定義yml(エンジニアはこのymlを定義する必要がある)
curl https://raw.githubusercontent.com/runconduit/conduit-examples/master/emojivoto/emojivoto.yml
- Conduitの設定が注入されたyml(一般的にこれはconduit inject経由で生成される)
curl https://raw.githubusercontent.com/runconduit/conduit-examples/master/emojivoto/emojivoto.yml | conduit inject - --skip-inbound-ports=80
5. デモアプリにアクセスし、dashboardを見てみる
デモアプリにアクセスしてみましょう。デモアプリのIPアドレスは以下のコマンドで確認できます。
kouki_dan% kubectl get service web-svc -n emojivoto
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-svc 10.3.242.127 35.189.148.214 80:31194/TCP 3h
この場合、35.189.148.214
がemojivotoのWebサーバーのアドレスなので、 http://35.189.148.214/ にアクセスします(この値は一人ひとり違うはずです)
EMOJI VOTEという絵文字を投票できるサービスが起動しました。このサービスにいくつかアクセスしたあとでdashboardを見ると値に変化が見られるはずです。
サービス間の通信はすべてConduit経由で行われているため、このようなメトリクスを表示することが可能になっています。
マイクロサービスを考えるときはサービスメッシュも一緒に考えよう
サービスメッシュのプロダクトの1つとして、先日発表されたばかりのConduitを取り上げてインストールし、サービス間の通信やそれらのモニタリングが簡単に行える事を見てきました。
Conduitはまだ新しく、機能も少ないですが、とても軽量で簡単に使いはじめる事ができたのが見て取れたと思います。
Kubernetesで動かすもう少し高機能で開発が進んでいるものとしては、Istioがあり、こちらにはConduitにない機能も実装されています。特にHandling Failuresにある、タイムアウトやリトライの管理はとても有用に感じる方が多いのではないでしょうか。
マイクロサービスのアプリを運用していく上でサービスをどこで切るかという切り口も重要ですが、同じようにサービス間はどのように通信され、管理されていくのかも必要です。サービスメッシュはまだ、これといったデファクトスタンダードのプロダクトが存在しませんが3、部分的にでも適用していくことでより信頼性の高いサービスを提供していくことができるのではないでしょうか。
おかたづけ
GKEを利用した方は余計なお金がかかってしまうのでお片付けをしましょう。ConduitとデモアプリのDeploymentを削除すれば良いので、
conduit install | kubectl delete -f -
curl https://raw.githubusercontent.com/runconduit/conduit-examples/master/emojivoto/emojivoto.yml | conduit inject - --skip-inbound-ports=80 | kubectl delete -f -
と、applyをdeleteに変えることでおかたづけ終了です