コンテナー技術について理解した事をまとめた

# 概要
SREの業務を行う際、コンテナー技術を使用して何らかの構築を行う事が多いです。基本的な構築であれば今までの経験で構築できますが、手順を覚えているだけで中身まで理解していないなと感じました。今回は、コンテナ義技術と`Docker`について理解した事をまとめます。


# コンテナ技術の概要
　仮想化技術のコンテナは、OS上に仮想的に複数のコンテナ(分離・独立した領域)の箱を設け、そのなかで、アプリケーションを実行・動作させる仕組み。コンテナ技術の仕組みを深掘り過ぎると永遠に終わらないので、触り程度でまとめています。

## 一般的なコンテナ技術の仕組み
- VirtualBoxなどの仮想マシンでは、ホストマシン上でハイパーバイザを利用しゲストOSを動かし、その上でミドルウェアなどを動かす。下記は、一般的な仮想マシンの構造を示す

![VirtualBoxなどの仮想マシン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664659/6ca3985a-fab5-d3f1-1cd1-5bd8d112046d.png)

### メリット
- ホストマシンから分離されている為、異なるOSやソフトウェアの環境を同時に実行出来る
- 仮想環境であれば、スナップショットを容易に取得出来る。これにより、仮想マシンの状態を容易に保存が出来て、更に状態を戻す事も容易に出来る

###  デメリット
- ホストマシンのリソースを使用する為、パフォーマンスはホストマシンの能力に依存する
- メモリ、ストレージ、CPUサイクルなどのリソースを消費する。これにより、ホストマシンのパフォーマンスに影響を与える
- 仮想マシンの起動に時間が掛かる

