使用docker部署python应用上线

程序员都遇到过上线部署项目的问题,那么在python中怎么部署一个应用呢?其实现在大家都用docker打包后进行部署。

为什么要用Docker?

同事是个老程序员,什么都喜欢手动,后来部署python应用他就出现了这些问题:

  1. 开发环境Python 3.9,服务器是3.6,某个语法不支持
  2. 本地用SQLite,线上用MySQL,连接方式完全不一样
  3. 依赖库版本对不上,一个隐蔽的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

生产环境优化

默认配置能用,但生产环境需要更多考虑:

  1. 资源限制——防止一个容器吃光所有内存
manyan:
  deploy:
    resources:
      limits:
        cpus: '1'
        memory: 512M
      reservations:
        memory: 256M
  1. 健康检查——让Docker知道应用是否健康
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1
  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分钟。

关键不是技术多先进,而是形成流程:

  1. 写代码 → 2. 写Dockerfile → 3. 本地测试 → 4. 推仓库 → 5. 服务器拉取运行

这套流程熟了之后,部署从玄学变成机械操作。再也不用说“我本地跑得好好的”了,因为本地和线上环境一模一样。

你的下一个Python项目,试试用Docker打包。第一次可能有点磕绊,但一旦跑通,你就回不去了。

posted @ 2025-12-23 15:11  深圳蔓延科技有限公司  阅读(13)  评论(0)    收藏  举报