はじめに
こんにちは。テクノプロで自動車関連の組み込み開発エンジニアをしている神崎 一郎です。
これまでの約2年間、業務にも 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 は、例え、1年後、また全く同様な 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 で上書きしてはいけないということです。