iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Modern Web

前端來點 AWS 技能樹!系列 第 26 篇

Day26 - 網站上線之後,EC2 還有哪些事要顧?

  • 分享至 

  • xImage
  •  

從 Day11 開第一台 EC2,到昨天接上自動部署,EC2 這條路終於走完了!
不過網站上線不是結束。Server 是我們自己的,壞掉了不會有人通知我們,也不會自己更新成新版本。今天整理一份上線之後的檢查清單,分成 logs、監控、安全和費用四個部分,每一項都附上我的 side project 實際的狀況,順便看看我自己漏了哪些ㄅ!

出事的時候,去哪裡看 logs?

網站出問題時,最怕的是不知道該從哪裡查起。先把這張表記下來:

想知道的事 去哪裡看 保留多久
部署有沒有成功、卡在哪一步 GitHub repo 的 Actions Tab 預設 90 天
EC2 收到了哪些指令、印出了什麼 Systems Manager 的 Run Command,Command history Tab 30 天
Next.js 有沒有報錯 EC2 上的 sudo docker logs --tail 100 my-app 到 container 被刪掉為止
Caddy 或憑證有沒有問題 EC2 上的 sudo journalctl -u caddy --since "1 hour ago" 到 journald 的空間用完為止,滿了會刪最舊的
誰在 AWS 上改了什麼設定 CloudTrail 的 Event history 90 天,不用錢

docker logs 那一行要特別注意:Day25 的 deploy.yml 每次部署都會刪掉舊的 container,它的 logs 也會一起消失。所以想查「部署之前」發生了什麼,要在部署之前先看。

Docker 的 logs 不會自己清掉

Docker 預設會把 container 的 logs 寫成一個 JSON 檔,而且在文件寫得很清楚:預設是不會被新的替換掉(By default, no log-rotation is performed)。所以檔案只會一直變大,直到 container 被刪掉為止。
像之前我有過 container 有3個月都沒有重新部署,container 的 JSON 檔就已經有 16MB、15 萬行。而且這還是在沒什麼人使用的情況下,如果程式出錯、一直狂印錯誤訊息或是使用者上來之後,8GB 的硬碟也可能被它吃光。
因此,文件推薦改用 local 這個格式,它預設就會替換,每個 container 最多保留約 100MB(5 個 20MB 的檔案,而且會壓縮)。在 EC2 上新增一個 Docker 的設定檔:

sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
  "log-driver": "local"
}
EOF
cat /etc/docker/daemon.json
sudo systemctl restart docker

有兩點要注意:

  • 重啟 Docker 時,container 也會跟著重啟,網站會中斷幾秒。設定檔如果寫錯,Docker 會起不來,所以先用 cat 確認內容。
  • 這個設定只對「之後新建立」的 container 有效。Day25 的 deploy.yml 每次部署都會重建 container,所以下一次部署之後就會生效。可以用 sudo docker inspect --format '{{.HostConfig.LogConfig.Type}}' my-app 確認,看到 local 就對了。

至於 Caddy 的 logs,是交給系統的 journald 管理。journald 預設最多使用檔案系統的 10%(上限 4GB),滿了會自動刪掉最舊的,所以不用另外處理。像我的 side project 的 journald 已經用了 566MB,大部分是系統服務的訊息,Caddy 一天只有十幾行。

監控:網站出事要有人通知你

CloudWatch 已經在幫你記錄

EC2 開起來之後,CloudWatch 就會免費記錄幾個基本指標:CPU、網路流量每 5 分鐘一筆,狀態檢查(status check)每 1 分鐘一筆。在 EC2 的 Console 點進自己起的 server,切到 Monitoring(監控) Tab 就看得到。
https://ithelp.ithome.com.tw/upload/images/20261010/20179793G4INuJqNP9.png
不過記憶體和硬碟用了多少,CloudWatch 預設沒有記錄,要另外安裝 CloudWatch agent,而且會算成自訂指標另外收費。小網站可以偶爾用 Session Manager 連進去自己看:

free -m
df -h /

https://ithelp.ithome.com.tw/upload/images/20261010/20179793vHjdRBTRJk.png

機器出問題時寄信給自己

