iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
Software Development

學校沒教的後端生存指南:30 天打造非同步 S3 微服務,部署 K8s 實現 HA 架構系列 第 30 篇

[ Day 30 ] CICD 串接 AWS EC2 0 成本雲端發布、CloudWatch 監控真相與 30 天架構師畢業之旅!

  • 分享至 

  • xImage
  •  

太棒啦,恭喜大家跟著我一起堅持到了最後一天,在過去 29 天裡,我們從最底層的 Netty 非同步 I/O 引擎切入,經歷了網路延遲混沌工程、Resilience4j 斷路器背壓防線、Docker 容器化、K8s 雙探針與 HPA 自動擴容,再到昨天實作的 GitHub Actions CI/CD 自動化交付。

今天,我們要為這個微服務劃下CI/CD的句點,我們會教大家將打包在 AWS ECR 的 Docker 鏡像,正式部署到 AWS EC2 雲端伺服器上,如此一來就可以將我們自己撰寫的服務給大家呼叫了喔!

https://ithelp.ithome.com.tw/upload/images/20260926/20183864Qeq5NxL6cY.png

AWS EC2

EC2 (Amazon Elastic Compute Cloud)簡單來說,就是向 AWS 租用的一台雲端虛擬專用伺服器(Virtual Machine),可以直接在上面執行docker

就像你向租屋網租房間一樣,以前企業要架設伺服器,必須自己花幾十萬元購買實體主機、拉專用光纖網路、開冷氣房維運;而 EC2 讓你只要在 AWS 網頁點幾下,幾秒鐘內就能租到一台擁有獨立 IP、可自由安裝 Linux/Windows 的雲端電腦,且隨開隨用、按小時或秒計費!

在本次鐵人賽中,為了讓大家 0 成本學習,選擇在 t3.micro 上運行單機 Docker 容器。但是在真實企業 Production 環境中,單台 1 GiB RAM 的 EC2 無法抵禦高流量並發請求,應該選擇更高規格(如 t3.medium 以上)或直接對接 AWS EKS 託管 K8s 叢集配合 HPA 自動擴充!

建立EC2

  1. 打開AWS console進入EC2 頁面並且選擇啟動執行個體,為了讓所有人都能免費體驗真實的雲端部署,我們進行以下選型:
  • 應用程式和作業系統映像 : Ubuntu
  • 執行個體類型:t3.micro
  • 金鑰對 (登入) : 按下建立新的金鑰對 輸入名稱,系統會自動幫你下載一個.pem的檔案,後續撰寫githun action檔案時會用到
  • 後面其他設定都先不動
  • 按下啟動執行個體 建立EC2

免費額度:AWS 12 個月免費帳戶每個月提供 750 小時免費執行時間,剛好可以讓一台 EC2 24 小時不間斷開著跑一整個月,完全不花半毛錢!

https://ithelp.ithome.com.tw/upload/images/20260926/20183864x2qJIaVpwY.png

  1. 綁定 IAM Role (Instance Profile)

    • 進入 IAM Console ➔ Roles ➔ Create role,Use case 選擇 EC2
    • 附加策略:搜尋並勾選 AmazonEC2ContainerRegistryReadOnly
    • 為iam角色建立一個名稱:ec2-ecr
    • 回到 EC2 Console 點擊你的虛擬機 Actions ➔ Security ➔ Modify IAM role ➔ 選取剛剛建好的 Role

https://ithelp.ithome.com.tw/upload/images/20260926/20183864PXXErGRyBD.png

  1. 安裝環境
    建立好ec2之後我們還要進虛擬機的console安裝docker環境,不然後續是沒辦法透過github action來執行的
    ,按照順序執行以下指令
sudo apt-get update
sudo apt-get install -y docker.io awscli
sudo usermod -aG docker ubuntu  # 讓 ubuntu user 能跑 docker,需要重新登入生效

重新登入後就可以透過docker ps指令看到docker被安裝,接著如過後續跑完cicd流程,我們再次使用docker ps也可以清楚看到目前ec2有一個docker container正在被執行

https://ithelp.ithome.com.tw/upload/images/20260926/20183864gCtWJ2BaXH.png

完整 CICD 部署設定

新增的 GitHub Secrets 變數清單:

為了讓 GitHub Actions 能自動 SSH 連進 EC2 拉取 ECR 最新鏡像並滾動重啟,回到 GitHub repo的 Settings ➔ Secrets and variables ➔ Actions 中,除了昨天已經有的連接ecr的ak,sk環境變數外,再額外補上以下環境變數:

  1. EC2_SSH_KEY:將上個階段建立ec2時下載的 .pem 用文字編輯器打開,複製全部內容(包含 -----BEGIN RSA PRIVATE KEY----- 到 -----END RSA PRIVATE KEY-----)

  2. S3_AK:Day6 建立去連線 S3 的 IAM Access Key

  3. S3_SK:Day6 建立去連線 S3 的 IAM Secret Key

修改 GitHub Actions Workflow

進入程式碼 .github/workflows/deploy.yml,我們昨天已經完成github push後會自動mvn test, docker build, docker push到ecr上,今天在最下面新增第七階段,從ec2上將既有的image拉下來並且執行,要填上自己的Public IPv4

