OthloBlog - オスロブログ -

名古屋のIT系学生コミュニティOthloTechのブログです。

マイクロサービス on Docker on Kubernetes

f:id:Juju_62q:20180313143045p:plain

おはこんばんちは!@ジュジュです!
最近インターンシップに参加していてマイクロサービスについて勉強をしています。
今回はそんな中で勉強したマイクロサービスの利点やどうやって実現していくのかということをまとめていきたいと思います。
実際マイクロサービスデザインパターンとかでもよかったんですが検索に引っ掛かりそうなのでこの名前にしています。

対象読者

  • マイクロサービスにすることでどんなメリットを享受できるか気になる人。
  • DockerとかKubernetesとか聞いたことあるけど何がいいのかわからない人。
  • モノリシックな開発にうんざりしている人。

記事の内容

  • マイクロサービスとモノリシックなサービスにおけるメリットデメリットをまとめていきます。
  • コンテナにすることの利点やコンテナ技術での開発パターンをまとめていきます。
  • コンテナオーケストレーションツールを利用することで得られる利点やデザインパターンをまとめていきます。

マイクロサービスとモノリシックなサービス

モノリシックなサービス

まず、モノリシックなサービスの説明から行っていきたいと思います。モノリシックという言葉の意味はこちらです。

「モノリシック」は一枚板という意味で、ソフトウェア的には、全体が1つのモジュールでできていて、分割されていないことを意味する。 特にカーネルの構造などで、必要な機能を1つのバイナリに全部組み込んでしまい、外部モジュールを必要としないようなものをモノリシックカーネルと呼ぶ。これとは逆に、最小限のものだけをカーネルに入れ、多くの機能を外部のモジュールで行うものを「マイクロカーネル」と呼ぶ。モノリシックカーネルは、このマイクロカーネルに対して従来のカーネル構造を指す言葉として使われる。 なお、現在では、マイクロカーネルではないもののモジュール構造を持ったり、一部だけを外部モジュールとして実現することも行われており、それぞれの違いは曖昧なものになってきている。

https://www.weblio.jp/content/%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B7%E3%83%83%E3%82%AFから引用しています。

つまり、すべての機能を同一アプリケーションで実現してしまう。というような状況ですよね。誤解を恐れずに言うとサービスを提供するにあたっての分割の最小単位がサービスの全体であるというような状態になります。(DBなどが切り出されているかと思いますが。。。)
結果としてアプリケーションではすべてにおいて共通のモデルを利用し、言語や依存関係なども共通のものとなります。

マイクロサービス

次にマイクロサービスについて解説をしていきます。
マイクロサービスの発案者はJames Lewis氏と呼ばれていて"Micro services - Java, the Unix Way"という論文内では以下のように定義づけられています。

マイクロサービスとはアーキテクチャスタイルの1つであり、小さなサービスの組み合わせにより単一のアプリケーションを開発するアプローチです。そして、その小さなサービスはそれぞれ自身のプロセスで動作し、軽量な方式で通信をします(通常、HTTP Resource APIが使われます)。個々のサービスは、業務上の機能に沿って構築され、その配備は完全に自動化されたものになります。それらサービスに対しての集中管理は最低限にし、また、それぞれのサービスは異なるプログラミング言語や異なるデータストレージ技術を利用します。

http://www.nttdata.com/jp/ja/insights/trend_keyword/2015072301.htmlから訳を引用しています。

つまり、1つのサービスを複数のアプリケーションの集合として作成し、それらの集合としてサービスが構成されるという形になります。Web APIを利用して通信が行われるため結果として各アプリケーション疎結合となり、アプリケーション同士で言語が異なっていてもバージョンが違っていても問題なく動作するし、モデルは自身が必要な分だけを持つという形になります。なんなら同一ネットワークに存在する必要も必ずしもありません。

画像で比較するとこんな感じです。 f:id:Juju_62q:20180313222620p:plain
https://qiita.com/LightSpeedC/items/47359dbc3b04907569d1から引用

アーキテクチャのメリットとデメリットについて

モノリシックなアーキテクチャを採用するメリットとしては下記のようなものがあげられます。

  • 通信を利用せずに必要な情報を得ることができるために応答速度が高速になる。
  • 多くのアプリケーションが配置されるわけではないためネットワーク構成図が単純なものになりやすい。
  • 共通に利用する部分が完全に同一コードになるために無駄が少ない。

これに対し、マイクロサービスアーキテクチャを採用するメリットとしては下記のようなものがあげられます。

  • アプリケーションを捨てたり追加するのが簡単。
  • 各アプリケーションが依存しているものがモノリシックなアーキテクチャに比べて少ないのでアップデートが容易。
  • インターフェースさえきちんと決めれば動作するので技術選定で攻めやすい&役割分担が容易。
  • アプリケーションの全容が理解しやすく、障害対応が簡単。
  • 1つのアプリケーションの不具合が必ずしも全体に波及しない。
  • アプリケーションレベルで負荷分散が可能。