一般狀態檢查分成兩種:

  • system status check 檢查 AWS 那一端(硬體、網路)
  • instance status check 檢查我們的作業系統
    前者出問題時,EC2 預設會自動把機器搬到健康的硬體上重新啟動,這個功能叫 simplified automatic recovery,t3 預設就是開著的,也不用錢;後者就要靠我們自己處理了。
    所以來建一個 Alarm,任何一種檢查失敗就寄信給自己:
  1. 在 EC2 的 Console 點 Instances(執行個體),選取你要的 server。
  2. 切到 Status checks Tab,按 Actions → Create status check alarm。
  3. 打開 Alarm notification,選一個建立的 SNS topic,填上自己的 email(關於 SNS 建立可以參考這篇文章到 sns 的 console 中建立)。
    https://ithelp.ithome.com.tw/upload/images/20261010/20179793yvcwRTGJoQ.png
  4. Alarm thresholds 維持預設的 Status check failed: either,按 Create。
  5. 到信箱找 AWS Notifications 寄來的信,點 Confirm subscription。沒有確認的話,Alarm 響了也收不到信。

CloudWatch 每個月有 10 個 Alarm 免費,SNS 每個月前 1,000 封 email 也免費,一個人用完全夠。

網站本身有沒有活著

不過剛剛設定的 system/instance Alarm,不會去檢查網站是否正常回應 HTTP 請求。因為機器本身都還是健康的, container 一直重啟或是 Caddy 停了,上面那個 Alarm 都不會響;Day25 的 smoke test 也只有在部署的時候檢查一次。
想從外面定期檢查網站的話,AWS 的做法是 Route 53 的 health check:每隔一段時間從世界各地連到網站,連不上就透過 CloudWatch Alarm 寄信。價格是每個 health check 每月 0.5 美元起,HTTPS 這類選項另外加價(AWS 上的端點有一些免費額度,細節以價格頁為準);另外有兩個小地方要注意:Alarm 要建在美東(us-east-1),HTTPS 的檢查不會驗證憑證,所以憑證過期它也不會發現。
就算你的 DNS 設在 Cloudflare 的話也可以用這個方式,而 Cloudflare 自家的 Health Checks,則需要 Pro 以上方案,Free 方案沒有提供。

費用超過預期時寄信給自己

如果開帳號時還沒設預算通知的話,可以到 Billing and Cost Management 左邊選單的 Budgets 按 Create budget,用範本建立一個每月預算,填上金額和 email 就好。一般的預算通知是免費的。
Budgets 會在帳務資料更新後判斷費用是否超過門檻,資料通常每 8~12 小時更新一次,所以它不是即時的扣款通知,也不會因為寄了信就自動停掉資源。是否把 credit 納入計算,也要確認預算的費用設定。

安全:再檢查一次門有沒有關好

可以用以下這張表整理 check 一下,最後一欄就是以我自己 side project 的狀況為例:

檢查項目 在哪裡看 我的 side project
Security group 只開 80、443 EC2 的 Security Groups,看 Inbound rules 有,只開 80、443
IMDSv2 是 Required EC2 點進執行個體,Details 裡的 IMDSv2 欄位 有,使用 AL2023 AMI 建立時的預設設定
root 和 IAM 使用者都開了 MFA IAM 的 Users,以及右上角帳號選單裡的 Security credentials 有
沒有長期有效的 access key IAM 的 Users → 使用者 → Security credentials Tab 沒有,7 月建的 access key 還在用
ECR 的 tag 不能覆寫 ECR 的 repo 設定 沒有,還是 Mutable
ECR 會掃描 Image 的弱點 ECR 的 Private registry 設定 沒有
ECR 會自動清掉舊版本 ECR repo 的 Lifecycle policy 沒有,8 個版本都還在
不能直接 push 到 main GitHub repo 的 Settings → Branches 或 Rules 沒有
actions 有新版本會提醒 Dependabot 沒有,還停在舊版,每次執行都有 Node 20 淘汰的警告
作業系統有更新 dnf check-release-update 沒有,開機 11 週都沒更新,新版本已經出了 12 個
Caddy 有更新 caddy version 沒有,還是 2.11.4,最新是 2.11.7

前三項只要確認一下,下面說明需要動手的幾項。

換掉長期有效的 access key

這個系列從 Day5 就用 aws login 拿短期憑證,照著做的話應該沒有 access key。而我自己的 side project 則是,建了一組 access key 放在自己開發用的電腦上,到現在都還是 Active。長期有效的 key 外洩了就能一直用,能換成 aws login 就換;暫時換不掉,至少看一下 Security credentials 裡的「Last used」,用不到的就停用、刪除。

