1.0 前言
我現職金融科技公司,主要業務是提供(1)金融交易數據和(2)宏觀資產配置方案的專業金融解決方案。目前,公司正在開發“宏觀資產組合”系統,用來支持其他部門,如宏觀經濟分析部門,交易系統部門,風險管理部門,金融深度學習部門,網絡安全工程師部門等。
新的“宏觀資產組合”系統要符合“最省力原則”,包括(1)快速開發和修改,以應對烏卡時代VOCA的金融市場多變性,和(2)快速部署項目,減少浪費時間在其他部門溝通和重覆的可自動化工作。
但是,目前開發工程師(沒錯,就是我了!)感到不舒服,因要跨多個部門來開發“宏觀資產組合”系統。如宏觀經濟分析部門的功能需求,風險管理部門的功能反饋,金融深度學習部門的代碼修改,和網絡安全工程師部門的代碼審查。
經過了兩周的“DIVE DEEP調查”,和各部門的“單一領導人”會談後,真正的問題是(1)項目部署時間太長,和(2)未實現可自動化部署工作。如果可以先灰度發布功能,在每周四前給“更新版API手冊”其他部門試用,就可整体提升+30%的項目開發速度。換句話說,顧客由需等13天,到只等10天時間,就可体驗到新的“宏觀資產組合”功能。
因此,我們將決定使用“AWS DevOps流水線”來部署“宏觀資產組合”系統,來加速整個“原型->開發->部署->使用->反饋->修改”的項目生命周期。
“Customer Obsession” is matter! -- Amazon 16 leadership principles
1.1 “AWS DevOps流水線”的核心目標
2024年10月,我花了一周時間,閱讀Akshay Kapoor [AWS Senior Cloud Infrastructure Architect] 的AWS DevOps Simplified: Build a solid foundation in AWS to deliver enterprise-grade software solutions at scale。然後,我明白了Raymond Tsang [AWS Senior Technical Trainer] 在2024年2月時在Hong Kong Re:Invent Recap上 跟我說過:“沒有絕對正確的解決方案,所以,即使只用一小部份AWS服務,而結果是變好了。那這就是好的解決方案。”
現在,我十分認同Raymond Tsang [AWS Senior Technical Trainer] 的論點。這一次“AWS DevOps流水線”架構,從結果上看是成功的,而神奇的是,只用到一小部份AWS服務。比如我們沒有用到Instance Auto Scaling,AWS ECS(Elastic Container Service),AWS ELB(Elastic Load Balancing),AWS CloudFormation等。
“Invent and Simplify” is matter! -- Amazon 16 leadership principles
“Any damn fool can make it complex. It takes a genius to make it simple.” -- Ray dalio, Principles
根據我的經驗,成功的原因是:(1) 其他部門只需小步快跑的小功能,而不需完整的解決方案。(2) 愈是簡單,表示愈理解問題根源。所以(3) 更快更有效率地“Deliver Results”,即使是只用了一小部份AWS服務。
由於金融服務領域是特殊的,每個部門負責不同的目標,來幫助顧客獲得價值。而金融DevOps不應是限制和阻礙,反而是根據不同的情況,去更好地服務其他部門和顧客。
同時,我明白了“Simplify & Insist on the Highest Standards”并不矛盾。雖然我們簡單化了整個項目,但簡單化正是高標準的良好結果,因我們進行了 (1)“DIVE DEEP調查” 和 (2) 理解問題根源。
盡管你可能不相信,在緊急情況,我們會用Excel來計算Black–Scholes model,因Excel是最快最簡單地解決緊急問題,也是最好地“Customer Obsession”和“Deliver Results”。
1.2 “AWS DevOps流水線”架構
“AWS DevOps流水線”用到的服務:
- (1) GitHub Actions
- (2) AWS CodeDeploy
- (3) Amazon EC2
- (4) IAM
Walkthrough:
1. 開發工程師commits代碼
2. Github Actions觸發workflows
3. IAMROLE_GITHUB_ARN授權access AWS資源
4. GitHub action觸發AWS CodeDeploy
5. AWS CodeDeploy觸發部署到Amazon EC2 instances
6. AWS CodeDeploy拉取Github資源,部署到Amazon EC2 instances
1.3 優化
這架構只適用目前“小步快跑”的敏捷交付和開發環境。如果是用在生產環境,就要根據需求額外使用Instance Auto Scaling,AWS ECS(Elastic Container Service),AWS ELB(Elastic Load Balancing)等。
另外,因讓各位容易明白“AWS DevOps流水線”机制,所以在之後的教程,在應用層刪除了Python和Backtrader,只剩下簡單的Nginx和靜態網頁。
1.4 應用 GenAI工具 - Developer Q 到 Financial Services DevOps
Developer Q是非常好用的GenAI Chatbot開發工具。
在2024年9月,我發現AWS帳單有一筆異常的收費,但我不知道EC2 EIP为什么變成了收費服務。
因此,我提問Q,只需10秒我就知道答案了。閑置的EIP是收費的。
- 選擇 EC2 -> Elastic IP addresses -> Network & Security
- 選擇 Elastic IPs
- 刪除閑置的EIP
另外,我用Q來學習AWS DevOps的相關知識。以下是我用Q的經驗,同時運用了AWS Certified Machine Learning - Specialty Certification的考試知識。
由於AWS Pipeline是AWS-Centric服務,所以integrate GitHub Actions不符合“Least Effort Principle”原則。
因此,AWS Pipeline不是最好的選擇。
我知道了AWS Pipeline是AWS-Centric Orchestrates。下一步,我知道AWS Pipeline是由CodeBuild和CodeDeploy組成。
我提問Q,知道CodeDeploy是我需要的AWS服務,而且可以與GitHub Actions組成最“Least Effort Principle”解決方案。
參考文章
我看完AWS DevOps博客的教程後,雖然它是EKS,但與我的解決方案已非常相似。
通過Q,我快速地了解每個AWS的服務異同,更有放地應用在我的日常工作。因此,我十分推薦大家用AI工具來提高生產力。
1.5 小總結
我分享了在金融服務行業的目前狀況,然後應用了“AWS 16 Leadership Principles”,Akshay Kapoor 和 Raymond Tsang的觀點,通過AWS云服務來解決商業和技術上痛點。
下一章,我會分享(1)建立AWS DevOps流水線,和(2)AWS云服務的預計成本。希望大家在AWS社區一起成長。
2.0 AWS DevOps流水線
上一章《AWS DevOps Agile Delivery of 16 Leadership Principles for the Financial Services Industry》,分享了AWS DevOps流水線怎样解決金融服務行業的痛點,并成巧運用Amazon 16 Leadership Principles和細節行動。
在這章,你會學到怎样建立AWS DevOps流水線:
AWS Services | Description |
IAM | Identity and Access Management |
EC2 | Cloud-computing platform |
Elastic IP address | Static IPv4 address designed for dynamic cloud computing |
Route53 | Cloud domain name system (DNS) service |
CodeDeploy | Automate application deployments to Amazon EC2 instances |
GitHub Actions | Easy to automate all your software workflows |
Pricing Calculator | Create an estimate for the cost of your use |
2.1 前置需求
2.1.1 知識前置需求
- 創建一台EC2服務器
- 已有Github帳戶,懂基本的Github Actions
- 會架設NGINX
- 懂基本的AWS服務,包括EC2,CodeDepoly,IAM
2.1.2 項目前置需求
先在Github上傳一個簡單的靜態網頁項目codedeploy.nginx.001。里面包括:
物件 | 位置 | 用途 |
index.html | ./ | 靜態網頁 |
圖片 ic_alana_002_20241022_a.jpg |
./icons | 顯示在靜態網頁上 |
appspec.yml | ./ | 編寫codeDeploy指令 |
application-stop.sh before-install.sh after-install.sh application-start.sh validate-service.sh |
./scripts | 編寫codeDeploy指令 |
appspec.yml | ./github/workflows | 編寫codeDeploy指令 |
另外,需要Github access tokens來配置codeDeploy權限。
Github -> Setting -> Developer Setting -> Tokens。新增一個Github access tokens。
2.2 創建IAM角色
良好的命名風格很重要,因隨著IAM角色愈來愈多,開發者會感到混亂。
AmazonSageMaker-ExecutionRole-20240805T101031 AmazonSagemakerCanvasBedrockRole-20240801T140683
{service}-{role}-{datetime}-{version}。AWS Bedrock和SageMaker自動生成的IAM命名風格。
AWSCodeDeployService-EC2AccessCodeDeployRole-20241024T000000 AWSCodeDeployService-DepolyEC2Role-20241024T000000 AWSCodeDeployService-GitAssumeRoleWithAction-20241024T000000
這是清晰的IAM命名風格,因此我們會按照這個官方IAM命名風格,分別為EC2 和 CodeDepoly 和 Github Actions 創建三個IAM角色。
2.2.1 AWSCodeDeployService-EC2AccessCodeDeployRole-20241024T000000
Use Case點選EC2。
AmazonEC2FullAccess AmazonEC2RoleforAWSCodeDeploy AmazonS3FullAccess AmazonSSMManagedInstanceCore AWSCodeDeployFullAccess AWSCodeDeployRole
分別配置AmazonEC2,AmazonS3,AWSCodeDeploy的權限。
2.2.2 AWSCodeDeployService-DepolyEC2Role-20241024T00000
Use Case點選CodeDeploy。
AWSCodeDeployFullAccess AWSCodeDeployRole
配置AWSCodeDeploy。
2.2.3 AWSCodeDeployService-GitAssumeRoleWithAction-20241024T000000
點選Access management -> Identity providers -> Add provider。
用來監聽Github Actions。
Provider URL: token.actions.githubusercontent.com
Audience: sts.amazonaws.com
然後,Github Identity Provider新增AWSCodeDeployService-GitAssumeRoleWithAction-20241024T000000角色。
點選Assign Role -> Web identity -> Github organization。
AmazonS3FullAccess AWSCodeDeployFullAccess
配置S3,AWSCodeDeploy的權限。
2.3 建立EC2
1. 填寫名稱ec2.cheaper.001
2. 點選Amazon Linux 2023 AMI
3. 點選t3a.nano
最後按"Launch instance"建立EC2。
2.3.1 Associate Elastic IP address
Associate Elastic IP address,配置静态IP给EC2。然后可以用route53配置专属域名。
1. 點選Elastic Ips
2. 點選“Allocate Elastic IP address”按鈕
1. 選擇剛建立EC2的名稱ec2.cheaper.001
2. 選擇預設的Private IP address
3. 點選"Associate"按鈕
2.3.2 Route53
1. 填寫sub-domain域名
2. 填寫EC2的
3. 點選"save"按鈕
成功設置好靜態域名和IP域名。
2.3.3 設置IAM角色
1. 點選Actions
2. 點選Security
3. 點選Mpdify IAM role
配置AWSCodeDeployService-EC2AccessCodeDeployRole-20241024T000000。
2.3.4 在EC2安裝CodeDeploy Agent
進入EC2終端。
1. 點選Connect
2. 點選EC2 Instance Connect
3. 點選Connect
成功登入EC2終端。
sudo apt update sudo yum install ruby sudo apt install wget cd /home/ec2-user wget https://aws-codedeploy-us-east-2.s3.us-east-2.amazonaws.com/latest/instal chmod +x ./install sudo ./install auto
安裝CodeDeploy Agent。
成功,CodeDeploy Agent正在運行中。
(Optional) 2.3.5 安裝GIT
如果想在EC2直接拉取git項目,請繼續以下步驟,否則可跳到2.3.7。
sudo yum install git-all git clone https://{YOUR_GITHUB_SECRET_ID}@github.com/{YOUR_GITHUB_ORGANIZATION_NAME}/{YOUR_GITHUB_PROJECT_NAME}.git git checkout . git pull origin main sudo chmod 777 -R PATH
安裝git,拉取項目到EC2。
(Optional) 2.3.6 安裝NGINX
sudo yum update sudo yum install nginx -y sudo service nginx start sudo service nginx status
安裝NGINX
sudo netstat -tunpl
顯示開放端口。這時NGINX已占用:80端口。
NGINX的預設主頁在/var/www/html/index.html。
確保Source和Destination是公開訪問,設置成0.0.0.0/0。
2.3.7 Appspec.yml
參考文章
- CodeDeploy AppSpec file reference
- (AWS DevOps Blog) Build and Deploy Docker Images to AWS using EC2 Image Builder
- (Github) Build and Deploy Docker Images to AWS using EC2 Image Builder
Appspec.yml是用指示codeDeploy的流程代碼。
Deployment主要分成了5個環節:(1) BeforeInstall -> (2) BeforeInstall -> (3) AfterInstall -> (4) ApplicationStart -> (5) ValidateService
在root目錄下新增./appspec.yml。
version: 0.0 os: linux files: - source: / destination: /usr/share/nginx/html hooks: ApplicationStop: - location: scripts/application-stop.sh timeout: 300 runas: root BeforeInstall: - location: scripts/before-install.sh timeout: 300 runas: root AfterInstall: - location: scripts/after-install.sh timeout: 300 runas: root ApplicationStart: - location: scripts/application-start.sh timeout: 300 runas: root ValidateService: - location: scripts/validate-service.sh timeout: 300 runas: root
source是github項目的根目錄。destination是拉取到EC2的項目。
另外,新增./scripts文件夾,在里面分別有5個xxxxxxx.sh。
application-stop.sh before-install.sh after-install.sh application-start.sh validate-service.sh
5個xxxxxxx.sh,分別是codeDeploy的5個環節。
(1) application-stop.sh
#!/bin/bash
空白。這次案例不需要停止應用。
(2) before-install.sh
#!/bin/bash
空白。這次案例不需要停止應用。
(3) after-install.sh
#!/bin/bash sudo yum update sudo yum install nginx -y
安裝NGINX
(4) application-start.sh
#!/bin/bash sudo service nginx start
啟動NGINX
(5) validate-service.sh
#!/bin/bash
空白。這次案例不需要停止應用。
2.3.8 靜態網站
新增./icons文件夾,里面是顯示網站圖片ic_alana_002_20241022_a.jpg。
另外,新增index.html網站主頁。
<html lang="en" data-bs-theme="dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js" integrity="sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" integrity="sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <title>Alana Lam</title> </head> <body> <div class="container"> <div class="row"> <div class="col-12 mt-4 text-center"> <h1>CodeDeploy + Github Actions + EC2</h1> <img src="./icons/ic_alana_002_20241022_a.jpg" class="mt-4 rounded-circle" alt="Alana Lam" width="200" height="200"> <h5 class="mt-4">Alana Lam (AWS Builder Community Manager, Hong Kong)</h5> </div> </div> </div> </body> <html>
一個簡單的靜態網站,顯示文字和圖片。
如果是完成了"2.3.5 安裝GIT"和"2.3.6 安裝NGINX",可以在瀏覽器上輸入EC2 EIP,或你設置的域名,就可以看到網頁了。
2.4 建立codeDeploy
2.4.1 創建codeDeploy應用
1. 填寫Application name,test.codeDeploy.001
2. 點選EC2/On-premises
3. 點選"Create application"按鈕
2.4.2 創建codeDeploy Deployment Group
1. 點選"Create deployment group"按鈕。
1. 填寫Deployment group名稱,test.deploymentGroup.001。
2. 選擇IAM角色,AWSCodeDeployService-DepolyEC2Role-20241024T000000。
3. 剔除"Enable load balancing",因這次是最簡單的DevOps流水線案例,所以不需要額外的AWS服務。
2.4.3 創建codeDeploy Deployment
進入"test.deploymentGroup.001"。
點選"Create deployment"按鈕。
點選"My application is stored in GitHub"。
1. 填寫"Github token name"。
2. 填寫"Repository name"。codedeploy.nginx.001。
3. 填寫"Commit ID"。
4. 點選"Create deployment"按鈕。
2.4.4 成功執行codeDeploy
成功執行codeDeploy。
2.5 建立Gtihub Actions
參考文章
2.5.1 創立Github Actions workflow
1. 點選"New workflow"按鈕。
2. 點選"set yp a workflow yourself"連接。
3. 編寫完GitHub Actions指令後,按"Commit changes"按鈕。
2.5.2 設置GitHub Actions secrets and variables
1. 點選Settings Tab
2. 點選Serects and variables (Actions) Tab
3. 點選Secrets Tab
2.5.3 新增Github Actions secrets變量
1. 新增secrets變量,名命IAMROLE_GITHUB_ARN。
2. 賦值是IAM角色的ARN。值格式是arn:aws:iam::{xxxxxxxx}:role/AWSCodeDeployService-GitAssumeRoleWithAction-20241024T000000
3. 點選"Add secret"按鈕。
2.5.4 新增Github Actions variables變量
1. 點選Variables Tab
2. 新增4個Actions Variables
Variables | 值 | 內容 |
AWS_REGION | us-east-1 | 預設部署在US East (N. Virginia) |
CODEDEPLOY_APPLICATION_NAME | test.codeDeploy.001 | 2.4.1 創建codeDeploy應用 |
CODEDEPLOY_DEPLOYMENT_GROUP_NAME | test.deploymentGroup.001 | 2.4.2 創建codeDeploy Deployment Group |
IAMROLE_GITHUB_SESSION_NAME | AWSGitAssumeRoleWithAction | 2.2.3 AWSCodeDeployService-GitAssumeRoleWithAction-20241024T000000 |
3. 點選"New repository variable"按鈕
2.5.5 編寫GitHub Actions指令
.github/workflows/main.yml
name: Deploy on: workflow_dispatch: {} jobs: deploy: runs-on: ubuntu-latest environment: Prod permissions: id-token: write contents: read steps: - name: Git clone the repository uses: actions/checkout@v2 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.IAMROLE_GITHUB_ARN }} role-session-name: ${{ vars.IAMROLE_GITHUB_SESSION_NAME }} aws-region: ${{ vars.AWS_REGION }} - run: | commit_hash=`git rev-parse HEAD` aws deploy create-deployment --application-name ${{ vars.CODEDEPLOY_APPLICATION_NAME }} --deployment-group-name ${{ vars.CODEDEPLOY_DEPLOYMENT_GROUP_NAME }} --github-location repository=${{ github.repository }},commitId=${{ github.sha }} --ignore-application-stop-failures
一個基礎版的GitHub Actions指令。
2.5.6 運行GitHub Actions指令
1. 點選Actions Tab
2. 點選Deploy Tab
3. 點選"Run workflow"按鈕
2.5.7 成功運行GitHub Actions
成功運行完main.yml。
4.0 成本
Monthly cost: $11.83 (USD)
Total 12 months cost: $141.96 (USD)
整体來說,AWS的價錢是相當有競爭力。最重要的CodeDeploy收費便宜,用EC2 t4g.nano的成本很低,是有低成本+高效益的云服務供應商。
4.1 Detailed Estimate
Service | Monthly | First 12 months total |
AWS CodeDeploy | $8.8 | $105.6 |
Amazon EC2 | $1.533 | $18.4 |
Amazon Route 53 | $0.4 | $4.8 |
VPN Connection | $1.1 | $13.2 |
5.0 總結
Github Actions + CodeDepoly 是很強大的DevOps工具,在商業環境里實現“思想宏大,小步快跑”的原則。
在最後,總結本章的重點:
5.1 原則
- 新的“宏觀資產組合”系統要符合“最省力原則”,包括(1)快速開發和修改,和(2)快速部署項目。
- 真正的問題是(1)項目部署時間太長,和(2)未實現可自動化部署工作。
- 成功的原因是:(1) 其他部門只需小步快跑的小功能。(2) 愈是簡單,表示愈理解問題根源。
5.2 行動
- 在每周四前給“更新版API手冊”其他部門試用,就可整体提升+30%的項目開發速度。
- 簡單化正是高標準的良好結果,因我們進行了 (1)“DIVE DEEP調查” 和 (2)理解問題根源。
5.3 AWS DevOps
- (1) 開發工程師commits代碼
- (2) Github Actions觸發workflows
- (3) IAMROLE_GITHUB_ARN授權access AWS資源
- (4) GitHub action觸發AWS CodeDeploy
- (5) AWS CodeDeploy觸發部署到Amazon EC2 instances
- (6) AWS CodeDeploy拉取Github資源,部署到Amazon EC2 instances
5.4 AWS IAM (CodeDeploy, EC2, Github)
- AWSCodeDeployService-EC2AccessCodeDeployRole-20241024T000000
- AWSCodeDeployService-DepolyEC2Role-20241024T000000
- AWSCodeDeployService-GitAssumeRoleWithAction-20241024T000000
5.5 AWS CodeDeploy (Appspec.yml)
- BeforeInstall
- BeforeInstall
- AfterInstall
- ApplicationStart
- ValidateService
5.6 成本
- Monthly cost: $11.83 (USD)
- Total 12 months cost: $141.96 (USD)