逆にデメリットとしてはメリットと逆の部分があげられます。マイクロサービスではネットワーク構成図が複雑になりやすかったり応答速度が遅くなったり、モノリシックなアーキテクチャでは依存関係がお化けのように巨大なものになっていてアップデートもしにくいという感じです。

近年マイクロサービスが推奨されている理由について

近年マイクロサービスを導入していこうというような流れが特にWeb業界では存在します。これはなぜなのかという部分を考えていきたいと思います。最近のWeb業界では下記に対応していきたいというニーズがあると考えています。

  • 新しい機能をどんどん追加して試していきたい。
  • ダメだったらすぐに切り捨てていきたい。
  • 変化の激しいユーザのニーズに対応したい。

これに対応できる形式がモノリシックなアーキテクチャよりもマイクロサービスアーキテクチャなのではないかと考えられているわけです。
モノリシックなアーキテクチャにするとある部分で言語の新機能を使いたいが、依存しているパッケージがその言語のバージョンに対応していないとか、全体で共有している部分で継ぎ足し継ぎ足し作られた秘伝のソースコードが生まれやすいという場合が存在します。つまり、技術的な負債を比較的抱えやすいわけです。マイクロサービスであればアプリケーションごと捨てることもできるし、依存も相対的に小さいのでこのような対応は比較的容易になったりするわけです。

さらに言えばモノリシックなアーキテクチャを採用する場合に関してアプリケーションのサイズが足かせになりCI(継続的インテグレーション)が遅くなってしまうという欠点も存在します。機能追加のたびにめちゃくちゃ待たないとテストが終わらないというような状況になってしまいます。もちろん、その時間を利用してほかの業務をすればいいのですが僕に関していえば脳みそに実装されているタスクスケジューラが無能でコンテキストスイッチに非常に時間がかかるというところがあり生産性がとても落ちます。もちろんコンテキストスイッチをきちんとしてマルチタスクを高いレベルでこなすという方もいると思うのですが、僕みたいなプライオリティーキューでコンテキストスイッチを基本的にしないスケジューラが実装されている人間にも人権が欲しいです(切実)。

Dockerとは

f:id:Juju_62q:20180313223825j:plain コンテナ技術を利用して作られているソフトウェアで、2013年にオープンソースとなりました。ユーザ空間を分割することで1つのPCで異なる環境を作成することができます。さらに、DockerHubにはさまざまな環境がバージョンに分けて用意されていてユーザはそのコンテナイメージを自らのPCにドンっと持ってくるだけで環境構築を行うことができ、削除してもPCが汚れることはあまりありません。また、環境をテキストで管理することができるためGitなどを利用したバージョン管理にも適しています。

細かい説明に関しては
knowledge.sakura.ad.jp
等をご覧いただければと思っています。

マイクロサービスとコンテナ技術の関係

途中でピンと来たかたもいるかと思うのですが、マイクロサービスとコンテナ技術はとても相性がいいです。コンテナには環境やさらに言えばアプリケーションも含めることができるので動作させるだけで1つのマイクロサービスとして実現することができ、不要であれば削除できます。すぐに作ってすぐに壊せるという部分がマイクロサービスを採用する背景と近く、利用がしやすいです。さらに、思ったよりもトラフィックが多くもっと動作するものを増やしたいという場合にもコンテナを引っ張ってきてドンっとPCに乗っけてしまえばおしまいです。

コンテナデザインパターン

コンテナを利用する上での設計パターンとしてはTwelve-Factor Appに記述されているようなものがあります。インフラをいかにコードで管理するかを書かれたもので、これに従って作ることで再現性、独立性の高いアプリケーションを実現することができます。ものをダウンロードしたりするのではなく環境変数で管理していくとか基本的に守っていきたいところですよね。ただ、自分は原文は読んでいません。。。

12factor.net

Kubernetesとは

f:id:Juju_62q:20180313223829p:plain Kubernetesはコンテナのオーケストレーションツール(配備/設定/管理の自動化ツール)のデファクトスタンダードと言われており、Googleが開発しているオープンソースソフトウェアです。(k8sと呼ばれることもあります。)GoogleではDockerがオープンソース化されるよりもかなり前からコンテナ技術を利用しており現在では毎週20億を超えるコンテナが立ち上がっているようです。Kubernetesはその知見を活かして開発が行われており、大規模開発において必要な機能を備えています。以下を読むとKubernetesが一体どんなソフトウェアなのかがつかめてくるかと思います。

