目次
はじめに
簡単なECR、ECS(Fargate)の構築方法を記載して、自らの理解とどなたかの手助けになればと思い記事にしました。ビギナー向けの内容となっております。
※検証環境で作成し、既に存在しないリソースですので細部まで記載しております。
構成
パブリックサブネットに配置したALBから、ECS(ECRはプライベートリポジトリを使用)にブラウザからアクセスし、簡単なアプリと連携してRDSにデータを格納するといったコンテナ主体の構成となっております。
前提
知識を整理しておきます。
Elastic Container Registry(ECR)とは?・・・
Amazon Elastic Container Registry (Amazon ECR) は、セキュリティ、スケーラビリティ、信頼性を備えた AWS マネージドコンテナイメージレジストリサービスです。
ECRについての公式ドキュメントです。
AWS公式:Amazon Elastic Container Registry とは
Amazon Elastic Container Service(ECS)とは?・・・
Amazon Elastic Container Service (Amazon ECS) は、コンテナ化されたアプリケーションを簡単にデプロイ、管理、スケーリングできる、完全マネージド型のコンテナオーケストレーションサービスです。
ECSについての公式ドキュメントです。
AWS公式:Amazon Elastic Container Service とは
Fargateとは?・・・
AWS Fargate はAmazon ECSで使用できるテクノロジーであり、サーバーやAmazon EC2インスタンスの クラスターを管理することなくコンテナを実行できます。AWS Fargate を使用すると、コンテナを実行するために仮想マシンのクラスターをプロビジョニング、設定、スケールする必要がありません。
Fargateについての公式ドキュメントです。
AWS公式:Amazon ECS の AWS Fargate
用途等
コンテナをEC2上又はFargate上に設置する場合の利点不利点について理解しきれていない部分がありました。また、開発者からすると喜ばれるサービスでバージョンなどの環境を気にすることなく作業できるので、優れモノだなというイメージもありました。
実際構築するとミドルウェアの設定起動など工夫が必要で、サイズなどの制限があるなどEKSについても知る必要があるなと思いました。
Fargateはアプリケーションの部分のみの責任範囲(後述)となっております。
つまり、ミドルウェアやその他アプリケーション以外の部分のカスタマイズ性を考慮するとともに、規模の大小によっても判断が必要であると考えられます。
責任共有モデル
ECSを構築するにあたって、責任共有モデルについて一度確認しておきます。下表は特徴について概要を理解するために記載しております。
項目 | EC2 (IaaS) | Fargate (サーバーレス/PaaS) |
---|---|---|
カスタマイズ性 | 高い | 低い |
OS/ミドルウェア管理 | ユーザーが担当 | AWSがOSを管理、ミドルウェアはユーザーが管理 |
ユーザーの責任 | 広い | 狭い |
適したユースケース | 高度なカスタマイズや特殊要件 | 小中規模ワークロード |
細部はリンクをご覧ください。
AWS公式:責任共有モデル
AWS公式:Infrastructure as a Service (IaaS) とは何ですか?(IaaS,PaaS,SaaSの違い)
コスト
ECSを導入するにあたって気になるのがコストですね。一度確認しておきます。
※中略しているので、細部はリンクから確認が必要です。
Fargate が EC2 と比べて87%のコスト削減を実現できていることがわかります。一方、 EC2 のリソースが完全に使用されている場合、 EC2 起動タイプは 20% 以上ものコスト削減を実現
常時稼働させるサービスにおいてはEC2のコストパフォーマンスはそもそも高い。Fargateは、EC2と同じスペックであっても、常に稼働しているわけではないので数十%のコストを削減できる。
AWS公式:Infrastructure as a Service (IaaS) とは何ですか?(IaaS,PaaS,SaaSの違い)
構築
VPC
手順 | 詳細 |
---|---|
VPCを選択 | 「VPCなど」を選択し、 VPCと関連リソースを一気に作成します。 |
パブリックサブネット | 2つのパブリックサブネットを作成 |
プライベートサブネット | 2つのプライベートサブネットを作成 |
インターネットゲートウェイ | インターネットゲートウェイを作成 |
NATゲートウェイ | パブリックサブネットにNATゲートウェイを配置し、ルート設定を行います。 |
その他 | デフォルト設定を使用 |
EC2
この手順通りに構築する必要はありません。一例として記載しております。改良しちゃいましょう!
項目 | 詳細 |
---|---|
OS | Amazon Linux 2023 |
配置サブネット | パブリックサブネット |
用途 | イメージ作成用のローカルPCとして構築 |
セキュリティグループ | SSH (ポート 22, 自分のIP) |
- | HTTP (ポート 80, 0.0.0.0) |
- | カスタム TCP (ポート 5000, 0.0.0.0) |
キーペア | 指定 |
その他 | デフォルト設定で問題なし |
アプリの作成に移ります。
Pythonがインストールされているか確認します。
python3 --version
出力例:
Python 3.9.20
pipがインストールされているか確認します。
pip3 --version
初期ではインストールされていないので、インストールしていきます。
sudo dnf install python3-pip -y
インストール完了を確認します。
pip3 --version
出力例
pip 21.3.1 from /usr/lib/python3.9/site-packages/pip (python 3.9)
Flaskがインストールされているか確認します。
pip3 show Flask
初期ではインストールされていないので、インストールします。
pip3 install Flask
インストールされたか確認します。
pip3 show Flask
出力例
Name: Flask
Version: 3.1.0
Summary: A simple framework for building complex web applications.
Home-page:
Author:
Author-email:
License:
Location: /home/ec2-user/.local/lib/python3.9/site-packages
Requires: blinker, click, importlib-metadata, itsdangerous, Jinja2, Werkzeug
Required-by:
MySQLクライアントをセットアップします。
インストールされているか確認します。
mysql --version
出力例
-bash: mysql: command not found
リポジトリをインストールします。
sudo dnf -y localinstall https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm
リポジトリが有効化されているか確認します。
sudo dnf repolist enabled | grep mysql
出力例
mysql-connectors-community MySQL Connectors Community
mysql-tools-community MySQL Tools Community
mysql80-community MySQL 8.0 Community Server
MySQLにGPGキーをインストールします(古い場合は任意にカスタマイズしましょう。)。
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023
MySQLクライアントをインストールします。
sudo dnf -y install mysql mysql-community-client
インストールされたことを確認します。
mysql --version
出力例
mysql Ver 8.0.41 for Linux on x86_64 (MySQL Community Server - GPL)
クライアントのみ構築して進めます。
Dockerをインストールします。
sudo dnf install -y docker
デーモンを起動します。
sudo systemctl start docker
自動起動を有効にします。
sudo systemctl enable docker
出力例
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
ステータスを確認しておきます。
sudo systemctl status docker
active (running)を確認しておきます。
バージョンも確認しておきます。
docker --version
出力例
Docker version 25.0.5, build 5dc9bcc
RDS
Aurora(MySQL)の場合は、RDSに比べてバージョン指定が異なる点や事前に決めることが多いものの基本的には以降の手順から構築できます。
Auroraについてもっと知りたい場合はリンクをご覧ください。
Aurora (MySQL)使ってみた。
手順 | 詳細 |
---|---|
標準作成 | - |
エンジンタイプ | MySQLを選択 |
バージョン | デフォルトのMySQL 8.0.40を選択 |
利用枠 | 無料利用枠 |
DBインスタンス識別子 | fargate |
パスワード | 任意 |
インスタンスタイプ | db.t3.micro |
ストレージ | gp3でストレージ20で進める |
EC2接続 | EC2コンピューティングリソースに接続しない |
VPC | 作成したVPCを使用 |
パブリックアクセス | なし |
セキュリティグループ | デフォルトのセキュリティグループを外し、作成したセキュリティグループを適用 |
最初のデータベース名 | fargate |
EC2からRDSへ接続
接続してみます。
mysql -h <RDSインスタンスのエンドポイント> -P 3306 -u <ユーザー名> -p
アクセスできたことを確認し、テーブルとカラムを作成します。
データベースを選択します。
USE fargate;
test_tableというテーブル及びnameというカラム(文字列)を作成します。
CREATE TABLE test_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255)
);
Query OKの出力を確認します。
そしてテーブルが作成されたか確認しておきます。
SHOW TABLES;
出力例
+-------------------+
| Tables_in_fargate |
+-------------------+
| test_table |
+-------------------+
1 row in set (0.00 sec)
次に、カラムが作成されたことを確認します。
DESCRIBE test_table;
出力例
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
ターゲットグループ
手順 | 詳細 |
---|---|
セキュリティグループ | HTTP (ポート 80) 、 カスタム TCP (ポート 5000) を開ける |
ターゲットタイプ | 「IPアドレス」 |
プロトコル及びポート | HTTP (ポート 5000) |
HTTPのバージョン | HTTP1 |
ヘルスチェック | デフォルト |
ターゲット登録画面 | 設定せずに進める(以降で自動的にコンテナを指すようになる) |
ポート(ターゲットへのルーティング) | 5000 |
ALB
手順 | 詳細 |
---|---|
スキーム | インターネット向け |
ターゲット | 先程作成したターゲットグループを設定 |
リスナー | HTTPS及びHTTPを作成し、HTTPSへリダイレクトするように設定 |
ポート | 5000番でターゲットにアクセスするように設定 |
ディレクトリ構成
作成するディレクトリ構成を確認しておきます。
Amazon Linux 2023内でイメージを作成してコンテナを作成していきます。
ざっと確認します。
/my-flask-app
├── app.py
├── Dockerfile
├── requirements.txt
└── templates
└ index.html
HTML
簡単なフロントを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Submit Name</title>
</head>
<body>
<h1>Submit Your Name</h1>
<form action="/submit" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<button type="submit">Submit</button>
</form>
</body>
</html>
Python
from flask import Flask, request, render_template, redirect, url_for
import pymysql
app = Flask(__name__)
# RDSの接続情報を入力します
DB_HOST = 'your-rds-endpoint'
DB_USER = 'your-username'
DB_PASSWORD = 'your-password'
DB_NAME = 'fargate'
TABLE_NAME = 'test_table'
def get_db_connection():
try:
return pymysql.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASSWORD,
db=DB_NAME,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
except pymysql.MySQLError as e:
logging.error(f"Error connecting to the database: {e}")
return None
@app.route('/')
def index():
return render_template('index.html')
@app.route('/submit', methods=['POST'])
def submit():
name = request.form['name']
conn = get_db_connection()
if conn is None:
return "Failed to connect to the database.", 500
try:
with conn.cursor() as cursor:
sql = f"INSERT INTO {TABLE_NAME} (name) VALUES (%s)"
cursor.execute(sql, (name,))
conn.commit()
except pymysql.MySQLError as e:
logging.error(f"Error executing query: {e}")
return "An error occurred while inserting the data.", 500
finally:
conn.close()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Dockerfile
FROM python:3.9.20-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
RUN apt-get update && apt-get install -y default-mysql-client
COPY . .
CMD ["python3", "app.py"]
requirements.txt
Flask
pymysql
ECR
手順 | 詳細 |
---|---|
リポジトリ | プライベートリポジトリ |
リポジトリ名 | 任意 |
プッシュコマンド | コンソールに表示されているコマンド |
認証トークンを取得し、レジストリに対してDockerクライアントを認証します。
AWS CLIの設定を確認しておきましょう。
また、以降はroot権限(sudo su)に移行してコマンドを実行していきます。
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <your_ID>.dkr.ecr.us-east-1.amazonaws.com
Login Succeededを確認して進めます。
ビルドします。
docker build -t fargate .
イメージが作成できたか確認します。
docker images
出力例
REPOSITORY TAG IMAGE ID CREATED SIZE
fargate latest b0c627697f77 13 seconds ago 137MB
ここでコンテナが意図するように起動するか確認してみます。
docker run -d -p 5000:5000 fargate
プロセスが存在するか確認します。
docker ps
htmlファイルが表示されているか確認します。
curl http://localhost:5000
出力例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Submit Name</title>
</head>
<body>
<h1>Submit Your Name</h1>
<form action="/submit" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<button type="submit">Submit</button>
</form>
</body>
コンテナを停止させておきましょう。
IDを確認します。
docker ps
表示されたIDを使用して停止させます。数秒かかります。
docker stop <コンテナID>
停止したか確認します。
docker ps
プロセスが表示されていないことを確認します。
次に早速、プッシュする準備を行っていきます。
イメージをプッシュできるようにタグ付けを行います。
docker tag fargate:latest <your_ID>.dkr.ecr.us-east-1.amazonaws.com/fargate:latest
イメージをプッシュします。
docker push <your_ID>.dkr.ecr.us-east-1.amazonaws.com/fargate:latest
ECS
手順 | 詳細 |
---|---|
セキュリティグループ | カスタムTCP (ポート 5000, ソース:ALBのセキュリティグループ) を許可 |
- | HTTP (ポート 80, ソース:ALBのセキュリティグループ) を許可 |
- | MySQL(ポート3306,ソース:RDSのセキュリティグループ)を許可 |
手順 | 詳細 |
---|---|
タスク定義 | コンソールで作成 |
OS | Linux/X86_64 |
スペック | CPU、メモリは最小(任意) |
タスクロール、実行ロール | ecsTaskExecutionRole |
コンテナ名 | fargate |
イメージURI | ECRコンソールからコピーペースト |
コンテナポート | 5000番 |
プロトコル | TCP |
ポート名 | 空欄(任意) |
アプリケーションプロトコル | http |
モニタリング | メトリクス収集を推奨 |
その他 | デフォルト設定を使用 |
手順 | 詳細 |
---|---|
デプロイボタン | 「サービスの作成」 |
クラスター作成 | - |
インフラストラクチャ | AWS Fargate |
モニタリング(オプション) | Container Insights(任意) |
暗号化(オプション) | KMS暗号化なし(任意) |
コンピューティングオプション | 起動タイプを選択 |
タスク数 | 任意 |
AZの配置 | 自動配置 |
デプロイサーキットブレーカー | 有効 |
ネットワーキング | 該当のVPC |
サブネット | プライベートサブネット |
パブリックIP | 無効 |
ロードバランシング | 既存のALB、リスナーを指定 |
動作確認
ブラウザから検索すると次のようにアプリが起動します。
適当な文字列を入力してSubmitします。
アプリ起動例:
Amazon Linux 2023(ローカル)からMySQLに接続してデータが格納されたか確認します。
mysql -h <RDS_endpoint> -P 3306 -u <user> -p
データベースを選択します。
USE fargate;
レコードを見てみます。
SELECT * FROM test_table;
出力例
+----+-------+
| id | name |
+----+-------+
| 1 | keiji |
+----+-------+
1 row in set (0.00 sec)
おわりに
最後まで読んでいただきありがとうございます。
冒頭にも記載しましたが、ECSを学んだ後はEKSを学習することで理解が深まるなと思いました。
では!
1つずつ誠実に取り組み、技術を身に着けて発信も併せて行っていきます!