Docker, Docker Compose, Kuberenetes用語ベース入門

# コンテナ

- OSとカーネルは共有し、プロセスを分離する仕組み。
- **コンテナ上で実行されたソフトウェアは単に1つのプロセスとして稼働しているにも関わらず、
コンテナ内のソフトウェアから見ると独立したOS環境を占有しているように見える**。

# コンテナ vs サーバー仮想化

- サーバー仮想化は複数のOSを同一のハードウェア上で実行する仕組み。
    - 「仮想マシン」上に「ゲストOS」を動作させる。
    - 例: Virtual box

[サーバー仮想化技術の基礎 - Qiita](https://qiita.com/NagaokaKenichi/items/123c54f3863816481bd7)
[各仮想化技術の違いをざっと理解するッ!! - Qiita](https://qiita.com/hiroki-it/items/0cea21a83394634d284a)
[[Cloud] 仮想化技術について](https://qiita.com/okkn/items/c0cb6feef4058e9d16b4)

# コンテナのメリット

1. **環境による差異の解消**
    - 開発環境やステージング環境、プロダクション環境等、複数の環境間のアプリケーションの依存関係（ライブラリのバージョンのずれ等）を全てコンテナ内で完結でき、意識する必要がなくなる。
2. **構成管理の容易さ**
    - サーバー仮想化と比較するとゲストOSやハードウェアのエミュレートが不要となり、プロセス単位で稼働するため効率的。
        - アプリケーションを動かすために必要となるコンピューティングリソースの消費は少なくなる。
        - アプリケーションの起動も高速。

# Docker

- **DockerfileによりDockerイメージをビルドし、そのイメージが元となるコンテナ内で作業orコンテナを実行することができる**。
- アプリケーションや必要なファイルを、Dockerイメージに同梱して、コンテナとして実行していく。
    - 例: Node.jsベースのイメージ（Node.jsが実行できるように環境を整えたLinux）を利用し、npmでのモジュールインストールやビルド処理をコンテナ内で実行する。

[入門 Docker](https://y-ohgi.com/introduction-docker/)
[7nohe/docker-lessons](https://github.com/7nohe/docker-lessons)
[Orientation and setup - Docker docs](https://docs.docker.com/get-started/)
[インフラエンジニアBooks 30分でわかる「Dockerコンテナ開発・環境構築の基本」](https://speakerdeck.com/cyberblack28/inhuraenziniabooks-30fen-dewakaru-dockerkontenakai-fa-huan-jing-gou-zhu-falseji-ben)

# Dockerfile

- Dockerイメージを作り上げるために実行するコマンドを含めたファイル。
- 主に以下のコマンドから構成される。

| コマンド | 説明 |
|:-:|:-:|
| **FROM**  | 書式: `FROM [--platform=<platform>] <image> [AS <name>]`<br><br>イメージビルドのための処理ステージを初期化し、ベースイメージを設定する。<br>正しいDockerfileは`FROM`から始めなければない。  |
| **RUN** | 書式:<br>`RUN <command>`<br>`RUN ["executable", "param1", "param2"]`<br><br>現在のイメージの最上位の最新レイヤーにおいて、あらゆるコマンドを実行する。そして処理結果を確定する。結果が確定したイメージは、Dockerfileの次のステップにおいて利用されていく。 |
| **CMD** | 書式: `CMD ["executable","param1","param2"]`<br><br>Dockerfile では`CMD`を1つしか記述できない。<br>`CMD`の主目的はコンテナの実行時のデフォルト処理を設定すること。<br>`docker run`において引数を指定することで、`CMD`に指定されたデフォルトを上書きすることができる。 |
| **EXPOSE** | 書式: `EXPOSE <port> [<port>/<protocol>...]`<br><br>コンテナの実行時に、所定ネットワーク上のどのポートをリッスンするかを指定する。<br>実際にはポートを公開するものではなく、イメージ作成者とコンテナ実行者との間で取り交わすメモのようなもの。 <br>どのポートを公開するつもりでいるのかを表わす。 コンテナーが実行されるときに実際にポートを公開するには、`docker run` の `-p` フラグを利用する。 |
| **ENV**| 書式: `ENV <key>=<value> ...`<br><br>環境変数 `<key>` に `<value>` という値を設定する。<br>ビルドステージ内（`FROM`以降のコマンド）の環境において、環境変数の値は維持される。 |
| **COPY** | 書式: `COPY [--chown=<user>:<group>] <src>... <dest>`<br><br>`<src>`からファイルやディレクトリを新たにコピーして、コンテナ内のファイルシステムのパス`<dest>`に追加する。<br>`<src>...`として複数のファイルあるいはディレクトリが指定されている場合、そのパスはビルドコンテキストからの相対パスとして解釈される。<br>`<dest>`は絶対パスか、あるいは `WORKDIR`からの相対パスにより指定する。対象としているコンテナ内において、そのパスに対してソースがコピーされる。<br><br>`ADD`されるファイルやディレクトリの`UID`と`GID`は、すべて`0`として生成される。<br>ただしオプションとして`--chown`フラグを用いると、引数に与えたユーザー空間、グループ名、あるいは`UID`と`GID`の組み合わせによる指定が可能になり、特定の所有権を満たした`ADD`を行うことができる。 |
| **ENTRYPOINT** | 書式: `ENTRYPOINT ["executable", "param1", "param2"]`<br><br>コンテナを実行モジュールのようにして実行する設定を行うもの。<br><br>1. Dockerfile には、`CMD`または`ENTRYPOINT`のいずれかが、少なくとも1つ必要。<br>2. `ENTRYPOINT`は、コンテナを実行モジュールとして実行する際に利用する。<br>3. `CMD`は、`ENTRYPOINT`のデフォルト引数を定義するために、あるいはその時点でのみコマンド実行を行うために利用する。<br>4. `CMD`はコンテナ実行時に、別の引数によって上書きされることがある。|
| **EXPOSE** | 書式: `EXPOSE <port> [<port>/<protocol>...]`<br><br>コンテナの実行時に、所定ネットワーク上のどのポートをリッスンするかを指定する。<br>実際にはポートを公開するものではなく、イメージ作成者とコンテナ実行者との間で取り交わすメモのようなもの。 <br>どのポートを公開するつもりでいるのかを表わす。 コンテナーが実行されるときに実際にポートを公開するには、`docker run` の `-p` フラグを利用する。 |
| **USER** | 書式: `USER <user>[:<group>] または USER <UID>[:<GID>]`<br><br>ユーザー名（または`UID`）と、オプションとしてユーザーグループ（または`GID`）を指定する。<br>イメージが実行されるとき、Dockerfile 内の後続の`RUN`、`CMD`、`ENTRYPOINT`の各コマンドにおいてこの情報を利用する。 |
| **WORKDIR**| 書式: `WORKDIR /path/to/workdir`<br><br>ワークディレクトリを設定する。 <br>Dockerfile内にてその後に続く`RUN`、`CMD`、`ENTRYPOINT`、`COPY`、`ADD`の各命令において利用することができる。`WORKDIR`が存在しないときは生成される。<br><br>`WORKDIR`はDockerfile内にて複数利用することができる。ディレクトリ指定に相対パスが用いられた場合、そのパスは、直前の`WORKDIR`からの相対パスとなる。 |
| **ARG**| 書式: `ARG <name>[=<default value>]`<br><br>変数を定義して、ビルド時にその値を受け渡す。 これは`docker build`コマンドにおいて`--build-arg <varname>=<value>`フラグを利用して行う。Dockerfile内において指定したビルド引数（`build argument`）が定義されていない場合は、ビルド処理時に警告メッセージが出力される。<br><br>オプションとしてデフォルト値を設定することができる。<br><br>`ARG`の変数スコープは、それが定義されたビルドステージが終了するときまで。<br>複数のビルドステージにおいて`ARG`を利用する場合は、個々に`ARG`を指定する必要がある。<br><br>`ARG`や`ENV`において変数を指定し、それを`RUN`にて用いることができる。`ENV`を使って定義された環境変数は、`ARG`において同名の変数が指定されていたとしても優先される。<br><br>`FROM`よりも前に宣言されている`ARG`は、ビルドステージ内に含まれるものではない。したがって`FROM`以降の命令において利用することはできない。初出の`FROM`よりも前に宣言された`ARG`の値を利用するには、ビルドステージ内において`ARG 命令を、値を設定することなく利用する。|

[Dockerfile リファレンス - docker docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/builder/)

### CMD vs ENTRYPOINT

[[docker] CMD とENTRYPOINT の違いを試してみた - Qiita](https://qiita.com/hihihiroro/items/d7ceaadc9340a4dbeb8f)
[ENTRYPOINTは「必ず実行」、CMDは「（デフォルトの）引数」 - POCKETSTUDIO.NET](https://pocketstudio.net/2020/01/31/cmd-and-entrypoint/)

### COPY vs ADD

[DockerfileにてなぜADDよりCOPYが望ましいのか - Qiita](https://qiita.com/momotaro98/items/bf34eef176cc2bdb6892)

## Dockerfileのサンプル

```dockerfile
# Dockerfile
# syntax=docker/dockerfile:1
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install

# コンテナが実行されるたびに毎回実行されるスクリプト
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# イメージが起動中の時に実行するメインプロセスの設定
CMD ["rails", "server", "-b", "0.0.0.0"]
```

```sh
# entrypoint.sh
#!/bin/bash
set -e

# Railsのserver.pidが残っているかもしれないので、それを削除する.
rm -f /myapp/tmp/pids/server.pid

# コンテナのメインプロセス（DockerfileでCMDでセットされているもの）を実行する。
exec "$@"
```

[Quickstart: Compose and Rails - Docker Docs](https://docs.docker.com/samples/rails/)

[rails s -b 0.0.0.0 のオプション-bの意味 - Qiita](https://qiita.com/Masato338/items/f162394fbc37fc490dfb)
Railsのプロセスは、外部からのリクエストを受け付けるために、ホストが持っているIPアドレスに結び付けられる（デフォルトでは `127.0.0.1` ）。
（コンテナのネットワーク上の）localhost（= `127.0.0.1`）で立ち上がっているプロセスは、外部（コンテナのネットワーク上から見た時のホストのネットワーク上など）からはアクセスできない。
`0.0.0.0` は全てのIPアドレスを表す。
Railsのプロセスを（コンテナのネットワーク上の）全てのIPアドレスにバインディング（`-b '0.0.0.0'`）することによって、外部からアクセスできないIPアドレスである `127.0.0.1` だけではなく、外部からアクセス可能なIPアドレスでもRailsアプリケーションを立ち上げている。

## Dockerfileのベストプラクティス

[Dockerfile のベストプラクティス - Docker-docs-ja](https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/dockerfile_best-practices/)
コンテナ毎に１つのプロセスだけ実行、コンテナはエフェメラルであるべき、などのプラクティス。

[社内のDockerfileのベストプラクティスを公開します - FORCIA CLUB](https://www.forcia.com/blog/002273.html)

[Dockerfileのベストプラクティス - 入門Docker](https://y-ohgi.com/introduction-docker/3_production/dockerfile/)

[Dockerfileのベストプラクティス - Qiita](https://qiita.com/Tsuyozo/items/c706a04848c3fbbaf055)

## Dockerコマンドのサンプル

Docker 1.13から、Dockerコマンドが新しくなった。
現場では新コマンドの代わりに、旧コマンドが引き続き使われていることも多い。

| 新コマンド(v1.13~) | 旧コマンド |
|:-:|:-:|
| docker image build  | docker build  |
| docker image rm  | docker rmi  |
| docker container run  | docker run  |
| docker container rm  | docker rm  |


[docker container / image コマンド新旧比較 - Qiita](https://qiita.com/zembutsu/items/6e1ad18f0d548ce6c266)
[Docker 1.13 – What’s New Including Docker Prune Features - Cloudshare](https://www.cloudshare.com/blog/blogdev-testwhats-new-docker-1-13/)

### Dockerfile から Dockerイメージをビルドする

```bash
$ docker image build -t yokoto/ansible_image:latest（イメージ名[:タグ]） .（Dockerfile配置ディレクトリのパス）
```

-t（--tag）: 作成するDockerイメージのタグを指定する。

[docker image build - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/image_build/)

### Dockerイメージを削除する

```bash
$ docker image rm -f (イメージ名[:タグ])
$ docker image rm $(docker images -q) # 全てのイメージを削除
$ docker image prune # 使用していない全てのイメージを削除
```

-f(--force）: コンテナが実行中の場合は、イメージを削除することができない。しかし、-f オプションを使用すると、使用中のイメージであっても強制的に削除することができる。

[docker image rm - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/image_rm/)
[docker image prune](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/image_prune/)
[Dockerコンテナとイメージを全削除する - Zenn](https://zenn.dev/ryuu/scraps/a1efb79aaa1bb2)
[Dockerイメージ、ボリューム、コンテナを簡単に削除する方法 - kinsta](https://kinsta.com/jp/blog/docker-remove-images/)


### 新しいコンテナを作成・起動し、そのコンテナでコマンド実行する

```bash
$ docker container run -p 9000:8080（ホストポート:コンテナポート） --name ansible_container（コンテナの命名） yokoto/ansible_image:latest（イメージ名[:タグ]） 
```

[docker container run - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_run/)

[Container networking - Docker Docs](https://docs.docker.com/config/containers/container-networking/)
ローカルホストのポートへの通信をコンテナポートへ転送するポートフォワーディングの解説。
ポートフォワーディングの設定により、コンテナポートにホストポートでの通信を許可する。

[docker runとdocker execの違いの解説 - めもたんす](https://www.memotansu.jp/docker/852/)
`docker container run` は以下と等しい。

```bash
$ docker container create -p 9000:8000 --name ansible_container yokoto/ansible_image:latest
$ docker container start ansible_container
```

[docker container create - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_create/)
新たなコンテナを生成します。
[docker container start - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_start/)
1つまたは複数の停止中コンテナを起動します。

### 実行中のコンテナでコマンド実行する

```bash
$ docker container run --name ansible_container yokoto/ansible_image:latest
$ docker container exec -it ansible_container /bin/bash　
```

[docker container exec - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_exec/)

[【Docker】「コンテナに入る」が何をしているか1分で理解する - Qiita](https://qiita.com/kondo0602/items/441aa7e423f4ebd42bd5)
`exec -it`の解説。
-i: 標準入力を受け付けることを示すオプション。-iをつけないとキーボードからの入力を受け付けてくれない。
-t: tty。-tをつけないとコマンド入力用のターミナルが割り当てられない。
/bin/bash: 対話形式のbashシェルを起動する。

[【docker】docker run と docker execの違いについて - 自由気ままに書いちゃおう](https://www.guri2o1667.work/entry/2020/11/03/%E3%80%90docker%E3%80%91docker_run_%E3%81%A8_docker_exec%E3%81%AE%E9%81%95%E3%81%84%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
[Dockerコンテナの作成、起動〜停止まで - Qiita](https://qiita.com/kooohei/items/0e788a2ce8c30f9dba53)

### 実行中のコンテナを停止する

```bash
$ docker container stop ansible_container
# or
$ docker container kill	ansible_container # 強制停止
```

[docker container stop - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_stop/)
[docker container kill - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_kill/)

### コンテナを削除する

```bash
$ docker container rm ansible_container
$ docker container rm $(docker ps -aq) # 全てのコンテナを削除
$ docker container prune # 停止中の全てのコンテナを削除
```

[docker container rm - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_rm/)
[docker container prune - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_prune/)
[Dockerコンテナとイメージを全削除する - Zenn](https://zenn.dev/ryuu/scraps/a1efb79aaa1bb2)
[Dockerイメージ、ボリューム、コンテナを簡単に削除する方法 - kinsta](https://kinsta.com/jp/blog/docker-remove-images/)

# イメージ（image）

- コンテナを実行するために必要なビルド済みパッケージ。
- レジストリにおいて、「タグ」によってバージョン管理されている。

[ruby - Docker Hub](https://hub.docker.com/_/ruby)
[ansible - Docker Hub](https://hub.docker.com/r/ansible/ansible)

DockerイメージのDockerfile。
[ruby/3.0/alpine3.14/Dockerfile - GitHub](https://github.com/docker-library/ruby/blob/2c3e1e09e881f8a1f24d1ddfe1d5c6117aaa62de/3.0/alpine3.14/Dockerfile)
[ansible/centos7/Dockerfile - GitHub](https://github.com/willhallonline/docker-ansible/blob/master/ansible/centos7/Dockerfile)

# レジストリ

- イメージのバージョン管理や配布を行えるサービス。
- 例: Docker Registory、Docker Hub、Amazon Elastic Container Registry（ECR）、GCP Container Registry（GCR）

## パブリックレジストリ vs プライベートレジストリ

- リポジトリを非公開にしたり、イメージのプルに対するアクセス制御を行いたい場合は、プライベートリポジトリを作成する。
    - Docker Registry、ECR、GCPは、基本的にプライベートレジストリを作成する用途で利用される。

[コンテナレジストリとは？パブリックレジストリとプライベートレジストリの違い](https://www.rworks.jp/system/system-column/sys-entry/21778/)
[ECRをパブリックレジストリとして利用可能になりました！ #reinvent](https://dev.classmethod.jp/articles/ecr-public-registry/)
[Amazon ECR プライベートレジストリ](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/Registries.html)

# リポジトリ

- レジストリにおいて、各イメージが保管されている場所。

[【Docker】レジストリとリポジトリ](https://amateur-engineer-blog.com/difference-docker-registry-repository/)
[Difference between Docker registry and repository - Stack Overflow](https://stackoverflow.com/questions/34004076/difference-between-docker-registry-and-repository)


# イメージ vs タグ vs リポジトリ

```bash
$ docker image ls # イメージの一覧
REPOSITORY               TAG     IMAGE ID       CREATED       SIZE
centos                   latest  91c95931e552   9 hours ago   812MB
ansible/centos7-ansible  latest  fb434121fc77   12 hours ago  605MB
tutum/centos             v1.1    1234abcd5678   21 hours ago  470MB
```

```bash
$ docker search centos # イメージの検索
NAME                     DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
centos                   The official build of CentOS.                   1034      [OK]
ansible/centos7-ansible  Ansible on Centos7                              43                   [OK]
tutum/centos             Centos image with SSH access. For the root...   13                   [OK]
...
```

```bash
# Image ID
centos # 91c95931e552
ansible/centos7-ansible:latest # fb434121fc77
ansible/centos7-ansible:v1.1 # fb434121fc77
tutum/centos:v1.1 # 1234abcd5678
```

| 用語 | 説明 | 例 |
|:-:|:-:|:-:|
| イメージ  | Image ID（例: `91c95931e552`, `fb434121fc77`, `1234abcd5678`）によって一意に参照できるものを指す。 |   |
| タグ  | Image IDのエイリアス。<br>デフォルトで `latest` となる。  | `latest`,<br> `v1.1` |
| イメージ名  | タグの全表記。<br>`[REGISTRYHOST/][USERNAME/]NAME[:TAG]`  | `centos`,<br>`ansible/centos7-ansible:latest` ,<br>`tutum/centos:v1.1` |
| リポジトリ  | 1つ以上のイメージ（Image ID）を持つ。 | `centos`,<br>`centos7-ansible`,<br>`centos` |
| リポジトリ名  | ユーザー名を名前空間として持つリポジトリの名前。  | `centos`,<br>`ansible/centos7-ansible`,<br>`tutum/centos`  |
| ユーザー名  | リポジトリ名の名前空間。<br>これにより、パブリックレジストリからリポジトリを検索する際に名前の競合を防ぐことができる。 | `ansible`,<br>`tutum` |

[Docker初心者がイメージとリポジトリの違いが分からなくて混乱したこと - Qiita](https://qiita.com/zaki_taka4/items/9d330556542c665b011c)
[What is the difference between an image and a repository? - Stack Overflow](https://stackoverflow.com/questions/31115098/what-is-the-difference-between-an-image-and-a-repository)
[Docker Hub 上のリポジトリ -  Docker-docs-ja](https://docs.docker.jp/docker-hub/repos.html)
[Dockerのリポジトリ名とイメージ名って同じもの？](https://ja.stackoverflow.com/questions/32345/docker%E3%81%AE%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E5%90%8D%E3%81%A8%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E5%90%8D%E3%81%A3%E3%81%A6%E5%90%8C%E3%81%98%E3%82%82%E3%81%AE)

# BuildKit

- Dockerでは、BuildKitというビルドの拡張機能が18.09から導入された。

## 機密情報を受け渡す

- これにより、`docker build` 時に `--secret` オプションを渡すことで、機密情報を受け渡せるようになった。
    - 機密情報は、最終的にイメージ内に保存されることはないので、安全に取り扱うことができる。
- 機密情報には、Docerfile の `RUN` が実行される際にアクセスすることができる。


```bash
$ echo 'WARMACHINEROX' > mysecret.txt
```

```Dockerfile
# syntax=docker/dockerfile:1.2

FROM alpine

# デフォルトの機密情報の置き場所から機密情報を表示する
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

# カスタムの機密情報の置き場所から機密情報を表示する
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
```

```bash
$  docker build --no-cache --progress=plain --secret id=mysecret,src=mysecret.txt .
...
#  [2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
#       digest: sha256:5d8cbaeb66183993700828632bfbde246cae8feded11aad40e524f54ce7438d6
#          name: "[2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret"
#       started: 2018-08-31 21:03:30.703550864 +0000 UTC
#  1.081 WARMACHINEROX
#     completed: 2018-08-31 21:03:32.051053831 +0000 UTC
#      duration: 1.347502967s
#  [3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
#        digest: sha256:6c7ebda4599ec6acb40358017e51ccb4c5471dc434573b9b7188143757459efa
#          name: "[3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar"
#       started: 2018-08-31 21:03:32.052880985 +0000 UTC
#  1.216 WARMACHINEROX
#     completed: 2018-08-31 21:03:33.523282118 +0000 UTC
#      duration: 1.470401133s
```

| オプション | 説明 |
|:-:|:-:|
| id  |  `docker build --secret id=:id` において受け渡される識別子。<br>Dockerfileの `RUN --mount...,id=:id` として関連づけられる。<br>※ これにより、Dockerfileの外の機密情報を含むファイル名を用いないようにしている。 |
|  dst | Dockerfile内にて用いられる `RUN` コマンドにおいての機密情報ファイルの置き場所を、任意の置き場所に変更する。<br>※ `dst` を指定しない場合、デフォルトで `/run/secrets/:id` に機密情報ファイルが置かれる。 |
|  src |  `docker build --secret` において受け渡される、機密情報ファイルの指定。 |

[BuildKit によるイメージ構築 - docker docs](https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/build_enhancements/)

## 特定のディレクトリをキャッシュする

- コンパイラやパッケージマネージャ（bundler等）用のディレクトリをキャッシュすることができる。
- キャッシュディレクトリの内容は、ビルド間で保持される。
- キャッシュマウントは、パフォーマンスを向上させるためだけに使用する。

```Dockerfile
# syntax=docker/dockerfile:1
FROM golang
RUN --mount=type=cache,target=/root/.cache/go-build \
  go build ...
```

```Dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
  --mount=type=cache,target=/var/lib/apt,sharing=locked \
  apt update && apt-get --no-install-recommends install -y gcc
```

| オプション | 説明 |
|:-:|:-:|
| id | 別々のキャッシュの識別子。<br>※ デフォルトでは `target` の値になる。  |
| target[^1] | マウントパス。 |
| from | キャッシュマウントのベースとして使用するビルドイメージ。<br>※ デフォルトでは空のディレクトリになる。 |
| source | マウントする `from` の中で指定するパス。<br>デフォルトでは `from` のルート。 |
| mode | 8進数で表される新しいキャッシュディレクトリのファイルモード。<br>デフォルトでは `0755`。 |
| uid | 新しいキャッシュディレクトリ用のユーザーID。<br>デフォルトでは `0`. |
| gid | 新しいキャッシュディレクトリ用のグループID。<br>デフォルトでは `0`. |

[Docker のキャッシュを全力で使いこなそう - Zenn](https://zenn.dev/kou64yama/articles/powerful-docker-build-cache)
[Docker 18.09 新機能 (イメージビルド&セキュリティ) - Medium](https://medium.com/nttlabs/docker-v18-09-%E6%96%B0%E6%A9%9F%E8%83%BD-%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%83%93%E3%83%AB%E3%83%89-%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3-9534714c26e2)
[buildkit/frontend/dockerfile/docs/reference.md - GitHub](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#run---mounttypecache)

# マルチステージビルド

- Dockerfileに `FROM` を複数記述することで複数のビルドを展開すること。
- 1ビルドの単位をステージと呼ぶ。
- **イメージをビルドする際に、使用しないファイル等が減り、結果作成されるイメージサイズが小さくなる**。

```dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.16 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# COPY --from=builder: builderステージを利用してファイルをコピー
COPY --from=builder /go/src/github.com/alexellis/href-counter/app ./
CMD ["./app"]
```

## ステージを指定してビルドする

- `builder` と名付けたステージのみビルドする。

```bash
$ docker build --target builder -t alexellis2/href-counter:latest 
```

## 前にビルドしたステージを参照して用いる

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine:latest AS builder
RUN apk --no-cache add build-base

FROM builder AS build1
COPY source1.cpp source.cpp
RUN g++ -o /binary source.cpp

FROM builder AS build2
COPY source2.cpp source.cpp
RUN g++ -o /binary source.cpp
```

[マルチステージビルドの利用 - docker docs](https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/multistage-build/)
[1つのDockerfileだけでGoの開発環境(ホットリロード)と本番環境(マルチステージビルド)を記述する - Qiita](https://qiita.com/po3rin/items/8b57e6c22f2b34751333)
[Docker multi stage buildで変わるDockerfileの常識 - Qiita](https://qiita.com/minamijoyo/items/711704e85b45ff5d6405)
[至高のDockerイメージ生成を求めて -2019年版- - Qiita](https://qiita.com/inductor/items/25d5accb80ea606d5c51)
[Docker のマルチステージビルドで Rails イメージを軽くする - Zenn](https://zenn.dev/tatsurom/articles/multi-stage-build)

# Docker Compose

- Docker Composeは、**複数のコンテナで動作するDockerアプリケーションの定義・実行をするためのツール**。
    - Dockerfileによって作成したイメージを組み合わせて1つのコマンド（`docker　compose up` など）で実行することができる。
    - コンテナだけではなく、Dockerの**ネットワークとボリューム**も管理できる。
    - 本番環境、ステージング環境、開発環境において動作し、CIワークフローとしても利用することができる。

# docker-compose.yml

- docker-compose.ymlは、Dockerコンテナを用いるアプリケーションの設計図に相当する。
  - 複数のコンテナ実行を一括で管理できる、主に以下を定義しているyaml形式のファイル。

| 属性 | 説明 |
|:-:|:-:|
|  **services** | 同じコンテナイメージ (および構成) を1回以上実行することによってプラットフォームに実装される抽象的な概念。<br>コンテナを実行するための実行時の制約と要件の定義。  |
|  services > **build** | Dockerイメージを持つDockerfileへの相対パス。  |
| services > **image** | Dockerイメージ。 |
| **networks** | サービスが相互に接続できるようにネットワークを作成するレイヤー。<br>サービスコンテナが接続するネットワークの定義。 |
| **volumes**  | 永続的なデータストア。<br>サービスコンテナ側にマウントするホスト側のパスまたは名前付きボリュームの定義。 |
| **configs** | サービスコンテナに付与できる、プラットフォームやランタイムに依存した `http` 等の構成データの定義。 |
| **secrets** | サービスコンテナに付与できる機密情報の定義。 |

## docker-compose.ymlのサンプル

```docker-compose.yml
version: "3.9" # YAMLのバージョン管理
services: # サービス（コンテナ）を定義するセクション
  db: # dbサービスの定義
    image: postgres # postgres公式イメージを使用
    volumes: # ボリュームに関する指定
      - ./tmp/db:/var/lib/postgresql/data # `./tmp/db` を `/var/lib/postgresql/data` コンテナ内のにマウント
    environment: # コンテナ内で利用できる環境変数の指定
      POSTGRES_PASSWORD: password # パスワードを指定
  web: # webサービスの定義
    build: . # Dockerfileのあるパスを指定
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" # デフォルトのコマンドを上書きする
    volumes:
      - .:/myapp # ホスト上の現在のディレクトリ `./` を `/myapp` にコンテナ内のマウント
      - logvolume01:/var/log # 名前付きボリューム `logvolume01` をコンテナ内の `/var/log` にマウント
    ports: # ポート公開指定
      - "3000:3000" # ホスト側のポート3000を、コンテナ内のポート3000にマッピング
    depends_on: # サービスの依存関係を指定
      - db # dbに依存している
  redis: # redisサービスの定義
    image: "redis:alpine" # redis公式イメージを使用
volumes: # ボリュームを定義するセクション
  logvolume01: {}
```

[Docker Compose の概要 / Overview - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/compose/)
[Docker Compose をはじめよう - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/compose/gettingstarted/)
[Compose specification - Docker Docs](https://docs.docker.com/compose/compose-file/)

[Docker Compose - docker-compose.yml リファレンス - Qiita](https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa)
[Difference between Docker Compose Vs Dockerfile](https://dockerlabs.collabnix.com/beginners/difference-compose-dockerfile.html)

## Docker Composeコマンドのサンプル

### サービスのビルド・再ビルド

```bash
$ docker compose build
```

[docker compose build - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose_build/)
サービスのDockerfileを変更した場合、このコマンドでサービスを再構築する。


### 全てのコンテナを作成・起動する

```bash
$ docker compose up -d 
Creating network "wordpress_wordpressnet" with the default driver
Creating volulme "wordpress_wordpress_db_volume" with default driver
Creating wordpress_wordpress-db_1 ... done
Creating wordpress_wordpress-app_1 ... done
```

[docker compose up - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose_up/)


### 全てのコンテナを一覧表示する

```bash
$ docker compose ps 
```

[docker compose ps - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose_ps/)
[docker network ls - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/network_ls/)
[docker compose logs - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose_logs/)
[docker volume ls- Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/volume_ls/)

### 全てのコンテナを停止・破棄する

```bash
$ docker compose down
Stopping wordpress_wordpress-app_1 ... done
Stopping wordpress_wordpress-db_1 ... done
Removing wordpress_wordpress-app_1 ... done
Removing wordpress_wordpress-db_1 ... done
Removing network wordpressnet
```

[docker compose ps - Docker Docs](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose_ps/)



# サービスとコンテナの違い

- サービスは、1つまたは複数のコンテナで実行できる。
    - Docker で "コンテナ" を処理する。
    - Docker Compose で "サービス" を処理できる。

- 以下の例では、2つのサービス持つDocker Composeが、
1つのサービス（`web`）をスケーリングをスケーリングすることで、6つのコンテナを作成している。

```
$ docker ps -a
CONTAINER ID   IMAGE        COMMAND          ...      NAMES
1c1683e871dc   test1_web    "nginx -g"       ...      test1_web_1
a41360558f96   test1_db     "postgres -d"    ...      test1_db_1

$ docker compose up --scale web=5
Creating and starting 2 ... done
Creating and starting 3 ... done
Creating and starting 4 ... done
Creating and starting 5 ... done

$ docker ps -a  
CONTAINER ID   IMAGE        COMMAND         ...      NAMES
1bf4c939263f   test1_web    "nginx -g"      ...      test1_web_3
d3033964a44b   test1_web    "nginx -g"      ...      test1_web_4
649bbda4d0b0   test1_web    "nginx -g"      ...      test1_web_5
a265ea406727   test1_web    "nginx -g"      ...      test1_web_2
1c1683e871dc   test1_web    "nginx -g"      ...      test1_web_1
a41360558f96   test1_db     "postgres -d'   ...      test1_db_1
```

[Difference between service and container in docker compose - stack overflow](https://stackoverflow.com/questions/35565770/difference-between-service-and-container-in-docker-compose)

# 永続化・ボリューム・マウント

- Docker Compose では、サービスによって利用されているボリューム（**Docker管理下のストレージ領域**）をすべて維持する。
    - `docker compose up` が実行されたときに、コンテナーがそれ以前に実行されていれば、以前のコンテナーから現在のコンテナーに向けてボリュームをコピーする。
        - この処理において、ボリューム内に作り出されていたデータは失われることはない。

## ボリュームマウント

- コンテナの特定のディレクトリをボリュームとしてホストマシン側で管理すれば、コンテナが削除されてもデータが消失しなくなる。
    - 例: Docker Engineというデータ領域に確保したボリューム（例: `mysqlvolume`）を、mysqlコンテナの `/var/lib/mysql` ディレクトリにマウントして起動することで、コンテナを削除してもDBのデータを残すこと（永続化）ができる。

```bash
# ボリュームマウントする。ボリューム（`mysqlvolume`）が作られていないときは新規にボリュームを作成する。
$ docker container run --name db01 \
  --volume mysqlvolume:/var/lib/mysql \
  --env MYSQL_ROOT_PASSWORD=password \
  mysql:5.7
# ボリュームマウントする。ボリューム（`mysqlvolume`）が作られていないときは新規にボリュームを作成せずエラーを発生する。
$ docker container run --name db01 \
  --mount type=volume,src=mysqlvolume,dst=/var/lib/mysql \
  --env MYSQL_ROOT_PASSWORD=password \
  mysql:5.7
```

または

```docker-compose.yml
services:
  db:
    volumes:
    - mysqlvolume:/var/lib/mysql
```

以下のように詳細に指定することもできる。

```docker-compose.yml
services:
  db:
    volumes:
      - type: volume
        source: mysqlvolume
        target: /var/lib/mysql
```

[実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本 Chapter 19 ３部: Docker Compose - Zenn](https://zenn.dev/suzuki_hoge/books/2022-03-docker-practice-8ae36c33424b59/viewer/3-8-docker-compose#%E3%83%9C%E3%83%AA%E3%83%A5%E3%83%BC%E3%83%A0%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%A8-db-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%B8%E3%81%AE%E3%83%9E%E3%82%A6%E3%83%B3%E3%83%88)
[第3章 コンテナアプリケーション開発のライフサイクル Build・Ship・Run 永続化データとネットワークモデル インフラエンジニアBooks 30分でわかる「Dockerコンテナ開発・環境構築の基本」 - SpeakerDeck](https://speakerdeck.com/cyberblack28/inhuraenziniabooks-30fen-dewakaru-dockerkontenakai-fa-huan-jing-gou-zhu-falseji-ben?slide=37)
[さわって学ぶクラウドインフラ docker 基礎からのコンテナ構築 5-2  データを独立させる](https://www.amazon.co.jp/%E3%81%95%E3%82%8F%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9-docker%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E6%A7%8B%E7%AF%89-%E5%A4%A7%E6%BE%A4-%E6%96%87%E5%AD%9D/dp/4296106422)
[MySQLのデータディレクトリを移動する - Qiita](https://qiita.com/ShuM/items/1a960b4ef53f8a08dd5a)
[MySQLがデータを保管する場所　〜　データディレクトリ - 日常メモ](https://financial-it-engineer.hatenablog.com/entry/20140911/1410450256)
[4.4.3 mysql_install_db — MySQL データディレクトリの初期化 - MySQL](https://dev.mysql.com/doc/refman/5.6/ja/mysql-install-db.html)
[Docker Machine 概要 Docker Engine と Docker Machine の違いは何ですか？ -- Docker-docs-ja](https://docs.docker.jp/machine/overview.html)

## バインドマウント

- **ホスト側のディレクトリをコンテナ内のディレクトリと共有する**。
- ソースコードのディレクトリをコンテナにバインドマウントしてホストマシン側と共有すれば、ホストマシンでコードを変更した際に同期や転送が不要になる。
    - 例1: **DBコンテナのイメージを配布する時点では用意できなかったDBの初期化クエリを、DBコンテナにマウントする**。
    - 例2: **開発時のソースコードなど、ホストマシンで変更したいがコンテナに随時反映したいものをコンテナ内のディレクトリにマウントする**。
- バインドマウントは、実体の面倒を見ているのがホストマシン上である。
    - 「仮想環境だから」と安易に削除すると、影響がホストマシンに波及する。
- まずはボリュームを検討し、どうしてもだめならバインドマウントを使う。

```docker-compose.yml
services:
  web:
    build: .
    volumes:
      - ".:/myapp"
```

以下のように詳細に指定することもできる。

```docker-compose.yml
services:
  web:
    build: .
    volumes:
      - type: bind
        source: "."
        target: "/myapp"
```

[実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本 Chapter 16 ３部: バインドマウント](https://zenn.dev/suzuki_hoge/books/2022-03-docker-practice-8ae36c33424b59/viewer/3-5-bind-mount)

## ボリュームマウント vs バインドマウント

| 用語 | 説明 | 例 |
|:-:|:-:|:-:|
| ボリュームマウント  | マウント元が「`/`」から始まらないとき。  | `-v(volume) mysqlvolume:/var/lib/mysql` |
| バインドマウント  | マウント元が「`/`」から始まるとき。  | `--v(volume) /tmp/db:/var/lib/mysql`  |

[Docker の Volume がよくわからないから調べた - Qiita](https://qiita.com/aki_55p/items/63c47214cab7bcb027e0)

# コンテナのネットワーク（bridge, host, none）

- コンテナはそれぞれIPアドレスを持つ。
- コンテナ間で通信や負荷分散を行いたいとき、通信先のコンテナをIPアドレスを指定するのではなく、コンテナ名で指定することができる。
    - コンテナ間の通信でIPアドレスとコンテナ名の名前解決を行うには、自分で「ブリッジネットワーク」を作成する必要がある。
- Dockerでは、複数のプロセス（コンテナ）を動かす必要がある時は、（ソケットではなく）ネットワークで通信を行うことが推奨されている。

## ブリッジネットワーク

- ブリッジとは、**別々のネットワーク間で通信できるようにする**働きを持つ一般的なネットワークの機能。
- **同じブリッジネットワーク上に接続しているコンテナは、お互いに通信できる**。
    - コンテナ間で通信できるようにするためには、自分でブリッジ・ネットワークを作成する必要がある。

[Docker Compose入門 (3) ～ネットワークの理解を深める～ - さくらのナレッジ](https://knowledge.sakura.ad.jp/23899/)
[ブリッジネットワークの利用 -  docker docs](https://matsuand.github.io/docs.docker.jp.onthefly/network/bridge/)

## ネットワークドライバ

- Dockerのネットワークには3種類のネットワークドライバがある。

![スクリーンショット 2022-10-17 21.02.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54467/0f621ba7-5d47-32b0-7a7d-8a2a9d2ae47f.png)

| ドライバ | 説明 |
|:-:|:-:|
| bridge  |  Dockerコンテナ作成時に何も指定しない場合はこちらが選択される。<br>Linuxのブリッジ機能を使って仮想ネットワーク上（≠ホストのネットワーク上）にコンテナを作成する。<br>インターネットとの通信はNAT形式で行う。 |
| host  |  ホストのネットワーク上にコンテナが作成される。<br>= ホストと同じネットワークインターフェイス、IPアドレスをもつ。 |
| none  |  ネットワークを持たないコンテナが作成される。<br>= コンテナ間の通信ができない。 |

## Dockerコンテナを任意のネットワークに参加させるコマンド

- コンテナは、接続されているブリッジネットワークを通じて、割り当てられたIPアドレスを介して互いに自由に通信できる。
 
```bash
# 新しいブリッジネットワークを作成する
$ docker network create mybridge_network
# 作成したブリッジネットワークを指定して、コンテナを作成 or 実行する
$ docker container run --name mycontainer1 myimage --net mybridge_network
# or
$ docker container create --name mycontainer1 myimage --net mybridge_network
# 同じブリッジネットワークを指定して、コンテナを作成する
$ docker container create --name mycontainer2 myimage --net mybridge_network
# コンテナに対して通信する
$ docker container run --name mycontainer1 myimage --net mybridge_network ping mycontainer2
64 bytes from 172.25.0.3: seq=0 ttl=64 time=0.119 ms
64 bytes from 172.25.0.3: seq=1 ttl=64 time=0.127 ms
64 bytes from 172.25.0.3: seq=2 ttl=64 time=0.132 ms
```

[Docker network 概論 - Qiita](https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9)
[network - 入門Docker](https://y-ohgi.com/introduction-docker/2_component/network/)
[Docker の volume と network の初歩 - 30歳からのプログラミング](https://numb86-tech.hatenablog.com/entry/2022/04/24/221235)

# Dockerを使った基本的なRailsアプリケーションの作成/コマンドのリンク

[クィックスタート: Compose と Rails - Docker-docs-ja](https://docs.docker.jp/compose/rails.html)
[Quickstart: Compose and Rails - Docker Docs](https://docs.docker.com/samples/rails/)
[docker-compose run - Docker-docs-ja](http://docs.docker.jp/compose/reference/run.html)
[docker compose run - Docker Docs](https://docs.docker.com/engine/reference/commandline/compose_run/)

```bash
$ docker compose run --rm web bundle exec rails console
```

`web` という名前のサービスに対して、 `bundle exec rails console` を実行する。
`--rm` オプションは、処理の実行が終了したらコンテナを削除する。

[Dockerを用いてRuby on Railsの環境構築をする方法( Docker初学者向け ) - Qiita](https://qiita.com/Yusuke_Hoirta/items/3a50d066af3bafbb8641)
[Docker Compose でローカルの Rails 開発環境を作る - Qiita](https://qiita.com/kbaba1001/items/39f81156589dd9a0d678)
[DockerでRails開発環境を作るワンライナー [Rails7/M1 Mac対応] - Qiita](https://qiita.com/masuidrive/items/7478fb9101652f2bbae1)


# コンテナオーケストレーション

## オーケストレータ

- 本番環境では多くの場合、サーバーを複数台用意し、負荷分散を行ったり耐障害性を高めたりする構成を作るため、本番環境でコンテナを利用したい場合、複数のコンテナを連携させる必要が出てくる。
- 多数のコンテナを、複数のホストから構成されたクラスターに対し、負荷分散やファイルオーバーを行うサービスをオーケストレータと呼ぶ。
- 例: Kubernetes、Amazon Elastic Container Service（ECS）、Amazon Elastic Kubernetes Service（EKS）


## Kubernetes

- Kubernetesはコンテナ化されたアプリケーションのデプロイ、スケーリングなどの管理を自動化するためのプラットフォームであり、コンテナオーケストレーションエンジンです。
- Docker単体では複数のホストで構成される一定規模以上のプロダクション利用に耐えうるシステムを構築するのは難しく、今日ではそのようなシステムを構築するには、Kubernetesに代表されるコンテナオーケストレーションエンジンを利用することが一般的です。

[Kubernetes完全ガイド 第2版](https://book.impress.co.jp/books/1119101148)

### クラスタ

![スクリーンショット 2022-05-13 23.17.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54467/71f9394f-0811-2217-7612-780748812238.png)

- 1つ以上のマスターノードと１つ以上のワーカーノードから成り立つもの。
- コンテナ化されたアプリケーションを実行する、**ノードと呼ばれるワーカーマシンの集合**。
- すべてのクラスターには少なくとも1つのワーカーノードがある。
- Kubernetesクラスターは以下の2種類のリソースで構成されています
  - **マスターがクラスターを管理する**
  - **ノードがアプリケーションを動かすワーカーとなる**

[標準化用語集 - Kubernetesドキュメント](https://kubernetes.io/ja/docs/reference/glossary/?all=true#term-cluster)
[Minikubeを使ったクラスターの作成 - Kubernetesドキュメント](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/)

### Deployment

- アプリケーションのインスタンスを作成および更新する責務がある。
- コンテナのデプロイ状態。
- Kubernetesクラスター上にコンテナ化アプリケーションをデプロイするために必要な設定。
    - アプリケーションのインスタンスを作成し、更新する方法を指示する。
    - **Deploymentを作成すると、KubernetesマスターはDeployment内に含まれるアプリケーションインスタンスをクラスター内の個々のノードで実行するようにスケジュールする**。
    - Deploymentを作成するときは、アプリケーションのコンテナイメージと実行するレプリカの数を指定する必要がある。


[kubectlを使ったDeploymentの作成 - Kubernetesドキュメント
](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/)

#### Deploymentのスケーリング

- トラフィックが増加した場合、ユーザーの需要に対応するためにアプリケーションをスケールする必要がある。
- **スケーリングは、Deploymentのレプリカの数を変更することによって実現可能**。
- **Deploymentをスケールアウトすると、新しいPodが作成され、使用可能なリソースを持つノードにスケジュールされる**。
    - **スケールすると、Podの数が増えて新たな望ましい状態になる**。

[アプリケーションの複数インスタンスを実行 - Kubernetesドキュメント](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/scale/scale-intro/)

### ノード

![スクリーンショット 2022-10-14 1.24.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54467/7f83ac9a-1169-6548-c224-55eee823c447.png)

- Podは常にノード上で動作する。
- ノードはKubernetesではワーカーマシンであり、クラスターに応じてVMまたは物理マシンになる。 
- 複数のPodを1つのノードで実行できる。
- すべてのKubernetesノードでは少なくとも以下のものが動作する。
  - Kubelet: Kubernetesマスターとノード間の通信を担当するプロセス。マシン上で実行されているPodとコンテナを管理します。
  - **レジストリからコンテナイメージを取得し、コンテナを解凍し、アプリケーションを実行することを担当する、Dockerのようなコンテナランタイム**。


[Podとノードについて - Kubernetesドキュメント](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/explore/explore-intro/)

### Pod

![スクリーンショット 2022-10-14 1.23.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54467/c45ff267-83d3-00b5-1e95-368e099eb277.png)

- 一番小さく一番シンプルなKubernetesのオブジェクト。
- クラスターで動作している**いくつかのコンテナのまとまり**。
- Podの中でコンテナが起動する。
- Podは常にノード上で動作する。
- Podは通常Deploymentによって管理される。
- Podは1つ以上のアプリケーションコンテナ(Dockerなど)のグループであり、共有ストレージ(ボリューム)、IPアドレス、それらの実行方法に関する情報が含まれています。
- Podには以下のものが含まれます:
  - **共有ストレージ(ボリューム)**
  - **ネットワーキング(クラスターに固有のIPアドレス)**
  - **Dockerイメージのバージョンや使用するポートなどの、各コンテナをどう動かすかに関する情報**
- Podの例
    - Node.jsアプリケーションを含むコンテナとNode.js Webサーバによって公開されるデータを供給するコンテナを含んだオブジェクト
- Kubernetes上に**Deploymentを作成すると、そのDeploymentはその中に(コンテナを直接作成するのではなく)コンテナを持つPodを作成する**。
    - 各Podは、スケジュールされているノードに関連付けられており、終了(再起動ポリシーに従って)または削除されるまでそこに残る。
    - コンテナ同士が密接に結合され、ディスクなどのリソースを共有する必要がある場合は、**コンテナを1つのPodにまとめてスケジュールする必要がある**。

[標準化用語集 - Kubernetesドキュメント](https://kubernetes.io/ja/docs/reference/glossary/?fundamental=true#term-pod)
[Podとノードについて - Kubernetesドキュメント](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/explore/explore-intro/)

### マニフェスト

- Pod等の定義の記述。
- JSONまたはYAMLフォーマットでの**Kubernetes API**オブジェクトの定義。

### Service

- Podの論理セットを定義する。
    - それらの**Podに対する外部トラフィックの公開、負荷分散、およびサービス検出を可能にする抽象化層**。
- YAML(推奨)またはJSONを使って定義される。
- **Serviceによって、アプリケーションはトラフィックを受信できるようになります**。
    - **各Podには固有のIPアドレスがありますが、それらのIPは、Serviceなしではクラスターの外部に公開されません**。
    - ServiceSpecでtypeを指定することで、Serviceをさまざまな方法で公開することができる。
- **Serviceには、公開されたDeploymentのすべてのPodにネットワークトラフィックを分散する統合ロードバランサがある**。
- **Serviceは、エンドポイントを使用して実行中のPodを継続的に監視し、トラフィックが使用可能なPodにのみ送信されるようにする**。
- *ClusterIP* (既定値)
    - クラスター内の内部IPでServiceを公開する。
    - この型では、Serviceはクラスター内からのみ到達可能になります。
- *NodePort*
    - ClusterIPのスーパーセット。
    - NATを使用して、クラスター内の選択された各ノードの同じポートにServiceを公開する。
    - `<NodeIP>`:`<NodePort>`を使用してクラスターの外部からServiceにアクセスできるようにする。
- *LoadBalancer*
    - NodePortのスーパーセット。
    - 現在のクラウドに外部ロードバランサを作成し(サポートされている場合)、Serviceに固定の外部IPを割り当てる。
- *ExternalName*
    - 仕様のexternalNameで指定した名前のCNAMEレコードを返すことによって、任意の名前を使ってServiceを公開する。
    - プロキシは使用されない。
    - このタイプはv1.7以上のkube-dnsを必要とする。

[Serviceを使ったアプリケーションの公開  - Kubernetesドキュメント](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/expose/expose-intro/)
[アプリケーションの複数インスタンスを実行 - Kubernetesドキュメント](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/scale/scale-intro/)

### Ingress

![スクリーンショット 2022-10-17 21.33.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54467/907d4071-7f68-c525-f149-85675702a04d.png)


- クラスター外からクラスター内ServiceへのHTTPとHTTPSのルートを公開する。
    - トラフィックのルーティングはIngressリソース上で定義されるルールによって制御される。
- Serviceに対して、外部疎通できるURL、負荷分散トラフィック、SSL/TLS終端の機能や、名前ベースの仮想ホスティングを提供するように設定できる。
- NGINX Ingress Controller for Kubernetesを使用することで、Nginx Webサーバー(プロキシ)として動作することができる。

[Ingress - Kubernetesドキュメント](https://kubernetes.io/ja/docs/concepts/services-networking/ingress/)
[Ingressコントローラー - Kubernetesドキュメント](https://kubernetes.io/ja/docs/concepts/services-networking/ingress-controllers/)

### 参考リンク

[Kubernetesドキュメント/チュートリアル - kubernetes](https://kubernetes.io/ja/docs/tutorials/)
[標準化用語集 - kubernetes](https://kubernetes.io/ja/docs/reference/glossary/?fundamental=true)
[Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー - slideshare](https://www.slideshare.net/ToruMakabe/kubernetes-120907020)
[ECS / Fargate / EKS ハンズオン資料まとめ - Qiita](https://qiita.com/HaraShun/items/56dab956708a3877aeb0)
[違いから見る Kubernetes #k8sjp / See Kubernetes through an Amazon ECS Lens - SpeakerDeck](https://speakerdeck.com/toricls/see-kubernetes-through-an-amazon-ecs-lens)
[EKSは本当にECSより難しいのか？ - Classmethod](https://dev.classmethod.jp/articles/ecs-and-eks/)
[AWS EKSとECSの比較と選択基準 - Zenn](https://zenn.dev/yoshinori_satoh/articles/2021-02-13-eks-ecs-compare)
[コンテナを使いこなすための心強い味方!「Kubernetes」(前編)](https://thinkit.co.jp/article/17453)
[10分くらいでわかる、KubernetesとEKSの何が便利なのか - Qiita](https://qiita.com/masachaco/items/3e50a1ac65cdd661a734)
[数時間で完全理解！わりとゴツいKubernetesハンズオン！！ - Qiita](https://qiita.com/Kta-M/items/ce475c0063d3d3f36d5d)
[Docker Composeユーザーに捧ぐKubernetes入門 - Zenn](https://zenn.dev/inductor/books/k8s-intro-for-docker-compose-users)
[AWS EKSとECSの比較と選択基準 - Zenn](https://zenn.dev/yoshinori_satoh/articles/2021-02-13-eks-ecs-compare)
[違いから見る Kubernetes #k8sjp / See Kubernetes through an Amazon ECS Lens - Speaker Deck](https://speakerdeck.com/toricls/see-kubernetes-through-an-amazon-ecs-lens)
[Kubernetes道場 Advent Calendar 2018 - Qiita](https://qiita.com/advent-calendar/2018/k8s-dojo)
[組織と事業の急拡大に立ち向かうためのマルチテナント Amazon EKS クラスタ/マルチアカウントアーキテクチャ - SpeakerDeck](https://speakerdeck.com/0gajun/multi-tenant-eks-muti-account-architecture-at-money-forward)