docker-composeのProjectという概念について

大本のディレクトリを分けても、同名フォルダ配下にあるymlを元に docker-compose up するとRecreating されてしまう。

例えばmyProjectに開発用のymlがあるとする(volumes等々だいぶ記述を省いている)。 フォルダ名をmyProjectとする。

myProject/docker-compose.yml

version: '2'

services:
  nginx:
    image: nginx
    container_name: "nginx-dev"
    ports:
      - "8080:80"

  app:
    build: ./php
    container_name: "app-dev"

普通に起動すると、こうなる。

$ docker-compose up -d
Creating network "compose_default" with the default driver
Creating app-dev   ... done
Creating nginx-dev ... done
$ docker-compose ps
  Name                 Command              State          Ports
------------------------------------------------------------------------
app-dev     docker-php-entrypoint php-fpm   Up      9000/tcp
nginx-dev   nginx -g daemon off;            Up      0.0.0.0:8080->80/tcp

あまり使うことはないが、docker ps でも見てみる。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
3e845fb43f2e        nginx               "nginx -g 'daemon of…"   53 seconds ago      Up 52 seconds       0.0.0.0:8080->80/tcp   nginx-dev
d60726667f0e        myproject_app         "docker-php-entrypoi…"   53 seconds ago      Up 52 seconds       9000/tcp               app-dev

コンテナ名はそれぞれ、ymlのcontainer_nameで指定したものになっている。 ただ気にしていなかったのは、appコンテナはDockerfileから作っているので、myproject_appというIMAGE名になっている点。

この環境を検証環境やステージングで使おうとしたとき、2環境欲しいなと思うことがある。 1つの環境はチームメンバーが通常開発に使用する安定的なもので、もう1つは設定や構成を変更する開発案件で使用するもの。

そこで、ymlを分けて以下のように管理することにした。

/myProject
|--docker-compose.yml
|--php
| |--Dockerfile
|--ymlfiles
| |--docker-compose.staging.develop.yml
| |--docker-compose.staging.stable.yml

ポートフォワーディングでホスト側を分ければ2環境同時に使うことができると考えた。

myProjectはgit cloneしてきた同じものだが、その上の階層で分けている。

  • /home/webmaster/stable/myProject/ymlfiles
  • /home/webmaster/develop/myProject/ymlfiles

そしてコンテナ名もそれぞれ変更した。これで問題ないように思えた。

version: '2'

services:
  nginx:
    image: nginx
    container_name: "nginx-staging-stable"
    ports:
      - "8080:80"

  app:
    build: ../php
    container_name: "app-staging-stable"
version: '2'

services:
  nginx:
    image: nginx
    container_name: "nginx-staging-develop"
    ports:
      - "8080:80"

  app:
    build: ../php
    container_name: "app-staging-develop"

stableを立ち上げる。

$ docker-compose -f docker-compose.staging.stable.yml up -d
app-staging-stable is up-to-date
Starting nginx-staging-stable ... done

$ docker-compose -f docker-compose.staging.stable.yml ps
        Name                      Command              State          Ports
-----------------------------------------------------------------------------------
app-staging-stable     docker-php-entrypoint php-fpm   Up      9000/tcp
nginx-staging-stable   nginx -g daemon off;            Up      0.0.0.0:8080->80/tcp

developを立ち上げる。

$ docker-compose -f docker-compose.staging.develop.yml up -d
Recreating app-staging-stable   ... done
Recreating nginx-staging-stable ... done
szk416s-MacBook-Pro:~/study/myProject/ymlfiles szk416 $ docker-compose -f docker-compose.staging.develop.yml ps
        Name                       Command              State          Ports
------------------------------------------------------------------------------------
app-staging-develop     docker-php-entrypoint php-fpm   Up      9000/tcp
nginx-staging-develop   nginx -g daemon off;            Up      0.0.0.0:8080->80/tcp

なんと、 Recreatingされてしまい、先に作ったapp-staging-stableとnginx-staging-stableは消えてしまった。

docker ps で見ても同じ。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
d569715fafaf        nginx               "nginx -g 'daemon of…"   56 seconds ago      Up 54 seconds       0.0.0.0:8080->80/tcp   nginx-staging-develop
159d41b57e5b        ymlfiles_app        "docker-php-entrypoi…"   56 seconds ago      Up 54 seconds       9000/tcp               app-staging-develop

何が起こったのか?

docker-compose にはProjectという概念がある

公式ドキュメントにはちゃんと書いてあるし、確認するコマンドもある

-p, --project-name NAME 別のプロジェクト名を指定 (デフォルト: directory name)

各設定ファイルはプロジェクト名を持っています。 -p フラグでプロジェクト名を指定できます。フラグを指定しなければ、Compose は現在のディレクトリの名前を使います。詳細は COMPOSE_PROJECT 環境変数 をご覧ください。

cf. docker-compose コマンド概要 — Docker-docs-ja 17.06.Beta ドキュメント

ここでいう、 フラグを指定しなければ、Compose は現在のディレクトリの名前を使います というのが重要で、 docker ps の結果の方を見ると、 ymlfiles_app と、ディレクトリ名 + サービス名になっていることがわかる。

つまり、いくら大本のディレクトリから分けていたとしても、親ディレクトリが ymlfiles なので同じプロジェクトとして扱われてしまっていた。 基本的にはない話だが、本番環境などであればシャレにならない。

そもそも、環境変数にymlを指定する手段があるところを見ると、複数立てるようなことはしない方が良いのだろう。

suin.io

フォルダごとに.envを置いてPROJECT_NAMEを指定する手段もあるようだが、こういうのは後からチームに加わった人が気付きづらいので良くないと考えている。

結局、ymlfiles-stable, ymlfiles_develop のように分けて管理することにした。 愚直だが一番わかり易いと思う。