クラウドネイティブ入門してみた

# はじめに
最近Kubernetesを習得するにあたり、クラウドネイティブ自体の理解度が不足していると感じたため体系的に学習しました。
今回学んだこと忘れず実務で必要になった時に参照できるよう、記事にまとめました。


# クラウドネイティブとは
　単に```AWS等のクラウドサービスを利用すること = クラウドネイティブ```と認識していたが、少し違っていた。
　正しくは、```クラウドサービスの利点を徹底的に活用することで、アプリ開発とリリースを迅速・柔軟に行うこと```を意味している。**クラウド利用は手段であり、昨今ニーズの高まってきた高速開発が目的にある**といえる。
　つまり、単にクラウドサービスツールを使うだけではなく、組織文化や開発プロセスも含めて迅速・柔軟性を持たせることでクラウドネイティブが実現できる。

　[CNCF](https://github.com/cncf/toc/blob/main/DEFINITION.md)ではクラウドネイティブ技術の代表例として以下を挙げている。
- **コンテナ**
- **マイクロサービス**
- **サービスメッシュ**
- **イミュータブルインフラストラクチャ**
- **宣言型API**

それぞれ以下で掘り下げてみる。


# クラウドネイティブの代表技術
## 1. コンテナ
### まず、サーバー型仮想化（ハイパーバイザー型）
　コンテナ型仮想化（後述）とよく比較されるものとして、サーバー型仮想化がある。**サーバー型仮想化**とは、ハイパーバイザーを使用してハードウェア上に複数の仮想マシン（VM）を実行できるようにしたもの。**各VM上はOSレベルで分離**されており、それぞれ異なるOS（ゲストOS）を実行できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577028/b850b8a7-6be7-611d-8fcf-623e5d6b962f.png)


### コンテナ型仮想化
　一方、コンテナ型仮想化では主にDokcerの技術を利用することで、**ホストOSのLinuxカーネルを各コンテナが共有する**。

### メリット
- **軽量**
コンテナではホストOSのカーネルを共有しゲストOSが不要なため、オーバーヘッドが少なくなる。そのためサーバー型仮想化と比較して消費リソース（プロセッサ・メモリ・ストレージ等）が少ない。

- **高速起動**
ホストOSから見ると各コンテナは単にプロセスであるため、起動が非常に素早い。

- **可搬性が高い**
コンテナイメージ内にアプリ実行に必要なファイル群がパッケージ化されており、イメージ自体もサイズは比較的軽量なため、異なる環境（ホスト）へのアプリケーション移動が非常に容易。

### デメリット
- **ホストOSに対する依存が発生**
  - サーバ型仮想化ではVMに応じてOSを選定できるが、コンテナではホストOSに依存しコンテナに応じたOS選定ができない。
  - そのためコンテナとホストのカーネルは互換性が担保されている必要があり、要件によってはコンテナ化不可能なケースがある。

- **セキュリティリスクが比較的高い**
  - ホストの状態がその上にあるコンテナ全体に影響することになるためホストOSに不具合が生じた場合、ホスト上の全コンテナが影響を受ける。
  - そのためコンテナ型アプリケーションでのセキュリティ対策は、ホストで実行中のLinuxプロセスに対するセキュリティ対策と非常に近いことになる。

## 2. マイクロサービス
マイクロサービスとは、アプリケーションをサービスごとに分割し疎結合化すること。
もちろんメリットも多数あるが、**主に運用面でデメリットも多い**ため、要件やメンバーの技術レベルに応じて慎重に導入を検討する。


### メリット
- **柔軟な言語選定**
従来型のモノリシックアプリケーションと異なり、**各サービスで任意に言語を選択できる**ため、要件や応じて最も適した言語選定ができる。

- **拡張性**
  - サービスの各コンポーネントが個別にスケーリングでき、**リソース使用率の最適化**が可能。
  - さらにコンテナを使うことで、OS単位ではなくサービス単位でリソースを割り当てることが可能となるため、リソース効率が向上する。（例えばKubernetesなら、同一ノード上で異なる複数のサービスを起動できるためノードのリソースを効率的に使える）

- **リリーススピードの向上**
  - サービス間の疎結合化により、サービス単位でデプロイ可能なため、**迅速な変更と新バージョンのリリースが実現**できる。
  - モノシリックなアプリケーションと比べてサービスあたりのコード量が少ないため、テストが容易となる。これにより**変更に対するテスト/リリースの自動化（CI/CDの構築）** も実装しやすくなる。

### デメリット
- **トラフィック管理の複雑化**
サービス（コンポーネント）が多いほど、サービス間をつながネットワークが網の目のようになりトラフィックが複雑化するため、以下のような機能実装が必要となる。
  - トラフィックのモニタリング
  - トラフィックの目的地となるサービスの検出（サービスディスカバリ）
  - トラフィックが偏らないようなロードバランシング機能

- **セキュリティ対策の難易度**
マイクロサービス内の各コンポーネントの通信のエンドポイントは攻撃可能性がある。そのためコンポーネントが増えるにつれて、攻撃対象も増えることになる。
サービス間のトラフィックは信頼できないものとし（ゼロトラスト）、セキュリティ対策を講じる必要性が出てくる。


