- 概要
- はじめに
- 前提とする環境
- Dockerのセットアップ
- Dockerコンテナの動作確認
- カスタムコンテンツの作成
- 外部公開する
- DockerイメージのECR管理
- リソース管理とクリーンアップ
- まとめ
概要
この記事では 「EC2上でDockerコンテナを使ってWebページをホストし、外部からアクセスできるようにする方法」について紹介します。
【本記事でわかること】
- EC2上でのDockerコンテナの基本的な操作方法
- ALBを使った外部公開の設定方法
- DockerイメージをECRで管理する方法
はじめに
こんにちは!カスタマーサクセス部 CS1課の圡井です!
最近コンテナ技術の活用が広がっており、AWSではECSやEKSの活用が主流です。 このECSやEKSはマネージドサービスであり、広い範囲のインフラ部分がAWSにて管理されます。 そのため、まずはコンテナの基本的なふるまいを理解するために、EC2上でDockerコンテナを動かしてみようと考えました。
本記事では、EC2上でDockerコンテナを使ってWebページをホストし、Application Load Balancer(ALB)を使って外部からアクセスできるようにする手順を、ハンズオン形式で紹介します。
前提とする環境
構成図
前提として以下のような構成を想定しています。

【ポイント!】
- EC2に使用しているCPUアーキテクチャを控えておきましょう。本手順では Arm系インスタンス(t4g.micro)を使用しています。
- x86_64系インスタンス(例:t3.micro)
- Arm系インスタンス(例:t4
g.micro)
- 本手順ではAWS Systems ManagerのSession Managerを使用してEC2にアクセスすることを想定しています。
- EC2インスタンスはプライベートサブネットに配置し、パブリックIPアドレスを持たない構成です。
- Security Group (SG)のインバウンドルールは、空にしています。(後ほど追加あり)
- EC2のIAMロールにSSMの権限を付与する必要があります。
- SSMは起動時にチェックされるため、後から追加した場合はインスタンスの再起動が必要です。
Session Managerの詳細については下記を参照してください。
参考:AWS Systems Manager Session Manager
Dockerのセットアップ
SSMを利用してEC2にログインします。
Dockerのインストール
AWS公式ドキュメントに従ってDockerをインストールします。
参考:Amazon ECS - AL2023 に Docker をインストールする
【ポイント!】
- 本手順では、SSMを使用してEC2にアクセスしているため、
ssm-userをDockerグループに追加する必要があります。
# Dockerのインストール $ sudo yum update -y $ sudo yum install -y docker $ sudo service docker start $ sudo usermod -a -G docker ssm-user # 設定反映のため一度ログアウトして再ログイン $ exit
Dockerfileの作成
公式手順に従いWebページをホストするDockerイメージを作成します。
FROM public.ecr.aws/amazonlinux/amazonlinux:latest # Update installed packages and install Apache RUN yum update -y && \ yum install -y httpd # Write hello world message RUN echo 'Hello World!' > /var/www/html/index.html # Configure Apache RUN echo 'mkdir -p /var/run/httpd' >> /root/run_apache.sh && \ echo 'mkdir -p /var/lock/httpd' >> /root/run_apache.sh && \ echo '/usr/sbin/httpd -D FOREGROUND' >> /root/run_apache.sh && \ chmod 755 /root/run_apache.sh EXPOSE 80 CMD /root/run_apache.sh
Dockerイメージのビルド
作成したDockerfileからイメージをビルドします。
# Dockerイメージのビルド $ docker build -t hello-world .
【ポイント!】
.はビルドコンテキスト(Dockerfileがあるディレクトリ)を指定します。- 今回はARM64アーキテクチャのEC2からビルドしています。ここでBuildされたイメージはARM64アーキテクチャ専用となりますので、他アーキテクチャ環境で動かすときには注意してください。
- より確実にマルチアーキテクチャ対応したい場合は、
docker buildxを使用してマルチプラットフォームビルドを検討してください。
Dockerコンテナの動作確認
コンテナの起動
SSMでログインしているため、バックグラウンドでコンテナを実行します。
# バックグラウンドでコンテナを起動 $ docker run -d -p 80:80 hello-world
動作確認
ローカル環境からアクセスして動作を確認します。
# HTTPアクセスで動作確認
$ curl http://localhost
Hello World!
コンテナの停止
バックグラウンドで実行しているコンテナを停止します。
# 実行中のコンテナを確認 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ae853b3238d9 hello-world "/bin/sh -c /root/ru…" 11 minutes ago Up 11 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp competent_mahavira # CONTAINER IDを使用してコンテナを停止 $ docker stop ae853b3238d9
停止確認
コンテナが正常に停止したことを確認します。
# 実行中のコンテナがないことを確認 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # curlでアクセスできないことを確認 $ curl http://localhost curl: (7) Failed to connect to localhost port 80 after 0 ms: Could not connect to server
カスタムコンテンツの作成
方法1: Dockerfileでの内容変更
Dockerfileの内容を変更してWebページの表示を変更します。
# 変更前 RUN echo 'Hello World!' > /var/www/html/index.html # 変更後 RUN echo 'My Original Message!' > /var/www/html/index.html
再ビルドして動作確認:
# 再ビルド $ docker build -t hello-world . # 実行して確認 $ docker run -d -p 80:80 hello-world $ curl http://localhost My Original Message!
方法2: ローカルファイルの使用
コンテンツを変更する際に、毎回Dockerfileを編集するのはとても面倒です。 より実用的な方法として、ローカルファイルをコンテナにコピーする方法を紹介します。
HTMLファイルの作成
# アセット用ディレクトリの作成 $ mkdir web_assets $ cd web_assets # index.htmlの作成 cat << EOF > index.html <html> <body> <h1>My Original Assets!!</h1> <p>This content is loaded from local files.</p> </body> </html> EOF
Dockerfileの更新
次に、Dockerfileを更新してローカルファイルをコンテナにコピーします。
FROM public.ecr.aws/amazonlinux/amazonlinux:latest # Update installed packages and install Apache RUN yum update -y && \ yum install -y httpd # Copy local files to container COPY web_assets/* /var/www/html/ # Configure Apache RUN echo 'mkdir -p /var/run/httpd' >> /root/run_apache.sh && \ echo 'mkdir -p /var/lock/httpd' >> /root/run_apache.sh && \ echo '/usr/sbin/httpd -D FOREGROUND' >> /root/run_apache.sh && \ chmod 755 /root/run_apache.sh EXPOSE 80 CMD /root/run_apache.sh
Dockerイメージのタグ管理
今回はイメージにタグを付けて管理します。
# タグ付きでビルド $ docker build -t hello-world:myassets . # イメージの確認 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world myassets 542cba53cad9 2 minutes ago 410MB hello-world latest e0a19d264bdc 4 days ago 410MB
【ポイント!】
- タグはイメージのバージョン管理や機能ごとの分類に役立ちます。
hello-world:myassets- 機能名でのタグ付けhello-world:2.0- バージョン番号でのタグ付け
実行と動作確認
# タグを指定して実行 $ docker run -d -p 80:80 hello-world:myassets # CURLコマンドで確認 $ curl http://localhost <html> <body> <h1>My Original Assets!!</h1> </body> </html>
うまく表示されていますね!
外部公開する
さて、EC2でコンテナからWebページをホストすることができるようになりました。 本ブログの最後に、外部に対してこのWebページを公開してみましょう!
EC2をプライベートサブネットに配置しパブリックIPアドレスをつけていないこと、 複数EC2を立てて冗長化する場合も考慮してApplication Load Balancer(ALB)経由でアクセスする構成とします。
ALB用のSecurity Group(SG)を作る
以下のパラメータでALBにアタッチするSGを作ります。 SGはEC2コンソールの左ペイン「セキュリティグループ」ページより作成できます。
インバウンドルールではソースをマイIPとすることで自身の端末が利用しているIPアドレスからのみアクセスできるので検証するうえで安全です。
※VPNを使用している場合、マイIPで設定されるIPが異なる場合があります。
| 項目 | パラメータ | 値 |
|---|---|---|
| 基本的な詳細 | ||
| - | セキュリティグループ名 | scg-container-handson-alb |
| - | 説明 | for container handson |
| - | VPC名 | vpc-container-handson |
| インバウンドルール | ||
| - | タイプ | カスタムTCP |
| - | ポート範囲 | 80 |
| - | ソース(値) | マイIP(<自身の端末のIPアドレス>) |
EC2用のSecurity Group(SG)を作る
EC2を構築する際に「セキュリティグループを作成」を選択している場合、launch-wizard-<連番>という名称でセキュリティグループが作成されます。
命名規則に沿って再作成します。
※めんどくさい方はlaunch-wizard-<連番>にインバウンドルールを適用してください。
【ポイント!】
ALBなどVPC上で動的に実態を作成作するマネージドサービスはその実態によりIPアドレスが変化します。 そのため、ALBのSGをソースとすることで、IPアドレスを考慮する必要なく通信の許可が可能です!
| 項目 | パラメータ | 値 |
|---|---|---|
| 基本的な詳細 | ||
| - | セキュリティグループ名 | scg-container-handson-ec2 |
| - | 説明 | for container handson |
| - | VPC名 | vpc-container-handson |
| インバウンドルール | ||
| - | タイプ | カスタムTCP |
| - | ポート範囲 | 80 |
| - | ソース(値) | カスタム (セキュリティグループ: scg-container-handson-alb) |
EC2にSGをアタッチ
EC2コンソールよりEC2(ec2-container-handson)を選択します。 右上の「アクション」 → 「セキュリティ」 → 「セキュリティグループを変更」を選択します。
「セキュリティグループを編集」欄から先ほど作成したscg-container-handson-ec2を選び、「セキュリティグループを追加」を押下します。
また不要なlaunch-wizard-<連番>は「削除」ボタンを押下します。
「保存」ボタンを押下して確定します。
ロードバランサーの設定
ターゲットグループの作成
ALBがトラフィックを転送する先のターゲットグループを作成します。
| 項目 | パラメータ | 値 |
|---|---|---|
| 基本的な詳細 | ||
| - | ターゲットタイプの選択 | インスタンス |
| - | ターゲットグループ名 | tg-container-handson |
| - | VPC | vpc-container-handson |
| 使用可能なインスタンス | ||
| - | ec2-container-handson | チェックを入れる |
「保留中として以下を含める」を押下します。
「ターゲットグループの作成」を押下します。
ALBの作成
下記のパラメータでALBを作成します。
| 項目 | パラメータ | 値 |
|---|---|---|
| ロードバランサータイプ | ||
| - | Application Load Balancer | 選択 |
| 基本的な詳細 | ||
| - | ロードバランサー名 | alb-container-handson |
| ネットワークマッピング | ||
| - | VPC | vpc-container-handson |
| - | アベイラビリティーゾーンとサブネット | ・ap-northeast-1a (apne1-az4) (vpc-container-handson-subnet-public1-ap-northeast-1a) ・ap-northeast-1c (apne1-az1) (vpc-container-handson-subnet-public2-ap-northeast-1c) |
| セキュリティグループ | ||
| - | default | チェックを外す |
| - | scg-container-handson-alb | チェックを入れる |
| リスナーとルーティング | ||
| - | デフォルトアクション | tg-container-handson |
「ロードバランサーを作成」を押下します。
ヘルスチェックを待つ
作成したロードバランサーを選択します。 「リソースマップ」タブより、ターゲットのインスタンスが「正常」になるまで待ちます。
パブリックからアクセス
ALBの「DNS名」よりalb-container-handson-<ランダム数字>.<リージョン>.elb.amazonaws.comの名前でALBへのFQDNが発行されています。
ブラウザやCURLコマンドでHTTP:80アクセスを行うことで外部からアクセスできます。
$ curl http://alb-container-handson-1427382583.ap-northeast-1.elb.amazonaws.com:80 <html> <body> <h1>My Original Assets!!</h1> </body> </html>
ブラウザからアクセスすると、以下のような画面が表示されます。

