DockerfileのPORT設定とホスト公開の対応関係|Compose連携で確認する実構成

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Docker > DockerfileのPORT設定とホスト公開の対応関係|Compose連携で確認する実構成
「DockerfileにEXPOSE 80と書いてコンテナを起動したのに、ブラウザでlocalhost:80にアクセスしても接続できない。」
こうした場面でつまずく方は少なくありません。

EXPOSE命令はDockerfileに書く命令ですが、ホスト側にポートを公開する処理は行いません。
ホストからコンテナへ通信を届けるには、docker runに-pオプションを指定するか、docker-compose.ymlのports設定が必要です。

この記事では、DockerfileのEXPOSE命令とdocker runの-pオプション・docker-compose.ymlのports設定の役割を整理します。
NginxコンテナをCompose管理するシンプルな構成を例にして、ポートの対応関係と動作確認の方法を確認します。
想定環境はDocker Engine 24以降、AlmaLinux 9またはUbuntu 24.04 LTSです。

この記事のポイント

・EXPOSEはポート番号を宣言するだけで、ホストへの公開は行わない
・ホストから接続するにはdocker run -p ホストポート:コンテナポート の形で指定する
・docker-compose.ymlのports:はdocker runの-pと同じ役割を担う
・ssコマンドでホスト側のリッスンポートを確認できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

DockerfileのEXPOSEはポート番号の宣言であり公開設定ではない

DockerfileのEXPOSE命令は、このイメージがどのポートを使用するかをイメージの利用者やDockerツールに伝えるためのメタデータです。
コンテナを起動したとき、EXPOSE 80と書いてあっても、ホストの80番ポートにトラフィックが届く設定は行われていません。

EXPOSEにはドキュメントとしての役割と、docker run --publish-all(-P)オプションとの連携という2つの用途があります。

EXPOSEの用途まとめ:
・イメージの利用者にポート番号を伝えるドキュメントとしての役割
・docker run -Pを使ったとき、ランダムなホストポートへのマッピングのヒントになる
・同一Composeネットワーク内でのコンテナ間通信では、EXPOSEされたポートが通信可能になる

「EXPOSE 80と書いたからポートが公開された」という理解は誤りで、ホストからアクセスするには別途-pオプションの指定が必要です。

docker runの-pオプションでホストにポートを公開する

1. 基本の書き方:ホストポートとコンテナポートを対応させる

docker runに-pオプションを指定すると、「ホストのXXX番ポートに来たリクエストをコンテナのYYY番ポートへ転送する」という設定が行われます。

# 書式 docker run -p ホストポート:コンテナポート イメージ名 # Nginxをホストの8080番ポートで公開する例 docker run -p 8080:80 nginx # バックグラウンドで起動する場合 docker run -d -p 8080:80 nginx

コンテナ起動後にブラウザでhttp://localhost:8080にアクセスすると、コンテナ内のNginxに通信が届きます。

コンテナポートの番号はDockerfileのEXPOSE命令で宣言されている番号と一致させるのが基本です。
Nginxの公式イメージはEXPOSE 80と宣言されているため、コンテナポートの指定は80になります。

2. 複数ポートを同時に公開する

-pオプションは複数指定できます。
HTTPとHTTPSを両方公開する場合など、必要なポート数だけ-pを繰り返します。

# HTTPとHTTPSを両方公開する例 docker run -d \ -p 80:80 \ -p 443:443 \ nginx

3. バインドアドレスを指定して公開範囲を絞る

-pには「どのネットワークインターフェースからの接続を受け付けるか」を指定できます。

# すべてのネットワークインターフェースから受け付ける(デフォルト) docker run -d -p 0.0.0.0:8080:80 nginx # ローカルループバックのみ受け付ける(外部からアクセス不可) docker run -d -p 127.0.0.1:8080:80 nginx

本番環境では外部に公開しないAPIサーバーなどには127.0.0.1を指定しておくと、意図しない外部アクセスを防げます。

docker-compose.ymlのports設定でCompose管理する

1. ports:のYAML記法

docker-compose.ymlではports:キーを使って、docker runの-pと同じポート公開設定を行います。

# docker-compose.yml の例 services: web: image: nginx ports: - "8080:80"

「"8080:80"」の書き方はdocker runの-p 8080:80と同じ意味で、ホストの8080番ポートをコンテナの80番ポートに対応させます。

Composeでは数値を文字列で書く形式(- "80:80")が最もよく使われます。
YAMLマッピング形式(target: 80、published: 8080)を使う書き方もありますが、現場の設定ファイルでは文字列形式が一般的です。

