初めてのDockerのお勉強〜備忘録〜

# はじめに
書いているうちに長くなってしまったので、~~ストック/LGTMして~~お暇なときに読んでください。誤字・脱字はひっそりと直していると思います。  
初めて **Docker** というものに触れるにあたって、一から勉強していくことにしました。ここでは、私が勉強した内容を、私なりに簡潔にまとめていくことを目指します。そこで、記事としては見づらくなることを承知の上で、敢えて勉強していく過程で直面した順(をベース)に話を進めていくことにします[^assert1]。  
備忘録として残すことが主な目的ですが、経験を積むためにも投稿することにしました。極力間違いのないようにしていますが、理解不足などによる間違いが無いとも言い切れません[^assert2]。その際は是非ご指摘頂けますと幸いです。

※ 本記事に書いてあることは、基本的に[ブログ記事][wakarimi][^ref]を参考にしてまとめているので、より詳細に知りたい場合にご参照下さい。

# Dockerとは
まず、Dockerとはそもそも何者なのかについてまとめていきます。Dockerとは、簡単に一言で言うと、<font color="Red">**コンテナを扱うための便利なツール**</font>です。  
Dockerを利用することで、誰かと共同作業する時に自慢の煩わしさを発揮する様々な環境整備（「環境整備」という言い回しの厳密性には触れませんがご容赦下さい）を高速・確実・楽にしてくれるようです。

# コンテナとは
コンテナ（型仮想化）[^container]は、1種の仮想化手法です。  
Dockerを初めて勉強する人が「仮想化」と言われると、`VirtualBox`や`Parallels Desktop`のように、仮想化用のソフトウェアをインストールして、その上でホストOS[^hostOS]とは異なるOS(ゲストOS)を利用する技術を思い浮かべるでしょう(私はそうでした)。  
これに対して、コンテナでは、ホストOSのコマンドやライブラリから隔離された場所で、ホストOSのカーネルとコンテナ独自のコマンドやライブラリを利用して、あたかも別なOSが動いているように動作してくれます。そのため、コンテナは仮想化ソフトウェアやゲストOSを必要とせず、高速に動いてくれるのです。

