Docker のイメージとコンテナの関係性の検証

> 検証メモ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/da428f65-8f78-a1e5-2d21-9711272d1bfe.png)

Dockerのイメージとコンテナの関係性がよくわからないので、
検証してみた。


# Docker Image のダウンロード

まずは image があるかどうか確認

```shell
$ docker images | grep golang
# なし
```

なかったです。
ということで、 image をダウンロードします。

```shell
$ docker pull golang
Using default tag: latest
latest: Pulling from library/golang
d6ff36c9ec48: Pull complete
c958d65b3090: Pull complete
edaf0a6b092f: Pull complete
80931cf68816: Pull complete
813643441356: Pull complete
d2d74a4aa2e6: Pull complete
568efbaeb143: Pull complete
Digest: sha256:4c3279e05a0131c0565466ac538755f104d8d936efbc4c30ba7d717c73f3e2c2
Status: Downloaded newer image for golang:latest
docker.io/library/golang:latest
```

再度 image を確認します。

```shell
$ docker images | grep golang
golang                           latest              75605a415539        2 weeks ago         839MB
```

あった。
ここでイメージというものができたことになります。

一応確認ですが、コンテナはできていません。

```shell
$ docker ps -a | grep golang
# なし
```

## Docker Image の概要

```shell
$ docker image inspect golang
[
    {
        "Id": "sha256:75605a4155391abe376fc8124083ec52a2409ceb8a6b5ac6aae7eca133353ce3",
        "RepoTags": [
            "golang:latest"
        ],
        "RepoDigests": [
            "golang@sha256:4c3279e05a0131c0565466ac538755f104d8d936efbc4c30ba7d717c73f3e2c2"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2020-08-12T00:22:46.039326176Z",
        "Container": "b90c34099f107af34b5e4581d76118f411d58162c68eea08415ce9b18a640c42",
        "ContainerConfig": {
            "Hostname": "b90c34099f10",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOLANG_VERSION=1.15",
                "GOPATH=/go"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) WORKDIR /go"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:1b1d02bcac5b6e48f9b2312bc8bed4f3bb3f96b61fb2bf70fcfd1a1f19b98032",
            "Volumes": null,
            "WorkingDir": "/go",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "18.09.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOLANG_VERSION=1.15",
                "GOPATH=/go"
            ],
            "Cmd": [
                "bash"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:1b1d02bcac5b6e48f9b2312bc8bed4f3bb3f96b61fb2bf70fcfd1a1f19b98032",
            "Volumes": null,
            "WorkingDir": "/go",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 838873792,
        "VirtualSize": 838873792,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/d131d3a907fd243f1930b59643d8a8063185972576e5d79edbf308e91e15a353/diff:/var/lib/docker/overlay2/e7a3845fa041337b03c7d45fed7a42b4e6906f73aac17504c41fa33baf8494f3/diff:/var/lib/docker/overlay2/0522b267b619c032b9959fd9ac957c6c45affa3375ee790320ca7d9521e9a4f6/diff:/var/lib/docker/overlay2/91468ffbb5607e8fcbab36d1315e257edceced8d959271b3f527f588f1b41203/diff:/var/lib/docker/overlay2/bfbbc63ca1366753931d7ba67a9e2e793abf216a54cdfbbae9c70959b5688716/diff:/var/lib/docker/overlay2/bb3852e88617e42f5cec2f2620bf5116eba6b846ce24e016193a8fd6a9eef963/diff",
                "MergedDir": "/var/lib/docker/overlay2/6a27891c4193c1c910515bf07d3138d5e377f986144545dde9e26bc639f5b071/merged",
                "UpperDir": "/var/lib/docker/overlay2/6a27891c4193c1c910515bf07d3138d5e377f986144545dde9e26bc639f5b071/diff",
                "WorkDir": "/var/lib/docker/overlay2/6a27891c4193c1c910515bf07d3138d5e377f986144545dde9e26bc639f5b071/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:0ced13fcf9441aea6c4ee1defc1549772aa2df72017588a1e05bc11dd30b97b6",
                "sha256:b2765ac0333ae89829bb991a50d961bbb20069bac6eefce6fab8ef4d253ba24c",
                "sha256:7a9460d5321859e34344b2817f9e87b4c18bc9eb42dca91e0822d3511ea42a79",
                "sha256:e5df62d9b33ae0f2e75d7a92270f20fcac04986ac22dd0674c0420c171cc0d56",
                "sha256:7279468fdfadf1018dd7787eafb864fedcbeb4f2877d7a541295948467c42ac9",
                "sha256:e63d5e7bcdc59f31b30c1074357ff73a75dd10c03494888fd47e6dc48950b87a",
                "sha256:2936bd2191b23bb4a430d31e0b62ddf95eaf8e46452ac11b9f2bbcfc882499b5"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]
```


# Docker コンテナの起動

docker run でコンテナが起動します。

> 内部的には run はイメージからコンテナの構築と起動を両方やります。
コンテナの構築だけであれば、 docker create でやるっぽいです。

```shell
$ docker run golang
```

これでコンテナが作られて動いたはずです。
内部的には docker create によるコンテナ構築が行われ、一瞬コンテナが起動し、`やること` をやってすぐに終わります。

**Docker run でやること**

ここにある `やること` というのは、 `Dockerfile` などに記載されているようなことです。

以下を参照してみてください。
https://github.com/docker-library/golang/blob/master/1.15/alpine3.12/Dockerfile
ここに書かれてある処理が動いて、すぐに終了します。


