Docker って、どの位規模の Container が作成出来ますか

# はじめに
こんにちは。テクノプロで自動車関連の組み込み開発エンジニアをしている神崎　一郎です。
これまでの約２年間、業務にも Docker の使う必要があるため、自宅で、組み込み系開発を勉強するための Docker Image を試行しながら構築してきた。
振り返し見ると、かなり大きな Docker Image となりました：

```
ci@debian:~$ docker images
REPOSITORY            TAG      IMAGE ID       CREATED       SIZE
bitwaves/blue-earth   1.0.0    421eeacb1ce3   7 months ago  22.5GB
```

今回、それについて書きたいと思います：物理 PC の OS インストールから同じ機能を揃えるまでセットアップするのに、数日かかるでしょう。これで、壊れるおそれがなく開発環境が出来上がり、また、修正したい時、テキストの Dockerfile を修正し、一つコマンドで新しい Docker Image が作れますから、環境構築には参考になるかと思います。
唯、当 Docker Image の構築における技術的な要素は少なく、それに期待しないほうが良いでしょう。

# 参考：当方の PC 環境

- HP Z400（メモリ 22 GB、HDD 4 TB 余り）
- OS: Debian 8
- 目標 Docker Image: 

```
(myanaconda2) di@blueci:~$ uname -a
Linux blueci 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 x86_64 x86_64 GNU/Linux
```

# 当 Docker Image の主な機能（含まれるもの）

- Ubuntu 16.04（xenial）
  - ubuntu debootstrap base
  - ubuntu standard
  - ubuntu desktop（X-Window 起動可能）
  - User
    - root user
    - 非 root user
- System Wide Python 2.7.12
- 言語系
  - Anaconda Python 3.6.5（Tensorflow を含む）
  - Anaconda Python 2.7.12
  - Ruby 2.5.1
  - Node 8.11.1
- Vim
- SSHD、Fabric、Ansible
- Supervisor Based サービス、カスタマイズ起動
- PostGreSQL、Redis
- ウェブ開発環境：Django 等
- Apache Airflow
- BuildBot
- Jupyter
  - Jupyter Notebook
  - JupyterLab
- PlatformIO（Core, IDE）

# Docker Build File の例
### Dockerfile

```
$ cat Dockerfile

# escape = \  (backslash)

FROM bitwaves/blue-iot:0.5.0

# ############################################################################################
#                             ---- USER ${MY_AC} ----
# ############################################################################################
USER ${MY_AC}
WORKDIR /home/${MY_AC}

RUN set -ex \
  && cd ~ \
  && source ~/.pyenv/versions/anaconda3-5.0.1/bin/activate ${TENSORFLOW_PYTHON}


# ############################################################################################
USER root

WORKDIR /root/


CMD ["bash", "/supervisor/sbin/root-supervisor-daemon.sh"]
```

### makefile

```
$ cat makefile

REGISTER = bitwaves
IMAGE = blue-earth
VER=0.5.0

default: build

build: $(IMAGE).dn

$(IMAGE).dn: Dockerfile
        docker-build $(REGISTER)/$(IMAGE):$(VER) $(IMAGE)

.PHONY: clean
clean:
        -rm -f $(IMAGE).dn

remove:
        -docker rmi $(REGISTER)/$(IMAGE):$(VER)
```

# 参考：docker inspect 出力

