使用 Streamlit Docker 镜像快速上线数据 App

解读

面试官抛出这道题,核心想验证三件事:

  1. 你是否能在国内网络环境下(镜像源、PyPI 源、企业内网 Artifactory)把 Streamlit 应用容器化;
  2. 镜像体积、构建速度、运行时安全是否达到生产交付标准
  3. 能否把“本地能跑”一键变成“线上可灰度、可回滚、可观测”的DevOps 闭环
    如果仅回答“FROM streamlit/streamlit 然后 docker run”,会被追问“镜像 1.3 GB 怎么优化?非 root 怎么写?Swarm 怎么滚动?Secrets 怎么注入?”因此回答必须体现国内实战细节云原生最佳实践

知识点

  1. 国内加速:/etc/docker/daemon.json 配置 registry-mirrors(阿里云、腾讯云、DaoCloud),pip 换清华源,构建机缓存挂载。
  2. 多阶段构建:python:3.11-slim 阶段装 gcc 编译依赖,最终阶段只保留 venv 与 app,把 1.3 GB 压到 120 MB
  3. 非 root 与 UID 统一:Dockerfile 里创建 uid=1000 的 app 用户,与 K8s securityContext.runAsUser 对齐,防止卷权限 777
  4. requirements 冻结:pip freeze > requirements.txt 并加 --no-cache-dir,避免“本地最新版线上没有”的国内 pip 源延迟问题。
  5. 健康检查:HEALTHCHECK CMD curl -f http://localhost:8501/_stcore/health 或 python -m streamlit hello 探测,Swarm/K8s 就绪探针复用
  6. Secrets 管理:Swarm 用 docker secret,K8s 用 sealed-secrets,本地开发用 docker-compose --env-file .env,绝不写死 AK/SK
  7. 镜像仓库:企业内网 Harbor 配项目级机器人账号,开启镜像扫描与策略 webhook,阻断 CVE≥High 的镜像上线
  8. CI/CD:GitLab-CI 中 docker buildx 跨平台构建,tag 用 ${CI_COMMIT_SHORT_SHA},推送后自动更新 Swarm service 或 ArgoCD 同步
  9. 资源限制:--memory=512M --cpus=0.5,结合 streamlit.server.maxUploadSize=50 避免 OOM,国内 2C4G 轻量云也能跑
  10. 日志与监控:stdout 输出 JSON,Filebeat 收集到阿里云 SLS,Prometheus 通过 streamlit-prometheus 暴露指标,告警直接飞书机器人

答案

  1. 项目结构
    streamlit-app/
    ├─ app.py
    ├─ requirements.txt
    ├─ .dockerignore
    └─ Dockerfile

  2. Dockerfile(国内优化版)

# 阶段1:依赖编译
FROM registry.cn-hangzhou.aliyuncs.com/acs/python:3.11-slim as builder
RUN sed -i 's@deb.debian.org@mirrors.aliyun.com@g' /etc/apt/sources.list && \
    apt-get update && apt-get install -y --no-install-recommends \
    build-essential gcc g++ && rm -rf /var/lib/apt/lists/*
COPY requirements.txt /tmp/
RUN pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir -r /tmp/requirements.txt

# 阶段2:运行镜像
FROM registry.cn-hangzhou.aliyuncs.com/acs/python:3.11-slim
RUN groupadd -r appuser && useradd -r -g appuser -u 1000 -m -d /app appuser
WORKDIR /app
COPY --from=builder /root/.local /home/appuser/.local
ENV PATH=/home/appuser/.local/bin:$PATH
COPY --chown=appuser:appuser app.py .
EXPOSE 8501
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD python -c "import requests,sys; sys.exit(0 if requests.get('http://localhost:8501/_stcore/health').status_code==200 else 1)"
USER appuser
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
  1. 构建与推送
docker buildx build --platform linux/amd64 -t harbor.mycompany.com/dataapp/streamlit-demo:1.0.0 --push .
  1. Swarm 部署(单命令上线)
echo $AK | docker secret create ak -
echo $SK | docker secret create sk -
docker stack deploy -c docker-compose.yml demo

docker-compose.yml 片段:

secrets:
  ak:
    external: true
  sk:
    external: true
services:
  streamlit:
    image: harbor.mycompany.com/dataapp/streamlit-demo:1.0.0
    ports:
      - "8501:8501"
    environment:
      AWS_ACCESS_KEY_ID_FILE: /run/secrets/ak
    secrets:
      - ak
      - sk
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
    healthcheck:
      test: ["CMD", "python", "-c", "import requests,sys; sys.exit(0 if requests.get('http://localhost:8501/_stcore/health').status_code==200 else 1)"]
      interval: 30s
      timeout: 3s
      retries: 3
  1. 灰度验证
curl -I http://demo.mycompany.com:8501/_stcore/health

返回 200 后,在 Harbor 把 1.0.0 标记为“已签名”,ArgoCD 自动同步到 K8s 集群,完成零停机上线

拓展思考

  1. 国内监管:如果 App 涉及个人信息,镜像里需预装国密 SM4 加密库,并在 Dockerfile 里声明 LABEL 安全责任人,满足《个人信息保护法》审计
  2. 边缘场景:在工厂内网用 Docker Swarm 部署,节点通过阿里云边缘镜像加速 ACR EE 实例拉取,断网时靠本地缓存镜像继续运行。
  3. 成本优化:利用 Harbor 的镜像代理缓存,把公网流量降到 0;同时用 cgroup v2 的 memory.high 做弹性限流,2C4G 机器可跑 8 个副本
  4. 回滚策略:在 GitLab-CI 里把旧版本镜像 tag 加 -rollback,Swarm update --rollback 可在 30 秒内完成,比 K8s 更轻量
  5. 可观测性:通过 OpenTelemetry 把 Streamlit 的 st.metric 指标直接打到阿里云链路追踪 XTrace,实现“代码无侵入,问题 1 分钟定位”。