【ハンズオン風】Docker on EC2でWebページをホストする【やってみた】

記事タイトルとURLをコピーする

概要

この記事では 「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系インスタンス(例:t4g.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>

ブラウザからアクセスすると、以下のような画面が表示されます。

パブリックからWebページの確認

DockerイメージのECR管理

現在作成したDockerイメージはEC2内にのみ存在しています。本格的な運用では、イメージを一元管理できるコンテナレジストリの活用が重要です。

AWSではElastic Container Registry(ECR)というマネージドコンテナレジストリサービスを提供しています。

本ブログの最後はDockerイメージをECRにプッシュ(アップロード)してみましょう!

ECRのコスト

事前にコストを確認しておきます。

参考:Amazon 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リポジトリの作成

ECRコンソールのRepositoriesページにアクセス

「リポジトリを作成」をクリック

項目 設定値
リポジトリ名 hello-world

「作成」を押下します。

ECRへのイメージプッシュ

プッシュコマンドの取得

  1. 作成した「hello-world」リポジトリを選択
  2. 「プッシュコマンドを表示」をクリック
  3. 表示されたコマンドに従って実行

実際の手順

# 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

以下のようにアップロードされているはずです。

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年度新卒入社しました。最近は自炊にはまっています。アパートのキッチンが狭くて困ってます。