經過27天的開發與測試,我們的智慧文檔分析系統已經具備完整功能。
但要真正為使用者提供服務,我們還需要將應用部署到生產環境。
今天我們將學習如何使用AWS的各種服務,將應用程式安全、穩定地部署到雲端,並建立監控與維護機制。
延續上一天的專案
是時候把一切集大成了
使用者請求
↓
CloudFront (CDN)
↓
Application Load Balancer
↓
ECS Fargate / App Runner
↓
├─ Bedrock (AI推論)
├─ Textract (文字識別)
├─ S3 (檔案儲存)
└─ RDS/DynamoDB (資料)
↓
CloudWatch (監控與日誌)
部署考量
Solution 1 : AWS app runner AWS app runner
特色 :
使用場景
中小型應用
快速上線需求
團隊規模較小
Solution 2 : ECS Fargate
使用場景
需要更多控制權
複雜的微服務架構
已有容器化經驗
Solution 3 : Lambda + API Gateway
使用場景
間歇性流量
API服務
成本敏感型專案
我們這裡展示 App runner 部署
這裡我們需要建立 Dockerfile
# 使用官方Python映像
FROM python:3.11-slim
# 設定工作目錄
WORKDIR /app
# 安裝系統依賴
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 複製requirements
COPY requirements.txt .
# 安裝Python依賴
RUN pip install --no-cache-dir -r requirements.txt
# 複製應用程式碼
COPY . .
# 建立非root使用者
RUN useradd -m -u 1000 appuser && \
chown -R appuser:appuser /app
USER appuser
# 暴露端口
EXPOSE 8501
# 健康檢查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8501/_stcore/health || exit 1
# 啟動應用
CMD ["streamlit", "run", "app.py", \
"--server.port=8501", \
"--server.address=0.0.0.0", \
"--server.headless=true", \
"--server.enableCORS=false", \
"--server.enableXsrfProtection=true"]
config.py
import os
from dataclasses import dataclass
@dataclass
class Config:
"""應用程式配置"""
# AWS配置
AWS_REGION: str = os.getenv('AWS_REGION', '<你的 region>')
S3_BUCKET: str = os.getenv('S3_BUCKET', 'my-doc-bucket')
# Bedrock配置
BEDROCK_MODEL_ID: str = os.getenv(
'BEDROCK_MODEL_ID',
'anthropic.claude-3-5-sonnet-20241022-v2:0'
)
# 應用配置
MAX_FILE_SIZE: int = int(os.getenv('MAX_FILE_SIZE', 10 * 1024 * 1024)) # 10MB
UPLOAD_TIMEOUT: int = int(os.getenv('UPLOAD_TIMEOUT', 300)) # 5分鐘
# 監控配置
LOG_LEVEL: str = os.getenv('LOG_LEVEL', 'INFO')
ENABLE_METRICS: bool = os.getenv('ENABLE_METRICS', 'true').lower() == 'true'
# 安全配置
ALLOWED_ORIGINS: list = os.getenv(
'ALLOWED_ORIGINS',
'*'
).split(',')
config = Config()
對 docker 相關的知識以及容器化不夠熟悉的可以參考 Docker官網
並參考 AWS ECR
aws ecr create-repository \
--repository-name document-analyzer \
--region <你的region>
# 登入ECR
aws ecr get-login-password --region <你的Region> | \
docker login --username AWS --password-stdin \
<account-id>.dkr.ecr.<你的Region>.amazonaws.com
# 建構映像
docker build -t document-analyzer:latest .
# 標記映像
docker tag document-analyzer:latest \
<account-id>.dkr.ecr.<你的Region>.amazonaws.com/document-analyzer:latest
# 推送映像
docker push <account-id>.dkr.ecr.<你的Region>.amazonaws.com/document-analyzer:latest
apprunner.yml
version: 1.0
runtime: python311
build:
commands:
build:
- pip install -r requirements.txt
run:
runtime-version: 3.11.0
command: streamlit run app.py --server.port=8080
network:
port: 8080
env: APP_PORT
env:
- name: AWS_REGION
value: <你的Region>
- name: LOG_LEVEL
value: INFO
# 建立服務
aws apprunner create-service \
--service-name document-analyzer \
--source-configuration '{
"ImageRepository": {
"ImageIdentifier": "<account-id>.dkr.ecr.<你的region>.amazonaws.com/document-analyzer:latest",
"ImageConfiguration": {
"Port": "8501",
"RuntimeEnvironmentVariables": {
"AWS_REGION": "<你的Region>",
"S3_BUCKET": "my-doc-bucket"
}
},
"ImageRepositoryType": "ECR"
},
"AutoDeploymentsEnabled": true,
"AuthenticationConfiguration": {
"AccessRoleArn": "arn:aws:iam::<account-id>:role/AppRunnerECRAccessRole"
}
}' \
--instance-configuration '{
"Cpu": "1 vCPU",
"Memory": "2 GB"
}' \
--health-check-configuration '{
"Protocol": "HTTP",
"Path": "/_stcore/health",
"Interval": 10,
"Timeout": 5,
"HealthyThreshold": 1,
"UnhealthyThreshold": 5
}' \
--auto-scaling-configuration-arn \
"arn:aws:apprunner:<你的Region>:<account-id>:autoscalingconfiguration/DefaultConfiguration/1/00000000000000000000000000000001"
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "build.apprunner.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel"
],
"Resource": "arn:aws:bedrock:*::foundation-model/*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-doc-bucket/*"
},
{
"Effect": "Allow",
"Action": [
"textract:DetectDocumentText",
"textract:AnalyzeDocument"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
其他部分關於成本以及監控,在先前已有展示,讀者可以自行練習