```

ci@debian:/home/ci/docker-world/env$ docker inspect bitwaves/blue-earth:1.0.0
[
    {
        "Id": "sha256:421eeacb1ce3afc8358f845f4b2cddad753ec3e65175f87d7329c19e75ce5e99",
        "RepoTags": [
            "bitwaves/blue-earth:1.0.0",
            "bitwaves/blue-earth:latest"
        ],
        "RepoDigests": [
            "bitwaves/blue-earth@sha256:f790b2cec5de8eca32d0f039c131ac6df3145a24425707c8a29444ed3af4d798"
        ],
        "Parent": "sha256:308a0d69705feac23e7e8a231282dc78456883a7835407c9ec5ffd2b0467596b",
        "Comment": "",
        "Created": "2018-09-18T22:41:37.99322569Z",
        "Container": "0de6b60576ac713c2bdc62ec21052302791082c318436078d49cc1e23f8c2c54",
        "ContainerConfig": {
            "Hostname": "31429f0bf036",
            "Domainname": "",
            "User": "root",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "22/tcp": {},
                "50000/tcp": {},
                "5050/tcp": {},
                "53/tcp": {},
                "53/udp": {},
                "5432/tcp": {},
                "5555/tcp": {},
                "6379/tcp": {},
                "80/tcp": {},
                "8000/tcp": {},
                "8010/tcp": {},
                "8080/tcp": {},
                "8088/tcp": {},
                "8180/tcp": {},
                "8780/tcp": {},
                "8793/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/opt/ansible/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=en_US.UTF-8",
                "LANGUAGE=en_US.UTF-8",
                "LC_ALL=en_US.UTF-8",
                "LC_CTYPE=en_US.UTF-8",
                "TERM=xterm-256color",
                "DEBIAN_FRONTEND=noninteractive",
                "VERSION_NAME=xenial",
                "GPG_KEY=C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF",
                "PYTHON_VERSION=2.7.12",
                "PYTHON_PIP_VERSION=9.0.1",
                "BUILD_VER=JUPITER Rev 2018.08.08",
                "MY_AC=di",
                "MY_GR=di",
                "MY_UID=1970",
                "MY_GID=1970",
                "ANACONDA_VER=3-4.4.0",
                "TENSORFLOW_PYTHON=anaconda3",
                "TENSORFLOW_PYTHON_VER=3.5.2",
                "MY_PYTHON=myanaconda2",
                "MY_PYTHON_VER=2.7.12",
                "MY_RUBY_VER=2.3.3",
                "GOROOT=/usr/local/go",
                "NODE_VERSION=5.4.0",
                "NVM_DIR=/home/di/.nvm",
                "INIT_ROOT_PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "INIT_MY_AC_PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "MY_DATA_DIR=/var/my-data",
                "DISABLE=",
                "GOPATH=/home/di/works",
                "GOBIN=/usr/local/go/bin",
                "NODEBIN=/usr/lib/node_modules/bin",
                "FABRIC_HOME=/fabric",
                "FABRIC_FILE_DIR=/fabric/fabfile",
                "PYTHONPATH=/etc/superset::/opt/ansible/lib",
                "ANSIBLE_LIBRARY=/opt/ansible/library",
                "LUIGI_CONFIG_DIR=/etc/luigi/",
                "GITLAB_CI_MULTI_RUNNER_VERSION=1.1.4",
                "GITLAB_CI_MULTI_RUNNER_USER=gitlab_ci_multi_runner",
                "GITLAB_CI_MULTI_RUNNER_HOME_DIR=/home/gitlab_ci_multi_runner",
                "GITLAB_CI_MULTI_RUNNER_DATA_DIR=/home/gitlab_ci_multi_runner/data",
                "SPUERVISOR_ROOT=/home/di/supervisor",
                "SV_ROOT=/supervisor",
                "SV_EXT=blue-moon",
                "SV_AC=root",
                "SV_GR=root",
                "REDIS_USER=redis",
                "REDIS_DATA_DIR=/var/lib/redis",
                "REDIS_LOG_DIR=/var/log/redis",
                "PG_APP_HOME=/etc/docker-postgresql",
                "PG_VERSION=9.6",
                "PG_USER=postgres",
                "PG_HOME=/var/lib/postgresql",
                "PG_RUNDIR=/run/postgresql",
                "PG_LOGDIR=/var/log/postgresql",
                "PG_CERTDIR=/etc/postgresql/certs",
                "PG_BINDIR=/usr/lib/postgresql//bin",
                "PG_DATADIR=//main",
                "PGADMIN4_VERSION=1.6",
                "DJANGO_BASE=/django",
                "JHOME=/home/di",
                "SUPERSET_VERSION=0.18.5",
                "AIRFLOW_VERSION=1.8.1",
                "AIRFLOW_HOME=/usr/local/airflow",
                "LC_MESSAGES=en_US.UTF-8",
                "JENKINS_HOME=/home/di/jenkins",
                "JENKINS_SLAVE_AGENT_PORT=50000",
                "TINI_VERSION=0.13.2",
                "TINI_SHA=afbf8de8a63ce8e4f18cb3f34dfdbbd354af68a1",
                "JENKINS_VERSION=2.7.3",
                "JENKINS_SHA=f822e70810e0d30c6fbe7935273635740faa3d89",
                "JENKINS_UC=https://updates.jenkins.io",
                "COPY_REFERENCE_FILE_LOG=/copy_reference_file.log",
                "JULIA=/opt/julia/bin/julia",
                "ANDROID_EMULATOR_USE_SYSTEM_LIBS=1"
            ],
            "Cmd": [
                "/bin/bash",
                "-c",
                "#(nop) ",
                "CMD [\"bash\" \"/supervisor/sbin/root-supervisor-daemon.sh\"]"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:308a0d69705feac23e7e8a231282dc78456883a7835407c9ec5ffd2b0467596b",
            "Volumes": null,
            "WorkingDir": "/root",
            "Entrypoint": null,
            "OnBuild": [],
            "Labels": {
                "org.label-schema.license": "PostgreSQL",
                "org.label-schema.name": "pgAdmin4",
                "org.label-schema.url": "https://www.pgadmin.org",
                "org.label-schema.vcs-url": "https://github.com/fenglc/dockercloud-pgAdmin4",
                "org.label-schema.version": "1.6"
            },
            "Shell": [
                "/bin/bash",
                "-c"
            ]
        },
        "DockerVersion": "17.05.0-ce",
        "Author": "",
        "Config": {
            "Hostname": "31429f0bf036",
            "Domainname": "",
            "User": "root",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "22/tcp": {},
                "50000/tcp": {},
                "5050/tcp": {},
                "53/tcp": {},
                "53/udp": {},
                "5432/tcp": {},
                "5555/tcp": {},
                "6379/tcp": {},
                "80/tcp": {},
                "8000/tcp": {},
                "8010/tcp": {},
                "8080/tcp": {},
                "8088/tcp": {},
                "8180/tcp": {},
                "8780/tcp": {},
                "8793/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/opt/ansible/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=en_US.UTF-8",
                "LANGUAGE=en_US.UTF-8",
                "LC_ALL=en_US.UTF-8",
                "LC_CTYPE=en_US.UTF-8",
                "TERM=xterm-256color",
                "DEBIAN_FRONTEND=noninteractive",
                "VERSION_NAME=xenial",
                "GPG_KEY=C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF",
                "PYTHON_VERSION=2.7.12",
                "PYTHON_PIP_VERSION=9.0.1",
                "BUILD_VER=JUPITER Rev 2018.08.08",
                "MY_AC=di",
                "MY_GR=di",
                "MY_UID=1970",
                "MY_GID=1970",
                "ANACONDA_VER=3-4.4.0",
                "TENSORFLOW_PYTHON=anaconda3",
                "TENSORFLOW_PYTHON_VER=3.5.2",
                "MY_PYTHON=myanaconda2",
                "MY_PYTHON_VER=2.7.12",
                "MY_RUBY_VER=2.3.3",
                "GOROOT=/usr/local/go",
                "NODE_VERSION=5.4.0",
                "NVM_DIR=/home/di/.nvm",
                "INIT_ROOT_PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "INIT_MY_AC_PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "MY_DATA_DIR=/var/my-data",
                "DISABLE=",
                "GOPATH=/home/di/works",
                "GOBIN=/usr/local/go/bin",
                "NODEBIN=/usr/lib/node_modules/bin",
                "FABRIC_HOME=/fabric",
                "FABRIC_FILE_DIR=/fabric/fabfile",
                "PYTHONPATH=/etc/superset::/opt/ansible/lib",
                "ANSIBLE_LIBRARY=/opt/ansible/library",
                "LUIGI_CONFIG_DIR=/etc/luigi/",
                "GITLAB_CI_MULTI_RUNNER_VERSION=1.1.4",
                "GITLAB_CI_MULTI_RUNNER_USER=gitlab_ci_multi_runner",
                "GITLAB_CI_MULTI_RUNNER_HOME_DIR=/home/gitlab_ci_multi_runner",
                "GITLAB_CI_MULTI_RUNNER_DATA_DIR=/home/gitlab_ci_multi_runner/data",
                "SPUERVISOR_ROOT=/home/di/supervisor",
                "SV_ROOT=/supervisor",
                "SV_EXT=blue-moon",
                "SV_AC=root",
                "SV_GR=root",
                "REDIS_USER=redis",
                "REDIS_DATA_DIR=/var/lib/redis",
                "REDIS_LOG_DIR=/var/log/redis",
                "PG_APP_HOME=/etc/docker-postgresql",
                "PG_VERSION=9.6",
                "PG_USER=postgres",
                "PG_HOME=/var/lib/postgresql",
                "PG_RUNDIR=/run/postgresql",
                "PG_LOGDIR=/var/log/postgresql",
                "PG_CERTDIR=/etc/postgresql/certs",
                "PG_BINDIR=/usr/lib/postgresql//bin",
                "PG_DATADIR=//main",
                "PGADMIN4_VERSION=1.6",
                "DJANGO_BASE=/django",
                "JHOME=/home/di",
                "SUPERSET_VERSION=0.18.5",
                "AIRFLOW_VERSION=1.8.1",
                "AIRFLOW_HOME=/usr/local/airflow",
                "LC_MESSAGES=en_US.UTF-8",
                "JENKINS_HOME=/home/di/jenkins",
                "JENKINS_SLAVE_AGENT_PORT=50000",
                "TINI_VERSION=0.13.2",
                "TINI_SHA=afbf8de8a63ce8e4f18cb3f34dfdbbd354af68a1",
                "JENKINS_VERSION=2.7.3",
                "JENKINS_SHA=f822e70810e0d30c6fbe7935273635740faa3d89",
                "JENKINS_UC=https://updates.jenkins.io",
                "COPY_REFERENCE_FILE_LOG=/copy_reference_file.log",
                "JULIA=/opt/julia/bin/julia",
                "ANDROID_EMULATOR_USE_SYSTEM_LIBS=1"
            ],
            "Cmd": [
                "bash",
                "/supervisor/sbin/root-supervisor-daemon.sh"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:308a0d69705feac23e7e8a231282dc78456883a7835407c9ec5ffd2b0467596b",
            "Volumes": null,
            "WorkingDir": "/root",
            "Entrypoint": null,
            "OnBuild": [],
            "Labels": {
                "org.label-schema.license": "PostgreSQL",
                "org.label-schema.name": "pgAdmin4",
                "org.label-schema.url": "https://www.pgadmin.org",
                "org.label-schema.vcs-url": "https://github.com/fenglc/dockercloud-pgAdmin4",
                "org.label-schema.version": "1.6"
            },
            "Shell": [
                "/bin/bash",
                "-c"
            ]
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 22537300072,
        "VirtualSize": 22537300072,
        "GraphDriver": {
            "Data": null,
            "Name": "aufs"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:03b0e0ae2faceac5c3d20dbf92f9fb1929cf045fe6d8794ce127210590f9235c",
                "sha256:4a8482eea7dd6829517877914838a1ec63a750a35c8d892ef0426eb8f0feb9ab",
                "sha256:cdb014f7dc0de0103b5de1670ca9a1d8c1f0cb23a4595e85291272714501d1a3",
                "sha256:fa05a9818618c670d1557ff4c33401e8c5742fca9fd59f09a5426398bff1e0cc",
                "sha256:a67a6169baabf2b10b60ce2490d0839abec87024be6b9a9035df853e9f6a0482",
                "sha256:c757bc9ec0a9b6091a0e9a7c904006bb76b97c1833b918e23260db9fd8873b80",
                "sha256:a02a3c366f05eeee06435a7ac873e548c8c365b03333ff00dfa66257f933c3c2",
                "sha256:804ae488a8352e61f186decfa8dcce261cebc97cb8df453ff180b51c89c39aef",
                "sha256:29a0fc68b3bfbf427ce414a319689c39c6c109a0dab1e624988ed9ff29d44125",
                "sha256:a83c2f36b10c231a51505a2ea2544de7e19a4b93cd01bd1d29e1585f02abea78",
                "sha256:144214dbaa33e479c68f9428386bff4b7becf99e36ce031e230b349d858aae98",
                "sha256:0841079aa9ec1c68d932d17c37fd81defad3024ae1e6b0f111982a0c92f9391e",
                "sha256:06c912e719279ccb4fe8770700c7d9c9b91bf80c3075a01bb3696779036555ac",
                "sha256:b7482be0b71fa055584ec5e0d223d4c424386fd9cadb0f2aa3616acf33e25f43",
                "sha256:613c40fda6bfa358ab36e27f8f95ff58a21ddcdd60ae62a409b28c3ae0482e9d",
                "sha256:7d0a7ccf5752573984a2fba8ffa0c77bd9de59b8f21ea6dab10511508f570915",
                "sha256:ab082e8f63163db1782df8fb8c6f25ab394060b753e09a63336d2a04de299d6c",
                "sha256:90b81b5c60691da289b425694f75347947e7259bfb02b2ae1f6245e964458fe7",
                "sha256:9602a1d82d62c319e0d619a80ff724f8a67d108d8952f16a27570d1677ac6704",
                "sha256:9b31c3080260839f7028c94c9ac8936a2364eb808b8419c9defbcf2f0bc163ba",
                "sha256:e4b358862e5563f4e1db5d181272d4cb2793e8ff08d09e29178971077999db42",
                "sha256:74144b4a86189ca29fcd999d84bd90643ec213b9b1298e7de1683fbd09a73dfb",
                "sha256:036db2c3f6da03730fe9deac219f5cd5cf1e9bb4b4afe67c938a95ad183cc855",
                "sha256:dfb77d6dba16e249139820f4f9f5897a4ba4c4b749d5dc70f0f5f3bbc99b9c53",
                "sha256:63425d47b2a2960ac74e0ff74e5ef99396396a13911ade6f4f0bcbc8474cb594",
                "sha256:6a935d999504a8955a579f77d3a05b44e98b294cdc107bd926547009f999e77b",
                "sha256:80e79ff105dd757777ef5260ce4b741cb38b7a985843b2221fcf17f9d9da074a",
                "sha256:e12047e7b17ea4e73b5c3599fba0071999b626d29aa8a49d7b87be4f76a9c0bf",
                "sha256:54356267e0a90ace69cbdba8abbbbe0d5bc570412d9d542f6d339a9a19a87a1e",
                "sha256:8cf2eed1749bce4ede40c29bca2ea670ad65b0b8616962551b4819d0b16e0cee",
                "sha256:3c85997417a4c029a2397f49f3f2def9d495d70142bb5476178c7f4b3b220cc1",
                "sha256:2a36e240f2a4af5dbbbe46be5d4f08b50fcc8170b9cf73648aa93b4d2f5f2018",
                "sha256:3f596d6ae3e1c829e6327d1ef99345c3febe77ab4738d653a6cd2b51c79aa9a9",
                "sha256:5f33626d71b684d3d6f4a6bbb9bf2aedefdac76b9a69f1d5310710d46c9073e4",
                "sha256:c2aa8927cef182724545b45e9b8c5f63093525156c55cd946e04f0051b467f5c",
                "sha256:b146f1dcdf5dac7a7c5d042a43464fccdf972072f69a79036509d4c9de22bdb9",
                "sha256:b535f665c8b81bc919c93c8701f5b5b1dc02d288bd5d67410ae9e60b8f5cc53e",
                "sha256:6afce37df4c6b91c85f178e4e4f3c0cdd0b481ac3f8ec250ac4eed8bb6c889b9",
                "sha256:d8614aced209448d1b97570ff5cf20e695f2d41813fa3ed4a71b56053fd64938",
                "sha256:7652fef89f327717851afd920f6c315fbf1d17e6b20d54607341437177791fe3",
                "sha256:4a743a92cdba80bbfc0a05dce72345a2fe1140f8b112538dd9b706dd0d759078",
                "sha256:f91f8b311baef2a0f4ea09a4b879b5b0d7aed0dd2c1f078eb786c8cd021828e9",
                "sha256:9c2179efed7148fae64a4de670a3b96a4efa4c8b6c4ce24735fcbf21a660abd7"
            ]
        }
    }
]
ci@debian:/home/ci/docker-world/env$
```

# 後書き：この Docker Image の作成で分かったこと

- Docker Layers Limit
- 
  Docker の Layer 数に制限がある。漫然で Dockerfile を書くと、制限の数を超え、Docker Build できなくなります。
  対策：Dockerfile に、Linux Shell コマンドはまとめて一つのRun コマンドに書く（例：&& で連結）。

- Dockerfile は、例え、１年後、また全く同様な Docker Image を Build 出来ますか
- 
  実は、同じ Docker Image の build されると保障出来ない（というより、ほぼ出来ない）。下記のコードを考えて下さい：

```
pip install lxml
``` 

  新しい lxml がリリースされた後、Docker Build を実行すると、当たり前ですが、新しい Version の lxml が取り込まれます。それにより、Docker Build エラーとなることや、Docker Image にある機能が動作しなくなることも考えられます。

例え、左記の例は下記のように書けば、問題が解消されますが、

```
pip install lxml==3.8.0
``` 

現状、そこまで丁寧に作成された Dockerfile は、珍しいでしょう。

なので、一言で当記事を終わりたいと思います、それは、動作中の Docker Image は大事にしたい、Docker Build で上書きしてはいけないということです。