DockerイメージのECR管理
現在作成したDockerイメージはEC2内にのみ存在しています。本格的な運用では、イメージを一元管理できるコンテナレジストリの活用が重要です。
AWSではElastic Container Registry(ECR)というマネージドコンテナレジストリサービスを提供しています。
本ブログの最後はDockerイメージをECRにプッシュ(アップロード)してみましょう!
ECRのコスト
事前にコストを確認しておきます。
| 項目 | 料金 | 今回の概算 |
|---|---|---|
| ストレージ | USD 0.10/GB/月 | USD 0.10(410MB → 1GB切り上げ) |
| データ受信 | USD 0.00/GB | USD 0.00 |
| データ送信 | USD 0.114/GB(9.999TB/月まで) | USD 0.114(410MB → 1GB切り上げ) |
ECRリポジトリの作成
「リポジトリを作成」をクリック
| 項目 | 設定値 |
|---|---|
| リポジトリ名 | hello-world |
「作成」を押下します。
ECRへのイメージプッシュ
プッシュコマンドの取得
- 作成した「hello-world」リポジトリを選択
- 「プッシュコマンドを表示」をクリック
- 表示されたコマンドに従って実行
実際の手順
# 1. ECR認証 $ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded # 2. イメージにECRタグを付与 $ docker tag hello-world:latest <アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest # 3. タグ付きイメージの確認 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world myassets 542cba53cad9 2 days ago 410MB <アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world latest e0a19d264bdc 7 days ago 410MB hello-world latest e0a19d264bdc 7 days ago 410MB # 4. ECRにプッシュ $ docker push <アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest ~略~ latest: digest: sha256:712b66abf527e87a013d20c5dea59793a7a39b032f6799f3cac8466202349c8d size: 1155
アップロード確認
リポジトリ内に以下のようにアップロードされているはずです。

