使用docker部署python应用上线
程序员都遇到过上线部署项目的问题,那么在python中怎么部署一个应用呢?其实现在大家都用docker打包后进行部署。
为什么要用Docker?
同事是个老程序员,什么都喜欢手动,后来部署python应用他就出现了这些问题:
- 开发环境Python 3.9,服务器是3.6,某个语法不支持
- 本地用SQLite,线上用MySQL,连接方式完全不一样
- 依赖库版本对不上,一个隐蔽的bug只在生产环境出现
他折腾了几天。如果用Docker,这些问题根本不会出现。
第一步
在打包之前,先整理检查一下你的应用。以我的manyan项目为例:
manyan/
├── app.py # 主程序
├── requirements.txt # 依赖清单
├── config/ # 配置文件
├── logs/ # 日志目录
└── migrations/ # 数据库迁移
关键检查点:
- 所有依赖都在requirements.txt里吗?(用
pip freeze > requirements.txt检查) - 敏感信息(密码、API密钥)从代码里剥离了吗?
- 日志是写到文件还是标准输出?(容器里建议用标准输出)
第二步
写Dockerfile配置文件,就是告诉Docker怎么打包你的应用。这是我给manyan项目写的:
# 选择基础镜像:Python 3.9的轻量版
FROM python:3.9-slim
# 设置工作目录:容器里的/app目录
WORKDIR /app
# 先复制依赖文件,这样能利用Docker的缓存层
COPY requirements.txt .
# 安装依赖(清华源加速)
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 复制整个项目代码
COPY . .
# 设置时区(避免日志时间不对)
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 创建一个非root用户运行应用(安全考虑)
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# 告诉Docker怎么启动应用
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "3", "app:app"]
关键点:
- 分阶段复制:先复制requirements.txt,这样改代码时不用重新安装依赖
- 非root用户:用root跑应用是大忌
- 国内镜像源:加速安装过程
第三步
打包前先本地测试:
# 1. 构建镜像(最后的点表示当前目录)
docker build -t manyan:latest .
# 2. 运行容器(-d后台运行,-p端口映射)
docker run -d --name manyan-test -p 8000:8080 manyan:latest
# 3. 测试访问
curl http://localhost:8000/health
# 4. 查看日志
docker logs manyan-test
# 5. 进入容器看看(调试用)
docker exec -it manyan-test /bin/bash
如果一切正常,你会看到应用在容器里欢快地跑着。
第四步
正确设置和读取配置文件。别把数据库密码写在代码里,然后打包进镜像了...
正确做法:环境变量 + 配置文件挂载
# app.py里这样读取配置
import os
from dotenv import load_dotenv
load_dotenv() # 加载.env文件
DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///local.db')
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
然后在运行容器时传入:
docker run -d \
--name manyan \
-p 8000:8080 \
-e DATABASE_URL=mysql://user:pass@db:3306/manyan \
-e DEBUG=False \
-v $(pwd)/config:/app/config \
manyan:latest
或者用.env文件:
# .env文件
DATABASE_URL=mysql://user:pass@db:3306/manyan
DEBUG=False
REDIS_URL=redis://redis:6379/0
# 运行
docker run --env-file .env -p 8000:8080 manyan:latest
第五步
多服务协作,真实应用很少单打独斗。manyan需要PostgreSQL数据库和Redis缓存:
# docker-compose.yml
version: '3.8'
services:
# 主应用
manyan:
build: .
ports:
- "8000:8080"
environment:
- DATABASE_URL=postgresql://manyan_user:password@db:5432/manyan_db
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
volumes:
- ./logs:/app/logs # 日志持久化
restart: unless-stopped # 自动重启
# 数据库
db:
image: postgres:13
environment:
POSTGRES_USER: manyan_user
POSTGRES_PASSWORD: password
POSTGRES_DB: manyan_db
volumes:
- postgres_data:/var/lib/postgresql/data
# Redis
redis:
image: redis:6-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
启动整个栈:
docker-compose up -d
一行命令,三个服务全部启动,网络自动配置好。
第六步
本地测试好了,现在要上线。
方案A:简单直接(适合小项目)
# 1. 把代码传到服务器
scp -r manyan user@server:/app/
# 2. 在服务器上构建和运行
ssh user@server
cd /app/manyan
docker-compose up -d
方案B:镜像仓库(更正规)
# 1. 推送到Docker Hub
docker tag manyan:latest yourname/manyan:1.0
docker push yourname/manyan:1.0
# 2. 服务器拉取并运行
docker pull yourname/manyan:1.0
docker run -d --name manyan -p 8000:8080 yourname/manyan:1.0
方案C:自动化部署(GitHub Actions)
name: 自动部署
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: 部署到服务器
uses: appleboy/ssh-action@v0.1.4
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /app/manyan
git pull
docker-compose down
docker-compose build
docker-compose up -d
生产环境优化
默认配置能用,但生产环境需要更多考虑:
- 资源限制——防止一个容器吃光所有内存
manyan:
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
memory: 256M
- 健康检查——让Docker知道应用是否健康
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
- 日志驱动——更好的日志管理
docker run --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3 ...
常见坑和填坑指南
坑1:容器时区不对
解决:Dockerfile里设置时区,或者运行容器时加-e TZ=Asia/Shanghai
坑2:应用写文件,重启后没了
解决:用volumes挂载需要持久化的目录
坑3:性能比直接部署慢
解决:可能是虚拟化开销,对于性能敏感应用,考虑--network=host模式
坑4:镜像太大,传输慢
解决:用alpine基础镜像,多阶段构建,清理不必要的文件
监控和维护:上线只是开始
应用跑起来后:
# 查看状态
docker-compose ps
# 查看日志
docker-compose logs -f manyan
# 进入容器调试
docker-compose exec manyan /bin/bash
# 更新应用
docker-compose pull manyan
docker-compose up -d
# 备份数据
docker-compose exec db pg_dumpall -U postgres > backup.sql
什么时候不该用Docker?
Docker不是万能的。如果你的应用:
- 对性能极端敏感(高频交易系统)
- 需要特殊硬件访问(GPU直通)
- 只是简单的脚本,跑完就结束
- 团队完全不懂容器技术
那可能直接部署更合适。
说点实在的
我第一次用Docker部署时,花了三天时间。现在,从零部署一个Python应用到上线,大概30分钟。
关键不是技术多先进,而是形成流程:
- 写代码 → 2. 写Dockerfile → 3. 本地测试 → 4. 推仓库 → 5. 服务器拉取运行
这套流程熟了之后,部署从玄学变成机械操作。再也不用说“我本地跑得好好的”了,因为本地和线上环境一模一样。
你的下一个Python项目,试试用Docker打包。第一次可能有点磕绊,但一旦跑通,你就回不去了。

浙公网安备 33010602011771号