昨天透過 Session Manager 連進 EC2,也成功跑出了 Hello from Docker!。今天就來把前幾天做的 Next.js Image 搬上去ㄅ!
昨天我們從 Docker Hub 拉過 hello-world,而今天是把自己做的 image 放進 Amazon ECR(Elastic Container Registry)。它是 AWS 提供的放 Image 倉庫。
而今天會比較複雜一點,會再多個平台間進行切換:
123456789012.dkr.ecr.ap-east-2.amazonaws.com/<repo 名稱><repo 名稱> 是 repository 名稱,後面再加 :v1,才是今天要使用的 image 名稱與 tag。接著來到自己電腦的終端機,我是 mac 。
aws --version
docker version
aws sts get-caller-identity --region ap-east-2
這邊要檢查一下帳號是否和剛才建立 ECR 的 AWS 帳號相同
2. 接著進到 Day9 專案根目錄,也就是有 Dockerfile 的地方;若你的路徑不同,換成自己的:
cd ~/ironman-lab/day09/my-app
docker buildx build --platform linux/amd64 --load -t my-app:day13 .
linux/amd64。arm64 image,單純改 tag 不會把它轉成 amd64。--load,是把建置結果載入本機 Docker,讓 docker tag 和 docker push 能使用;my-app:day13 則是本機標籤。docker image inspect my-app:day13 --format '{{.Os}}/{{.Architecture}}'

我們把 image 做好了,但它還是在我們的電腦裡,現在要把它 push 到 ECR 上才能讓機器使用
ECR_REGION=ap-east-2
ECR_ACCOUNT_ID=$(aws sts get-caller-identity --region "$ECR_REGION" --query Account --output text)
ECR_REGISTRY="${ECR_ACCOUNT_ID}.dkr.ecr.${ECR_REGION}.amazonaws.com"
ECR_IMAGE="${ECR_REGISTRY}/<repo 名稱>:v1"
ECR_ACCOUNT_ID 從目前 CLI 身分取得帳號 IDECR_IMAGE 就是完整的 image 位址aws ecr get-login-password --region "$ECR_REGION" \
| docker login --username AWS --password-stdin "$ECR_REGISTRY"
這裡分成兩段:
| 交給 Docker。--username AWS 的 AWS 是固定寫法,不用換成 IAM 使用者名稱。Login Succeeded,這次登入是進到 registry,所以後面沒有 /my-app。docker tag my-app:day13 "$ECR_IMAGE"
docker push "$ECR_IMAGE"
docker tag 只是替同一份 image 增加名稱,真正上傳的是 docker push。my-app repository 重新整理,應該會找到 tag 為 v1 的 image。
昨天的角色(role)只有 Systems Manager 所需權限,現在要加上 ECR 權限。
AmazonEC2ContainerRegistryPullOnly並打勾建立AmazonEC2ContainerRegistryPullOnly 提供拉取 image 所需的權限,不包含一般 image push 所需的上傳權限*,並沒有只限定 my-app。之後要限制到特定 repository,可以再改成自訂 policy。目前我們就把工作分開了:
回到 EC2 頁面,用昨天的 Connect → Session Manager 連進去
aws --version
sudo systemctl is-active docker
aws sts get-caller-identity --region ap-east-2
看到顯示:
aws-cli/2.33.15 Python/3.9.25 Linux/6.18.48-109.150.amzn2023.x86_64 source/x86_64.amzn.2023
active
{
"UserId": "...:...",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/role 名稱/..."
}
就表示成功了!
active;若尚未啟動用 sudo systemctl start docker 來啟動。Arn 包含 assumed-role/role 名稱/,表示 EC2 正在使用我們設定的 roleaws configure 輸入長期 access key。ECR_REGION=ap-east-2
ECR_ACCOUNT_ID=$(aws sts get-caller-identity --region "$ECR_REGION" --query Account --output text)
ECR_REGISTRY="${ECR_ACCOUNT_ID}.dkr.ecr.${ECR_REGION}.amazonaws.com"
ECR_IMAGE="${ECR_REGISTRY}/<repo 名稱>:v1"
aws ecr get-login-password --region "$ECR_REGION" \
| sudo docker login --username AWS --password-stdin "$ECR_REGISTRY"
sudo docker pull "$ECR_IMAGE"
我們一樣習慣在 Docker 指令都加 sudo,包含 docker login。Docker 的登入設定依使用者儲存;如果用一般使用者登入,卻用 sudo docker pull 拉取,可能會讀到不同的設定,出現 no basic auth credentials。
sudo docker run -d \
--name my-app \
--restart unless-stopped \
-p 80:3000 \
"$ECR_IMAGE"
前面用過 -d,表示讓容器在背景執行。今天多注意兩個設定:
--restart unless-stopped:設定容器重新啟動的策略。搭配昨天 Docker 的開機啟動設定,讓原本執行中的容器能在 Docker 重啟後恢復;如果自己手動停止容器,就需要手動啟動。-p 80:3000:把 EC2 的 TCP 80 對應到 容器的 TCP 3000。對外連線用 80,Next.js 在容器裡仍使用 3000。HOSTNAME=0.0.0.0,讓 Next.js 接受容器網路介面的連線sudo docker ps --filter name=my-app
sudo docker logs --tail 50 my-app
curl --fail --silent --show-error --output /dev/null --write-out '%{http_code}\n' http://127.0.0.1
回傳 200表示 Next.js 首頁有成功起來了!但它還不能證明外面的瀏覽器連得進來。
這裡的 127.0.0.1 指的是 EC2 本機,可以先確認容器和 port mapping 有正常工作。
之前我們把 Security Group 的 inbound rules 留空,現在終於有網站可以開放了!
HTTP
IP 會填入目前電腦對外的公網 IPv4,通常是 /32
http://你的-EC2-公網-IPv4
http://,這台主機還沒設定 HTTPS。:3000
今天終於把 Next.js 搬上 EC2 了!也把之前幾篇文章終於接在一起了。
目前我們是透過公網 IP 和 HTTP 存取,也只開放自己的來源 IP。接下來,就來處理固定 IP、網域和 HTTPS,讓這個網站一步步變成可以正式分享的樣子ㄅ!