演習クイズ
myassetsタグのイメージもECRにアップロードしてみましょう!
解答例
# myassetsタグをECR用にタグ付け $ docker tag hello-world:myassets <アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:myassets # ECRにプッシュ $ docker push <アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:myassets
以下のようにアップロードされているはずです。

うまくできましたか?
リソース管理とクリーンアップ
作成したリソース一覧
本ブログで作成したリソースを整理しておきましょう。
| リソース | リソース名 | 補足 |
|---|---|---|
| VPC | vpc-container-handson-vpc | VPC削除時に依存関係となっているリソースが表示されます |
| EC2 | ec2-container-handson | |
| セキュリティグループ | scg-container-handson-ec2 | EC2に紐づいていると削除できません |
| セキュリティグループ | scg-container-handson-alb | EC2のSGを先に削除します |
| ALB | alb-container-handson | |
| ターゲットグループ | tg-container-handson | ALBとは個別に削除します |
| ECRリポジトリ | hello-world | リポジトリ内にイメージがある場合、削除前にイメージの削除が必要です。 |
まとめ
本記事では、EC2上でDockerコンテナを使ったWebページホスティングを実践しました。
学習ポイント
- EC2でのDocker環境構築
- Dockerfileによるカスタムイメージ作成
- ALBを使った外部公開設定
- ECRでのイメージ一元管理
実用性
単純なWebサーバーインストールと比較すると、Dockerfileの記述やビルド作業が必要ですが、 コンテナ化することで以下のメリットがあります。
- 可搬性: 環境に依存しないアプリケーションの実行
- 再現性: Dockerfileによる環境の再現
- スケーラビリティ: ECRを活用した複数環境への展開
ネクストステップ
AWSにはElastic Container Service(ECS)やAWS Fargateなど、フルマネージドなコンテナサービスがあります。 今回学んだDockerの基礎知識を活かして、次はマネージドサービスの活用にチャレンジしてみてください!
最後まで読んでいただき、ありがとうございました!
圡井一磨(執筆記事の一覧)
23年度新卒入社しました。最近は自炊にはまっています。アパートのキッチンが狭くて困ってます。