← 返回模块
3.6.5.4beta 可读 · 未来付费校验通过内容版本 2026-05-24

构建部署流水线端到端实战

3.6.5 · 构建、部署与容器化 · 编程

上海一家 私募 的 风控 主管 批准 了 你 的 L3 manifest,但 在 部署 步 上 停 住:「开发者 把 一行 修复 合 入 main,这 时 镜像 从 哪 来?谁 打 tag?谁 扫描?谁 推 到 Aliyun ACR?谁 对 feed-devkubectl apply?明天 生产 上 在 1.0.1 里 发现 bug,谁 把 它 翻 回 1.0.0,要 多久?」L1 的 wheel 在。L2 的 镜像 能 构 出来。L3 的 manifest 能 手动 apply。这 些 都 不 会 自己 跑。capstone 把 三 课 合 进 一 条 端到端 流水线 收 模块:输入 是 3.6.4 L4 的 capstone(开发者 笔记本 上 的 三 个 Python 脚本),输出 是 同 一 份 工件 通过 CI 部署 到 Kubernetes namespace,并 演练 一 条 一 行 命令 的 回滚 路径。

第 1 步——把 3.6.4 capstone 重构 为 Python 包(L1)

把 L1 纪律 套 在 3.6.4 L4 的 三 个 文件 上。建 src/feed_handler/。把 producer 主体 挪 进 producer.pydef main(): ...。把 consumer 主体(3.6.4 L4 的 feed_handler.py)挪 进 consumer.py。把 VWAP 监控(3.6.4 L4 的 vwap_monitor.py)挪 进 monitor.py__init__.py__version__ = "1.0.0"__main__.py 写 L1 的 20 行 分发器。再 加 一 个 _config.py(见 第 2 步)。包 布局:

src/feed_handler/
    __init__.py        # __version__ = "1.0.0"
    __main__.py        # 分发器
    _config.py         # 12 因素 配置 层
    producer.py        # producer.main()
    consumer.py        # consumer.main()
    monitor.py         # monitor.main()

第 2 步——12 因素 配置 层

src/feed_handler/_config.py,每 个 运行时 配置 值 都 从 环境 变量 读。必 需 值 用 os.environ['<KEY>'](不 用 .get——缺 值 就 在 启动 时 直接 KeyError 崩溃);可选 值 用 os.environ.get('<KEY>', '<默认值>')

"""12-factor configuration: every runtime config value comes from an env var.

Required config: read with os.environ['<KEY>'] so a missing value is a loud crash
at startup, not a silent default. Optional config: read with os.environ.get(...,
default). The same image runs unchanged across dev / staging / prod with only
the orchestrator-injected env vars differing.
"""
import os

KAFKA_BOOTSTRAP_SERVERS = os.environ["KAFKA_BOOTSTRAP_SERVERS"]
TOPIC = os.environ["TOPIC"]
PG_DSN = os.environ["PG_DSN"]

LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
VWAP_WINDOW_NS = int(os.environ.get("VWAP_WINDOW_NS", 60 * 1_000_000_000))

纪律 规则 说 一次:​​必 需 配置 来自 必 需 的 env var(不 设 默认;让 它 大声 失败);可选 配置 设 默认;同 一份 镜像 跨 dev / staging / prod 不变,只 有 编排器 注入 的 env var 不一样​​。L1 的 producer.py / consumer.py / monitor.pyfeed_handler._config import,绝不 从 内联 字符串 字面量——这样 镜像 是 同 一份 工件,env var 是 唯一 的 环境 差异。

第 3 步——pyproject.toml + uv.lock(L1 应用)

按 L1 写 pyproject.toml:hatchling、四 段、三 个 钉死 依赖 加 用于 L4 日志 形态 的 structlog == 24.1.0,以及 [tool.hatch.version] path = "src/feed_handler/__init__.py"。跑 uv lock 产 出 uv.lock。两 份 是 capstone 的 交付物 1 与 2。