```shell
$ docker ps -a | grep golang
86f4bdeb8a98        golang                         "bash"                   5 seconds ago       Exited (0) 4 seconds ago                        festive_dhawan
```
`festive_dhawan` のように、コンテナに勝手に名前がつきます。

また、 `docker run golang` を実行する度に、コンテナは増えていきます。

```shell
$ docker run golang
$ docker ps -a | grep golang
d53900629ae3        golang                         "bash"                   5 minutes ago       Exited (0) 5 minutes ago                        quizzical_aryabhata
86f4bdeb8a98        golang                         "bash"                   13 minutes ago      Exited (0) 13 minutes ago                       festive_dhawan
```
次は `quizzical_aryabhata` という名前がつきました。
このままでは、 docker run をする度にコンテナは増えていきます。

## Docker run で作った後、コンテナを自動的に消したい

```
$ docker run --rm golang 
```

`--rm` をつけると使用後、即コンテナが削除されます。

## Docker run で作られるコンテナの名前を指定したい

```
$ docker run --name golang_test golang
$ docker ps -a | grep golang
2b871a22d588        golang                         "bash"                   About a minute ago   Exited (0) About a minute ago                       golang_test
```
golang_test という名前が指定できています。
コンテナの名前は重複した名前が設定できないため、もう一度同じ名前でコンテナを作ろうした場合は、
しっかりエラーになってくれます。

## コンテナを削除

```shell
$ docker rm golang_test
# または   docker rm 2b871a22d588
```
名前か id を指定します。

## Docker でもっと細かい設定をしたい

その時は docker run ではなく、
Dockerfile を作ったり、 docker-compose を使ってください。
ここでは説明を割愛します。

> docker run < Dockerfile < docker-compose の順番で、
管理対象が複雑になった時に移行していくものかなと思います。
おそらくはじめから docker-compose 作っちゃっていい気もします。

*参考*

* [Qiita - Dockerfileを書いてみる](https://qiita.com/nl0_blu/items/1de829288db2670276e8)
* [Qiita - Docker compose ことはじめハンズオン](https://qiita.com/TsutomuNakamura/items/7e90e5efb36601c5bc8a)

# Docker イメージ、コンテナの容量確認

```shell
$ docker system df -v | grep golang
golang                           latest              75605a415539        2 weeks ago         838.9MB             0B                  838.9MB             2
d53900629ae3        golang                         "bash"                   0                   0B                  11 minutes ago      Exited (0) 11 minutes ago   quizzical_aryabhata
86f4bdeb8a98        golang                         "bash"                   0                   0B                  19 minutes ago      Exited (0) 19 minutes ago   festive_dhawan
```
1行目は イメージ の容量 838.9MB が表示されていて、
2行目、3行目は コンテナの容量 0B が表示されています。

Go言語自体や、Dockerが用意しているOS領域などはイメージにて容量がかかっていて、
コンテナには容量がかかってないことがわかります。
コンテナはイメージのデータを使っているようです。
そのため、コンテナをたくさん作っても容量はそこまで増えません。

## Dockerコンテナはどこで容量を使うのか

```shell
$ docker run -it golang
root@a8c84548d1d5:/go#
```
`-it` のオプションをつけることで、コンテナ作成後、コンソールに入ることができます。

容量を増やすため、 `apt update` を実行してみます。

```shell
root@a8c84548d1d5:/go# apt update
Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:2 http://deb.debian.org/debian buster InRelease [122 kB]
Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:4 http://security.debian.org/debian-security buster/updates/main amd64 Packages [224 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7906 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7868 B]
Fetched 8378 kB in 2s (4638 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
All packages are up to date.
```

容量確認します。

```shell
$ docker system df -v | grep golang
golang                           latest              75605a415539        2 weeks ago         838.9MB             0B                  838.9MB             3
a8c84548d1d5        golang                         "bash"                   0                   17.5MB              3 minutes ago       Exited (0) 24 seconds ago   objective_curran
d53900629ae3        golang                         "bash"                   0                   0B                  43 minutes ago      Exited (0) 43 minutes ago   quizzical_aryabhata
86f4bdeb8a98        golang                         "bash"                   0                   0B                  51 minutes ago      Exited (0) 51 minutes ago   festive_dhawan
```

2行目の `objective_curran` の容量に注目してください。
`17.5MB` と他のコンテナが `0B` であるのと比べて、容量がかかっています。
コンテナの中でダウンロードや更新した容量がかかっていることがわかりました。

> イメージはいつ削除しても大元が消えなければ再度ダウンロードできそう。

# まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/da428f65-8f78-a1e5-2d21-9711272d1bfe.png)

| 名称|概要|入っているデータ|削除してもいいか|
|:-----------|:------------|:------------|:------------|
|イメージ|共有利用のベース|OSの情報や、テーマとなっているパッケージ|削除しても再度ダウンロードすればOK。キャッシュ的意味合い|
|コンテナ|用途ごとに用意|イメージから作成後の個別の変更|要確認ではあるが、削除しても問題ないように設計した方がいい|

* コンテナはそもそもサーバー外部にデータを持つか、 volumes などを使い、必要データはホストOS側に持つ方が良い
* コンテナをイメージ化することもできるみたい。自分で Docker hub にあげてもいいみたい。
  * [Qiita - Dockerイメージの作り方](https://qiita.com/Kitanotori/items/c1cfe19fcd29f7b0746c)