2. EXPOSEとports:の役割分担

DockerfileのEXPOSEとdocker-compose.ymlのports:は、次のように役割が分かれています。

設定箇所 役割 ホスト公開
Dockerfile EXPOSE コンテナが使うポートの宣言(ドキュメント) しない
docker run -p ホストポート→コンテナポートの転送設定 する
docker-compose ports: docker run -pと同じ転送設定(Compose管理) する
docker-compose expose: コンテナ間通信用のポート宣言(ホストには公開しない) しない

docker-compose.ymlのexpose:はDockerfileのEXPOSEと同じ効果で、同一Composeネットワーク内のコンテナ間通信にのみ影響します。
ホストからアクセスするにはports:の設定が必要です。

NginxとAPIサーバーのCompose実構成例

フロントにNginxを置き、バックエンドのAPIサーバーとCompose管理する構成を見てみます。

Dockerfileの例:

# Dockerfile(Node.js APIサーバーの例) FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm install COPY . . EXPOSE 3000 CMD ["node", "server.js"]

docker-compose.ymlの例:

# docker-compose.yml services: web: image: nginx:alpine ports: - "80:80" depends_on: - api api: build: . expose: - "3000"

この構成では、Nginxだけがホストの80番ポートを公開し、APIサーバーはComposeの内部ネットワーク内でのみNginxからアクセスできます。
Dockerfileに書いたEXPOSE 3000は、docker-compose.ymlのexpose:の値と対応しています。

外部に公開する必要のないAPIサーバーをports:でホストに公開してしまうのはセキュリティ上のリスクになるため、このようにNginxをフロントエンドに置く設計がよく使われます。

Dockerの設計パターンや実践的な構築方法を体系的に学びたい方は、Docker実践講座もご覧ください。

ポートが公開されないときの確認手順

コンテナを起動してもホストからアクセスできない場合、次の順で確認します。

1. コンテナが起動しているかdocker psで確認する

docker ps # 出力例(環境により異なります) CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a1b2c3d4e5f6 nginx "/docker-entrypoint..." 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp my_nginx

PORTS列に「0.0.0.0:8080->80/tcp」のような表示があれば、ホストの8080番ポートがコンテナの80番ポートに転送される設定が有効になっています。
何も表示されていない場合は-pオプションを指定せずに起動しています。

2. ホスト側でポートが待受状態になっているかssで確認する

# ホスト側のリッスンポートを確認する ss -tlnp | grep 8080 # 出力例(環境により異なります) LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=12345,fd=4))

「docker-proxy」プロセスが8080番ポートをリッスンしていれば、Dockerのポートフォワードが設定されています。
出力が空の場合は-pオプションの指定が抜けています(Linux ポート確認の全コマンド)。

3. ファイアウォールでポートが遮断されていないか確認する

ホスト側のファイアウォール設定でポートが遮断されている場合もあります。

# firewalldが有効な環境で確認する場合 sudo firewall-cmd --list-ports # iptablesで確認する場合 sudo iptables -L DOCKER -n --line-numbers

4. コンテナ内でサービスが起動しているか確認する

ポートフォワードの設定は正しくても、コンテナ内のサービスが起動していなければアクセスできません。

# コンテナ内でプロセスを確認する(コンテナIDは実際のIDに置き換えてください) docker exec -it a1b2c3d4e5f6 bash # コンテナ内で実行 ps aux

まとめ

DockerfileのEXPOSEとdocker runの-p・Composeのports:の対応関係をまとめます。

やりたいこと 設定方法
ホストからコンテナのポートにアクセスする docker run -p ホストポート:コンテナポート
Composeでポートを公開する docker-compose.ymlのports: - "ホスト:コンテナ"
コンテナ間通信のみ(ホスト非公開) docker-compose.ymlのexpose: - "コンテナポート"
ポート公開状態を確認する docker ps のPORTS列、またはss -tlnp

EXPOSEはポート番号のドキュメントであり、ホスト公開の設定ではありません。
「コンテナが起動しているのにアクセスできない」場合は、まず-pオプションまたはports:設定が抜けていないかを確認してください。

Composeでは内部サービス(DBやAPIなど)はexpose:のみで管理し、外部に公開するフロントエンドだけにports:を指定する設計が、セキュリティ上もシンプルな管理の面でも有効です。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、

Dockerコンテナの基礎からComposeを使った実践的なサーバー構築まで、ハンズオン形式でスキルを身につけられます。
>>Docker実践講座の詳細はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。