フリーランチ食べたい

機械学習、Python、ソフトウェアエンジニアリング、プロダクティビティなど

`docker-compose run` は portをmappingしない

dokcer-composeでちょっとハマったのでメモ

TLDR

  • docker-compose run a すると設定したportがmappingされない
  • docker-compose run --service-ports a すれば良い

詳細

↓のようなdocker-compose.ymlがあったときに

version: '3.5'
services:
    a:
        image: hoge
        ports:
            1234:1234

service_aだけ実行したかったので、 $ docker-compose run a /bin/bash とaだけrunした。

プロセスをチェックしてみると、portsをmapping されていない。

$ docker-compose ps 
          Name                         Command               State            Ports
--------------------------------------------------------------------------------------------
reponame_a_1     /bin/bash    Up

この問題に関してはGithubで質問されていたりして、詰まっている人は多いようだ。 Docker-compose run command doesnt map ports · Issue #1259 · docker/compose · GitHub

原因と解決策は、公式ドキュメントにしっかり書かれている。 run — Docker-docs-ja 17.06.Beta ドキュメント

使い方: run [オプション] [-e キー=バリュー...] サービス [コマンド] [引数...]

オプション:
-d                    デタッチド・モード: コンテナをバックグラウンドで実行し、新しいコンテナ名を表示
--name NAME           コンテナに名前を割り当て
--entrypoint CMD      イメージのエントリーポイントを上書き
-e KEY=VAL            環境変数を指定 (複数回指定できる)
-u, --user=""         実行時のユーザ名または uid を指定
--no-deps             リンクしたサービスを起動しない
--rm                  コンテナ実行後に削除。デタッチド・モードの場合は無視
-p, --publish=[]      コンテナのポートをホスト側に公開
--service-ports       サービス用のポートを有効化し、ホスト側に割り当て可能にする
-T                    疑似ターミナル (pseudo-tty) 割り当てを無効化。デフォルトの `docker-compose run` は TTY を割り当て
-w, --workdir=""      コンテナ内のワーキング・ディレクトリを指定

のうち、↓を使えばよい。

--service-ports       サービス用のポートを有効化し、ホスト側に割り当て可能にする

なので結論としては、

$ docker-compose run a /bin/bash --service-ports

とすればよい。

$ docker-compose ps 
          Name                         Command               State            Ports
--------------------------------------------------------------------------------------------
reponame_a_1     /bin/bash    Up    0.0.0.0:1234->1234/tcp

正しくmappingされた🎉

「なんでそういう仕様なの?」という声も聞こえてきそうだが(Githubで「直したほうが良くね?」って言ってる人もいた)

理由もしっかり公式ドキュメントに書いてある。 run — Docker-docs-ja 17.06.Beta ドキュメント

2つめの違いとして、 docker-compose run コマンドはサービス設定ファイルで指定したポートを作成しません。これは、既に開いているポートとの衝突を避けるためです。

確かに?ただ docker-compose up を2回すると衝突しそうだよな。と思って試したら新しくコンテナは作成されなかった。 公式ドキュメントにはその辺り明言されていないようにも見えるが雰囲気から、そういう仕様ということはわかる。

up — Docker-docs-ja 17.06.Beta ドキュメント もしサービス用のコンテナが存在している場合、かつ、コンテナを作成後にサービスの設定やイメージを変更している場合は、 docker-compose up -d を実行すると、 設定を反映するためにコンテナを停止・再作成します(マウントしているボリュームは、そのまま保持します)。Compose が設定を反映させないようにするには、 --no-recreate フラグを使います。

まとめ

公式ドキュメントをしっかり読むと色々わかるからしっかり読もう