Docker入門から実践へ!ECSでコンテナアプリケーションを動かす
こんにちは!現役エンジニアのAkrです。
「【AWSプロフェッショナルへの道】現役エンジニアが贈るクラウド実践ガイド」の第13回をお届けします。前回はSQSとSNSでメッセージングの基本を学び、疎結合システムの設計に不可欠なスキルを身につけましたね。これで、システムの耐障害性とスケーラビリティが大きく向上しました。
今回から、クラウドネイティブなアプリケーション開発に欠かせない技術「コンテナ」に焦点を当てます。特に、コンテナ技術のデファクトスタンダードであるDockerの基本から、AWSでコンテナを動かすためのマネージドサービスであるECS (Elastic Container Service) の実践までを徹底的に解説します。
「コンテナって何?」「なぜ必要なの?」といった疑問を持つかもしれません。コンテナは、アプリケーションとその実行に必要なすべての環境を1つのパッケージにまとめることで、どこでも同じように動作することを保証する技術です。本記事では、Dockerの基本概念から、ECSでのコンテナデプロイまでの流れを網羅的に学び、現代的なアプリケーション開発スキルを身につけます。
1. コンテナとは?Dockerの基本
コンテナは、アプリケーションとその依存関係(ライブラリ、設定ファイルなど)をすべて含んだ、軽量で独立した実行環境です。OSを丸ごと仮想化する従来の仮想マシン(VM)と異なり、ホストOSのカーネルを共有するため、より高速に起動し、リソース効率も高いのが特徴です。
コンテナが解決する課題
-
「私の環境では動くのに...」問題の解決:
- 開発環境、テスト環境、本番環境でOSやライブラリのバージョンが異なり、動作が変わってしまう問題を解決します。コンテナイメージは「どこでも同じように動く」ことを保証します。
-
環境構築の標準化と効率化:
- 新しい開発者がプロジェクトに参加した際、複雑な環境構築に何時間も費やす必要がなくなります。
docker run
コマンド一つで、すぐに開発を始められます。
- 新しい開発者がプロジェクトに参加した際、複雑な環境構築に何時間も費やす必要がなくなります。
-
リソースの効率的な利用:
- VMのようにOSのオーバーヘッドがないため、より多くのアプリケーションを1台のサーバーで実行できます。
Dockerの主要な構成要素
-
Dockerfile:
- コンテナイメージを作成するための設計図です。
- どのベースイメージを使うか、どのファイルをコンテナにコピーするか、どのようなコマンドを実行するかなどを記述します。
-
Docker Image:
- Dockerfileからビルドされた、アプリケーションの実行に必要なすべての情報(コード、ランタイム、システムツールなど)をまとめた読み取り専用のテンプレートです。
-
Docker Container:
- Docker Imageを実行したインスタンスです。
- イメージは静的ですが、コンテナは動的に実行されるプロセスです。
2. AWSでコンテナを動かすためのサービス群
AWSでは、コンテナを管理・実行するための様々なサービスが提供されています。
-
Amazon ECR (Elastic Container Registry):
- Dockerイメージを保存、管理するためのプライベートなコンテナレジストリです。
- Docker Hubのような公開レジストリではなく、ECRにイメージをプッシュすることで、セキュリティが確保された状態でAWSサービスと連携できます。
-
Amazon ECS (Elastic Container Service):
- コンテナ化されたアプリケーションを簡単にデプロイ、管理、スケーリングできるコンテナオーケストレーションサービスです。
- コンテナの配置やヘルスチェック、スケーリングなどを自動化してくれます。
-
Amazon EKS (Elastic Kubernetes Service):
- KubernetesをAWS上で実行するためのマネージドサービスです。Kubernetesの深い知識がある場合に選択されます。
-
AWS Fargate:
- サーバーレスのコンテナ実行環境です。EC2インスタンス(サーバー)を管理する必要なく、コンテナを実行できます。ECSとEKSの両方で利用可能です。
-
Amazon ECS on EC2:
- 自分でEC2インスタンスを管理して、その上でコンテナを実行するモードです。より細かい制御が必要な場合に利用されます。
今回は、最もAWSのサービスと親和性が高いECSに焦点を当て、ECRと連携してコンテナアプリケーションをデプロイする一連の流れを学びます。
3. 実践!DockerとECR/ECSを使ってWebアプリケーションをデプロイしよう
それでは、Dockerコンテナイメージを作成し、ECRにプッシュ、そしてECSでコンテナとして実行するまでの手順を実践しましょう。今回は、シンプルなNode.jsのWebサーバーを例にします。
3.1. DockerfileとWebアプリケーションの準備
まず、コンテナ化するWebアプリケーションとDockerfileを作成します。
-
作業ディレクトリを作成し、移動します。
mkdir my-ecs-app cd my-ecs-app
-
index.js
というファイルを作成し、以下の内容を記述します。// index.js const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('<h1>Hello from ECS!</h1>'); }); app.listen(port, () => { console.log(`App listening at http://localhost:${port}`); });
-
package.json
ファイルを作成します。{ "name": "my-ecs-app", "version": "1.0.0", "description": "Simple Express app for ECS", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "express": "^4.17.1" } }
-
Dockerfile
を作成し、以下の内容を記述します。# Dockerfile # Node.jsの公式イメージをベースとして使用 FROM node:18-alpine # コンテナ内の作業ディレクトリを設定 WORKDIR /app # package.jsonとpackage-lock.jsonをコンテナにコピー COPY package*.json ./ # アプリケーションの依存関係をインストール RUN npm install # アプリケーションのコードをコンテナにコピー COPY . . # アプリケーションがリッスンするポートを公開 EXPOSE 3000 # アプリケーションを起動するコマンド CMD [ "npm", "start" ]
- このDockerfileは、Node.jsの軽量な
alpine
イメージをベースに、依存関係をインストールし、アプリケーションを起動するまでの一連の手順を定義しています。
- このDockerfileは、Node.jsの軽量な
3.2. Dockerイメージのビルドとテスト
作成したDockerfileを使って、ローカルでDockerイメージをビルドし、コンテナを起動して動作を確認します。
-
Dockerイメージをビルドします。
docker build -t my-ecs-app:latest .
-
-t
オプションでmy-ecs-app:latest
という名前とタグを付けます。
-
-
ビルドしたイメージからコンテナを起動します。
docker run -p 8080:3000 --name my-web-container my-ecs-app:latest
-
-p
オプションでホストの8080ポートをコンテナの3000ポートにマッピングします。
-
-
Webブラウザで
http://localhost:8080
にアクセスし、Hello from ECS!
と表示されれば成功です。 -
動作確認後、
Ctrl+C
でコンテナを停止し、docker rm my-web-container
で削除しておきましょう。
3.3. ECRリポジトリの作成とDockerイメージのプッシュ
次に、作成したDockerイメージをECRに保存します。
-
AWSマネジメントコンソールにサインインし、「ECR」サービスに移動します。
-
「リポジトリの作成」をクリックします。
-
可視性設定: 「プライベート」を選択します。
-
リポジトリ名:
my-ecs-app-repo
-
「リポジトリの作成」をクリック。
-
作成したリポジトリ(
my-ecs-app-repo
)を選択し、「プッシュコマンドの表示」をクリックします。 -
表示されたコマンドを順番に実行します。(AWS CLIが設定済みである必要があります)
- ログインコマンド (
aws ecr get-login-password | docker login --username AWS --password-stdin ...
) - ビルドコマンド (
docker build -t my-ecs-app:latest .
) - タグ付けコマンド (
docker tag my-ecs-app:latest ...
) - プッシュコマンド (
docker push ...
)
これらのコマンドを実行すると、ローカルのDockerイメージがECRリポジトリにアップロードされます。
- ログインコマンド (
3.4. ECSクラスターとタスク定義の作成
ECSでコンテナを実行するための環境を構築します。
-
AWSマネジメントコンソールで「ECS」サービスに移動します。
-
左のナビゲーションペインから「クラスター」を選択し、「クラスターの作成」をクリックします。
-
クラスター名:
my-ecs-cluster
-
インフラストラクチャ: 「AWS Fargate」を選択します。(サーバー管理が不要なため、学習には最適です)
-
「作成」をクリック。
-
次に、コンテナの実行方法を定義するタスク定義を作成します。
-
左のナビゲーションペインから「タスク定義」を選択し、「新しいタスク定義の作成」をクリックします。
-
タスク定義名:
my-ecs-app-task-definition
-
コンテナ:
- 「コンテナの追加」をクリックします。
-
コンテナ名:
my-ecs-app-container
-
イメージURI: ECRリポジトリのURIを貼り付けます。
aws_account_id.dkr.ecr.region.amazonaws.com/my-ecs-app-repo:latest
-
ポートマッピング:
-
コンテナポート:
3000
(アプリケーションがリッスンするポート) -
プロトコル:
tcp
-
コンテナポート:
- 「追加」をクリック。
-
「作成」をクリック。
3.5. ECSサービスとELBの作成
作成したタスク定義に基づいてコンテナを起動し、トラフィックを分散させるためのサービスとELBを構築します。
- ECSコンソールで、作成したクラスター(
my-ecs-cluster
)を選択します。 - 「サービス」タブの「作成」をクリックします。
-
環境:
- 起動タイプ: 「Fargate」
- プラットフォームバージョン: 「LATEST」
-
デプロイ設定:
- アプリケーションタイプ: 「サービス」
-
タスク定義:
my-ecs-app-task-definition
-
サービス名:
my-ecs-app-service
-
タスク数:
1
(実行したいコンテナの数)
-
ネットワーキング:
- VPC: 前回までに作成したVPCを選択します。
- サブネット: パブリックサブネットを複数選択します。(ALBと連携するため)
- セキュリティグループ: 新規作成し、HTTP(80番)とコンテナポート(3000番)を許可するSGを作成します。
-
ロードバランシング:
- 「Application Load Balancer」を選択します。
-
ロードバランサー名: 「新しいロードバランサーの作成」を選択し、
my-ecs-alb
と入力します。 - リスナー: 「80:HTTP」を選択します。
-
ターゲットグループ: 「新しいターゲットグループの作成」を選択し、
my-ecs-tg
と入力します。 - 「次へ」をクリック。
-
Auto Scaling:
- 「サービスAuto Scaling」を有効にし、希望するタスク数を
1
に設定します。 - 「作成」をクリック。
- 「サービスAuto Scaling」を有効にし、希望するタスク数を
これで、ECSクラスター内にFargateでコンテナが起動され、ALBを介してアクセスできるようになります。
3.6. Webアプリケーションにアクセスしてみよう
- EC2コンソールで「ロードバランサー」を選択し、
my-ecs-alb
の「DNS名」をコピーします。 - Webブラウザで、コピーしたDNS名にアクセスします。
Hello from ECS!
と表示されれば成功です!
4. コンテナとECSのベストプラクティス
- Dockerfileの最適化: マルチステージビルドを活用してイメージサイズを小さくしたり、キャッシュを効率的に利用する順序でコマンドを配置したりしましょう。
- コンテナレジストリの活用: ECRにイメージを保存することで、セキュリティとバージョン管理を徹底しましょう。
- ECS起動タイプの選択: サーバー管理の負担を減らしたい場合はFargate、より細かくインスタンスを制御したい場合はEC2を選択しましょう。
- タスク定義の管理: タスク定義はバージョン管理され、最新版だけでなく過去のバージョンも利用可能です。CI/CDパイプラインと連携して、新しいバージョンを自動デプロイできるようにしましょう。
- タスクスケジューリングとサービス: サービスのタスク数やデプロイ設定を適切に管理し、Auto Scalingと組み合わせて負荷に応じたスケーリングを実現しましょう。
-
コンテナのセキュリティ:
root
ユーザーでコンテナを実行しない、機密情報は環境変数ではなくSecrets ManagerやSSM Parameter Storeと連携して管理するなど、コンテナセキュリティのベストプラクティスを実践しましょう。 -
ロギングとモニタリング: コンテナのログは
awslogs
ドライバを使ってCloudWatch Logsに集約し、CloudWatchでパフォーマンスメトリクスを監視しましょう。
まとめ
今回は、コンテナ技術の基本であるDockerから、AWSでのコンテナ実行環境であるECSまでを実践的に学びました。
- コンテナは、アプリケーションとその実行環境を一つのパッケージにまとめ、環境差を吸収する強力な技術です。
- Dockerを使ってDockerfileからイメージをビルドし、コンテナとして実行する基本を学びました。
- ECRにDockerイメージを保存し、ECSクラスター(Fargate) でタスク定義を作成し、サービスとしてコンテナをデプロイする一連の流れを実践しました。
DockerとECSを組み合わせることで、開発者はアプリケーションの実行環境の差異を気にすることなく、より効率的に開発・運用ができるようになります。これは、クラウドネイティブな開発への大きな一歩です。ぜひ、ご自身のアプリケーションをコンテナ化し、ECSで動かしてみてください。
この記事が皆さんのAWS学習の一助となれば幸いです。
もしこの記事が役に立ったと感じたら、ぜひ「いいね」👍をお願いします!励みになります!