main:添加核心文件并初始化项目

新增内容:
- 创建基础项目结构。
- 添加 `.gitignore` 和 `.dockerignore` 文件。
- 编写 `pyproject.toml` 和依赖文件。
- 添加算法模块及示例算法。
- 实现核心功能模块(日志、错误处理、指标)。
- 添加开发和运行所需的相关脚本文件及文档。
This commit is contained in:
2026-02-02 10:46:01 +08:00
commit 31af5e2286
54 changed files with 5726 additions and 0 deletions

31
deployment/Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
FROM python:3.11-slim
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY src/ ./src/
# 创建非 root 用户
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# 暴露端口
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz')"
# 启动命令
CMD ["uvicorn", "src.functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -0,0 +1,33 @@
# Redis Exporter Dockerfile
FROM python:3.11-slim
WORKDIR /app
# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir redis prometheus-client
# 复制 exporter 代码
COPY src/functional_scaffold/core/metrics_redis_exporter.py .
# 暴露端口
EXPOSE 8001
# 启动 HTTP 服务器提供指标
CMD ["python", "-c", "\
from http.server import HTTPServer, BaseHTTPRequestHandler; \
from metrics_redis_exporter import get_metrics; \
class MetricsHandler(BaseHTTPRequestHandler): \
def do_GET(self): \
if self.path == '/metrics': \
self.send_response(200); \
self.send_header('Content-Type', 'text/plain; version=0.0.4'); \
self.end_headers(); \
self.wfile.write(get_metrics()); \
else: \
self.send_response(404); \
self.end_headers(); \
def log_message(self, format, *args): pass; \
server = HTTPServer(('0.0.0.0', 8001), MetricsHandler); \
print('Redis Exporter 启动在端口 8001'); \
server.serve_forever()"]

View File

@@ -0,0 +1,108 @@
version: '3.8'
services:
app:
build:
context: ..
dockerfile: deployment/Dockerfile
ports:
- "8111:8000"
environment:
- APP_ENV=development
- LOG_LEVEL=INFO
- METRICS_ENABLED=true
# 方案1Pushgateway 配置
- PUSHGATEWAY_URL=pushgateway:9091
- METRICS_JOB_NAME=functional_scaffold
# 方案2Redis 配置
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_METRICS_DB=0
volumes:
- ../src:/app/src
restart: unless-stopped
depends_on:
- redis
- pushgateway
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz')"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
# Redis - 用于集中式指标存储方案2
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# Pushgateway - 用于短生命周期任务的指标推送方案1推荐
pushgateway:
image: prom/pushgateway:latest
ports:
- "9091:9091"
restart: unless-stopped
command:
- '--persistence.file=/data/pushgateway.data'
- '--persistence.interval=5m'
volumes:
- pushgateway_data:/data
# Redis Exporter - 将 Redis 指标导出为 Prometheus 格式方案2需要
redis-exporter:
build:
context: ..
dockerfile: deployment/Dockerfile.redis-exporter
ports:
- "8001:8001"
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_METRICS_DB=0
depends_on:
- redis
restart: unless-stopped
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ../monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
restart: unless-stopped
depends_on:
- pushgateway
- redis-exporter
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
- ../monitoring/grafana:/etc/grafana/provisioning
restart: unless-stopped
depends_on:
- prometheus
volumes:
prometheus_data:
grafana_data:
redis_data:
pushgateway_data:

View File

@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: functional-scaffold
labels:
app: functional-scaffold
spec:
replicas: 3
selector:
matchLabels:
app: functional-scaffold
template:
metadata:
labels:
app: functional-scaffold
spec:
containers:
- name: functional-scaffold
image: functional-scaffold:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
name: http
env:
- name: APP_ENV
value: "production"
- name: LOG_LEVEL
value: "INFO"
- name: METRICS_ENABLED
value: "true"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /healthz
port: 8000
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3

View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: Service
metadata:
name: functional-scaffold
labels:
app: functional-scaffold
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8000
protocol: TCP
name: http
selector:
app: functional-scaffold
---
apiVersion: v1
kind: Service
metadata:
name: functional-scaffold-metrics
labels:
app: functional-scaffold
spec:
type: ClusterIP
ports:
- port: 8000
targetPort: 8000
protocol: TCP
name: metrics
selector:
app: functional-scaffold

View File

@@ -0,0 +1,40 @@
# 阿里云函数计算配置
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
functional-scaffold:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: '算法工程化 Serverless 脚手架'
LogConfig:
Project: functional-scaffold-logs
Logstore: function-logs
VpcConfig:
VpcId: 'vpc-xxxxx'
VSwitchIds:
- 'vsw-xxxxx'
SecurityGroupId: 'sg-xxxxx'
prime-checker:
Type: 'Aliyun::Serverless::Function'
Properties:
Description: '质数判断算法服务'
Runtime: custom-container
MemorySize: 512
Timeout: 60
InstanceConcurrency: 10
CAPort: 8000
CustomContainerConfig:
Image: 'registry.cn-hangzhou.aliyuncs.com/your-namespace/functional-scaffold:latest'
Command: '["uvicorn", "src.functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"]'
EnvironmentVariables:
APP_ENV: production
LOG_LEVEL: INFO
METRICS_ENABLED: 'true'
Events:
httpTrigger:
Type: HTTP
Properties:
AuthType: ANONYMOUS
Methods:
- GET
- POST

View File

@@ -0,0 +1,46 @@
# AWS Lambda 配置(使用 Lambda Container Image
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: FunctionalScaffold Serverless Application
Globals:
Function:
Timeout: 60
MemorySize: 512
Environment:
Variables:
APP_ENV: production
LOG_LEVEL: INFO
METRICS_ENABLED: 'true'
Resources:
FunctionalScaffoldFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
ImageUri: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/functional-scaffold:latest'
Events:
ApiEvent:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
Policies:
- AWSLambdaBasicExecutionRole
FunctionalScaffoldApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Cors:
AllowMethods: "'*'"
AllowHeaders: "'*'"
AllowOrigin: "'*'"
Outputs:
ApiUrl:
Description: "API Gateway endpoint URL"
Value: !Sub "https://${FunctionalScaffoldApi}.execute-api.${AWS::Region}.amazonaws.com/prod/"
FunctionArn:
Description: "Function ARN"
Value: !GetAtt FunctionalScaffoldFunction.Arn