- name: 7. Automated Remote Deployment to EC2 via SSH
  uses: appleboy/ssh-action@v1.0.0
  with:
    host: {your_EC2_ip}  #EC2 的公網 IP (Public IPv4 地址)
    username: ubuntu  #若選 Amazon Linux ➔ 填寫 `ec2-user`
    key: ${{ secrets.EC2_SSH_KEY }}
    script: |
      # 1. 依靠 EC2 綁定的 IAM Role 自動登入 ECR
      aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${{ steps.login-ecr.outputs.registry }}

      # 2. 拉取 AWS ECR 最新的 Docker Image
      docker pull ${{ steps.login-ecr.outputs.registry }}/s3-app-service:latest

      # 3. 滾動重啟容器並注入 S3 環境變數
      docker stop s3-app || true
      docker rm s3-app || true
      docker run -d -p 8080:8080 --name s3-app --restart always  -e AWS_ACCESS_KEY_ID="${{ secrets.S3_AK }}"  -e AWS_SECRET_ACCESS_KEY="${{ secrets.S3_SK }}"  ${{ steps.login-ecr.outputs.registry }}/s3-app-service:latest                     

EC2 安全群組調整

部署成功後可能還會發現一個問題,明明github action亮綠燈,但是為什麼我們實測http請求的時候就還是連不上呢?答案很簡單因為ec2出於安全問題,將有對外開放的port限定在22而已,而我們前面對外開的port是8080 (docker run -d -p 8080:8080) 當然也可以直接將docker輸出的port改成22,但我今天要額外讓大家來試試看新增安全群組的部分

  • Type: Custom TCP
  • Port: 8080
  • Source: 0.0.0.0/0(所有人都能訪問)
    正式環境中通常不會設定0.0.0.0/0,會建議限縮 IP 範圍或改用 HTTPS + ALB
    https://ithelp.ithome.com.tw/upload/images/20260926/20183864oFidvDScM3.png

儲存規則後再次測試從自己的Public IPv4來測試就成功啦!我們自己開發的服務就可以正式上線讓大家使用啦!

https://ithelp.ithome.com.tw/upload/images/20260926/20183864zEnwAMTzLW.png

AWS Cloudwatch vs. Prometheus + Grafana

開立 EC2 後,AWS 提供基本的 CloudWatch 免費監控,只有當你手動開啟1 分鐘一次的高頻 Detailed Monitoring、日誌收集超過 5GB、或是建立了幾十個告警時才會產生微量費用。預設狀態下完全 0 元

  • Basic Monitoring (基本監控):預設自動開啟,免費,每 5 分鐘自動收集一次主機數據
  • Metrics (指標):包含 10 個自訂指標 (Custom Metrics)免費額度
  • Alarms (告警):包含 10 個免費告警指標(如:CPU > 80% 時發送通知)。
  • Logs (日誌收錄):提供 5 GB 的 Log 資料收錄與 5 GB 儲存空間免費額度。
  • Dashboards (儀表板):提供 3 個免費自訂儀表板(最多 50 個指標)。

https://ithelp.ithome.com.tw/upload/images/20260926/20183864QsYc1t6aMP.png

既然 AWS 已經提供了免費的 CloudWatch,為什麼我們在 Day 17~18 還要自己用 Docker Compose 架設 Prometheus 與 Grafana 呢?因為這兩者的觀察視角有所不同:

  • CloudWatch: 優點是免安裝任何 Agent,預設監控 EC2 實體機的 CPU、網路流量與磁碟 Read/Write。但它看不見容器內部的狀態(如:Spring Boot JVM 記憶體 Heap 是否爆掉?GC 停頓多久?Netty EventLoop 阻塞幾秒?)。
  • **Prometheus + Grafana **: 類似顯微鏡可以透過 Spring Boot Actuator 的 /actuator/prometheus 端點,深入容器內部抓取微服務指標。

通常會使用CloudWatch 負責監控硬體與雲端服務健康,並在 EC2 當機時發送 Email/Slack 告警,然後 Prometheus + Grafana 負責即時調校 API 效能,抓出 Memory Leak 與連線池瓶頸。

結語:架構沒有最完美,只有最適合!

這 30 天我們從 localhost 一步步成長,最終獲得的數據對照:

評測指標 / 演進階段 Day 4 同步 Apache Day 7 非同步 Netty Day 18 防禦型 API Day 27 K8s HPA 擴充
極限 QPS 吞吐量 ~6.5(線程飢餓) ~6.6 QPS ~10.5 QPS (背壓保護) 16.2 QPS(突破單機天花板)
P99 回應延遲 4,477 ms (佇列阻塞) 5.953 ms 921 ms 3906 ms (流量分流)
高壓錯誤率 (Error Rate) 32.4% (全站崩潰) 44.4% (Bufferbloat) 0.00% 0.00% (0 封包遺失)
高可用自癒力 (RTO) 無 (Tomcat 執行緒卡死) 無(瞬間拋任務卡頻寬) Semaphore(50) + Double-Check HPA (3 ➔ 8 Pods)+雙探針
部署架構 本地 localhost 本地 Docker Docker Compose K8S

老實說這三十天也比我想像中的還要煎熬和困難,和我一開始預估要花費的時間和內容也有點差距,不過過程中也讓我慢慢學習了更多概念,這個AI時代或許開發模式漸漸轉變,我們不在需要一行一行手刻程式碼了,但是整體架構的敏銳度,對於專案有bug時要從哪裡切入找到可能的原因和修正,以及每一段 API、一個 Dockerfile、一個 K8s Deployment,背後都隱含著無數效能調校與資安考量

身為後端工程師,最寶貴的資產從來不是記住了多少 API 語法,而是具備剖析系統瓶頸的底層思維,以及用數據說服團隊的架構決策力。

感謝這 30 天陪同這套系統一起演進的自己與每一位讀者,我們的架構師修煉之旅,正式圓滿成功!


上一篇
[ Day 29 ] DevOps 自動化交付 - GitHub Actions + AWS ECR + K8s 一鍵 CI/CD 零人工干預部署
系列文
學校沒教的後端生存指南:30 天打造非同步 S3 微服務,部署 K8s 實現 HA 架構 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言