僕らは何故Kubernetesを使うのか
September 8, 2020
最初に
「Kubernetes はいいよ」とか「案件で使いたい」と言うと
「何がいいんですか?」とか「何ができるの?」とか聞かれてうまく答えれない事がまぁまぁあったので自分なりに Kubernetes がなぜ生まれたのか、なんで使いたいのかと何ができるかをまとめてみた
リソース調達の歴史から見る Kubernetes が現在の地位につくまで
リソース(アプリケーションを動かすためのサーバなど)調達の視点から、Kuberenetes 誕生までを見ていきます。
物理サーバを調達する時代
原初のアプリケーション開発では、アプリケーションを開発してキャパシティを予測して、リソース見積もりを行い、サーバ購入を行っていました。
この方法では以下のような課題がありました。
リソースを用意するのに、数週間から数ヶ月かかる
サーバを注文してから、到着するまでの時間もかかりました。
またその前のリソース見積もりや、社内での承認なども時間がかかったと思います。
リソース用意後にスペックの変更などが難しい
実稼働前にキャパシティを予測するのは非常に難しいでしょう。特に BtoC 的なサービスだと
予測したキャパシティより低いと余剰リソースは無駄になってしまいますし、高いと処理が捌けきれずに問題となります。
サーバ仮想化の誕生
より柔軟にリソースを扱えるように 1 つの物理サーバの上で複数のサーバを動かすサーバ仮想化という技術が生まれます。 1998 年に VMware が生まれたあたりから広まっていきます。
サーバ仮想化により、物理サーバ時代の課題が解決されます。
リソース(仮想サーバ)は数分で用意できるようになり、仮想サーバのスペック変更や起動台数なども柔軟に変更できるようになりました。
しかしながら、仮想サーバを動かす物理サーバを社内で抱えてるかぎり、余剰リソース分の費用もかかるようという課題は変わっていませんでした。
IaaS の誕生
2005 年に AWS が生まれたあたりから、IaaS という利用体系が生まれます。
IaaS のサービス提供者は大量の物理マシンを管理しており、ユーザーはその物理サーバから指定したスペックの仮想サーバを作成・管理できます。
またユーザーは利用した仮想サーバ分の料金だけを支払います(オンデマンド)
これにより仮想サーバで課題だった余剰料金の問題を解決しました。
リソース利用の効率に関する新たな課題
ほとんどの課題はパブリッククラウド誕生で解決しましたが、人間は現状に満足できないもので
もっと便利になりたいと思い始めます。
IaaS/クラウドの利用者は如何にお金を安く抑えるかということを考え始めました。
そのためには以下 2 つの課題があると認識しました
- より短時間でのリソース量の調整
- アプリケーションが使う以外のリソースが無駄になっている
より短時間でのリソース量の調整 -> より高速に
お金を抑えるために、リソースの要求に応じてサーバをスケールすることが行われ始めました。
ですが、仮想サーバの起動時間では無駄なリソース消費であったり、トラフィックが捌けないことも発生し得ました
より短時間でのリソース量の調整を行うためには、リソースをより高速に起動できるようにしたいという要求が発生しました。
アプリケーションが使う以外のリソースが無駄になっている -> より軽量に
リソースの要求に応じてサーバをスケールするのには水平スケールがよく利用されました。
水平スケールで複数の仮想サーバを立ち上げると、アプリケーションが使うリソース以外にカーネル周りなどでも消費されて、無駄なリソース利用が発生しました。
ここを効率よく使用したいという要求が発生しました。
高速・軽量
という要求の実現のためにサーバレス、コンテナと言った技術が誕生します(サーバレスは今回の対象じゃないので割愛します)
コンテナ技術の誕生
コンテナはサーバ仮想化技術の 1 つになります
一般的な仮想サーバ(ハイパーバイザ型)と比較して、OS のカーネル部分などをコンテナ間で共通利用することで
アプリケーションなどの部分だけを仮想化することで、高速起動・軽量を実現しています。
2013 年に Docker が誕生してから一気に普及した(技術・使用自体は以前からあった)
Docker でコンテナ技術の実装が誕生したことにより、リソース調達が数分単位から、数秒単位に縮まり、リソースをより効率的に扱えるようになりました。
また、それまでの仮想サーバでは環境間(Dev/QA/Prod)で差分が発生しないように
ansible や chef と言った構成管理ツールを利用したり、仮想サーバをそのままインポートするといったことをしていましたが
Docker はよりシンプルに環境間差分を発生を減らすこと(ポータビリティ)も利点の一つでした(コンテナは、カーネルのタイプ(Linux, Windows)さえ合ってれば基本的にどの環境でも動作する)
コンテナを商用環境で動かすためのコンテナオーケストレーション技術
コンテナの利用シーンとしては、
当初は開発者が手元でミドルウェアを動かしたりするなど、開発の効率化的な利用シーンが多かった印象です。
2014 年に Google が社内の全てのサービスを 20 億以上のコンテナで動かしていると発表したり
徐々にコンテナを商用環境で動かすという流れが出始めました。
シンプルに単一サーバで複数のコンテナを固定台数動かすだけであれば、docker-compose などを利用すれば良いでしょう。
しかし商用のワークフローでは
- 複数のサーバ上で複数のコンテナを動かしたい
- コンテナに割り当てるリソースを制御したい
- コンテナの稼働状況を監視したい
- web アプリコンテナをリクエスト量に応じてスケールするようにしたい
- cron 的にコンテナを起動して処理したい
- 複数のコンテナで 1 つのストレージを共有したい。
などなど、多数の要求が生まれました。
これらを解決するための方法として、2015 年あたりからコンテナオーケストレーションという技術が誕生しました。
コンテナオーケストレーション戦国時代
先にあげた商用ワークフローを解決するためのコンテナオーケストレーションですが
多数の実装が生まれました。
- Docker 公式の Swarm
- Google を中心とした OSS の Kubernetes
- Mesos 社による Marathon
- CoreOS 社による fleet
- HashiCorp 社による Nomad
- AWS による Elasic Container Service
などなどが生まれます。
以下は個人的な体感ですが
2016 年くらいまでは Docker Swarm が標準の座につきそうに見えました。
Swarm は Docker が公式に開発していることもありとっつきやすかた認識です
Kubernetes は当時は構築・管理が複雑すぎるという意見が多かった印象です
その他のツールは各社の環境に依存するため、ベンダーロックイン的な理由で避けられてるように見えました。
Kubernetes がデファクトスタンダードになるまで
Kubernetes は技術的な完成度、コミュニティの成長という 2 点でデファクトスタンダードになったと思います。
技術的な完成度
Kuberenetes は Google が長年社内で仮想サーバのオーケストレーションとして使われていた Borg という技術がベースになっています。
そのためコンテナ、仮想サーバという違いはありますが、長年の実績があったこと
また Kuberenetes では 3 ヶ月に 1 回アップデートを行うという、とても速いリリースサイクルがあります。
これにより多数の要求に素早く答えた点も普及につながった点だと考えられます。
コミュニティの成長
コンテナオーケストレーション技術のうち Kuberenetes は Google を中心としつつも OSS で、他技術は各社が開発してる状況でした。
コミュニティの規模というのは重要だと思います。(デカすぎても舵きりできずに大破しそうですが)
2015 年に Google は「クラウドネイティブソフトウェアのための持続可能なエコシステムの構築」のために Cloud Native Computing Foundation(CNCF)を設立しました。
そして、Google は CNCF のファーストプロジェクトとして Kuberenetes を献上しました。
CNCF は徐々に参加企業を増やしていき、Microsoft や Amazon と言った主要クラウドプロバイダーも参加しました。
そして 2017 年には
- Azure で AKS, AWS が EKS という Kubernetes のマネージドサービスを発表1
- fleet を開発していた CoreOS 社が fleet の開発終了宣言と Kuberenetes の採用2
と言った追い風が生まれ
この辺りから Kubernetes がデファクトスタンダードとして扱われるようになっていき、2020 年の現在では標準の座を確固たるものにしています。
Kubernetes の歴史まとめ
サーバ調達の視点からコンテナ技術が誕生して、それを商用環境で動かすために kuberenetes が生まれた経緯を見ました。
- リソースを効率的に利用するためにコンテナ技術が使われだした
- コンテナを商用環境でスケーラブルに扱うためにコンテナオーケストレーション技術が誕生した
- 多数の企業を巻き込んだ Kubernetes がコンテナオーケストレーションのデファクトスタンダードになった
Kubernetes の概要
全てを説明するには kubernetes は巨大すぎるので、特徴的だと思う点を 3 つ紹介します。
- 多様なワークフローに対応できるほどに多機能
- 宣言的設定と突き合わせループによるリソース管理
- CRD など拡張性が高い
多様なワークフローに対応できるほどに多機能
Kubernetes には多種多様なリソースが存在します。
これらのリソースは Kubernetes クラスタを構築後その中で論理的なリソースとして扱えます。
これらを正しく選択, 設定して起動させることで商用でコンテナ利用する際に求められるワークフローのほとんどに対応できます。
以下に代表的なリソースをあげておきます。
名称 | icon | 概要 |
---|---|---|
Pod | kubernetes 上で動かしたいコンテナ | |
Deployment | Pod の管理方法を定義 | |
DaemonSet | クラスタが動作するサーバ 1 つにつき、必ず 1 つは起動させたい Pod を定義する(サーバのメトリクス収集とかで使われる) | |
Job | 処理を行って終了するような Pod を定義する | |
CronJob | Job リソースを Cron のように定期的に定義する | |
Service | 外部やクラスタ内からのリクエストを Pod に割り振るようなネットワーク定義 | |
ConfigMap | Pod で利用する設定(環境変数など)を定義する | |
Secret | Pod で利用する設定のうち秘匿な情報を定義する | |
Volume | Pod で利用するストレージを定義する |
宣言的設定と突き合わせループによるリソース管理
Kubernetes では前述の各種リソースをマニフェストと呼ばれるファイルを書き、それをクラスタに渡すことで各種リソースを生成できます。
このマニフェストでリソースを定義/生成は宣言的設定
と突き合わせループ
という考え方が使われています。3
宣言的設定(Declarative Configuration)
マニフェストは「リソースをいくつ起動しろ」という命令的
な定義ではなく、「リソースをいくつある状態にしろ」という宣言的
な定義になります。
これにより Kubernetes は自律的に動作することが可能になります。
突き合わせループ(Reconciliation loop)
マニフェストをクラスタに渡すと、クラスタ内でのリソースの状態と,マニフェストのリソース定義を比較し
リソース定義の状態になるように調整を行います。
突き合わせループはこれを繰り返すことになります。
宣言的設定と突き合わせループで障害に強くなる
宣言的なリソース定義は障害に対して強くなります。
例えば負荷量に合わせて Pod の数を調整することを考えます。
命令的アプローチとして、負荷が増えたら1つPodを増やす
というなことをして、あるタイミングで Pod を増やす処理を失敗した場合、以降のスケールは想定の Pod 数より 1 つ少なくなることが考えれます。
宣言的アプローチとして、負荷N%に対して、PodをM個存在するようにする
というようなことをすると、あるタイミングで Pod 数の変更処理を失敗したとしても、突き合わせループの次サイクルでまた正しい数に変更できます。
このように Kubernetes は宣言的アプローチを取ることで、障害に対して強くなります。
これの実現のために Kubernetes はトレードオフとして、複雑なコンポーネント構成・アーキテクチャになっています。
ただ、前述の通り現在ではほぼ全てのクラウドプロバイダーが Kubernetes のマネージドサービスを用意しており
この複雑さをクラウドプロバイダーが負担してくれているので、パブリッククラウドを利用すれば恩恵のみを受け取ることができます。
CRD など拡張性が高い
Kubernetes では Pod や Deployment といったリソースがあるというのは前述の通りですが
Custom Resource Definition という機能を使ってユーザーが独自のリソースを定義することができます。
例として、Argo CDでは、CI/CD を Kubernetes 上で行える OSS があります。
この Argo CD では CD のパイプラインを CRD で定義しており、Pod や Deployment のマニフェストと同じフォーマットで CD パイプラインを定義できます。
また最近では GCP や AWS のリソースも CRD で扱えるサービスも出てきたりしてきてます4
これは何が嬉しいかというと「プロジェクト内で扱うリソースを統一したフォーマットで統一した管理が行える」ということだと思います。
例えばあるプロジェクトで AWS 上で Kubernetes や DB を動かして、システム開発をするとします。
ここで AWS のリソースは terraform, アプリのリソースを kubernetes のマニフェスト, アプリの CI/CD 設定を Github Actions の設定などで管理すると,
それぞれ管理がバラバラになりますし、それぞれの記法を学習する必要があります。
CRD を用いれば、これらを統一した kubernetes マニフェストという形で定義し管理することができます。
(また GitOps などを用いれば、運用も統一化が夢見れます。)
CRD は日々新しいのが Github などで生まれていってるため、今後どんどんいろんなリソースを手軽に扱えることが想定できます。
僕らが Kubernetes を使うべきな理由
最後に Kubernetes を使うべき利点(個人的主観)などを書いていきます。
企業的利点
会社として Kubernetes を採用した際の利点です。
機能・使用性にコストを割くことができる
Kubernetes を利用して開発を行うと、チームは機能・使用性に集中して取り組むことができます。
この理由は 2 つあります。
1 つは kubernetes というよりコンテナ技術寄りの話ですが、コンテナにメインアプリケーションを乗せて
その他の補助的な機能(ロギングや通信時の暗号化など)をアタッチアブルにできる点です。
サイドカーパターンと呼ばれるものがあり5
メインアプリケーションとセットでサイドカーコンテナを動かし
メインアプリケーションが他コンテナと通信時にプロキシ的に動作し、通信を暗号化したり
メインアプリケーションとボリュームを共有し、アプリケーションが吐いたログをログ収集基盤に送ったりします。
このような一般的なサイドカーの機能は OSS として公開されていることが多く手軽に利用できます。
これによりチームはメインアプリケーションのコア機能に集中して取り組むことができます。
2 つ目は Kubernetes のエコシステムが非常に発達している点です。
前述のサイドカーなどもそうですが、Kubernetes を動かす上での一般的な課題などを解決する OSS は非常に多く開発されています。
またその多くは Kubernetes の標準リソースもしくは CRD を用いたものが多く
簡単に用意できます。
例えば Kubernetes クラスタのメトリクスを可視化する Kuberenetes Dashboard は以下のコマンド 1 つで用意できます。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml
このように企業特有の要求などがない限りは、既存のものを利用でき
同じくアプリケーション開発に専念できます。
障害に強い構成を作りやすい
前述の通り、Kubernetes は宣言的定義のアプローチを取っているため、障害に対して強い構成を組みやすいです。
移植性が高い
Kuberenetes は OSS として開発されており、各種クラウドベンダーはもちろんオンプレミスでも動作できます。
また Kuberenetes 上で動かすものはほとんど Kubernetes リソースとして抽象化されているので、
たとえ AWS から GCP へ移行したとしても、マニフェストなどをほとんど変えずに移行することができます。
開発者的利点
開発サイクルを高速に回しやすい
作り方によるとは思いますが、自分は机上で細かく検討してから作るというよりは
とりあえず作って動かしてみて、ログやメトリクスを見て、また修正して動かしてという開発スタイルが好きです。
Kubernetes を利用すると、このサイクルが非常に回しやすいです。
- ローカルでアプリを修正
- docker build
- docker push
- kubectl rollout restart
- メトリクスやログの確認
といったサイクルになります。
体感的にすごく高速で回せるなと思います。
開発言語で Go とかを採用していると、docker build や push も早いので、1 サイクルを 1 分で回したりもできます。
使ってて楽しい
すごく主観的ですが、楽しいです。
上の開発サイクルを回しているのも楽しいですし、エコシステムが発展しており Kubernetes 周りの技術が日々作られていて、追っているだけで最先端にいる気がして楽しいです。
欠点
利点だけではあれなので欠点も少し触れておきます。
定期的にクラスタのアップデートが必要
Kubernetes では 1 つのバージョンが 9 ヶ月間しか保守されないため、かなり早いサイクルでクラスタのアップデートをかけないといけません。
Kubernetes のバージョンは x.y.z の形式で表現され、x はメジャーバージョン、y はマイナーバージョン、z はパッチバージョンを指します
Kubernetes プロジェクトでは、最新の 3 つのマイナーリリースについてリリースブランチを管理しています。
マイナーリリースは約 3 ヶ月ごとに行われるため、マイナーリリースのブランチはそれぞれ約 9 ヶ月保守されます。6
クラウドプロバイダーのマネージドサービスなどでは、クラスタの更新機能などもサポートはしていますが
バージョンアップによって Kubernetes リソース定義の一部が deprecated された場合はユーザ側で対応しないといけません。
長期的に学習を続けていかないといけない
前の話と被りますが、kubernetes はリリースサイクルが早い上に頻繁に機能が廃止・追加されます。
こういった部分を学習していかないと安定した稼働は難しくなります。
参考
https://gihyo.jp/admin/column/newyear/2018/container-and-cloud ↩︎
https://www.publickey1.jp/blog/17/kubernetescoreosfleetkubernetes.html ↩︎
https://deeeet.com/writing/2018/12/13/how-kubernetes-change-our-way-of-automation/ ↩︎
https://aws.amazon.com/jp/blogs/opensource/aws-service-operator-kubernetes-available/ ↩︎
https://docs.microsoft.com/ja-jp/azure/architecture/patterns/sidecar ↩︎
https://kubernetes.io/ja/docs/setup/release/version-skew-policy/ ↩︎