- 投稿日:2020-11-19T18:34:40+09:00
docker-compose コマンドでの args:, environment:, env_file: 及び .env ファイルの使い方
docker-compose コマンドでの args:, environment:, env_file: 及び .env ファイルの使い方
docker-compose v3 での、
args:
,environment:
,env_file:
の使い方と.env
ファイルの関係で迷子になることがあったので自分用に整理した。まとめ
args:
について
build 用変数
だよ- なので、
run
時は存在してないよ- 同じ変数を宣言した場合
docker-compose.yml > Dockerfile
だよdocker-compose.yml
で宣言するとDockerfile
内で宣言したのと同等になるよ
environment:
について
- 環境変数を設定できるよ
run
時にdocker-compose.yml
で宣言した変数が追加・上書きされるよDockerfile
のENV
命令で宣言したものは、build
時にARG
命令の変数の様に使えてしまうので注意が必要だよ- かつ、
build
時は、上述の様にdocker-compose.yml
で宣言した変数は渡っていないので注意が必要だよ
env_file:
について
- ファイルから環境変数を追加する仕組みだよ
- 同名の環境変数が存在する場合の優先度は
environment: > env_file:
だよ- 複数の
env_file:
を指定した場合は、リストの後者の値で追加・上書きされるよ
.env
について
docker-compose
が利用する特殊なファイルが.env
だよ- 変数置換機能を便利にしてくれるファイルが
.env
だよ- (おそらく)
.env
というファイル名を別名にして利用することは出来ないよ.env
で宣言・定義した変数がdocker-compose.yml
上で変数として利用できる仕組みだよ※コードは https://github.com/hokutoasari/how-to-use-args-environment-env-file-dotenv-file-with-docker-compose に。
args: の使い方
まずは、公式ドキュメント。
https://docs.docker.com/compose/compose-file/#args
Add build arguments, which are environment variables accessible only during the build process.
意訳: ビルド用の変数を設定できます。
ビルド用変数を設定できる仕組み。
※
environment variables
が後述のenvironment:
で指定する、所謂環境変数
と紛らわしいので、ここではビルド用変数
と読み替えた。ARG_VALUE1 - ARG_VALUE4 までを以下のように宣言・値設定して、振る舞いを確認します。
Dockerfile docker-compose.yml ARG_VALUE1 arg1_in_Dockerfile ARG_VALUE2 arg2_in_Dockerfile arg2_in_yml ARG_VALUE3 arg3_in_yml ARG_VALUE4 ./args/Dockerfile
FROM busybox ARG ARG_VALUE1="arg1_in_Dockerfile." ARG ARG_VALUE2="arg2_in_Dockerfile." RUN echo "ARG_VALUE1 is ${ARG_VALUE1}" \ && echo "ARG_VALUE2 is ${ARG_VALUE2}" \ && echo "ARG_VALUE3 is ${ARG_VALUE3}" \ && echo "ARG_VALUE4 is ${ARG_VALUE4}" RUN echo "ARG_VALUE1 is $ARG_VALUE1" >> /tmp/outs.txt \ && echo "ARG_VALUE2 is $ARG_VALUE2" >> /tmp/outs.txt \ && echo "ARG_VALUE3 is $ARG_VALUE3" >> /tmp/outs.txt \ && echo "ARG_VALUE4 is $ARG_VALUE4" >> /tmp/outs.txt CMD cat /tmp/outs.txt \ && echo "-----" \ && echo "ARG_VALUE1 is ${ARG_VALUE1}" \ && echo "ARG_VALUE2 is ${ARG_VALUE2}" \ && echo "ARG_VALUE3 is ${ARG_VALUE3}" \ && echo "ARG_VALUE4 is ${ARG_VALUE4}"./args/docker-compose.yml
/args/docker-compose.ymlversion: '3' services: with-args: build: context: ./ args: ARG_VALUE2: "arg2_in_yml" ARG_VALUE3: "arg3_in_yml"実行。
% docker-compose build --no-cache && docker-compose up ...略... Step 4/6 : RUN echo "ARG_VALUE1 is ${ARG_VALUE1}" && echo "ARG_VALUE2 is ${ARG_VALUE2}" && echo "ARG_VALUE3 is ${ARG_VALUE3}" && echo "ARG_VALUE4 is ${ARG_VALUE4}" ---> Running in 64893f52d5bc ARG_VALUE1 is arg1_in_Dockerfile. ARG_VALUE2 is arg2_in_yml ARG_VALUE3 is ARG_VALUE4 is Removing intermediate container 64893f52d5bc ---> a66e7626d5eb ...略... [Warning] One or more build-args [ARG_VALUE3] were not consumed ...略... with-args_1 | ARG_VALUE1 is arg1_in_Dockerfile. with-args_1 | ARG_VALUE2 is arg2_in_yml with-args_1 | ARG_VALUE3 is with-args_1 | ARG_VALUE4 is with-args_1 | ----- with-args_1 | ARG_VALUE1 is with-args_1 | ARG_VALUE2 is with-args_1 | ARG_VALUE3 is with-args_1 | ARG_VALUE4 is args_with-args_1 exited with code 0結果。
Dockerfile docker-compose.yml build 時 run 時 ARG_VALUE1 arg1_in_Dockerfile arg1_in_Dockerfile ARG_VALUE2 arg2_in_Dockerfile arg2_in_yml arg2_in_yml ARG_VALUE3 arg3_in_yml [Warning] ARG_VALUE4
docker-compose.yml
のargs:
で値は上書きされるdocker-compose.yml
で宣言したargs:
で未使用の変数があると Warning となるDockerfile
で利用しているが、docker-compose.yml
で宣言していない変数は警告などは無い- 当然ながら、
run
時には利用できないenvironment: の使い方
まずは、公式ドキュメント。
https://docs.docker.com/compose/compose-file/#environment
Add environment variables.
環境変数を追加できる仕組み。
前述の
ビルド用変数
とは違い、こちらは所謂環境変数
を設定する為の命令。ENV_VALUE1 - ENV_VALUE4 までを以下のように宣言・値設定して、振る舞いを確認。
Dockerfile docker-compose.yml ENV_VALUE1 env1_in_Dockerfile ENV_VALUE2 env2_in_Dockerfile env2_in_yml ENV_VALUE3 env3_in_yml ENV_VALUE4 ./environment/Dockerfile
FROM busybox ENV ENV_VALUE1="env1_in_Dockerfile." ENV ENV_VALUE2="env2_in_Dockerfile." RUN echo "ENV_VALUE1 is ${ENV_VALUE1}" \ && echo "ENV_VALUE2 is ${ENV_VALUE2}" \ && echo "ENV_VALUE3 is ${ENV_VALUE3}" \ && echo "ENV_VALUE4 is ${ENV_VALUE4}" \ RUN echo "ENV_VALUE1 is $ENV_VALUE1" >> /tmp/outs.txt \ && echo "ENV_VALUE2 is $ENV_VALUE2" >> /tmp/outs.txt \ && echo "ENV_VALUE3 is $ENV_VALUE3" >> /tmp/outs.txt \ && echo "ENV_VALUE4 is $ENV_VALUE4" >> /tmp/outs.txt CMD cat /tmp/outs.txt \ && echo "-----" \ && echo "ENV_VALUE1 is ${ENV_VALUE1}" \ && echo "ENV_VALUE2 is ${ENV_VALUE2}" \ && echo "ENV_VALUE3 is ${ENV_VALUE3}" \ && echo "ENV_VALUE4 is ${ENV_VALUE4}"./environment/docker-compose.yml
/environment/docker-compose.ymlversion: '3' services: with-environment: environment: ENV_VALUE2: "env2_in_yml" ENV_VALUE3: "env3_in_yml"実行。
% docker-compose build --no-cache && docker-compose up ...略... Step 4/6 : RUN echo "ENV_VALUE1 is ${ENV_VALUE1}" && echo "ENV_VALUE2 is ${ENV_VALUE2}" && echo "ENV_VALUE3 is ${ENV_VALUE3}" && echo "ENV_VALUE4 is ${ENV_VALUE4}" ---> Running in bb4ae383c1e7 ENV_VALUE1 is env1_in_Dockerfile. ENV_VALUE2 is env2_in_Dockerfile. ENV_VALUE3 is ENV_VALUE4 is Removing intermediate container bb4ae383c1e7 ---> a01b51cd008a ...略... with-environment_1 | ENV_VALUE1 is env1_in_Dockerfile. with-environment_1 | ENV_VALUE2 is env2_in_Dockerfile. with-environment_1 | ENV_VALUE3 is with-environment_1 | ENV_VALUE4 is with-environment_1 | ----- with-environment_1 | ENV_VALUE1 is env1_in_Dockerfile. with-environment_1 | ENV_VALUE2 is env2_in_yml with-environment_1 | ENV_VALUE3 is env3_in_yml with-environment_1 | ENV_VALUE4 is environment_with-environment_1 exited with code 0結果。
Dockerfile docker-compose.yml build 時 run 時 ENV_VALUE1 env1_in_Dockerfile env1_in_Dockerfile env1_in_Dockerfile ENV_VALUE2 env2_in_Dockerfile env2_in_yml env2_in_Dockerfile env2_in_yml ENV_VALUE3 env3_in_yml env3_in_yml ENV_VALUE4
build
時は、Dockerfile
記載の値が使われるrun
時に、docker-compose.yml
に設定した値が渡され上書きされるENV
命令及びenvironment:
あくまで、環境変数をセットするものであることを意識して使うことbuild
時にENV
命令で用意した値をビルド用変数
的に使えてしまうので、注意することenv_file: の使い方
まずは、公式ドキュメント。
https://docs.docker.com/compose/compose-file/#env_file
Add environment variables from a file.
所謂
環境変数
を"ファイル"から追加する仕組み。ENV_VALUE1 - ENV_VALUE5 までを以下のように宣言・値設定して、振る舞いを確認。
Dockerfile docker-compose.yml some_env.env ENV_VALUE1 env1_in_Dockerfile ENV_VALUE2 env2_in_Dockerfile env2_in_yml ENV_VALUE3 env3_in_yml env3_in_file ENV_VALUE4 env4_in_file ENV_VALUE5 ./env_file/Dockerfile
FROM busybox ENV ENV_VALUE1="env1_in_Dockerfile." ENV ENV_VALUE2="env2_in_Dockerfile." RUN echo "ENV_VALUE1 is ${ENV_VALUE1}" \ && echo "ENV_VALUE2 is ${ENV_VALUE2}" \ && echo "ENV_VALUE3 is ${ENV_VALUE3}" \ && echo "ENV_VALUE4 is ${ENV_VALUE4}" \ && echo "ENV_VALUE5 is ${ENV_VALUE5}" RUN echo "ENV_VALUE1 is $ENV_VALUE1" >> /tmp/outs.txt \ && echo "ENV_VALUE2 is $ENV_VALUE2" >> /tmp/outs.txt \ && echo "ENV_VALUE3 is $ENV_VALUE3" >> /tmp/outs.txt \ && echo "ENV_VALUE4 is $ENV_VALUE4" >> /tmp/outs.txt \ && echo "ENV_VALUE5 is $ENV_VALUE5" >> /tmp/outs.txt CMD cat /tmp/outs.txt \ && echo "-----" \ && echo "ENV_VALUE1 is ${ENV_VALUE1}" \ && echo "ENV_VALUE2 is ${ENV_VALUE2}" \ && echo "ENV_VALUE3 is ${ENV_VALUE3}" \ && echo "ENV_VALUE4 is ${ENV_VALUE4}" \ && echo "ENV_VALUE5 is ${ENV_VALUE5}"./env_file/docker-compose.yml
/env_file/docker-compose.ymlversion: '3' services: with-env_file: build: context: ./ environment: ENV_VALUE2: "env2_in_yml" ENV_VALUE3: "env3_in_yml" env_file: - some_env.env./env_file/some_env.env
/env_file/some_env.envENV_VALUE3="env3_in_file" ENV_VALUE4="env4_in_file"実行。
% docker-compose build --no-cache && docker-compose up ...略... Step 4/6 : RUN echo "ENV_VALUE1 is ${ENV_VALUE1}" && echo "ENV_VALUE2 is ${ENV_VALUE2}" && echo "ENV_VALUE3 is ${ENV_VALUE3}" && echo "ENV_VALUE4 is ${ENV_VALUE4}" && echo "ENV_VALUE5 is ${ENV_VALUE5}" ---> Running in 5851a9b3aa91 ENV_VALUE1 is env1_in_Dockerfile. ENV_VALUE2 is env2_in_Dockerfile. ENV_VALUE3 is ENV_VALUE4 is ENV_VALUE5 is Removing intermediate container 5851a9b3aa91 ---> 39f56354d7cd ...略... with-env_file_1 | ENV_VALUE1 is env1_in_Dockerfile. with-env_file_1 | ENV_VALUE2 is env2_in_Dockerfile. with-env_file_1 | ENV_VALUE3 is with-env_file_1 | ENV_VALUE4 is with-env_file_1 | ENV_VALUE5 is with-env_file_1 | ----- with-env_file_1 | ENV_VALUE1 is env1_in_Dockerfile. with-env_file_1 | ENV_VALUE2 is env2_in_yml with-env_file_1 | ENV_VALUE3 is env3_in_yml with-env_file_1 | ENV_VALUE4 is env4_in_file with-env_file_1 | ENV_VALUE5 is env_file_with-env_file_1 exited with code 0結果。
Dockerfile docker-compose.yml some_env.env build 時 run 時 ENV_VALUE1 env1_in_Dockerfile env1_in_Dockerfile env1_in_Dockerfile ENV_VALUE2 env2_in_Dockerfile env2_in_yml env2_in_Dockerfile env2_in_yml ENV_VALUE3 env3_in_yml env3_in_file env3_in_yml ENV_VALUE4 env4_in_file env4_in_file ENV_VALUE5
env_file:
で指定した値よりもenvironment:
の値が優先されるenv_file:
で指定し、docker-compose.yml
で未設定の場合は、env_file:
で指定した値が利用される- なお、実験はしてないが、ドキュメントにも記載がある通り、
env_file:
に複数ファイルを指定すると、リストの後者の値で追加・上書きされる.env ファイルの使い方
.env
ファイルは、docker-compose
の中で特別に扱われるファイル。変数置換機能にて利用される。
変数置換機能
.env
ファイルは、docker-compose
の変数置換機能にて利用される為、まずは変数置換機能を試す。公式ドキュメント。 https://docs.docker.com/compose/compose-file/#variable-substitution
Your configuration options can contain environment variables. Compose uses the variable values from the shell environment in which docker-compose is run.
意訳:
docker-compose
を実行するシェルの環境変数を docker-compose の変数として利用する事ができます。以下の内容で
./variable-substitution/docker-compose.yml
を用意する。/variable-substitution/docker-compose.ymlversion: '3' services: variable-substitution: image: busybox:${BUSYBOX_VERSION}一時的に
BUSYBOX_VERSION=latest
という環境変数を設定しながらdocker-compose up
する。(build
の必要が無いので、直接up
となる。)% env BUSYBOX_VERSION="latest" docker-compose up ...略... variable-substitution_variable-substitution_1 exited with code 0無事に pull して up して終了した。
同様に、
BUSYBOX_VERSION=musl
を環境変数に設定し、docker-compose up
する。% env BUSYBOX_VERSION="musl" docker-compose up ...略... variable-substitution_variable-substitution_1 exited with code 0こちらも同様に無事に pull して up して終了した。
確認のため、
docker images
で手元の image 一覧を確認する。% docker images REPOSITORY TAG IMAGE ID CREATED SIZE busybox musl 8bce8d24824c 5 weeks ago 1.47MB busybox latest f0b02e9d092d 5 weeks ago 1.23MB確かに、
latest
,musl
TAG が打たれた image が存在することを確認した。
docker-compose
には、このように、シェルを実行する環境の環境変数をdocker-compose
に渡す仕組みがある。これが、変数置換機能の1つ。
.env ファイル
公式ドキュメントには、以下とある。
https://docs.docker.com/compose/compose-file/#variable-substitution
You can set default values for environment variables using a .env file, which Compose automatically looks for. Values set in the shell environment override those set in the .env file.
意訳:
docker-compose
は、.env
ファイルを見つけると、デフォルトの環境変数を設定します。また、シェルの環境変数から設定された値は、.env
ファイルで設定された値で上書きされます。以下のように、
./variable-substitution-dotenv/.env
ファイルを用意する。/variable-substitution-dotenv/.envBUSYBOX_VERSION=latest先程と同じ内容だが、
./variable-substitution-dotenv/docker-compose.yml
を用意する。/variable-substitution-dotenv/docker-compose.ymlversion: '3' services: variable-substitution-dotenv: image: busybox:${BUSYBOX_VERSION}この状態で、今度は一時的な環境変数を設定せずに
up
してみる。※事前に作成済みのコンテナを
docker rm
から削除、同様に pull 済みの images もdocker rmi
で削除しておくと動作がわかりやすいかも知れない。% docker-compose up Creating network "variable-substitution-dotenv_default" with the default driver Pulling variable-substitution-dotenv (busybox:latest)... latest: Pulling from library/busybox 9758c28807f2: Pull complete Digest: sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d Status: Downloaded newer image for busybox:latest Creating variable-substitution-dotenv_variable-substitution-dotenv_1 ... done Attaching to variable-substitution-dotenv_variable-substitution-dotenv_1無事に、
latest
が pull されて、 up したことがわかる。続けて、
./variable-substitution-dotenv/.env
を以下の内容に書き換える。/variable-substitution-dotev/.envBUSYBOX_VERSION=muslこの状態で、再度
docker-compose up
してみる。% docker-compose up Pulling variable-substitution-dotenv (busybox:musl)... musl: Pulling from library/busybox 7c3804618ebb: Pull complete Digest: sha256:605de95bca536139f324abdecf88dcab492c8457346e7fc92e37dff6e263f341 Status: Downloaded newer image for busybox:musl Recreating variable-substitution-dotenv_variable-substitution-dotenv_1 ... done Attaching to variable-substitution-dotenv_variable-substitution-dotenv_1 variable-substitution-dotenv_variable-substitution-dotenv_1 exited with code 0無事に、
musl
が pull されて、 up したことがわかる。このように、
.env
ファイルを用いると、シェル実行環境の環境変数を汚染せずに、docker-compose
に変数を渡す事が可能となる。ちなみに、公式ドキュメントには、以下の注意書きがある。
Note when using docker stack deploy
The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy.意訳
ノート:
docker stack deploy
を使う方へ
.env
ファイルを用いた本機能は、docker-compose up
コマンドのみ動作します。docker stack deploy
では、動かないよ。
docker stack deploy
利用時の注意書きなので、only works when you use the docker-compose up command
と書いてるのだと思うが、実際はdocker-compose up
コマンドだけではなく、dockre-compose
コマンドに対して機能する。具体的には、
docker-compose build
やdocker-compose config
コマンドでも機能する。試しに、現在の状態で
docker-compose config
を実行すると下記となる。(docker-compose config
は、最終的に実行される yml を確認する為のコマンド。)% docker-compose config services: variable-substitution: image: busybox:musl version: '3'
${BUSYBOX_VERSION}
部分が変数展開されて、busybox:musl
となっているのがわかる。続けて、
./variable-substitution-dotenv/.env
を以下の内容に書き換えてdocker-compose config
を実行すると以下となる。/variable-substitution-dotenv/.envBUSYBOX_VERSION=latest% docker-compose config services: variable-substitution: image: busybox:latest version: '3'
同様に
${BUSYBOX_VERSION}
部分が変数展開されて、busybox:latest
となっているのがわかる。
.env
ファイルを用いることでdocker-compose
に変数が渡せる事が確認できた。.env ファイルを用いた変数置換機能で勘違いしやすい点と対処法
なお、当然ながら、以下の
.env
,Dockerfile
及びdocker-compose.yml
の構成はbuild
出来ない。./variable-substitution-dotenv-dockerfile-not-work/.env
/variable-substitution-dotenv-dockerfile-not-work/.envBUSYBOX_VERSION="latest"./variable-substitution-dotenv-dockerfile-not-work/Dockerfile
FROM busybox:${BUSYBOX_VERSION}./variable-substitution-dotenv-dockerfile-not-work/docker-compose.yml
/variable-substitution-dotenv-dockerfile-not-work/docker-compose.ymlversion: '3' services: variable-substitution-dotenv-dockerfile-not-work: build: context: ./実行。
% docker-compose build --no-cache Building variable-substitution-dotenv-dockerfile-not-work Step 1/1 : FROM busybox:${BUSYBOX_VERSION} ERROR: Service 'variable-substitution-dotenv-dockerfile-not-work' failed to build : invalid reference formatこれまでの動作確認や公式ドキュメントを読めば当然なのだが、以下の状態となっている。
Dockerfile
の冒頭で用いているbusybox:${BUSYBOX_VERSION}
のBUSYBOX_VERSION
変数はbuild 用変数
としてDockerfile
として宣言されていない.env
ファイルを用いてdocker-compose
に変数を渡す仕組みは、当然ながらdocker-compose
までしか値が渡らない- つまり、
Dockerfile
まで変数が渡っていない
build
できるようにするには、以下の構成とする必要がある。./variable-substitution-dotenv-dockerfile-work/.env
/variable-substitution-dotenv-dockerfile-work/.envBUSYBOX_VERSION="latest"./variable-substitution-dotenv-dockerfile-work/Dockerfile
ARG BUSYBOX_VERSION FROM busybox:${BUSYBOX_VERSION}./variable-substitution-dotenv-dockerfile-work/docker-compose.yml
/variable-substitution-dotenv-dockerfile-work/docker-compose.ymlversion: '3' services: variable-substitution-dotenv-dockerfile-work: build: context: ./ args: BUSYBOX_VERSION: ${BUSYBOX_VERSION}実行。
% docker-compose build --no-cache Building variable-substitution-dotenv-dockerfile-work Step 1/2 : ARG BUSYBOX_VERSION Step 2/2 : FROM busybox:${BUSYBOX_VERSION} latest: Pulling from library/busybox 9758c28807f2: Pull complete Digest: sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d Status: Downloaded newer image for busybox:latest ---> f0b02e9d092d Successfully built f0b02e9d092d Successfully tagged variable-substitution-dotenv-dockerfile-work_variable-substitution-dotenv-dockerfile-work:latest
Dockerfile
にてARG
命令を使いBUSYBOX_VERSION
変数を宣言docker-compose.yml
のargs:
節でBUSYBOX_VERSION
変数を宣言- また、
docker-compose.yml
のargs:
節でBUSYBOX_VERSION
変数宣言に対して、.env
のBUSYBOX_VERSION
変数を割り当て.env
ファイルにて、BUSYBOX_VERSION
変数の値を設定これで、
.env
の中で定義したBUSYBOX_VERSION
の値を変更することで、シェル実行環境の環境変数を汚染せずに値を変更できるようになる。ただ、上記の例示だと、
BUSYBOX_VERSION
という変数名が各所(.env
,Dockerfile
及びdocker-compose.yml
)で用いられていて、少々わかりにくい。もう少しわかりやすく明示的に書くと、
.env
,Dockerfile
及びdocker-compose.yml
は以下となる。./variable-substitution-dotenv-dockerfile-work-easy-to-read/.env
/variable-substitution-dotenv-dockerfile-work-easy-to-read/.envDOCKER_COMPOSER_BUSYBOX_VERSION="latest"./variable-substitution-dotenv-dockerfile-work-easy-to-read/Dockerfile
ARG BUSYBOX_VERSION="latest" FROM busybox:${BUSYBOX_VERSION}./variable-substitution-dotenv-dockerfile-work-easy-to-read/docker-compose.yml
/variable-substitution-dotenv-dockerfile-work-easy-to-read/docker-compose.ymlversion: '3' services: variable-substitution-dotenv-dockerfile-work-easy-to-read: build: context: ./ args: BUSYBOX_VERSION: ${DOCKER_COMPOSER_BUSYBOX_VERSION}
Dockerfile
にてARG
命令を使いBUSYBOX_VERSION
変数を宣言し、かつ、 docker-compose から値が渡されない場合はデフォルト値としてlatest
を用いるように宣言docker-compose.yml
のargs:
節でBUSYBOX_VERSION
変数を宣言- また、
docker-compose.yml
のargs:
節でBUSYBOX_VERSION
変数宣言に対して、.env
のDOCKER_COMPOSER_BUSYBOX_VERSION
変数を割り当て.env
ファイルにて、DOCKER_COMPOSER_BUSYBOX_VERSION
変数の値を設定"変数"や"環境変数"という単語が多くなりややこしいので、具体的な変数名を見ると、何がどこに変数・値として受け継がれていくのかが分かると思う。
名称(ラベル)がややこしいだけで、
.env
->docker-compose.yml
->Dockerfile
と、変数名と値を受け渡していく仕組みが分かる。
.env
ファイルを用いた変数置換機能に関しては、(この表現が正しいか怪しいが...).env
ファイルを用いた変数置換機能はdocker-compose.yml
に変数と値を渡す仕組み と捉えるとわかりやすいかも知れない。ちょっとした余談
実は、先に例示した以下の書き方はあまり推奨しません。
ARG BUSYBOX_VERSION="latest" FROM busybox:${BUSYBOX_VERSION}例えば、 github actions (等)の制約で、以下のようなケースが、ままあります。
Dockerfileファイル中の最初の命令はFROMでなければなりません。
そもそも FROM の TAG 値は、(開発|実行)環境の統一性を考えると "latest" すら使わずに、確実な値を使う方が望ましいと考えています。
もちろん、この限りじゃないケースもあると思いますが、 build のタイミングによっては不本意なメジャーバージョンアップが行われてしまうなどの問題があります。
活用例
例えば、
docker-compose build
する際に、ローカル、ステージング、プロダクションなどの環境によってyarn run {script}
の実行を制御するなどが実現できます。ローカル、ステージング、プロダクション用のビルド環境が各々別で存在するとし、かつ、それぞれに
.env
ファイルも存在するとします。ローカル用
.env
#...略... DOCKER_COMPOSE_BUILD_TYPE="dev" #...略...ステージング用
.env
#...略... DOCKER_COMPOSE_BUILD_TYPE="dev" #...略...プロダクション用
.env
#...略... DOCKER_COMPOSE_BUILD_TYPE="prod" #...略...また、これらの
.env
は gitignore されており、リポジトリで管理されていないとします。この状態で、
Dockerfile
とdocker-compose.yml
を以下のように用意しておくことで、単一ソースコードを保ちながら、環境ごとの制御が可能となります。Dockerfile
#...略... ARG BUILD_TYPE="local" #...略... RUN yarn run ${BUILD_TYPE} #...略...docker-compose.yml
docker-compose.yml#...略... build: #...略... args: BUILD_TYPE: ${DOCKER_COMPOSE_BUILD_TYPE} #...略...他にも、
environment:
を使って、各環境ごとのログの向き先やメールドライバの変更、 DB ドライバの変更なども可能です。php を使った開発なら xdebug 有効無能の設定や、各種設定値を各個人の
.env
経由で自由に変更可能とするなども実現できます。
- 投稿日:2020-11-19T17:03:26+09:00
Dockerについて
なぜ使うか
環境をキレイに保つため.
Dockerがないと,ローカル環境でpython3.7やらpython3.8やら混在したり,もうごっちゃごっちゃ.カオス.
また,開発環境と本番環境を合わせられるのも大きい.デプロイの度に環境が違うせいでエラーが生じることは多々あるが,これを防ぐことができる.
Virtual BoxよりもDockerはかなり高速で立ち上がるので,Dockerが良い.
自分はDockerを使い始めてから,かなり開発時の健康状態が良くなりました.整理された机で勉強した方が気持ちがイイのと同じ感覚.Docker 基本編
本番環境を意識せずに,sandbox内で色々弄るだけならこれで十分ではという内容.最初はこれだけでよいと思う.慣れてきたら応用編へと進みたい.
# ベースとなるイメージを引っ張ってくる.大本の環境を構築する感じ.この上にパッケージなどを乗せていく. $ docker pull イメージ名 # anaconda -> pandasなど大体機械学習に必要なパッケージがインストール済みだが重い.本番環境では軽さが大事だが,ローカル開発ではこれでいいと思う. $ docker pull continuumio/anaconda3 # -itコマンドでDockerを起動し続ける.ないと一度起動するだけで切れてしまい,その中で作業できない.また末尾に/bin/bashを付けることで,バッシュの中で作業できる.コマンドラインを使えるイメージ.ないとpythonの対話モードになる. $ docker run -it continuumio/anaconda3 /bin/bash # コンテナ内でパッケージをインストールするなどの変更を行ったら,コンテナを抜けた後,その変更を保存しておく.しないと,初期の環境のままになる. # 起動したコンテナの履歴 $ docker ps -a # コンテナをイメージとして保存する $ docker commit container_id container_name # 保存したイメージの一覧を確認する $ docker images # 保存したコンテナを起動する $ docker run -it container_name /bin/bash # ローカルディレクトリをマウント(Dockerと共有)する. -vの後に「ローカルディレクトリ:Dockerディレクトリ」を記述. docker run -it -v /c/Users/user/Python:/home container_name /bin/bashDocker 応用編
少し難しいかもしれないが,慣れるとより快適にかつ効率的に開発できる.自分はここで時間がかかった記憶がある.
基本的な利用の流れは以下.
- Dockerfileとrequirements.txtを作成する
- VSCodeに拡張機能Remote-Containersを入れる
- VSCode左下コードボタンからre-open in containerを実行&Dockerfileを実行
- Docker環境下でインストールしたパッケージを, requirements.txtに追加で記述
- 次回,再びビルド.
ここでは,Dockerfile単体・docker-compose利用本・番環境用Dockerfileの3つに分けて話したい.
最終的には,docker-composeを利用しての開発に慣れていきたい.また,本番環境用のDockerfileまで作れるようになると良いだろう.1. Dockerfile単体
# 上部に記述したものほどキャッシュを利用しやすくなっているので,よく変更を加えるものは下の方に記述しよう. # python-buster -> pythonを動かすための最小限のパッケージ.OSはdebian. 自分はこれで開発している. FROM python:3.8-buster # パスは絶対パスを使用する.ローカルとコンテナでディレクトリ構造が異なるから. WORKDIR /app # パッケージマネージャの更新とパッケージの取得はまとめる. aptの方がapt-getよりも良い. RUN apt update -y && apt upgrade -y && \ apt install -y ffmpeg # ADDよりCOPYの方が良い.appディレクトリにファイルをコピー.ローカルからコンテナへとファイルをコピーしている. COPY requirements.txt /app # requirements.txtを参照してpip install. python3ではpip3を利用したい. RUN pip3 install --upgrade pip && \ pip3 install -r requirements.txt # 指定したディレクトリを各環境で共有できる. # VOLUME /data # コピーするディレクトリは明示的に指定.変更部のみ反映させるため.自分は面倒なので「.」で済ませてしまっている. # COPY src /app/src # COPY data /app/data COPY . /app # CMD ["/bin/bash"]2. Docker-Compose利用
Docker-composeを利用することで,複数のサーバーを同時に使うことができる.例えば,python実行用だけでなく,postgresなどデータベースやjupyterなど.資源を共有できるのも良い.
コード例は以下.
docker-compose.yml
version: '3'
services:
notebook:
# image: jupyter/datascience-notebook -> Dockerfileでベースイメージ記述しているから不要.
# container_nameを指定しないと,自動で生成されて後で確認しづらくなる.
container_name: vad-sandbox
ports:
- "8888:8888"
# 「.」で同じディレクトリにあるDockerfileを実行してくれる.
build: .
# マウントするディレクトリを指定.
volumes:
- .:/app
working_dir: /app
# 自動でコマンドを実行してくれる.僕は自分で打った方が分かりやすいので自分で打っている.
# command: jupyter lab --ip=0.0.0.0 --allow-root
そして,こちらがdocker-compose利用時のdockerfileFROM python:3.8-buster WORKDIR /app RUN apt update -y && apt upgrade -y && \ apt install -y ffmpeg COPY requirements.txt /app RUN pip3 install --upgrade pip && \ pip3 install -r requirements.txt # ipywidgetsを利用. jupyterをインタラクティブに使える. RUN jupyter nbextension enable --py widgetsnbextension --sys-prefix COPY . /app # CMD ["/bin/bash"]3. Docker本番環境用
本番環境では極力容量を削減することが肝要である.そのために,マルチステージビルドを採用する(ビルドと実行で環境を分ける).
# pythonではalpineよりbusterの方が良い.slimではc拡張が使えない # マルチステージビルドでビルドと実行でイメージを分け,極力容量を小さくする # キャッシュを利用したいものほど上部に記述.変更があるとそれ以降破棄されるため. # ビルド用.busterはgccが利用できる.webrtcvadのインストールに必要. FROM python:3.8-buster as builder # パスは絶対パスを使用する WORKDIR /app # pytorchはインストールに時間がかかるため,キャッシュを再利用しやすく. RUN pip3 install --upgrade pip && \ pip3 install torch # ADDよりCOPYの方が良い.appディレクトリにファイルをコピー. COPY requirements.txt /app RUN pip3 install --upgrade pip && \ pip3 install -r requirements.txt #実行用コンテナ FROM python:3.8-slim-buster as runner # インストールしたpythonパッケージを実行用へとコピー. 1GBほど削減できた. COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages # パッケージマネージャの更新とパッケージの取得はまとめる. aptの方がapt-getよりも良い. RUN apt update -y && apt upgrade -y && \ apt install -y ffmpeg COPY . /app最後に
抽象度が高いため,初見では戸惑うこと間違いなしだが,慣れれば単なる作業と化す.最初はストレスを感じるかもしれないが,がんばろう.就活でもアピれるはずだ.
- 投稿日:2020-11-19T16:09:43+09:00
公式Dockerとvscodeを使ったKaggleの環境構築
記事の内容
この記事はkaggleをローカル環境で行うための環境構築についての備忘録です。
ネットではgcpの記事が多いため、とりあえずローカルで試してみたい方に向けたものになります。この記事が参考になる方
- kaggleをローカル環境で行いたい方
- vscodeを用いて快適な環境を作りたい方
なおこの記事ではvscodeのremote containerを利用します。
gcpで行いたい方は他の記事を参考にしてください。なお自身の環境はUbuntuの20.4です。
他環境でうまく動作するかは保証できませんが、マウントのやり方さえ気をつければ問題なくできるはずです。
windowsの場合はwslを入れておいてください。
参考:(https://qiita.com/matarillo/items/61a9ead4bfe2868a0b86)手順
- まずはvscodeをダウンロード
- この記事を参考にgit cloneし、buildします。
- vscodeのextentionからremote containerをインストールします。
- remote containerからopen folder in containerを選択し、Dockerを選択します。
- kaggle.jsonを
~/.kaggle/
に置きます。- .devcontainer/devcontainer.jsonのマウント先を編集します。必要であればextentionsも編集します。
これで快適な環境が出来上がります。順に解説します。
1. まずはvscodeをダウンロード
公式から各々のOSにあったものをダウンロードしてください。
2. この記事を参考にgit cloneし、buildします。
記事の通りにbuildします。
1時間以上かかるので気長に待ってください。
gpuを使用しない場合は--gpuを変更してください。3. vscodeのextentionからremote containerをインストールします。
4. remote containerからopen folder in containerを選択し、Dockerを選択します。
Remote Explorer(左のディスプレイのようなマーク)を選択し、CONTAINERの横にカーソルを持っていくと+マークが出ます。new containerをクリックするとopen folder in containerが選択でき、先程git cloneしたdockerフォルダーを選び、Dockerファイルを選択します。
左下の緑色のマークを選択しても同じように開くことができます。5. kaggle.jsonを
~/.kaggle/
に置きます。kaggle公式のprofileからedit profileを選択し、create New API Tokenを選択してkaggle.jsonをダウンロードします。
terminalからkaggleコマンドを使用している場合は~/.kaggleが作成されているため、cpコマンドなどを使用して~/.kaggleにkaggle.jsonを起きます。もし実行していない場合は自分でディレクトリを作っても問題ないです。このままkaggleコマンドを打つとwarningが出ます。
kaggle.jsonの権限を変更する必要があります。
以下のコマンドを入力してください。
chmod 600 ~/.kaggle/kaggle.json
6. .devcontainer/devcontainer.jsonのマウント先を編集します。必要であればextentionsも編集します。
この時点ではdockerを動かすことはできますが、docker-python下以外のローカルディレクトリにアクセスすることができません。
docker-pythonの中を作業ディレクトリにする方はいいですが、僕はkaggle用の作業ディレクトリを用意しているため、そこにアクセスできるようにします。.devcontainer/devcontainer.jsonに以下のコードを各々の作業ディレクトリにあった場所に変更して記述してください。
"mounts": [ "source=/home/artela/works/kaggle,target=/root/kaggle/,type=bind" , "source=/home/artela/.kaggle/,target=/root/.kaggle/,type=bind"],sourceがローカルディレクトリを指し、targetにはアクセス方法を記述します。
例えば下記のようにコマンドを叩くと/home/artela/works/kaggle
にアクセスできます。lsの結果が空なのは環境構築をやり直す際にすべて消えてしまったためであり、なにかおいてある場合はlsで表示されるはずです。
おすすめはしませんが
source=/home/user/,target=/root/
を追加しておけば、すべてのディレクトリにアクセスできるようになります。最後に
自身ができただけであるため、動作を保証するものではありません。なにかわかりにくい点や、間違えている点などがありましたらご指摘いただけると助かります。
最後にtwitterアカウントを貼っておきます。
よければフォローお願いします。
https://twitter.com/Artela_ML
- 投稿日:2020-11-19T16:03:10+09:00
Ruby がない環境で Rails プロジェクトを一撃で作る Docker コマンド
Dockerはないとダメです。
docker run --rm -it --workdir /app/ --volume $PWD:/app/ ruby:2.6.3 bash -c "gem install rails -v 5.2.4 && rails new sample_project"以上です。
- 投稿日:2020-11-19T15:08:02+09:00
padrino+PostgreSQLで作ったサイトを高速全文検索対応にする
概要
Dockerコンテナ上で動かしているpadrino+postgresqlなサービスに全文検索機能をつけたいとおもった。
ここではpgroongaを用いる。
タイトルに高速といれたのは、同種の機能拡張pg_bigmより早いみたいなので、groongaを選定したことによる。
が、どちらかというと手軽さをとった。準備
Dockerfileで指定しているpostgresイメージを、pgroongaに変更した。
PostgreSQL向けにpgroongaというgroonga用エクステンションがあることは知っていたが、pgroongaイメージはPostgreSQLを内包しており、差し替えるだけで全文検索対応したPostgreSQLとして利用できる。docker/pgroonga/DockerfileFROM groonga/pgroonga:2.2.6-debian-12 #FROM postgres:12docker-compose.yamlはdb部分だけは↓みたいな感じ。Windows上でつかっているので、別途
docker volume create --name pgdata1
している。docker-compose.ymlversion: '2' services: db: build: docker/pgroonga container_name: pgoongadb ports: - "15432:5432" environment: - POSTGRES_USER=sa - POSTGRES_PASSWORD=sa - POSTGRES_DB=pgdb volumes: - pgdata1:/var/lib/postgresql/data volumes: pgdata1: external: trueみてのとおり、Dockerfileを準備するまでもなく postgresをgroonga/pgroongaにしただけである。
(あとでmecab-ipadic-neologdを使うつもりでDockerfileを分けている)こまったこと
データベースは上記で準備できた。
しかし、肝心の全文検索むけインデックスをpadrinoでいい感じに作成する方法がわからなかった。
ActiveRecordのadd_indexではチュートリアルにあるようなwith~的な記述が出来ない。
事例を検索してみたが見つからない。ActiveGroongaというのもあったが、それはちょっと違う。groongaのコミュニティに相談したところ、須藤さんよりredmineでの事例を教えていただく。
またpadrinoでもこうすれば動くよ、というアドバイスもいただき、試した。解決編
padrinoのプロジェクト内にある、libフォルダに下記のようなスクリプトを配置。
lib/migrate_plugin_add_index.rbmodule Migration module PostgreSQLAdapterOptionable def add_index_options(table_name, column_name, with: nil, **options) result = super(table_name, column_name, **options) result[3] += " WITH (#{with})" if with result end end ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PostgreSQLAdapterOptionable) end上記プラグインを追加した状態で、padrino g migration add_fulltext_indexとかなんとかマイグレーションを作成。
005_add_fulltext_index.rbclass AddFulltextIndex < ActiveRecord::Migration[5.2] def self.up add_index(:contacts, :name, using: 'pgroonga', with: "tokenizer='TokenMecab(\"use_reading\", true)'") add_index(:contacts, :description, using: 'pgroonga', with: "tokenizer='TokenMecab'") add_index(:contacts, :tel, using: 'pgroonga', with: "normalizer='NormalizerNFKC100(\"unify_hyphen_and_prolonged_sound_mark\", true)',tokenizer='TokenNgram(\"loose_symbol\", true,\"loose_blank\", true)'") end def self.down end endrake db:migrateすると無事、以下のようなSQLが発行され、create indexされた。
add_index(:contacts, :name, {:using=>"pgroonga", :with=>"tokenizer = 'TokenMecab(\"use_reading\", true)'"}) DEBUG - (47.6ms) CREATE INDEX "index_contacts_on_name" ON "contacts" USING pgroonga ("name") WITH (tokenizer = 'TokenMecab("use_reading", true)')試しにテストデータをつっこんでDataGripのクエリコンソールで、「東京都生まれヒップホップ育ち」みたいなデータを持つカラムに対し検索を実行。正しくおもったとおり動作。
select * from contacts where description &@ '京都' -- > なし select * from contacts where description &@ '東京' -- > 検索結果 ○まとめ
- Docker上で動かしているなら、イメージをpostgresからpgroongaにするだけで全文検索対応にできる
- プラグイン用ライブラリを1ファイル置いておけばpadrinoでもadd_indexするmigrationでインデックス作成できる
調べてわからなかったらコミュニティに聞いてみるのも手。場当たり対応でなくrails(ActiveRecord)側にもリクエストしておいたほうがいいかもという話をもらって、添削してもらいつつでissueも出してみた。
- 投稿日:2020-11-19T14:42:59+09:00
DockerでWordpressのローカル環境構築&開発手順
Wordpressのローカル環境を構築したい時の選択肢
・MAMP
・XAMMP
・Local by flywheel
・Docker
おそらく一番簡単なのは3つめのLocal by flywheelだと思います。
私の場合は前者3つが手持ちのPC(MacOS13)で使えなかったので、Dockerでできる方法を調べました。Dockerによるローカル環境を構築
(参考: 初心者|Docker-ComposeでWordPressとMySQLとphpMyAdminのローカル環境の構築 )
Dockerとは...??って感じの人はかめさんのDocker超入門①〜Dockerってなに?〜【初心者向け】でまず勉強するといいと思います。プロジェクトファイルの中にymlファイルを作成
terminal.$ touch docker-compose.ymlymlファイルに以下をコピペ
docker-compose.ymlversion: "3" services: db: image: mysql:5.7 #container_name: "mysql57" volumes: - ./db/mysql:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: root_pass_fB3uWvTS MYSQL_DATABASE: wordpress_db MYSQL_USER: user MYSQL_PASSWORD: user_pass_Ck6uTvrQ wordpress: image: wordpress:latest #container_name: "wordpress" volumes: - ./wordpress/html:/var/www/html - ./php/php.ini:/usr/local/etc/php/conf.d/php.ini restart: always depends_on: - db ports: - 8080:80 environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: wordpress_db WORDPRESS_DB_USER: user WORDPRESS_DB_PASSWORD: user_pass_Ck6uTvrQ phpmyadmin: image: phpmyadmin/phpmyadmin:latest #container_name: "phpmyadmin" restart: always depends_on: - db ports: - 8888:80docker-composeをアップ
terminal.$ docker-compose up -dhttp://localhost:8080/ にアクセスしてみて、wordpressの管理画面が表示されてればok。
- 投稿日:2020-11-19T14:42:59+09:00
DockerでWordpress
Wordpressのローカル環境を構築したい時の選択肢
・MAMP
・XAMMP
・Local by flywheel
・Docker
おそらく一番簡単なのは3つめのLocal by flywheelだと思います。
私の場合は前者3つが手持ちのPC(MacOS13)で使えなかったので、Dockerでできる方法を調べました。Dockerによるローカル環境を構築
(参考: 初心者|Docker-ComposeでWordPressとMySQLとphpMyAdminのローカル環境の構築 )
Dockerとは...??って感じの人はかめさんのDocker超入門①〜Dockerってなに?〜【初心者向け】でまず勉強するといいと思います。プロジェクトファイルの中にymlファイルを作成
terminal.$ touch docker-compose.ymlymlファイルに以下をコピペ
docker-compose.ymlversion: "3" services: db: image: mysql:5.7 #container_name: "mysql57" volumes: - ./db/mysql:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: root_pass_fB3uWvTS MYSQL_DATABASE: wordpress_db MYSQL_USER: user MYSQL_PASSWORD: user_pass_Ck6uTvrQ wordpress: image: wordpress:latest #container_name: "wordpress" volumes: - ./wordpress/html:/var/www/html - ./php/php.ini:/usr/local/etc/php/conf.d/php.ini restart: always depends_on: - db ports: - 8080:80 environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: wordpress_db WORDPRESS_DB_USER: user WORDPRESS_DB_PASSWORD: user_pass_Ck6uTvrQ phpmyadmin: image: phpmyadmin/phpmyadmin:latest #container_name: "phpmyadmin" restart: always depends_on: - db ports: - 8888:80docker-composeをアップ
terminal.$ docker-compose up -dhttp://localhost:8080/ にアクセスしてみて、wordpressの管理画面が表示されてればok。
- 投稿日:2020-11-19T10:44:02+09:00
DockerでPythonにてGDALを利用する
概要
geotiffを利用する際に、少しハマったので、備忘録。
結論から言うと、Pyhonにおける「GDAL」ライブラリと「libgdal-dev」のバージョン対応が間違っていたことが原因でした。
apt標準リポジトリにおいて管理される安定版「libgdal-dev」はv2.4.0です(2020年11月19日現在)。これにより、pipにて単純に「pip install GDAL」とするとv3.2.0がダウンロードされますが、v3.2.0に対応する「libgdal-dev」はv3.2.0以上必要です。そのため、インストールする際は「pip install GDAL==2.4.4」とし、バージョン指定する必要があります。
この辺りを踏まえたdockerfileなどを以下に記載します。前提条件
ここでは、以下のことを考えています。
- dockerを利用し、環境を使いまわせるようにする。
- あまりanacondaは好きじゃない
- Pythonを利用するのは、学習コストが低いため
- docker-composeはあくまで動作テスト用に記載
- コード変更がきくようにボリュームを設定
- 特にこだわらないので、ベースイメージは「python:3.8」(多分OSはDebian)
構造
/ |-/app | |-/image # tifファイルを入れる | |-test.py # テストコード | '-Dockerfile '-docker-compose.yamlDockerfile/docker-compose.yaml
DockerfileFROM python:3.8 ENV APP_HOME /app WORKDIR $APP_HOME RUN apt-get update && apt-get install -y tzdata \ libgdal-dev RUN pip install --upgrade pip RUN pip install gdal==2.4.4 CMD ["python", "/app/test.py"]docker-compose.yamlversion: "2" services: test: container_name: "test" build: context: ./app volumes: - ./app:/appテスト
テストコードは以下の通り。
test.pyfrom osgeo import gdal, gdalconst if __name__ == "__main__": print("gdal version", gdal.VersionInfo()) file_name = '/app/image/1_index_ndvi.tif' src = gdal.Open(file_name, gdalconst.GA_ReadOnly) # tifの読み込み (read only) print(type(src)) # "osgeo.gdal.Dataset"実行は、docker-composeを使用しているので、以下の通り。
docker-compose upおわりに
結構こういうことってよくありますね。ライブラリの最新バージョンを利用する場合は、debianだとパッケージがなかったりするので、ubuntuで環境構築する必要があったりしますし(ubuntuだとリポジトリ登録すればtestバージョン利用できることが多いイメージ)。基本的にある程度データが読める状態にさえなってくれれば、あとは自分で数値処理した方が早いので、stable版で十分だと思います。
- 投稿日:2020-11-19T00:52:45+09:00
awesome-composeでローカル開発環境をお手軽にセットアップする
この記事は
「awesome-compose」をつかってローカル環境に開発環境を作る方法です。
自己紹介
Java(Spring Boot)のWebアプリ開発を主にやってます。
きっかけ
ローカル環境がこわれた
ローカルでSpring Bootの開発でごちゃごちゃやっていたらGradleが壊れてしまいました。
gradle install
実行時に、こんなエラー(↓)がでました。FAILURE: Build failed with an exception. * What went wrong: Task 'install' not found in root project 'frontend'. # 以下略ググってもAndroid系の記事ばかり出てきてなんかよくわからなかったです。
もっと調べろよ!と言われればそれまでですが、いい機会なのでDockerできれいな環境を作りたくなりました。ときには別の道に逃げましょう。
docker-composeちゃんと書くの大変
ネットでググりつつ自分の環境に合わせて書くわけですが、Dockerの基礎力が弱いので、つまづいたときになかなか先に進めません。リファレンス見ても直感的に理解するまでの道は遠いです。
真似ながら学んでいきたい性質(たち)なので、質の良いサンプルがあると助かります。
awesome-composeとは
Docker公式のdocker-composeのサンプル集です。以下にあります。
https://github.com/docker/awesome-composeREADME.mdには以下のように書いています。
(以下一部引用。Google翻訳)These samples provide a starting point for how to integrate different services using a Compose file and to manage their deployment with Docker Compose.
これらのサンプルは、Composeファイルを使用してさまざまなサービスを統合し、DockerComposeを使用してそれらのデプロイメントを管理する方法の開始点を提供します。サンプルとしてまずは動かしてみて、自分の環境にあうようにカスタマイズしていくイメージでしょうか。
The following samples are intended for use in local development environments such as project setups, tinkering with software stacks, etc. These samples must not be deployed in production environments.
次のサンプルは、プロジェクトセットアップ、ソフトウェアスタックの調整など、ローカル開発環境での使用を目的としています。これらのサンプルは、実稼働環境にデプロイしないでください。使い所としてはローカル開発環境であることが明記されてます。じっさいのところ、本番環境ではクラウドのマネージドサービスを使うなど選択肢がいろいろあるかと思います。
awesome-composeの特徴
- ご覧いただくとわかるように、さまざまなコンテナの組み合わせがサンプルとして用意されてます。探せば自分がほしいものが見つかるのではないでしょうか。
- docker-compose.ymlだけでなく、アプリのサンプルもついてきます。アプリも含めてDocker環境をいちからつくるのは結構骨が折れるので、そこはありがたいですね。
動かしてみる
1. Docker環境のインストール
詳細は割愛します。Mac版は以下にあります。
Docker Desktop for Mac
https://hub.docker.com/editions/community/docker-ce-desktop-mac/2. awesome-composeの入手
先に紹介したGitHubのサイトからクローンします。
git clone https://github.com/docker/awesome-compose.git3. コンテナの起動
SpringとPostgreSQLのコンテナを起動する「spring-postgres」を使ってみます。
プロジェクトルートからspring-postgres
ディレクトリを移動し、cd spring-postgres
docker-compose
コマンドで起動します。docker-compose up -d
4. 動作確認
初期ページが表示されれば起動成功です。
詳細は省きますが、「Hello from Docker」の「Docker」は、PostgreSQLコンテナ起動時にINSERTされたレコードをSpringから参照、画面表示したものです。
解説(docker-compose.yaml)
とりあえず動けばいいや、でよければこれ以上読まなくても大丈夫です。
以降は、docker-compose.yamlの雑な解説をするので、興味があればお読みください。backendサービス(Spring)の設定
version: "3.7" services: backend: build: backend # (1) ports: - 8080:8080 environment: - POSTGRES_DB=example # (2) networks: - spring-postgres
- (1) backendサービスのイメージ作成は、
build
に指定したディレクトリ名backend
にあるDockerfile
でおこないます。- (2)
environment
はコンテナ内で使用する環境変数を設定します。POSTGTES_DB=example
は、SpringからPostgreSQLへ接続するときの接続文字列で使用するDB名です。backend/src/main/resources/application.properties
内で参照しています。dbサービス(PostgreSQL)の設定
db: image: postgres restart: always secrets: - db-password # (3) volumes: - db-data:/var/lib/postgresql/data # (4) networks: - spring-postgres environment: - POSTGRES_DB=example - POSTGRES_PASSWORD_FILE=/run/secrets/db-password # (5) volumes: db-data: # (6) secrets: db-password: file: db/password.txt # (7) networks: spring-postgres:
- (3) 機密情報(パスワード)を指定します。
- (4) コンテナ内のPostgreSQLのデータディレクトリをホストマシンのディレクトリにマウントします。
- (5) 機密情報(パスワード)が記載されたファイルのパスを環境変数に設定します。
- (6) (4)にたいしてマウントするホスト側のディレクトリを指定します。ここでは記載がないので、永続化はされないようですね。
- (7) コンテナ内のPostgreSQLで使用するパスワードファイルのパスを設定します。デフォルトでは、ここで指定したファイルはコンテナの
/run/secrets
ディレクトリにマウントされるらしい。最後に
とりあえず動かすだけはできました。
次はカスタマイズして自分なりの環境を作りたいです。参考
- Compose ファイル・リファレンス
- Docker Compose入門 (1) ~アプリケーションをコンテナで簡単に扱うためのツール~
- Docker Compose入門 (2) ~ウェブサーバの開発環境を作るための準備~
- Docker Compose入門 (3) ~ネットワークの理解を深める~
- Docker Compose入門 (4) ~ネットワークの活用とボリューム~
- Dockerfileを改善するためのBest Practice 2019年版
- docker images を全削除する
- 《滅びの呪文》Docker Composeで作ったコンテナ、イメージ、ボリューム、ネットワークを一括完全消去する便利コマンド
- 投稿日:2020-11-19T00:32:44+09:00
[Docker入門]機械学習用のDockerイメージを作成してJupyter notebookを使用する
この記事について
機械学習の学習環境をDockerに移行したので、Dockerの使い方を忘れたときのための備忘録用記事です。
環境
基本Mac前提なのでWindowsの場合のコマンドなどは書いていないです。
- MacOS Mojave
GitHub
この記事で紹介しているDockerfileはGitHubに公開しています。
GitHub:/kuboshu/pythonmlこの記事でわかること
機械学習用ライブラリをインストールしたDockerイメージを構築し、コンテナのJupyter-notebookを外部から使用して機械学習で遊ぶ方法。
Dockerイメージにインストールされているライブラリ
Pythonを使用するのでPythonの機械学習関連のライブラリを適当に入れてみました。
- python 3.8.2
- scikit-learn 0.23.2
- pandas 1.1.2
- numpy 1.18.5
- jupyterlab 2.2.8
- pycaret 2.1.2
- lightgbm 3.0.0
- xgboost 1.2.0
- scipyt 1.5.2
- matplotlib 3.3.2
- tensorflow 2.3.1
- pytorch 1.6.0
- pyocr 0.7.2
- opencv-python 4.4.0.44
- optuna 2.1.0
- mecab
作成したDockerfileの内容
Ubuntu20.04をベースに作成しました。基本的にはpipでPythonのパッケージをインストールしているだけなので、特別なことは何もしていないです。
FROM ubuntu:20.04 LABEL maintainer="kuboshu83" ENV DEBIAN_FRONTEND noninteractive ARG INSTALLDIR_PYOCR="/app/ocr" RUN apt-get update && \ apt-get -y upgrade && \ apt-get install -y git \ make \ cmake \ gcc \ g++ \ wget \ zip \ curl && \ # ~~~~~Pythonのインストール~~~~~ apt-get install -y python3 python3-pip && \ ln -s $(which python3) $(dirname $(which python3))/python && \ ln -s $(which pip3) $(dirname $(which python3))/pip && \ # ~~~~~Python用ML関連ライブラリのインストール~~~~~ # TensorflowとPytorchは容量が大きいので必要なければコメントアウトしてください。 # 容量の目安はtensorflow=1.2GB, pytorch=2GBです。 # Tensorflow, Pytorch以外のML様ライブラリで約2GBです。 pip install pystache \ numpy==1.18.5 \ pandas \ scikit-learn \ matplotlib \ jupyterlab \ pycaret \ lightgbm \ alembic==1.4.1 \ sqlalchemy==1.3.13 \ optuna && \ pip install tensorflow && \ pip install torch torchvision && \ # ~~~~~OpenCVのインストール~~~~~ pip install opencv-python && \ apt-get install -y libgl1-mesa-dev && \ # ~~~~Tesseractのインストール~~~~~ apt-get install -y libleptonica-dev tesseract-ocr && \ # ~~~~PyOCRのインストール~~~~~ pip install pyocr && \ mkdir -p /usr/local/share/tessdata/ && \ curl https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/master/jpn.traineddata -sS -L -o /usr/share/tesseract-ocr/4.00/tessdata/jpn.traineddata && \ # ~~~~MeCabのインストール~~~~ apt-get install -y mecab libmecab-dev mecab-ipadic && \ pip install --no-binary :all: mecab-python3 && \ pip install neologdn && \ #~~~~作業ディレクトリの作成~~~~ mkdir -p /home/share # デフォルトでPythonシェルを起動 CMD ["python"]Dockerイメージのビルド方法
Dockerイメージは以下のコマンドでビルドできます。また、Githubにあるbuild.shに同様のコマンドが記載されているので、build.shを実行してもイメージがビルドできます。
docker build -t イメージ名:バージョン Dockerfileの場所
Jupyter-notebookを起動する方法
カレントディレクトリにshare/を作成して以下のコマンドを実行すると、コンテナに次いでJupyter-notebookが起動します。あとは表示されたURLをブラウザで開けばJupyter-notebookを使用することができます。
Dockerイメージのバージョンは適当なものを指定してください。以下の例ではv0.1.0を使用した場合になります。# コンテナの/home/shareと共有するためのディレクトリを作成する > mkdir share # コンテナを起動する。 # -rm: コンテナ停止と同時にコンテナを削除する。 # -it: コンテナでターミナルを使用するために必要。 # 今回みたいにJupyter-notebookを使用するだけなら不要だけど何となく入れてある。 # -p : ホストの8888番ポートをコンテナの8888番ポートに割り当てる。 # -v : ホストの(カレントディレクトリ)/share/をコンテナの/home/share/にマウントする。 # -w : コンテナ起動時のコンテナのカレントディレクトリを/home/share/にする。 # Jupyter-labは8888番ポートで起動しています。 > docker run --rm -it -p 8888:8888 -w /home/share -v $(pwd)/share:/home/share pythonml:v0.1.0 /usr/local/bin/jupyter lab --ip=0.0.0.0 --port 8888 --allow-rootコンテナを起動すると作業用として用意してある/home/share/がカレントディレクトリになるので、これをホスト側のディレクトリと共有すると使いやすいです。
Dockerfileを書くときに調べたこと
[インタラクティブなインストールを避ける]
完全に自動でDockerイメージをビルドしたいので、パッケージなどのインストール時に手動での設定を求められたくないので、インストール時のインタラクティブな設定を無効化したかったので環境変数として以下を設定した。
ENV DEBIAN_FRONTEND noninteractive[RUNの使用回数を減らす]
最初は何も考えずにRUN命令を多用していたが、docker image ls -aでイメージを確認すると下の様に中間レイヤーのイメージが量産されていた。どうやら、DockerはDockerfileで命令を使用する毎に中間レイヤーを作成して、最終的に中間レイヤーを合成して最終イメージを作成するらしい。よって、なるべく使用する命令数を少なくしました。
中間レイヤーが多いと問題があるのかどうかは、まだ理解していないのでわかりません。ただ、イメージ一覧を表示した際に<none>が大量にあるのが気持ち悪かったので、中間レイヤーを減らす様に記述してみました。
REPOSITORY TAG IMAGE ID pythonml v0.1.0 xxxxxx <none> <none> xxxxxx <= これとか <none> <none> xxxxxx <= これとか <none> <none> xxxxxx <= これとか <none> <none> xxxxxx <= これとか <none> <none> xxxxxx <= これとか <none> <none> xxxxxx <= これとか <none> <none> xxxxxx <= これもか ubuntu 20.04 xxxxxxまとめ
今回は単にPythonのパッケージをインストールしたDockerイメージを構築して、ホストからJupyter-notebookを使用して機械学習で遊ぶ環境の構築方法をメモしました。まだ、遊んでみたいライブラリとかがあるので今後入れていきたいです。
また、今回はDockerfileの見た目を優先させ、ライブラリは全てapt-getかpipで入れているため古いバージョンのものもあります。なので、今後ソースコードからビルドして最新のバージョンのインストールも時間があればやっていきたいです。
参考にさせていただきました