ECR:不能覆寫、掃描弱點、自動清理

tag 不能覆寫:Day25 開始,每個版本都用 commit SHA 當 tag,本來就不需要覆寫。到 ECR 點進你的 repo,在 repo 的設定(Edit)把 Image tag mutability 改成 Immutable,之後同一個 tag 就推不上去了,可以避免同一個 tag 被後來推送的 Image 覆寫。
這個會影響 Day25 保留的手動部署功能:按鈕雖然還在,但直接重跑已經推送過的 commit,會在 push 那一步失敗,因為相同的 SHA tag 已經存在。之後要部署新版本,就用新的 commit;要撤銷程式修改,則沿用 Day25 的 git revert,讓 workflow 重新 build 撤銷後的程式碼。
掃描弱點:ECR 的基本掃描(Basic scanning)不用錢,打開之後每次 push 都會檢查 Image 裡的作業系統套件有沒有已知的漏洞(CVE),結果會顯示在 Image 的詳細頁面。設定在 ECR 左邊選單 Private registry 底下的掃描設定,確認掃描類型是 Basic scanning,把 scan on push 打開、篩選條件填 *(所有 repo)就好。Basic scanning 不涵蓋 npm 套件,所以 Next.js 和其他 npm 相依套件的漏洞仍要另外檢查。
https://ithelp.ithome.com.tw/upload/images/20261010/20179793NA8LC03rJ9.png
自動清掉舊版本:在 repo 中的 Lifecycle policy 建一條規則,只保留最新的 10 個 Image:Image status 選 Any,Match criteria 選 Image count,數量填 10,Rule action 選 Expire。
https://ithelp.ithome.com.tw/upload/images/20261010/20179793ZektRb6EfV.png
寫成 JSON 是這樣:

{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Keep only the 10 most recent images",
            "selection": {
                "tagStatus": "any",
                "countType": "imageCountMoreThan",
                "countNumber": 10
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}

可以先用 preview 看看哪些 Image 會被刪除,再套用規則。規則不是立刻執行,符合條件的 Image 通常會在 24 小時內被清掉;如果有想長期保留的版本,要先調整規則,不能只靠「最新 10 個」來保留它。我的 side project 的 ECR 目前有 8 個版本、共 621MB,每個月不到 0.07 美元,錢不多,但不設的話就會一直累積。

作業系統、Caddy、Node.js 的更新

Amazon Linux 2023:作業系統不會自動更新,每台機器都會固定用開機時那個版本的套件來源。
可以用 Session Manager 連進去查:

sudo dnf check-release-update

沒有任何輸出,代表已經是最新版;有新版本的話,會列出版本號和升級指令,例如 dnf upgrade --releasever=2023.12.20260930。照著執行(前面加上 sudo),AWS 文件建議寫出明確的版本號,不要用 --releasever=latest。更新完再檢查要不要重開機:

sudo dnf needs-restarting -r

看到 Reboot should not be necessary. 就不用重開;如果更新到 kernel,就用 sudo reboot 重開機。重開機時網站會中斷一兩分鐘,但 Docker 和 Caddy 都有設定開機啟動,container 也有 --restart unless-stopped,它們會自己回來。
Caddy:我們在 Day22 是直接下載執行檔安裝的,不會跟著 dnf 更新。
所以先用 caddy version 看版本,再到 Caddy 在 GitHub 上的 Releases 頁面對照最新版。
要更新的話,重跑 Day22 下載和 install 的那幾行,再 sudo systemctl restart caddy。Caddy 也有實驗性質的 caddy upgrade 指令,但它只會換掉執行檔,一樣要重新啟動才會生效喔!
Node.js:Dockerfile 用的是 node:22-alpine,GitHub Actions 每次 build 都會重新下載,所以每次部署都會拿到最新的修補版本。

EC2 這條路到這裡就告一段落了!下一篇換一條完全不需要 Server 的路:把 my-app 匯出成靜態檔案,放上 S3,再用 CloudFront 送出去ㄅ!

參考資料


上一篇
Day25 - push 到 main,讓 GitHub Actions 自動部署到 EC2
系列文
前端來點 AWS 技能樹! 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言