Dockerでサーバー構築する際のポート指定で気をつけること

Docker で社内向けのWebアプリをホストするサーバーを構築しようと考えていて、ひとまず Vagrant 上で色々と試していたのですが、これまで Docker はローカルの開発用環境にしか使っていなかったので、今まであまり気にしてなかったり知らなかったことをちょっとまとめてみます。

ほぼほぼ、dockerとufwの設定が独立なせいで無駄にポートが開いてしまう件と、解決するためのdocker runオプションの記法について #Docker – Qiita でまとめられている内容ですが。

  1. Dockerコンテナ間だけで共有したいポートは expose を使う
    • 自分と同じように Docker はローカルの開発用環境で使う前提のサンプルコードなど、ポートの共有はほぼほぼ ports になっている場合が多いですが、ports だとホストOSへポートフォワードして、結果外部にも公開されます。なので、Dockerコンテナ間だけで共有したいポートは expose で指定します。
  2. 外部に共有したいけど対象がホストOSだけの場合、ports を使って IPアドレスで限定する

例えば、Redmine コンテナを立ち上げるとして、

  • 3000ポートをホストOSのみに公開、外部には開放しない
  • 3306ポートはDockerコンテナ間だけに開放、ホストOSからもアクセス不可

といった設定だと、以下のような docker-compose.yml の記述になります。

version: '3.1'

services:
  app:
    image: redmine:5.1.2
    restart: always
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      REDMINE_DB_MYSQL: db
      REDMINE_DB_USERNAME: redmine
      REDMINE_DB_PASSWORD: redmine
      REDMINE_DB_DATABASE: redmine
      REDMINE_PLUGINS_MIGRATE: 1
      REDMINE_SECRET_KEY_BASE: supersecretkey

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: redmine
      MYSQL_USER: redmine
      MYSQL_PASSWORD: redmine
      MYSQL_RANDOM_ROOT_PASSWORD: 1
    volumes:
      - ./mysql:/var/lib/mysql
    expose:
      - 3306

この辺り、事前に調べてたり、もともと知ってたりしてないと第一感で「ufw でポートを塞げば良いんじゃね?」って思って設定するも、公開されっぱなしで「え…?」ってなりがちですが、前に上げた dockerとufwの設定が独立なせいで無駄にポートが開いてしまう件と、解決するためのdocker runオプションの記法について #Docker – Qiita でも触れられてる通り、ufw の設定は効きません。これ、結構罠ですよね。