![container](https://tech-lab.sios.jp/wp-content/uploads/2020/02/Screen-Shot-2020-02-08-at-9.00.49.png "container")
仮想化とコンテナ(~~より良い図を描ける気がしないので~~ [引用][wakarimi][^ref])

上図のように、通常のプロセスではホストOSのコマンド・ライブラリを使用してホストOSのカーネルにアクセスします。  
一方、コンテナはホストOSのコマンド・ライブラリから隔離されていて、コンテナ内のものを使用しますが、コンテナ内にはゲストOSが存在しないため、ホストOSのカーネルにアクセスします[^kernel]。

<details><summary>コンテナのOSについて</summary><div>

```
$ docker run -it centoOS:centoOS7 /bin/bash
```

(まだ[下の基本的な使い方](#チュートリアルになってたら嬉しい)を見ていない方の実行はオススメしませんが、)このコマンドを実行することで、CentOS7の環境を作ってbashを起動できます。(`-it`は実行時のオプション指定です)
このOSのイメージは、[Docker Hub][docker_hub]という、インターネット上に公開されているリポジトリから取得されるそうです。

</div></details>

# Docker を使う

## 前提
使用環境は下記の通りとします。
>macOS Catalina バージョン10.15.7

この使用環境を前提に話を進めていきますが、ご了承ください。
他のOSなど、詳しくは、公式ドキュメント Docker docs の [Supported platforms](https://docs.docker.com/engine/install/) 
から、ご自身の使用環境への対応をご確認ください。m(_ _)m

## 準備
Mac で Docker を使用するために、 [Docker Desktop for Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac) をインストールします。
インストールが完了したら、 Docker.dmg を実行してアプリケーションを追加します。
これで Docker がお手元の Mac で利用することができます。

## チュートリアル（になってたら嬉しい）
### コンテナの起動
Docker コンテナを起動するために以下のコマンドを実行します。

```
$ docker run --name tutorial centos:centos7 /bin/echo hoge
```

>書式:
>docker run --name [コンテナ名] [イメージ名]:[タグ名] [コンテナ起動直後に実行するコマンド]

実行結果：

```
hoge
```

`hoge`と出力されました。

<details><summary>コマンドの書式について</summary><div>

* `docker` は、（筆者の経験上） Docker コマンドにはお決まりでくっついています。
* `run` は、Docker コンテナを起動するための命令で、他にも起動中のコンテナを一覧で確認する `ps` など、様々な命令があります。
* `--name` は、起動するコンテナに名前をつけるためのオプションです。上記のコマンドでは、`tutorial` という名前がつけられています。
* `centos`は、[Docker Hub][docker_hub] 上での CentOS のOSを提供しているイメージの名前です。
* `centos7`は、上で指定したイメージの中から、`centos7`というタグのつけられたバージョンのイメージを取得することを意味します。
* `/bin/echo hoge`は、書式の通り、コンテナ起動直後に実行するコマンドです。今回の場合は、よく見る(?)`echo`コマンドで、実行結果のように`hoge`を出力しています。`/bin/echo`はコマンドなので、実際にはホストOSのカーネルを利用しています。

</div></details>

※ 本来、イメージを取得するには、`Docker pull centos:centos7`というコマンドが使用されますが、`Docker run`コマンドでも、指定したイメージが取得されていなければ自動で取得してくれるみたいです。

### コンテナの確認
[コンテナの起動](#コンテナの起動)をしたら、次のコマンドを実行してコンテナの状況を確認してみましょう。

```
$ docker ps
```

実行結果:

```
CONTAINER ID   IMAGE         COMMAND                  CREATED      STATUS      PORTS                    NAMES
```

表の列名のようなものしか出てこない。。。？  
`docker ps`は、稼働中のコンテナの一覧を表示してくれます。
実は、コンテナは、起動した後、指定のコマンドを実行すると（内部で動作しているプロセスが終了すると）停止するようになっています。  
では、停止中のコンテナも表示してくれるオプションをつけて再度確認してみましょう。

```
$ docker ps -a
```

実行結果：

```
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS                      PORTS                    NAMES
53f4db7f38f4   centos:centos7   "/bin/echo hoge"         12 minutes ago   Exited (0) 12 minutes ago                            tutorial
```

<details><summary>各列の説明</summary><div>

* `CONTAINER_ID` : 作成されたコンテナのID(上の例とは異なるはずです)
* `IMAGE` : コンテナに用いられていたイメージとそのタグ
* `COMMAND` : 起動直後に実行されたコマンド
* `CREATED` : コンテナが作成された時間(上の例とは異なるはずです)
* `STATUS` : コンテナの状態(時間の部分は、上の例とは異なるはずです)
* `PORTS` : ポートの接続関係（詳細は割愛）
* `NAMES` : コンテナの名前

</div></details>

確かに、`tutorial`という名前のコンテナがありますね。
`STATUS`が`Exited`になっていることから、コンテナが稼働中ではないことがなんとなくわかると思います。  
また、`COMMAND`を見ると、`/bin/echo hoge`となっています。
初めにコンテナを起動したときに、実行されるコマンドが決まるんですね。

### コンテナの削除
（気にならない人は、やり方だけ確認して飛ばしてもらっても結構です）
では、停止したまま残っているコンテナを一度削除してしまいましょう。  
コンテナの削除には、次のコマンドを実行します。

```
$ docker rm tutorial
```

>書式：
>docker rm [コンテナ名 or コンテナID]

これで、先ほど作ったコンテナが削除されているはずです。`docker ps -a`で確認してみてください。  
ちなみに、`docker rm $(docker ps -aq)`とすることで、停止している全てのコンテナを削除できます。
また、`docker images`でイメージの一覧表示、`docker rmi`で指定したイメージの削除もできます。

### コンテナの起動（２）
それでは、改めてコンテナの起動をしてみましょう。
次は、起動してもすぐに停止することのないようなコンテナを作成します。

```
$ docker run -itd --name tutorial2 centos:centos7 /bin/bash
```

実行結果：

```
3e98ba03038860506113697a075c4d2ce9a9a2a730edd3db3c625a099acada31
```

実行結果では、何やら不思議な数字と文字の羅列が出力されていると思います。
`docker ps`で確認してみると、

```
3e98ba030388   centos:centos7   "/bin/bash"              3 seconds ago   Up 3 seconds                            tutorial2
```

`STATUS`が`Up`の`tutorial2`という名前のコンテナが出来ていると思います。  
コマンドの中で、[コンテナの起動](#コンテナの起動)の時と違う部分について説明します。

* `/bin/bash`先ほどは、`/bin/echo hoge`となっていました。これは、`bash`を起動することになります。今皆さんが使っているはずのものです。(mac なら bash だったり zsh だったり)
* `-itd`はオプションです。オプションは繋げられるので`-i -t -d`でも同じです。
    * `-i` : *interactive* らしいです。インタラクティブシェルってことですね。ホストの標準入力をコンテナの標準入力にせつぞくしてくれるらしい。
    * `-t` : *tty* だそうです。どうやらコンテナ内の標準出力をホストの標準出力に繋いでくれるらしい。
    * `-d` : *detach-mode* らしい。バックグラウンドでコンテナが実行されます。

(`run`)コマンドのオプションについては[Docker公式のリファレンス](https://docs.docker.jp/engine/reference/commandline/run.html)などを参照してみてください。  
※ ちなみに、オプションについては、`-id`、`-td`でも同様の結果が得られました。これは、筆者自身、解釈に自信がないのですが、`-d`のみでは、バックグラウンドで実行された際に入出力プロセスが終了しているためにコンテナが停止してしまい、`-i`か`-t`どちらかでも追加されることで、入出力のプロセスが生き残ってコンテナが稼働したままなのだと思っています。（偉い人教えてください。。）

### コンテナにログイン
先ほどのコマンドを実行しただけでは、コンテナは稼働中でもコンテナを「使う」ことはできていないですよね。
オプションの説明でも描いたように、コンテナはバックグラウンドで動いています。
そこで、裏で待機してくれているコンテナに、下のコマンドでログインします。

```
$ docker exec -it tutorial2 /bin/bash
```

>書式：
>docker exec [オプション] [コンテナ名 or コンテナID] [コマンド]

実行結果：

```
[root@3e6c16e91968 /]#
```

上記のように、`root@[コンテナID]`という形でコンテナ内のbashに入れたと思います。
ここで、`echo hoge`を実行すると、期待通り`hoge`が出力されます。
コンテナを抜けるときは、`exit`コマンドを使用します（通常のターミナルのコマンドと同じですね）。  
コンテナを抜けた後、もう一度`docker ps`を実行すると、コンテナがちゃんと裏で待機してくれていることがわかります。

### コンテナの停止
コンテナ`tutorial2`は、バックグラウンドで稼働しているため、こちらから停止させる手段が欲しくなりますね。
そんなときには、次のコマンドを実行します。

```
$ docker stop tutorial2
```

実行結果：

```
tutorial2
```

シンプルですね。`docker ps`と`docker ps -a`の出力を比較するとコンテナが停止していることをより実感できると思います。

### コンテナの再起動
「`tutorial2`コンテナを停止したけど、もう一度使いたい」という場合には、下のコマンドでコンテナを再起動してあげます。

```
$ docker restart tutorial2
```

>書式：
>docker restart [コンテナ名 or コンテナID]

これで、`tutorial2`コンテナを初めて起動した時と同じように、バックグラウンドで待機している状態になります。

# 最後に
これで、Dockerのインストール、イメージの取得、コンテナの作成・起動、停止、再起動、ログイン、削除ができると思います。
ひとまず、ここまでで今回のまとめは終わりにしたいと思います。  
筆者自身まだまだ勉強中の身なので、これからも頑張っていきたいと思います。
結論：世のエンジニアは偉い~~（異論は認めません）~~

[^assert1]: 用語などの全ての説明を保証する記事ではありません。

[^assert2]: 特に、表現の仕方などには曖昧な表現が多分に含まれている可能性があります。

[^ref]: [【連載】世界一わかりみが深いコンテナ&Docker入門][wakarimi]

[^hostOS]: 実際に使用しているマシンのOS

[^container]: 「コンテナ」という概念自体はDockerに特有のものではなく、（例えば、プログラミングにおけるデータ構造やクラスなど）いくつかの種類を持っているようです。

[^kernel]: ホストOSのカーネルを利用するので、ホストOSのカーネルが対応していない操作はできないようです(ex : ホストが MacOS 系なのにコンテナ内では WindowsOS 系の操作を要求する場合)

[wakarimi]:https://tech-lab.sios.jp/archives/18811

[docker_hub]:https://hub.docker.com/