LoginSignup
8
3

More than 3 years have passed since last update.

【Docker Compose】プロジェクト名を指定していなくてハマった話

Posted at

デフォルトに甘えてComposeのプロジェクト管理を意識せずにいたら、いざという時に意図通りのコンテナ操作ができずにハマったという話です。

前のコンテナを止められない

ある日、僕はとあるサービスのデプロイをしました。
プロジェクトをDocker Composeでまとめ、ssh,pull等のデプロイ作業を1行のコマンドにまとめた。
はじめは動いていましたが…

次のデプロイでコンテナ起動時に問題発生。

ERROR: {省略} Bind for 0.0.0.0:3000 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.
# 本番にsshして確認
$ docker ps
{省略} days ago  0.0.0.0:3000->3000/tcp                     0200122040412_1

前のコンテナが起動したままになっており、ポートが被って起動できないというエラーです。
原因はわかりませんが、とりあえずstop。

$ docker-compose stop
$ docker ps
{省略} days ago  0.0.0.0:3000->3000/tcp                     0200122040412_1

残ってる…

コンテナとdocker-compose.yamlの関係はどうやって決まる?

ここでdocker-composeではなくdockerコマンドでコンテナを止めるのは簡単ですが、ちょっと待ってください。
普通は同じプロジェクトのdocker-compose.yamlを使えば、再起動時に自動で前のコンテナをシャットダウンしてくれます。くれてました。
なぜその対応関係が切れてしまったんでしょうか。

コンテナかDockerが記憶しているのかと思いましたが、そんな記述は見当たりません。
現実はもっとシンプルだった。

Docker Composeのプロジェクト名とは

Docker Composeはプロジェクト単位でコンテナを操作します。
プロジェクト(とコンテナ)にはプロジェクト名が付き、コマンド操作(up,run,stop,etc)はそれを参照して行われる。

で、このプロジェクト名は別に設定しなくても動く。

このプロジェクト名の設定はオプションです。設定をしなければ、 COMPOSE_PROJECT_NAME (Composeのプロジェクト名)は、デフォルトではプロジェクトのディレクトリを ベース名 にします。
http://docs.docker.jp/v1.12/compose/reference/envvars.html

デフォルトでディレクトリ名になる。

プロジェクト名を設定しないとどうなる?

[1] 複数のプロジェクトでディレクトリ名がダブると、意図しないコンテナを操作してしまう
(例:日付、バージョン、"app", etc…)
[2] ディレクトリ名を変えるとプロジェクト名が変わり、以前そのディレクトリ内のdocker-compose.yamlで起動したコンテナを操作できなくなる

こういう問題が発生します!!!

実例:Capistranoでデプロイ

Capistranoはruby製のデプロイ自動化gemで、標準でバージョン管理もしてくれる優れもの。
別にRails専用というわけではないので今回はssh→pull→up -d --buildとかする用途で使っていた。
…が、今回このバージョン管理機能が仇になった。

Capistranoのバージョン管理機能とは

Capistranoのデプロイは、Datetime名のディレクトリを都度作成して行われる。

releases]$ ls
20200122033238  20200122033501  20200122040412  20200122041011  20200122041121

その上で、デプロイ先の指定ディレクトリ「標準ではcurrent」は最新バージョンへのsymlinkになる。

app]$ ls
current # ←これが実際には20200122041121へのsymlink

まァ、それは良いのだが、この状態でdocker-compose upすると…

current]$ docker-compose up -d
Starting 20200122033501_db_1    ... done
Starting 20200122033501_web_1         ... done

symlink先の正式なディレクトリ名(=日時のほう)が付けられて起動する。

こうなるともうだめだ

次にCapでデプロイを行うと、それはまた先の日時のディレクトリ名に置かれる。
つまり、 もう別のプロジェクト名になってしまう。
docker-compose upしても古いコンテナを自動終了してくれず、このようにポートダブりエラーが出る。

(前略 )connectivity on endpoint 20200122041121_web_1 (中略): Bind for 0.0.0.0:3000 failed: port is already allocated

今まで何も考えずに使っていても勝手に古いコンテナを操作できていたのは、ディレクトリ名が同じだったからなんですね。
Capが日時でディレクトリを切るから、それが転記された「プロジェクト名」が固有のものって感覚が全然なかったよ…(言い訳、責任転嫁)

プロジェクト名はちゃんと設定しよう。

ちなみに、コンテナをすべて削除するコマンドはこう。

$ docker rm $(docker ps -qa) -f

-fをつけなかった場合は起動中のものは生き残る。

解決策:プロジェクト名の設定方法

というわけでプロジェクト名を設定します。 yamlファイルに直接は書けません。

.envファイル

docker-compose.yamlと同じ場所に置けばOK。

.env
COMPOSE_PROJECT_NAME=hogefuga_project

ただ、.envファイルはそうgit pushするものではないし、docker-composeだけが使うものでもないことに注意。

コマンドライン引数

docker-composeコマンドに-pを付けることで、プロジェクト名を指定できる。

docker-compose -p hoge_project up

ただ、毎回引数にプロジェクト名を付けるのは冗長なので、このコマンド自体を何かに登録する前提だろう。
Capistranoのようなデプロイ自動化スクリプトを使用する場合はどんどん使っていこう。

deploy.rb
namespace :container do
  desc 'Up containers'
  task :up do
    on roles(:docker) do
      execute "cd #{release_path} && docker-compose -p hoge_project up -d"
    end
  end
end
8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3