はじめに
2021年に発行された「AWSコンテナ設計・構築[本格]入門」をみなさん手に取られたことはありますでしょうか。
概要や考え方から始まり、ハンズオンで基本的な構築、応用編まで1冊にまとまっていて、コンテナ入門の良書だと思います。私はよく忘れるので、何度も読み返してきた本になります。
ただ、発行されて4年近くが経過していますので、その間にAWSの環境等も変わり、本書に記載の通りに実施できない部分もいくつか出てきていました。入門書としてハンズオンを実施しようとした際にうまくできなくて躓いてしまう方もいらっしゃるのではないかと思います。
かくいう私も、先日、自宅のIntel PCが旅立ってしまい、AWSアカウントも心機一転準備して、再度同様の環境を準備しようとしたところ、色々と躓きました。発行後にGithubに追加された情報、本書のサポートページに掲載された情報もありますが、私自身の備忘のため、残しておきます。
GitHub
(参考)私の実行環境
参考までに今回実施した時の私の場合は以下の環境です。
m1 mac
nvm v22.14.0
yarn 1.22.22
※私はus-east-1で実施したのですが、本書に記載のハンズオンはap-northeast-1になっています。
一通り、書き換えて記載したつもりですが、残っていたら読み替えていただければと思います。
躓いたところなど
以下に記載していきます。
順不同なところがあるかもしれませんがご了承ください。
Cloud9が使えない
本書のハンズオンはCloud9上でのGit操作等がメインで進みます。
ただ、新たに作ったAWSアカウントではCloud9にはもう逢えません。Cloud9、あなたのことはずっと忘れないよ。
ということで、私はローカル環境のIDE(VScode)で実施しました。
ローカルで実行しますので、4章に記載のCloud9用IAMロール、Cloud9のストレージのリサイズはスキップしました。
nvmやyarnのインストールがありますが、ローカルでインストール済みのバージョンで進めることにしました。
(nvmの古いバージョンですと、arm系のmacには対応していないのではないかと思い、現状のバージョンで実施しました)
CPUのアーキテクチャを意識
arm系macでビルドする場合、CPUのアーキテクチャを意識する必要がありました。
そのままビルドすると、arm64アーキテクチャでビルドされてしまうため、docker runをした際にエラーになることがあります。
例えば以下のような形で、ビルド時にプラットフォームを指定しました。
バックエンドコンテナのビルド(P241)
docker image build -t sbcntr-backend . --platform linux/amd64
フロントエンドコンテナのビルド(P245)
docker image build -t sbcntr-frontend . --platform linux/amd64
ビルド時の実行時間が長くなるのは我慢が必要です。
私の環境ではフロントエンドコンテナのビルドは約8分/回かかりました。
踏み台コンテナを準備
Cloud9が使えないため、5章で紹介されている踏み台用コンテナを使ってDBへアクセスして、構築しました。
実施したのは以下の流れです。
1. ECRでリポジトリ sbcntr-base
を作成 (P217を参考)
・alpineイメージを取得、ECRへ格納
docker image pull golang:1.16.8-alpine3.13
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\n"
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
aws ecr --region ap-northeast-1 get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-base
docker image tag golang:1.16.8-alpine3.13 ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-base:base:golang1.16.8-alpine3.13
docker image push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-base:golang1.16.8-alpine3.13
2. Fargate Bastionを作成(P408からP422を実施)
本書に記載の流れで踏み台コンテナを作成
3. Session Manager Pluginをインストール(macOS)
インストール済みでしたら、読み飛ばしてください。
Session Manager Pluginをダウンロード
# インストールスクリプトをダウンロード
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
# ンストールスクリプトを解凍
unzip sessionmanager-bundle.zip
# インストールスクリプトを実行
sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
# インストールの確認
session-manager-plugin --version
# バージョン情報が表示されれば、インストールは成功です。
4. ssmで接続
以下のコマンドでSSMを使用してBastionコンテナに接続し、ポートフォワードでAurora MySQLへ接続できました。
mi-XXXXXXXXXXXXXXXXX
は、Sesion Managerで確認できるコンテナインスタンスのインスタンスIDです。
sbcntr-db.cluster-XXXXXXXXXXXX.ap-northeast-1.rds.amazonaws.com
はMySQLのライターインスタンスのエンドポイントです。
aws ssm start-session --target mi-XXXXXXXXXXXXXXXXX --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"portNumber":["3306"],"localPortNumber":["3306"],"host":["sbcntr-db.cluster-XXXXXXXXXXXX.ap-northeast-1.rds.amazonaws.com"]}'
この状態で別ターミナルを起動し、MySQLにセッションが接続できることを確認します。
mysql -h 127.0.0.1 --port 3306 -u admin -p
※MySQL Clientがインストールされていない場合は、別途インストールをしてください。
(参考)
# MySQLクライアントのみをインストール
brew install mysql-client
# パスを通す
echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# バージョン確認
mysql --version
mysql Ver 9.3.0 for macos14.7 on x86_64 (Homebrew)
MySQL接続後はP309からのユーザー作成を実施します。
Blitz.jsのmigrateコマンドがうまく動かない(P311)
バージョンや依存関係の問題でうまく動かせませんでした。少々試してみたのですが私のスキルではスッキリ解決できず、Amazon Q Developer for CLIに相談したら、純粋なJavaScriptファイルを作成し、それを直接Node.jsで実行することを提案してくれたので、そちらで回避しました。
./sbcntr-frontend/にて以下のコマンドを実施してrun-seeds.jsを作成
# run-seeds.jsファイルを作成
cat > run-seeds.js << EOF
const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
async function addItems() {
// Flower
await prisma.item.create({
data: {
name: "Flower",
title: "Flower",
favorite: true,
img: "/flower-park.jpeg",
updatedAt: new Date(),
},
});
// Apple
await prisma.item.create({
data: {
name: "Apple",
title: "My apple",
favorite: false,
img: "/apple.jpeg",
updatedAt: new Date(),
},
});
// Goods
await prisma.item.create({
data: {
name: "Goods",
title: "My goods",
favorite: false,
img: "/goods.jpeg",
updatedAt: new Date(),
},
});
// Dice
await prisma.item.create({
data: {
name: "Dice",
title: "Cool dices",
favorite: true,
img: "/dice.jpeg",
updatedAt: new Date(),
},
});
// Darts
await prisma.item.create({
data: {
name: "Darts",
title: "Antique darts board",
favorite: false,
img: "/darts.jpeg",
updatedAt: new Date(),
},
});
}
async function addNotifications() {
for (let i = 0; i < 2; i++) {
await prisma.notification.create({
data: {
title: \`通知\${i + 1}\`,
description: "コンテナアプリケーションの作成の時間です。",
category: "information",
updatedAt: new Date(),
},
});
}
}
async function main() {
try {
// アイテムを追加(既存のアイテムを削除)
await prisma.item.deleteMany({})
await addItems()
console.log("Added items")
// 通知を追加(既存の通知を削除)
await prisma.notification.deleteMany({})
await addNotifications()
console.log("Added notifications")
console.log("Seed data inserted successfully!")
} catch (error) {
console.error("Error seeding database:", error)
throw error
}
}
main()
.catch(e => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.\$disconnect()
})
EOF
package.jsonの書き換え
続いて、./sbcntr-frontend/package.json
の13行目
"seed": "npx blitz db seed"
を以下に書き換えました。
"seed": "node run-seeds.js"
(参考)シンプルにSQLクエリ実行
seedの中身をみましたが、私のレベルだと、シンプルにMySQLで接続してクエリを実行する方法が一番早いと思いました。。
クエリにするなら以下の流れになると思います。
# MySQLに接続
mysql -h 127.0.0.1 -P 3306 -u sbcntruser -p
# Itemテーブルにデータを挿入
INSERT INTO Item (name, title, favorite, img, createdAt, updatedAt) VALUES
('Flower', 'Flower', 1, '/flower-park.jpeg', NOW(), NOW()),
('Apple', 'My apple', 0, '/apple.jpeg', NOW(), NOW()),
('Goods', 'My goods', 0, '/goods.jpeg', NOW(), NOW()),
('Dice', 'Cool dices', 1, '/dice.jpeg', NOW(), NOW()),
('Darts', 'Antique darts board', 0, '/darts.jpeg', NOW(), NOW());
# Notificationテーブルにデータを挿入
INSERT INTO Notification (title, description, category, unread, createdAt, updatedAt) VALUES
('通知1', 'コンテナアプリケーションの作成の時間です。', 'information', 1, NOW(), NOW()),
('通知2', 'コンテナアプリケーションの作成の時間です。', 'information', 1, NOW(), NOW());
# 接続を終了
exit;
CodeCommitが使えない(P338)
本書ではリポジトリにCodeCommitを使用していますが、CodeCommitが新規アカウントでは使えないということもあり、今回はGithubと連携して使いました。
GitHub連携
CodePipelineサービスに移動
左側のナビゲーションペインから「設定」→「接続」を選択
接続を作成
を選択して、接続を作成する
画面に遷移します。
プロバイダーはGitGitHub
を選択し、接続名はgithub-connection
を入力して、GitHubに接続する
をクリックします。
GitHubのサインイン画面が出てきますので、サインインします。
マネコンに戻ってきますので、新しいアプリをインストールする
を選択して、改めてGitHubページに遷移します。
AWS Connector for GitHubのアクセスを許可すると、マネコンに戻ります。
アプリインストールの項目に値が入っているので、接続をクリックします。
コネクションが作成できました。これでCodePipelineのパイプラインから指定できるようになります。
あとはGitHubでリポジトリを作成していけば進められます。
リポジトリ接続( P340)
codecommitの代わりにGitHubのリポジトリURLを指定します。
git remote set-url origin https://github.com/xxxxxxx/sbcntr-backend.git
buildspec.ymlの作成(P341)
buildspec.ymlで10-12行目を、コメントアウトしました。
現在、ランタイムとしてDockerは指定できないようです。
version: 0.2
env:
variables:
AWS_REGION_NAME: ap-northeast-1
ECR_REPOSITORY_NAME: sbcntr-backend
DOCKER_BUILDKIT: "1"
phases:
#install: #ここをコメントアウト
# runtime-versions:
# docker: 19
pre_build:
commands:
- AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
- aws ecr --region ap-northeast-1 get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-backend
- REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com/${ECR_REPOSITORY_NAME}
# タグ名にGitのコミットハッシュを利用
- IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7)
build:
commands:
- docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} .
post_build:
commands:
- docker image push ${REPOSITORY_URI}:${IMAGE_TAG}
- printf '{"name":"%s","ImageURI":"%s"}' $ECR_REPOSITORY_NAME $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
artifacts:
files:
- imageDetail.json
codebuildのソース設定 (P344)
GitHubを選択して、先ほど作成したConnectionsやリポジトリを指定します。
taskdef.jsonの作成(P354)
ECSのタスク定義からJSONファイルをコピーして作成しますが、以下2点にご注意ください。
本文に記載のある<IMAGE1_NAME>
に書き換える
コピペした段階だと、"image": "xxxxxxxxxxxx.dkr.ecr.ap-northeast-1:.amazonaws.com/sbcntr-backend:0000000",
のような名称になっています。
最後の"tags": []
を消す。
記載を残しているとタグは空にできないため、エラーになります。
codepipelineのソースステージの設定(P359)
GitHub用に設定しました。
アクションプロバイダーはGitHub(GitHubアプリ経由)
を選択
接続は先ほど作成したConnectionを選択
リポジトリ名は自分のリポジトリを指定します。
まとめ
いかがでしたでしょうか。CloudFormationでIaC化したコードを上げてしまうこともできますが、やはり最初は手を動かして流れを把握する方が有用と考えているため、敢えてIaCは載せずにおきます。
環境が必ずしも一致しないため、上に記載した内容でうまくいかない部分もあると思います。クラウドサービスの移り変わりは早いので、過去に出版されている本のハンズオンを完全には再現できないことがよくあります。(私はよくハマります)その際は、お近くのつよつよエンジニアに相談するか、Amazon Q Developer for CLIのAIエージェント機能に相談しながら進めていくと良いのではないかと思います。
2025年に初めて本書を手に取ってコンテナに入門しようとするどなたかの一助になれば幸いです。