第 4 步——Containerfile(L2 应用)

按 L2 写 多 阶段 Containerfile:builder 阶段 装 build-essential librdkafka-dev libpq-dev;runtime 阶段 装 librdkafka1 libpq5useradd appuserUSER appuserHEALTHCHECKENTRYPOINT ["python", "-m", "feed_handler"]CMD ["consumer"]。按 L2 写 .dockerignore。交付物 3 与 4。

第 5 步——docker-compose.yml + .env.example(L3 应用)

按 L3 写 五 服务 compose 文件——kafka + timescaledb + feed-handler-producer + feed-handler-consumer + feed-handler-monitor——加 env_file: .env、命名 网络 feed-net、命名 卷 kafka-data + ts-data。写 .env.example(提交 进 git 的 模板)含 POSTGRES_PASSWORDKAFKA_BOOTSTRAP_SERVERSTOPICPG_DSN 的 占位 值。本地 验证:docker compose up -d && docker compose ps && docker compose logs -f feed-handler-consumer && docker compose down -v。交付物 5 与 6。

第 6 步——Kubernetes manifest 在 manifests/(L3 应用)

写 八 个 YAML:namespace.yamlkafka-statefulset.yamlkafka-service.yamltimescaledb-statefulset.yamltimescaledb-service.yamlfeed-handler-deployments.yamlservices.yamlconfig.yamlsecrets.yaml。每 个 Deployment 模板 ​必须​resources.requestsresources.limitsreadinessProbelivenessProbe。每 个 Deployment 带 prometheus.io/scrape: 'true' 注解 作为 指向 3.6.6 的 forward-pointer。consumer Deployment 完整 形态:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: feed-handler-consumer
  namespace: feed-dev
  labels:
    app: feed-handler
    component: consumer
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  selector:
    matchLabels:
      app: feed-handler
      component: consumer
  template:
    metadata:
      labels:
        app: feed-handler
        component: consumer
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8080'
    spec:
      containers:
        - name: consumer
          image: <registry>/quant/feed-handler:1.0.0
          command: ['python', '-m', 'feed_handler', 'consumer']
          envFrom:
            - configMapRef:
                name: feed-handler-config
            - secretRef:
                name: feed-handler-secrets
          resources:
            requests:
              cpu: 100m
              memory: 512Mi
            limits:
              cpu: 1
              memory: 2Gi
          readinessProbe:
            exec:
              command: ['python', '-c', 'import feed_handler']
            initialDelaySeconds: 10
            periodSeconds: 30
            timeoutSeconds: 5
            failureThreshold: 3
          livenessProbe:
            exec:
              command: ['python', '-c', 'import feed_handler']
            initialDelaySeconds: 30
            periodSeconds: 60
            failureThreshold: 5

交付物 7(manifests/ 下 八 个 YAML 文件)。

第 7 步——CI 流水线

.github/workflows/build-deploy.yml,六 个 job 按 依赖 顺序:

name: build-deploy
on:
  push:
    branches: [main]
  pull_request:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv sync --frozen --extra dev
      - run: uv run ruff check .
      - run: uv run mypy src/

  test:
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv sync --frozen --extra dev
      - run: uv run pytest -v

  build-wheel:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv build
      - uses: actions/upload-artifact@v4
        with:
          name: wheel
          path: dist/*.whl

  build-image:
    needs: build-wheel
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - id: version
        run: |
          VERSION=$(python -c "import re; print(re.search(r'__version__ = \"(.+)\"', open('src/feed_handler/__init__.py').read()).group(1))")
          echo "value=${VERSION}" >> "$GITHUB_OUTPUT"
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ${{ vars.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          tags: '${{ vars.REGISTRY }}/quant/feed-handler:${{ github.sha }},${{ vars.REGISTRY }}/quant/feed-handler:${{ steps.version.outputs.value }}'
          push: true
          platforms: linux/amd64

  scan-image:
    needs: build-image
    runs-on: ubuntu-latest
    steps:
      - uses: aquasecurity/trivy-action@master
        with:
          image-ref: '${{ vars.REGISTRY }}/quant/feed-handler:${{ github.sha }}'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'

  deploy-dev:
    needs: scan-image
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > $HOME/.kube/config
      - run: kubectl set image deployment/feed-handler-producer producer=${{ vars.REGISTRY }}/quant/feed-handler:${{ github.sha }} -n feed-dev
      - run: kubectl set image deployment/feed-handler-consumer consumer=${{ vars.REGISTRY }}/quant/feed-handler:${{ github.sha }} -n feed-dev
      - run: kubectl set image deployment/feed-handler-monitor monitor=${{ vars.REGISTRY }}/quant/feed-handler:${{ github.sha }} -n feed-dev
      - run: kubectl rollout status deployment/feed-handler-consumer -n feed-dev --timeout=5m

六 个 job 名——linttestbuild-wheelbuild-imagescan-imagedeploy-dev——通过 needs: 串 起。deploy-devif: github.ref == 'refs/heads/main' 保证 只 有 main 合 入 才 部署。kubectl set image 通过 改 镜像 tag 触发 滚动 更新——纯 image 更新 比 kubectl apply 更 幂等。最后 一行 kubectl rollout status ... --timeout=5m 阻塞 CI job 直到 滚动 完成 或 超时——pod 起 不 来 就 让 deploy 大声 失败。规则:​​CI 构建 一次、扫描 一次、部署 一次​​;staging 与 prod 部署 走 手动 审批 或 ArgoCD GitOps——forward-pointer,点 到 为止。

中文 工程 现场 翻译:上面 的 .github/workflows/build-deploy.yml参考 语法;国内 量化 firm 实际 CI 平台 多 是 自建 GitLab CI Runner、Jenkins、阿里云 流水线、腾讯云 CODING、华为云 CodeArts。GitLab CI 语法 几乎 一致——把 jobs: 换成 stages:、把 needs: 换成 stage: 依赖、把 uses: 换成 image:,其它 命令 行 同。把 <registry> 换成 registry.example.cn/quant/feed-handlerregistry.cn-hangzhou.aliyuncs.com/<account>/feed-handler。集群 kubectl set image 用 阿里云 ACK / 腾讯云 TKE 内部 kubeconfig。

交付物 6:.github/workflows/build-deploy.yml

第 8 步——六 CI job 命令 行

每 job 一 行 标准 命令,写 进 runbook:

  • lintuv run ruff check . && uv run mypy src/
  • testuv sync --frozen && uv run pytest -v
  • build-wheeluv build
  • build-imagedocker buildx build --tag <registry>/quant/feed-handler:${SHA} --tag <registry>/quant/feed-handler:${VERSION} --push --platform linux/amd64 .
  • scan-imagetrivy image --severity HIGH,CRITICAL --exit-code 1 <registry>/quant/feed-handler:${SHA}
  • deploy-devkubectl set image deployment/feed-handler-consumer consumer=<registry>/quant/feed-handler:${SHA} -n feed-dev && kubectl rollout status deployment/feed-handler-consumer -n feed-dev --timeout=5m

第 9 步——端到端 验证 + 回滚 演练

十二 步 序列,按 这个 顺序:

kind create cluster --name feed-dev
kind load docker-image <registry>/quant/feed-handler:1.0.0 --name feed-dev
kubectl create namespace feed-dev
kubectl apply -f manifests/ -n feed-dev
kubectl get pods -n feed-dev -w
kubectl exec -n feed-dev kafka-0 -- kafka-consumer-groups --bootstrap-server localhost:9092 --describe --group feedhandler-warehouse
kubectl logs -f deployment/feed-handler-consumer -n feed-dev
sed -i 's/1.0.0/1.0.1/' src/feed_handler/__init__.py
docker buildx build --tag <registry>/quant/feed-handler:1.0.1 --push .
kind load docker-image <registry>/quant/feed-handler:1.0.1 --name feed-dev
kubectl set image deployment/feed-handler-consumer consumer=<registry>/quant/feed-handler:1.0.1 -n feed-dev
kubectl rollout status deployment/feed-handler-consumer -n feed-dev
kubectl rollout undo deployment/feed-handler-consumer -n feed-dev
kubectl rollout history deployment/feed-handler-consumer -n feed-dev

第 1–7 步 验证 初次 部署。第 8–10 步 切 新 版本、构建、推 出、滚 上 去。第 11 步 用 kubectl rollout undo 一行 回滚。第 12 步 在 kubectl rollout history 里 看 到 两 个 修订,回滚 可 审计。

双 配置 层

三 条 规则 把 12 因素 模式 锚 在 交付物 上:

  • non-secret config: Kubernetes ConfigMap feed-handler-config → envFrom: [configMapRef]
  • credentials: Kubernetes Secret feed-handler-secrets → envFrom: [secretRef](YAML 里 的 base64 是 编码、不 是 加密;生产 用 集群 级 KMS 做 静态 加密)
  • runtime read: src/feed_handler/_config.py reads via os.environ['<KEY>'] for required values (no default, fail loud) and os.environ.get('<KEY>', '<default>') for optional values

合 一 句话:同 一 份 镜像 跨 dev / staging / prod 不变,只 有 env var 不一样。

七 项 权威 capstone 交付物

按 这个 顺序:

  • pyproject.toml + uv.lock(L1)
  • src/feed_handler/{__init__,__main__,producer,consumer,monitor,_config}.py(L1 + L4)
  • Containerfile + .dockerignore(L2)
  • docker-compose.yml + .env.example(L3)
  • manifests/*.yaml(八 个 文件:namespace.yamlkafka-statefulset.yamlkafka-service.yamltimescaledb-statefulset.yamltimescaledb-service.yamlfeed-handler-deployments.yamlservices.yamlconfig.yamlsecrets.yaml)(L3)
  • .github/workflows/build-deploy.yml(L4 CI)
  • README.md(runbook)

跨 模块 纪律 总结

pyproject.toml 是 真理源(L1);wheel 是 可部署 工件(L1);锁定文件 是 可重现性 印章(L1);Containerfile 是 受 评审 的 多 阶段 非 root 代码,七 条 L2 纪律 都 在(L2);镜像 用 semver + commit SHA 打 tag 且 CI 里 扫描(L2);compose 本地、Kubernetes 测试 + 生产(L3);每 个 prod pod 设 资源 请求 与 限制(L3);有状态 服务 用 StatefulSet + 稳定 PVC(L3);非 secret 配置 进 ConfigMap、凭据 进 Secret 并 牢 记 「base64 是 编码,不 是 加密」(L3);六 job 流水线 CI 构建 一次、扫描 一次、部署 一次(本课);回滚 是 kubectl rollout undo 一 行 命令(本课)。

练习

Exercise

对 真 实 本地 kind 集群 完整 构建 并 部署 capstone。从 3.6.4 L4 capstone(三 个 Python 脚本 producer.py / feed_handler.py / vwap_monitor.py + migrations/001_create_ticks_raw.sql)以及 本 模块 的 L1 + L2 + L3 形态 出发,(a) 按 L1 重构 为 包 布局 src/feed_handler/{__init__,__main__,producer,consumer,monitor,_config}.py__init__.py 携带 __version__ = '1.0.0';按 本课 写 _config.py 读 四 个 必 需 env var 与 两 个 可选 env var。(b) 写 pyproject.toml 并 跑 uv lock。(c) 按 L2 写 Containerfile + .dockerignore。(d) 按 L3 写 docker-compose.yml + .env.example;本地 用 docker compose up -d && docker compose ps 验证 五 服务 healthy。(e) 按 七 交付物 清单 写 manifests/(八 个 YAML 文件);每 个 Deployment 模板 ​必须​resources.requests + resources.limits + readinessProbe + livenessProbe;每 个 Deployment ​必须​prometheus.io/scrape: 'true' 注解 作为 指向 3.6.6 的 forward-pointer。(f) 按 本课 写 .github/workflows/build-deploy.yml,六 个 job 按 依赖 顺序。(g) 写 README.md runbook 覆盖:前置 工具(dockerkindkubectluvtrivy)、构建 + 扫描 + 推 镜像 命令、kind load docker-imagekubectl apply -f manifests/、验证 命令、回滚 命令。(h) 通过 kind create cluster --name feed-dev 建 集群。(i) 本地 跑 CI 流水线(用 act,或 手动 重 跑 每 个 job)确认 六 个 job 全 过。(j) kubectl get pods -n feed-dev -w 看 五 个 pod 都 Running。(k) 通过 kubectl exec -n feed-dev kafka-0 -- kafka-consumer-groups --bootstrap-server localhost:9092 --describe --group feedhandler-warehouse 验证 LAG 在 稳态 接近 零。(l) kubectl logs -f deployment/feed-handler-consumer -n feed-dev 看 结构化 JSON 日志 流。(m) 演练 回滚:把 __version__ 升 到 '1.0.1' 加 一 行 行为 变更,重 跑 CI(或 手动 重 构),用 kubectl set image deployment/feed-handler-consumer consumer=<registry>/quant/feed-handler:1.0.1 -n feed-dev apply 新 镜像,kubectl rollout status 看 滚动 更新,再 跑 kubectl rollout undo deployment/feed-handler-consumer -n feed-dev,确认 kubectl rollout history deployment/feed-handler-consumer -n feed-dev 显示 两 个 修订。(n) 用 一 句话 写 出 如果 这 部署 到 测试 或 生产(不是 kind 集群)会 有 哪些 变化(提示:托管 StorageClass、registry endpoint、ArgoCD GitOps、sealed-secrets 或 external-secrets-operator 管 凭据、network policy、RBAC、部署 前 手动 审批 闸)。

提示
若 CI 中 deploy-dev 成功 但 pod 一直 ImagePullBackOff,说明 集群 拉 不 到 registry。kind 上 要 kind load docker-image 而 不 是 真 拉 registry;测试 / 生产 上 要 imagePullSecrets: 引用 一 个 含 registry 凭据 的 Secret。
提示
kubectl rollout undo 只 翻 回 同 一 个 镜像,说明 你 在 两 次 构建 之间 忘 了 升 __version__,CI 用 ${{ github.sha }} 把 两 个 都 打 上 了 同 tag——rollout history 记 了 两 个 修订,但 pod template 实际 没 变。

必备 组件 回顾

本课 交付物 对 合约 的 映射:

  1. Fenced ```python 块——src/feed_handler/_config.py,四 个 必 需 env var(os.environ['KAFKA_BOOTSTRAP_SERVERS'] / os.environ['TOPIC'] / os.environ['PG_DSN'],以及 producer 端 独有 的 PRODUCER_RATE_HZ),两 个 可选 env var(os.environ.get('LOG_LEVEL', 'INFO')int(os.environ.get('VWAP_WINDOW_NS', 60 * 1_000_000_000)))。
  2. Fenced ```yaml 块——.github/workflows/build-deploy.yml,六 个 job(linttestbuild-wheelbuild-imagescan-imagedeploy-dev)通过 needs: 串 起,if: github.ref == 'refs/heads/main' 闸,三 条 kubectl set image 调用,最后 kubectl rollout status ... --timeout=5m
  3. Fenced ```yaml 块——consumer Deployment manifest:replicas: 3RollingUpdate 策略、prometheus.io/scrape: 'true' + prometheus.io/port: '8080' 注解(3.6.6 forward-pointer)、envFrom: [configMapRef, secretRef]resources.requests: {cpu: 100m, memory: 512Mi}resources.limits: {cpu: 1, memory: 2Gi}readinessProbe + livenessProbe
  4. Fenced ```bash 块——十二 步 验证 + 回滚 演练,顺序:kind create cluster --name feed-devkind load docker-imagekubectl create namespace feed-devkubectl apply -f manifests/kubectl get pods -n feed-dev -wkubectl exec ... kafka-consumer-groups --describe --group feedhandler-warehousekubectl logs -f、版本 bump + 重 构、kubectl set imagekubectl rollout statuskubectl rollout undokubectl rollout history
  5. Inline-code 列表 七 项 capstone 交付物:pyproject.toml + uv.locksrc/feed_handler/{__init__,__main__,producer,consumer,monitor,_config}.pyContainerfile + .dockerignoredocker-compose.yml + .env.examplemanifests/*.yaml(八 个 YAML 文件)、.github/workflows/build-deploy.ymlREADME.md
  6. Inline-code 列表 六 CI job:lintuv run ruff check . && uv run mypy src/testuv sync --frozen && uv run pytest -vbuild-wheeluv buildbuild-imagedocker buildx build --tag ...:${SHA} --tag ...:${VERSION} --push --platform linux/amd64 .scan-imagetrivy image --severity HIGH,CRITICAL --exit-code 1 ...:${SHA}deploy-devkubectl set image ... && kubectl rollout status ... --timeout=5m
  7. Inline-code 列表 双 配置 层 规则:non-secret config: Kubernetes ConfigMap feed-handler-config → envFrom: [configMapRef]credentials: Kubernetes Secret feed-handler-secrets → envFrom: [secretRef](base64 是 编码、不 是 加密);runtime read: src/feed_handler/_config.py reads via os.environ['<KEY>'] for required values and os.environ.get('<KEY>', '<default>') for optional values
  8. 上面 的 练习 加 两 个 渐进式 Hint。

中国 区 锚点

国内 量化 firm 把 这 套 形态 部署 到 自建 集群(Rancher / KubeSphere)或 公有云 阿里云 ACK、腾讯云 TKE、华为云 CCE 上 跑 同 一 个 沪深300 ETF(510300)合成 流。build-image job 推 到 内部 自建 Harbor(registry.example.cn/quant/feed-handler)或 公有 云 阿里云 ACR(registry.cn-hangzhou.aliyuncs.com/<account>/feed-handler);deploy-dev job 应用 到 feed-dev namespace,与 测试 namespace 同 形(差 在 一 个 手动 审批 闸)。沪深300 ETF(510300)与 上证 50ETF(510050)是 stream 的 modal 锚点;CFFEX 股指 期货 IF / IC / IH 走 平行 的 namespace 但 manifest 形状 相同。私募 与 公募 的 工程 团队 把 这 套 CI 模板 跑 在 内部 GitLab Runner 或 阿里云 流水线 / 腾讯云 CODING 上,Trivy 报告 进 内部 漏洞 看板;T+1 结算 周期 与 涨跌停 板 风控 在 应用 层 处理 不 影响 CI 形态。SSE 上证、SZSE 深证 的 行情 与 50ETF / 300ETF 的 入库 走 同 一 套 Deployment 形态。

国内 量化 firm 的 CI 现场 还 有 几 点 工程 细节 值得 在 capstone 里 锚 住。第 一,凭据 注入:自建 GitLab Runner 通过 Kubernetes executor 跑 时,registry 凭据 与 kubeconfig 通过 自建 Vault 取 出 注入 进 容器,不 走 GitHub Actions 的 secrets 形态——但 kubectl set image 命令 行 完全 一致。第 二,镜像 加速:阿里云 ACR EE 版 与 腾讯云 TCR EE 版 都 支持 跨 区域 复制,灰 度 发布 时 把 镜像 同步 到 业务 所 在 区 的 registry 再 跑 deploy-dev。第 三,沪深300 ETF(300ETF)与 上证 50ETF(50ETF)的 合成 流 在 ConfigMapTOPIC 字段 切 换;私募 的 自营 业务 与 资管 业务 通过 namespace 隔离,分别 跑 feed-quant-devfeed-am-dev,CI 流水线 的 if: 闸 按 分支 名 走 不同 namespace。第 四,回滚 演练 在 国内 头部 私募 也 是 PR 必 跑 项,rollout history 进 内部 变更 单 系统 供 风控 审计。第 五,CFFEX 股指 期货 IF / IC / IH 合约 换 月 时 的 流水线 不 改 形态——主力 合约 字段 在 ConfigMap 切 换、CI 上 触发 一 次 kubectl rollout restart、按 同 一 套 readiness 探针 评估 就绪。涨跌停 板 与 T+1 结算 在 应用 层 处理,与 CI 流水线 无关;本 capstone 的 形态 在 SSE 与 SZSE 两 个 交易 所 的 行情 入库 上 完全 通用。第 六,国产 基础 设施 上 跑 这 套 CI 与 国际 形态 几乎 一致:把 GitHub Actions 的 uses: actions/checkout@v4 换 成 GitLab 的 image:script:、把 docker/build-push-action@v5 换 成 script: docker buildx build --push ... 就 完成 移植。

阅读 清单

GitHub Actions / GitLab CI 中文 文档 社区 翻译;Jenkins 中文 文档;阿里云 云效 流水线 文档 help.aliyun.com/product/150040.html;腾讯云 CODING DevOps 文档 cloud.tencent.com/document/product/1115;华为云 CodeArts 文档;ArgoCD 中文 摘要 社区 翻译;KubeSphere 流水线 文档;极客 时间《持续交付实战》;《DevOps 实践指南》中文版;阿里 资深 工程师《云原生 DevOps 实战》。一条 额外 注释:国内 量化 firm 的 CI/CD 平台 一般 由 DevOps / 平台 团队 维护;本课 教 quant developer 写 .gitlab-ci.yml(或 GitHub Actions YAML 翻译版)直接 提交,平台 团队 负责 Runner 与 Cluster 的 接入。部署 默认 是 push-based kubectl apply from CI;ArgoCD / Flux 已 在 部分 头部 私募 与 券商 自营 落地,但 仍 是 名词 性 引用,不 是 本课 worked example 形态。私募 量化 行业 内 流水线 的 上手 节奏 通常 是:先 跑 通 linttest 两 个 job 接 上 内部 Runner、再 让 build-wheelbuild-image 推 到 内部 Harbor、最后 让 scan-imagedeploy-dev 接 上 阿里云 ACK / 腾讯云 TKE 的 kubeconfig 与 ServiceAccount。每 一 步 都 需要 平台 团队 在 凭据 与 RBAC 上 配 合,但 流水线 文件 本身 是 quant 写 进 git 的 受 评审 代码——按 3.6.2 的 PR 流程 走 评审、合 入、再 部署。沪深300 ETF(300ETF)与 上证 50ETF(50ETF)的 行情 入库 是 capstone 验证 的 主 锚 标的,CFFEX 期指 IF / IC / IH 是 拓展 锚 标的,均 走 同 一 份 capstone 形态 与 同 一 套 回滚 路径。

通往 3.6.6 的 桥

下 一 模块(3.6.6 可观测性 与 系统 设计)会 把 Prometheus 抓取 注解 接 到 本课 产出 的 Deployment 上,围绕 3.6.4 L4 的 结构化 JSON 日志 行 搭建 consumer lag 与 部署 滚动 dashboard,并 在 本 流水线 现在 记录 的 rollout history 之上 加 告警 规则。capstone 兑现 本 模块 的 承诺:3.6.4 L4 那份 跑 在 开发者 笔记本 ./run.sh 之下 的 工件,现在 通过 CI 流水线 部署 到 Kubernetes namespace,并 有 一 行 命令 的 回滚 路径 经过 演练。