## 3. サービスメッシュ
### 概要
上記で触れたように、マイクロサービスのデメリットにサービス間の通信複雑化がある。
これを解決するのが**サービスメッシュ**である。


- サービスメッシュとは、サービス間の通信制御を各サービスから分離して担わせる機能。
- サービス全体規模が大きくなってもサービス間通信の信頼性と可観測性を維持するための手段の一つ。
- OSSでは``Istio``や``Linkerd``などが有名。他にもAWSではマネージドサービスとして``AWS AppMesh``が提供されておりEKSと親和性が高い。
- これらをサービスコンテナと同居するサイドカープロキシとしてデプロイし、外部との通信制御を担う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577028/7344fe45-60a4-4d3e-b982-1a7802ec1550.png)

- 具体的に以下のような多岐にわたる制御を担う。（大抵は選択的に使う）
  - **サービス検出**
  - **負荷分散**
  - **暗号化**
  - **認証・認可**
  - **通信の監視**
  - **ヘルスチェック**
  - **通信のタイムアウト/再試行**
  - **モニタリング**
  - **トラフィック管理**（canary デプロイ等も可能）


### メリット
- どのサービスであっても **一貫した方法で** サービス間通信を制御できる。
→ゼロトラストへの対応、トラブル発生時の迅速な原因特定など
- **各サービスでコードを変更せずに導入できる**ため、開発者は通信を意識する必要がなくなり開発に集中できるようになる。

### デメリット
- 多機能な反面、習得と実装に時間がかかる。

https://aws.amazon.com/jp/what-is/service-mesh/


## 4. イミュータブルインフラストラクチャ
### 概要
- 直訳すると「不変なインフラ」だが、**一度構築したインフラには変更は加えないこと**を意味する。
- 従来のオンプレでのインフラ運用では、稼働中のインフラに対してパッチ適用や設定値の変更を行なってきた。
- 一方イミュータブルインフラストラクチャでは、インフラに変更必要性が生じた場合、稼働中のリソースに変更を行うのではなく廃棄し、**新しいインフラリソースと入れ替えるような運用方法**をとる。
- イミュータブルインフラストラクチャ実現のためには、ミスのない構築のために**Infrastructure as Code（Terraform, CloudFormation等）によるインフラ構成管理が必要不可欠**。
- コンテナにシェルアクセスして変更を行うような運用はアンチパターンとされている。（IaCで記述した構成からずれて想定外の構成となるため）

### メリット
- テスト環境で十分にテストされた環境を、ミスなく容易に本番環境に適用できるため、サービスの安定性が向上する。
- インフラ更新後に問題が発生した場合は、変更前インフラへの**切り戻しが容易**。

### デメリット
- IaCの習慣やコーディングスキルの習得が必要。


## 5. 宣言型API
### 「宣言型」と「命令型」
宣言型と対になる概念に、**命令型**がある。
- **命令型**は、実行する必要のあるコマンドを順次実行していく方式。
  - 手順を把握できるが、想定と実環境が異なるなどの原因でコマンドの修正が必要になり、手順の管理が必要というデメリットがある。
- **宣言型**はシステムの望ましい状態を宣言する形で定義してアプリケーションを実行する方式。
  - **手順ではなく目的となる結果を記述してapply**することで、あとはシステムが自律的にその理想状態となるよう動作する。
  - 宣言型方式を採用することで、たくさんの命令実行や都度システムの状態確認が不要となるため、**アプリ/インフラの運用負荷が軽減されるメリット**がある。

### 宣言型APIの活用
- **クラウドネイティブのソフトウェアでは宣言型APIが採用されており、運用がシンプルになるため高速な開発とリリースを助けることができる。**
  - 例えば、KubernetesではYAML形式の``マニフェスト``によりリソースの理想状態を記述して適用することで、リソース作成・削除・変更といった操作をする。


# 最後に
　クラウドネイティブの技術やメリデメについてまとめてみましたが、全体的に運用の自動化・シンプル化によって高速な開発・リリースを助けることが目的の技術といえます。
　非常に魅力的ではありますがその反面、セキュリティ・ネットワークの基礎的なスキルや、ツールの習得が必要で技術的難易度は高いです。
　要件やメンバーの技術レベルを十分考慮して、本当に必要な技術から導入していくべきだと思います。




# 参考記事
- [クラウドネイティブセキュリティ入門](https://www.amazon.co.jp/%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%8D%E3%82%A4%E3%83%86%E3%82%A3%E3%83%96%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E5%85%A5%E9%96%80-%E6%BE%A4%E6%A9%8B-%E6%9D%BE%E7%8E%8B/dp/4863543492)
- [コンテナ型仮想化 vs サーバー仮想化を比較、利用するメリットとは？](https://cloudnavi.nhn-techorus.com/archives/2702)
- [コンテナ・セキュリティ入門 と Kubernetes](https://qiita.com/MahoTakara/items/b3baafe3a6ea9a26fef4)
- [クラウド・ネイティブ基礎知識解説](https://www.ibm.com/blogs/think/jp-ja/cloud-native-concept-03/)