## 用語補足
### ハイパーバイザ
- 仮想マシン (VM) の作成と実行を行うソフトウェア
- ユーザーが自分のニーズに応じて設定を行う必要がある
- 物理的なハードウェアのリソースを複数の異なる仮想マシン（VM）に分割し、その仮想マシンを管理する為に使用する
- ハイパーバイザには、`Type1`と`Type2`の2種類がある。この2種類の説明に関しては、説明を割愛する。詳細説明は、[ハイパーバイザの種類](https://www.redhat.com/ja/topics/virtualization/what-is-a-hypervisor#%E3%83%8F%E3%82%A4%E3%83%91%E3%83%BC%E3%83%90%E3%82%A4%E3%82%B6%E3%83%BC%E3%81%AE%E7%A8%AE%E9%A1%9E)を読んで下さい

### ホストOSとゲストOS
- 仮想マシン環境を動作させている土台のOSを**ホストOS**
- 仮想マシン上で動作しているOSを**ゲストOS**

### スナップショット
- ある時点でのソースコードや、ファイル、ディレクトリ、データベースファイルなどの状態を抜き出した状態のもの
- スナップショットを取得するには、システムの状態を一時的に**フリーズ**させ、その瞬間の状態を保存する

#### ホストOS(メインOS)でスナップショットの取得が難しい理由
　OSが直接ハードウェアにアクセスする際、プロセスの起動、ファイルの開閉、メモリの割り当や解放等、常に様々な処理が同時行われている。この状態で、システムを一時的にフリーズさせ、スナップショットを取得するとシステムの安定性を損なう可能性がある。その為、ホストOSでのスナップショットの作成は難しい。

## Dockerの仕組み
Dockerは、Linuxカーネルの機能である**cgroups（コントロールグループ）**と**namespaces**を使用して、コンテナの作成、実行を行う。これらの機能を使用する事で、各コンテナに対してプロセスの隔離、ネットワークの隔離、リソースの制限等を行える。下記は、Dockerの構造を示す

![Dockerの仕組み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664659/8aa61bb7-5367-0ff1-039b-940d7923b601.png)

### メリット
- 仮想マシンよりも軽量で、ホストOSのカーネルを共有する為、リソース消費が少ない
- 仮想マシンに比べて起動が高速
- Dockerイメージはどのシステムでも同じ挙動を示す

### デメリット
- ホストOSのカーネルを共有する為、異なるOSカーネルを持つアプリケーションを実行することはできない
（例えば、LinuxのDocker上でWindowsアプリケーションを実行することはできません）
- ホストOSのカーネルを共有する為、脆弱性がある場合、ホストマシンに影響を与える可能性がある



## 用語補足 
### カーネル
- 一般的にオペレーティングシステムの中心的な部分を示す
- ハードウェアとソフトウェアの間のブリッジとなり、ハードウェアリソース（CPU、メモリ、ディスクなど）の管理とアプリケーションの実行を制御する
- カーネルは、すべてのオペレーティングシステム(OS：Windows、macOS、Linuxなど）に存在する

### [Linux カーネル](https://www.redhat.com/ja/topics/linux/what-is-the-linux-kernel)
- Linuxオペレーティングシステム(OS)のカーネルの事を示す
- オープンソースで、世界中の開発者によって開発と改善が行われている
- コンピュータのオペレーティングシステムの中心的な部分で、ハードウェアとソフトウェアの間のブリッジとなる役割を担っているp 

#### Linuxカーネルの主な機能
- システムの物理メモリ（RAM）を管理している。どのアプリケーションがどの程度のメモリを使用しているか把握したり、どの部分のメモリが空いているか把握したりする。また、それらを同時に行いながら、アプリケーションが必要とするメモリを割り当てたり、使用後には解放したりする
- システム上で動作するすべてのプロセス（実行中のプログラム）を管理している。また、どのプロセスがいつ、どれだけの期間、CPUを使用するかスケジューリングもしている。これにより、複数のプロセスが効率的に動作する事が可能
- ハードウェアデバイス（キーボード、マウス、ディスプレイ、ネットワークインターフェース等）とソフトウェア間の通信を管理している。これは、デバイスドライバという特殊なプログラムを通じて行われ、各デバイスが適切に動作する様にしている
- アプリケーションがハードウェアリソースにアクセスする為のインターフェースを提供している。これをシステムコールと呼ぶ。また、カーネルはシステムのセキュリティも担当し、アクセス権の管理やセキュリティポリシーの適用等も行っている

### [cgroups（コントロールグループ）](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/resource_management_guide/ch01)
- プロセスをグループ化し、そのグループに対してCPU、メモリ、ディスクI/O等のシステムリソースの使用を制限・監視・管理する為の機能

### [Linuxのnamespaces](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/what-namespaces-are_setting-limits-for-applications)
- あるプロセスが他のプロセスの存在やシステムリソースを認識できないようにする機能
- Dockerのようなコンテナ技術で重要な役割を果たす


## 一般的な仮想マシンとDockerの共通したメリット、デメリット
### 共通のメリット
- 新しいソフトウェアやアップデートをテストする際に、主要なシステムに影響を与えずに行う事が出来る
- 仮想アプリケーションとその依存関係を分離した環境を作成、実行が出来る。これにより、異なるアプリケーションが互いに干渉することなく、同じシステム上で同時に実行が可能となる
- 一度設定した環境を再現する事が容易。これにより、開発、テスト、本番環境間での一貫性が保てる

### 共通のデメリット
- システムの管理を複雑にする可能性がある。例えば、リソースの割り当て、ネットワークの設定、セキュリティの管理等、これらのツールを使用すると管理する項目が増加する
- ホストマシンから分離されているが、仮想環境が攻撃の対象になる可能性がある


## [Docker Engine](https://docs.docker.com/engine/)
- `Docker`の中核をなすソフトウェア
- `Docker Engine`は、主に以下の3つの部分から構成されている

### [Docker Daemon（dockerd）](https://docs.docker.jp/engine/reference/commandline/dockerd.html)
- コンテナのライフサイクル(システムを運用する為の一連の過程)を管理するバックグラウンドプロセス
- ユーザーが`Docker`コマンドを実行すると、`Docker Daemon`がそれを受け取り、コンテナの作成、開始、停止などの操作を行う

### [Docker CLI（Command Line Interface）](https://docs.docker.jp/engine/reference/commandline/toc.html)
- ユーザーが`Docker Daemon`と対話する為のコマンドラインツール
- `Docker CLI`がある為、`docker run`、`docker build`等のコマンドが使用できる

### [Docker REST API](https://docs.docker.com/engine/api/)
- `Docker Daemon`と通信するためのインターフェース
- この`API`を使用して`Docker Daemon`と通信する
- Docker CLIを実行すると`UNIXドメインソケット/var/run/docker.sock`を使用して、`REST API`が叩かれる


![engine-components-flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664659/239746a3-51b2-a440-a6af-4186c0bfd800.png)
（[出典：Docker-docs-ja、Docker 概要「Docker Engine とは何ですか？」](https://docs.docker.jp/v1.12/engine/understanding-docker.html#docker-engine)）

# [Docker Compose](https://docs.docker.com/compose/)
- 複数のDockerコンテナを定義し、管理する為のツール
- YAMLファイル（通常は`docker-compose.yml`）を使用して、アプリケーションのサービスを設定する
- 単一のコマンドでこれらのサービスをすべて一緒に起動したり停止したりする事が出来る
- 現在は、`Compose V2`が提供されている。また、`Go`言語で書き直されており、Dockerコマンドライン機能との統合が改善された模様。コマンドは下記の様に叩く
```yml
docker compose 任意のコマンド
# docker-composeコマンドも使用出来るが、旧バージョンの叩き方となる
```
#### 主な機能
- アプリケーションを構成する各サービス（例えば、ウェブサーバー、データベース、バックエンドAPIなど）を定義する事が出来る。各サービスは独自のコンテナで実行され、それぞれが独自のイメージを使用して起動する
- サービス間のネットワーク接続やデータの永続化を管理する。これにより、サービス間の通信やデータの保存が容易となる
- `docker compose up`コマンドを使用して、定義されたすべてのサービスを一度に起動できる。同様に、`docker compose down`コマンドを使用して、すべてのサービスを一度に停止できる



# 参考資料
- [[公式]Docker 概要](https://docs.docker.jp/v1.12/engine/understanding-docker.html#id25)
- [AWSでコンテナを支えるサービスについて ECS、EKS、Fargateの違いは？　第１回](https://www.sunnycloud.jp/column/20201215-01/)
- [[Red Hat]テクノロジーのトピック](https://www.redhat.com/ja/topics)
- [[公式] Docker Compose overview](https://docs.docker.com/compose/)


# まとめ
コンテナ技術についての基本的な事が今回まとめてわかりました。今後は、Dockerについて、より深ぼって理解して、Dockerマスターになれる様に精進したいと思います。