Flask 笔记十七:Docker 打包 Flask 应用

上一篇我们用 pytest 给路由和 API 加了自动化测试。第十四篇是在服务器上 手动装 Python、配 venv、起 Gunicorn------能跑,但换一台机器往往又要重来一遍。

这一篇做一件事:用 Docker 把「应用 + 运行环境」打成一个镜像,再用 docker-compose 一键拉起 Flask 和 MySQL。

例子仍是通用的 Note 备忘录项目,不涉及任何真实业务。


1. 学完后你能做什么

  • Dockerfile,用 Gunicorn 启动 Flask
  • docker-compose.yml,Flask + MySQL 一起跑
  • 用 环境变量 传配置(接第十二篇)
  • 知道 卷(volume) 持久化数据库
  • 本地一条命令 docker compose up 复现「接近生产」的环境

2. Docker 解决什么问题

没有 Docker 有 Docker
「我机器上能跑啊」 镜像里环境一致
Python 版本、系统包装一堆 镜像自带依赖
新人搭环境半天 docker compose up
生产和本地差一截 同一套镜像可部署

Docker 不是必须,小项目直接 Gunicorn 也完全可以。团队变大、要 CI/CD、要多环境一致时,Docker 很省心。


3. 整体架构

docker compose up

├── 容器 web(Flask + Gunicorn :5000)

│ │

│ └── 连 → db:3306

└── 容器 db(MySQL 8)

└── volume 持久化数据

浏览器访问:http://127.0.0.1:5000(映射到 web 容器)。


4. 项目里要加哪些文件

myproject/

├── app/

├── manage.py

├── requirements.txt

├── Dockerfile # 新增

├── docker-compose.yml # 新增

├── .dockerignore # 新增(减小镜像)

└── .env.docker # 可选,compose 读环境变量


5. Dockerfile(Web 镜像)

FROM python:3.11-slim

WORKDIR /app

系统依赖(MySQL 客户端库等,按需)

RUN apt-get update && apt-get install -y --no-install-recommends \

gcc default-libmysqlclient-dev pkg-config \

&& rm -rf /var/lib/apt/lists/*

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt gunicorn

COPY . .

ENV FLASK_APP=app

ENV PYTHONUNBUFFERED=1

EXPOSE 5000

CMD "gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "app:app"

说明:

  • python:3.11-slim:体积小,够用
  • 先 COPY requirements 再 COPY 代码:改代码时重建层更快
  • CMD gunicorn:接第十四篇,不用 app.run()
  • worker 容器里 2 个 即可,别贪多

若只用 SQLite、不连 MySQL,可去掉 gccmysqlclient 相关 apt 包。


6. .dockerignore

避免把垃圾打进镜像:

.venv

pycache

*.pyc

.git

.pytest_cache

instance/*.db

.env

*.md

tests/


7. docker-compose.yml

services:

db:

image: mysql:8.0

environment:

MYSQL_ROOT_PASSWORD: rootpass

MYSQL_DATABASE: notes

MYSQL_USER: notes

MYSQL_PASSWORD: notespass

volumes:

  • mysql_data:/var/lib/mysql

ports:

  • "3306:3306"

healthcheck:

test: "CMD", "mysqladmin", "ping", "-h", "localhost"

interval: 5s

timeout: 5s

retries: 10

web:

build: .

ports:

  • "5000:5000"

environment:

FLASK_DEBUG: "0"

SECRET_KEY: "change-me-in-production"

DATABASE_URL: "mysql+pymysql://notes:notespass@db:3306/notes"

depends_on:

db:

condition: service_healthy

command: >

sh -c "

flask db upgrade &&

gunicorn -w 2 -b 0.0.0.0:5000 app:app

"

volumes:

mysql_data:

要点:

  • 服务名 db → Web 容器里主机名就是 db(不是 127.0.0.1
  • depends_on + healthcheck:等 MySQL 就绪再起 Flask
  • command 里先 flask db upgrade(接第十五篇),再起 Gunicorn
  • mysql_data volume:删容器数据还在

app/__init__.py 需能读 DATABASE_URL(第十二篇环境变量那套)。


8. 启动与常用命令

构建并后台启动

docker compose up -d --build

看日志

docker compose logs -f web

进 web 容器执行 CLI

docker compose exec web flask create-admin admin

停掉

docker compose down

停掉并删数据库卷(慎用!)

docker compose down -v

浏览器打开 http://127.0.0.1:5000


9. 环境变量怎么管理

不要把真密码写进 Dockerfile 提交 Git。

方式 用法
docker-compose.ymlenvironment 本地演示可以,生产换 secrets
.env 文件(compose 自动读) SECRET_KEY=xxx 一行一个
服务器上 export + compose 生产常见

.env 示例(加入 .gitignore):

SECRET_KEY=本地随机长字符串

MYSQL_PASSWORD=notespass

docker-compose.yml 里可写:

environment:

SECRET_KEY: ${SECRET_KEY}

DATABASE_URL: mysql+pymysql://notes:${MYSQL_PASSWORD}@db:3306/notes


10. 开发时:代码热更新(可选)

生产镜像不必挂载源码;本地开发可挂载目录,改代码重启容器即生效:

web:

build: .

volumes:

  • .:/app

environment:

FLASK_DEBUG: "1"

command: flask run --host=0.0.0.0 --port=5000

注意:FLASK_DEBUG=1 只限本地 Docker 开发,生产 compose 仍用 Gunicorn + FLASK_DEBUG=0

很多人 开发仍用本机 venv + flask run,Docker 只用来测「和生产一致」的集成------这样也行。


11. 和前面各篇怎么串起来

在 Docker 里
十二 环境变量 environment / .env
十四 Gunicorn CMD 或 compose command
十五 CLI docker compose exec web flask ...
十六 pytest CI 里 docker compose run web pytest(可选)
七 Migrate 启动前 flask db upgrade

12. 流程示意

docker compose up --build

构建 web 镜像(pip install + COPY 代码)

启动 db(MySQL + volume)

db healthcheck 通过

web:flask db upgrade → gunicorn

http://127.0.0.1:5000 可访问


13. 新手常踩的 6 个坑

  1. Web 连 127.0.0.1:3306 --- 在容器里 127.0.0.1 是自己,MySQL 要用主机名 db
  2. 没等 MySQL 就绪就 migrate --- 用 healthcheck + depends_on
  3. .env 提交 Git --- 进 .gitignore
  4. 镜像里用 app.run(debug=True) --- 生产用 Gunicorn。
  5. 不设 volume --- 容器删了数据库没了。
  6. 镜像巨大 --- 用 .dockerignore、多阶段构建(进阶再学)。

14. 小结

记住五件事:

  1. Dockerfile:装依赖 + gunicorn app:app
  2. docker-compose.yml:web + db + volume
  3. 数据库主机名用服务名 db
  4. 启动前 flask db upgrade
  5. 密钥走环境变量,别写进镜像

十七篇下来,你已经会:本机开发 → 测试 → Gunicorn 部署 → CLI 运维 → Docker 一键环境。