qiita.com

Kubernetesにおける基本的な概念

マスタ
Kubernetesでは複数のコンピュータにコンテナ(後述)を展開していきます。そのうえでどのコンピュータにどのくらいのリソースがあるのかという部分を管理し、どこにどうコンテナを起動していくのかを決めたりします。また、Kubernetes内の各コンテナの名前解決やコンテナに割り当てられるIPアドレスの管理もマスタで行われます。

ノード
マスタに管理されるコンピュータを指します。アプリケーションコンテナは基本的にノードで実行されます。Kubernetesの制御に関してはマスタを介して行いますが、ノードも必要な手順を踏めばインターネットから直接アクセスできるようになります。

ポッド
いままで散々コンテナコンテナといっていましたがポッドがKubernetes上で管理されるアプリケーションの最小単位です。ポッドではコンテナを動作させるのですが1つのコンテナだけでなく必ず一緒に動作してほしいものを複数まとめて管理することができます。このように管理することでコンテナに複数の役割を持たせることなくアプリケーションの定義を行えます。また、ポッド内のコンテナではdocker-composeに近い要領で資源共有が行われます。また、ポッドにはかならずKubernetes内でIPアドレスが割り当てられます(したがってポッド内のコンテナで同一ポートを利用するのは不可能)。実際にはポート番号を用いてKubernetesがうまく処理をしています。

デーモンセット
すべてのノードで動作するポッドです。コンピュータの状態を確認するなど絶対にすべてのコンピュータの上で動いていないといけないもので利用します。

以上を実現するアーキテクチャはこんな感じです。 f:id:Juju_62q:20180313233159p:plain

Kubernetesを利用するメリット

Kubernetesを利用することで得られるメリットはかなりたくさんあります。その中で自分が大事だと思うものを抜粋していこうと思います。

ハードウェアを最大限に利用する。
ポッドの数をシームレスに増加させる。
動作するポッドの数を自動的に管理させる。

Kubernetesではマスタがノードで余裕のある部分に入りそうなポッドを当て込んでいきます。この機能のおかげでインフラエンジニアはどこでアプリを動かしているかは考える必要がなくなります。考えることとしては「あのアプリのポッドがn個動いてる」とかそういう感じになっていきます。また、ポッドの数を増やして!とお願いするだけでポッドの数は増えます。さらに何らかの異常が発生し、指定されたポッドの数よりもよりも動作しているポッドが少ない場合には自動的にポッドを増やすという動作を行います。

高速にデプロイする。

Kubernetesでのデプロイはコンテナをプルするだけで行われます。したがってオンプレとして届くサーバを待つ必要もなければ、クラウドサービスの割り当てを待つ必要もありません。結果として超高速にデプロイができます。変化の速いアジャイル開発やマイクロサービスの開発ではうってつけの機能だと思います。

新機能を少しずつ展開し、だめだったら過去の状態に戻す。

Kubernetesでのコンテナのバージョンアップはローリングアップデートという方式で行われることが多いです。ローリングアップデートではポッドを1つずつ最新の状態に合わせていきます。その過程でコンテナが起動できない場合にはバージョンを自動で戻すという機構が備えられています。したがってアプリケーションに問題が発生した場合にも動作の不良が全体に波及する可能性は小さいです。

とりあえずテストしたいアプリを動かしてみる(カナリアデプロイ)

Kubernetesではポッドを1つだけ異なるものにするということが可能です。これにより、実運用で実際のリクエストで試しながらのテストが可能です。万が一適切なデータが送られない場合にもKubernetesでは自動的にロードバランシングが行われるので再送の際には別のポッドがリクエストを受け正常に動作します。

Kubernetesデザインパターン

Kubernetesのデザインパターンに関しては下記に非常に上手にまとめられています。Kubernetesではポッドが必ずしも1つのコンテナと対応するわけではないという部分を上手に利用することで必要な機能を詰め合わせていくことが可能です。

qiita.com

終わりに

マイクロサービスの考え方とコンテナ技術、Kubernetesという組み合わせは非常に親和性が高くこれからガンガン使われていく概念になってくるんじゃないかと思っています。ただしコンテナ技術自体はまだローンチから日が浅く、正解というものが確実でないような気がしています。本記事でも自分の知識部分で間違っている部分があるのかもしれません。そんな時はコメントを頂けるととてもうれしく思います。OthloTechでインフラエンジニアを目指しているのはたぶん自分だけなのでインフラでごりっとした部分を書いてみました。お楽しみいただけたら幸いです。

ちなみにJAPAN CONTAINER DAYS V18.04に行きた過ぎて生きていくのがつらいです。交通費高いですよね。

containerdays.jp

以上、@ジュジュでした。