目录
- 将你的Django/Flask应用部署到云服务器(Docker实战)
-
- [1 引言](#1 引言)
-
- [1.1 为什么需要容器化部署?](#1.1 为什么需要容器化部署?)
- [1.2 Django与Flask简介](#1.2 Django与Flask简介)
- [2 Docker基础](#2 Docker基础)
-
- [2.1 Docker核心概念](#2.1 Docker核心概念)
- [2.2 Docker的优势](#2.2 Docker的优势)
- [3 准备工作](#3 准备工作)
-
- [3.1 项目结构准备](#3.1 项目结构准备)
- [3.2 环境配置](#3.2 环境配置)
- [4 编写Dockerfile](#4 编写Dockerfile)
-
- [4.1 Flask应用Dockerfile](#4.1 Flask应用Dockerfile)
- [4.2 Django应用Dockerfile](#4.2 Django应用Dockerfile)
- [4.3 多阶段构建优化](#4.3 多阶段构建优化)
- [5 使用Docker Compose编排多容器应用](#5 使用Docker Compose编排多容器应用)
-
- [5.1 Flask多服务编排](#5.1 Flask多服务编排)
- [5.2 Django多服务编排](#5.2 Django多服务编排)
- [5.3 生产环境优化](#5.3 生产环境优化)
- [6 生产环境配置](#6 生产环境配置)
-
- [6.1 使用Gunicorn作为WSGI服务器](#6.1 使用Gunicorn作为WSGI服务器)
- [6.2 Nginx配置](#6.2 Nginx配置)
- [6.3 环境变量管理](#6.3 环境变量管理)
- [7 完整示例代码](#7 完整示例代码)
-
- [7.1 Flask应用完整示例](#7.1 Flask应用完整示例)
- [7.2 Django应用完整示例](#7.2 Django应用完整示例)
- [8 部署到云服务器](#8 部署到云服务器)
-
- [8.1 服务器准备](#8.1 服务器准备)
- [8.2 部署流程](#8.2 部署流程)
- [8.3 使用CI/CD自动化部署](#8.3 使用CI/CD自动化部署)
- [9 常见问题与解决方案](#9 常见问题与解决方案)
-
- [9.1 部署常见错误](#9.1 部署常见错误)
- [9.2 性能优化建议](#9.2 性能优化建议)
- [10 总结](#10 总结)
-
- [10.1 关键要点回顾](#10.1 关键要点回顾)
- [10.2 后续学习方向](#10.2 后续学习方向)
『宝藏代码胶囊开张啦!』------ 我的 CodeCapsule 来咯!✨
写代码不再头疼!我的新站点 CodeCapsule 主打一个 "白菜价"+"量身定制 "!无论是卡脖子的毕设/课设/文献复现 ,需要灵光一现的算法改进 ,还是想给项目加个"外挂",这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 👉 CodeCapsule官网
将你的Django/Flask应用部署到云服务器(Docker实战)
1 引言
1.1 为什么需要容器化部署?
在现代软件开发中,将应用程序快速、可靠地部署到不同环境是一项关键挑战。传统部署方式常常面临"在我机器上能运行"的问题,因为开发、测试和生产环境之间的差异导致应用程序行为不一致。容器化技术通过将应用程序及其所有依赖项打包在一起,彻底解决了环境一致性问题。
Docker作为目前最流行的容器化平台,提供了一种轻量级的虚拟化解决方案。与传统虚拟机相比,Docker容器共享主机操作系统内核,启动更快、资源开销更小,同时仍能保持应用程序的隔离性。对于Python Web应用而言,无论是使用轻量级的Flask还是全功能的Django,Docker都能确保它们在各种环境下具有完全相同的行为。
1.2 Django与Flask简介
Django是一个高级Python Web框架,遵循"包含电池"(batteries-included)理念,提供了ORM、认证、管理后台等丰富功能,适合快速构建复杂的企业级应用。Flask则是一个轻量级微框架,核心简单但可通过扩展增强功能,给予开发者更多灵活性,适合小型项目、API服务和微服务架构。
尽管这两个框架在设计哲学和功能集上有所不同,但它们都可以通过Docker实现标准化部署,这也是本文将要重点介绍的内容。
2 Docker基础
2.1 Docker核心概念
在开始容器化部署之前,需要了解以下几个核心概念:
- 镜像(Image):只读模板,包含运行应用程序所需的一切------代码、运行时、库、环境变量和配置文件。
- 容器(Container):镜像的运行实例,是一个隔离的进程,拥有自己的文件系统、网络和进程空间。
- Dockerfile:文本文件,包含一系列构建镜像的指令。
- Docker Compose:工具用于定义和运行多容器Docker应用程序。
2.2 Docker的优势
使用Docker部署Python Web应用带来了多重优势:
- 环境一致性:确保应用从开发到生产在不同环境中具有完全相同的行为。
- 快速部署:容器启动秒级完成,极大缩短部署周期。
- 资源高效:容器共享主机OS内核,无需为每个应用分配完整操作系统资源。
- 易于扩展:结合Kubernetes等编排工具,可以轻松实现应用的水平扩展。
3 准备工作
3.1 项目结构准备
在开始容器化之前,需要合理组织项目结构。一个典型的Docker化Python Web项目结构如下:
mywebapp/
├── app/ # 应用代码目录
│ ├── __init__.py
│ ├── models.py # 数据模型
│ ├── views.py # 视图函数
│ └── static/ # 静态文件
├── requirements.txt # Python依赖
├── Dockerfile # Docker构建文件
├── docker-compose.yml # 多服务编排
├── entrypoint.sh # 启动脚本
└── .dockerignore # Docker忽略文件
3.2 环境配置
为适应容器环境,需要对应用配置进行一些调整:
Flask应用配置调整(app.py):
python
from flask import Flask
import os
app = Flask(__name__)
# 从环境变量读取配置,增强灵活性
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-secret-key')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///app.db')
@app.route('/')
def hello():
return 'Hello, Dockerized Flask!'
if __name__ == '__main__':
# 关键:监听所有网络接口
app.run(host='0.0.0.0', port=5000)
Django设置调整(settings.py):
python
import os
# 从环境变量读取密钥
SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-dev-key')
# 从环境变量读取数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'mydatabase'),
'USER': os.environ.get('DB_USER', 'myuser'),
'PASSWORD': os.environ.get('DB_PASSWORD', 'mypassword'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
}
}
# 静态文件配置
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
4 编写Dockerfile
4.1 Flask应用Dockerfile
创建Flask应用的Dockerfile:
dockerfile
# 使用官方Python精简版作为基础镜像
FROM python:3.10-slim
# 设置环境变量
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
FLASK_APP=app.py \
FLASK_ENV=production
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc python3-dev \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非root用户(安全最佳实践)
RUN useradd -m -u 1000 webuser && chown -R webuser:webuser /app
USER webuser
# 暴露端口
EXPOSE 5000
# 定义启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:app"]
4.2 Django应用Dockerfile
Django应用的Dockerfile与Flask类似,但有一些特定配置:
dockerfile
# 使用官方Python精简版作为基础镜像
FROM python:3.10-slim
# 设置环境变量
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
gcc \
python3-dev \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非root用户
RUN useradd -m -u 1000 webuser && chown -R webuser:webuser /app
USER webuser
# 收集静态文件(在启动脚本中处理更合适)
# RUN python manage.py collectstatic --noinput
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "myproject.wsgi:application"]
4.3 多阶段构建优化
对于生产环境,可以使用多阶段构建来减小镜像大小:
dockerfile
# 第一阶段:构建阶段
FROM python:3.10-slim as builder
WORKDIR /app
COPY requirements.txt .
# 安装构建依赖
RUN apt-get update && apt-get install -y --no-install-recommends gcc python3-dev
# 安装依赖到用户目录
RUN pip install --user -r requirements.txt
# 第二阶段:最终镜像
FROM python:3.10-slim
WORKDIR /app
# 从构建阶段复制已安装的Python包
COPY --from=builder /root/.local /root/.local
COPY . .
# 确保使用的Python可以找到用户安装的包
ENV PATH=/root/.local/bin:$PATH
# 创建非root用户
RUN useradd -m -u 1000 webuser && chown -R webuser:webuser /app
USER webuser
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "myproject.wsgi:application"]
5 使用Docker Compose编排多容器应用
5.1 Flask多服务编排
大多数Web应用不仅包含应用本身,还需要数据库、缓存等支撑服务。以下是一个典型的Flask多服务编排示例:
yaml
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- DATABASE_URL=postgresql://flaskuser:flaskpass@db:5432/flaskdb
- REDIS_URL=redis://redis:6379/0
- SECRET_KEY=your-secret-key-here
depends_on:
- db
- redis
volumes:
- .:/app # 开发时使用,生产环境应移除
restart: unless-stopped
db:
image: postgres:13
environment:
- POSTGRES_DB=flaskdb
- POSTGRES_USER=flaskuser
- POSTGRES_PASSWORD=flaskpass
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:6-alpine
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
postgres_data:
redis_data:
5.2 Django多服务编排
Django项目的Docker Compose文件与Flask类似,但可能包含更多服务:
yaml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DJANGO_SETTINGS_MODULE=myproject.settings.production
- DATABASE_URL=postgresql://djangouser:djangopass@db:5432/djangodb
- REDIS_URL=redis://redis:6379/0
- SECRET_KEY=your-django-secret-key
depends_on:
- db
- redis
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/mediafiles
command: >
sh -c "python manage.py migrate &&
python manage.py collectstatic --noinput &&
gunicorn --bind 0.0.0.0:8000 --workers 3 myproject.wsgi:application"
restart: unless-stopped
db:
image: postgres:13
environment:
- POSTGRES_DB=djangodb
- POSTGRES_USER=djangouser
- POSTGRES_PASSWORD=djangopass
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:6-alpine
volumes:
- redis_data:/data
restart: unless-stopped
nginx:
image: nginx:1.21-alpine
ports:
- "80:80"
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/mediafiles
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- web
restart: unless-stopped
volumes:
postgres_data:
redis_data:
static_volume:
media_volume:
5.3 生产环境优化
生产环境的Docker Compose需要更多优化配置:
yaml
version: '3.8'
services:
web:
build:
context: .
target: builder # 多阶段构建
ports:
- "8000:8000"
environment:
- DJANGO_SETTINGS_MODULE=myproject.settings.production
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- SECRET_KEY=${SECRET_KEY}
env_file:
- .env.production
depends_on:
- db
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/mediafiles
command: >
sh -c "python manage.py migrate &&
python manage.py collectstatic --noinput &&
gunicorn --bind 0.0.0.0:8000 --workers 4 --threads 2 myproject.wsgi:application"
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
image: postgres:13
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
command: >
postgres -c shared_preload_libraries=pg_stat_statements
-c pg_stat_statements.track=all
-c max_connections=100
nginx:
image: nginx:1.21-alpine
ports:
- "80:80"
- "443:443" # HTTPS端口
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/mediafiles
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./ssl:/etc/nginx/ssl # SSL证书
depends_on:
- web
restart: unless-stopped
volumes:
postgres_data:
static_volume:
media_volume:
6 生产环境配置
6.1 使用Gunicorn作为WSGI服务器
Python内置的开发服务器不适合生产环境,应当使用专业的WSGI服务器如Gunicorn或uWSGI。
Gunicorn基础配置:
python
# gunicorn.conf.py
# 并行工作进程数,通常建议 (2 * CPU核心数) + 1
workers = 4
# 指定每个工作者的线程数
threads = 2
# 监听内网端口
bind = '0.0.0.0:8000'
# 工作模式协程
worker_class = 'sync'
# 最大请求数,防止内存泄漏
max_requests = 1000
max_requests_jitter = 100
# 超时时间
timeout = 30
# 访问日志文件
accesslog = '-'
# 错误日志文件
errorlog = '-'
# 日志级别
loglevel = 'info'
对于I/O密集型应用,可以使用异步worker:
python
# 安装异步worker支持
# pip install gevent
worker_class = 'gevent'
workers = 2
worker_connections = 1000
6.2 Nginx配置
Nginx作为反向代理,可以提供静态文件服务、负载均衡和SSL终端等功能。
基础Nginx配置(nginx.conf):
nginx
# 定义上游应用服务器
upstream webapp {
server web:8000;
}
server {
listen 80;
server_name yourdomain.com;
# 静态文件配置
location /static/ {
alias /app/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# 媒体文件配置
location /media/ {
alias /app/mediafiles/;
expires 30d;
add_header Cache-Control "public";
}
# 动态请求代理
location / {
proxy_pass http://webapp;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_redirect off;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 安全头
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
6.3 环境变量管理
敏感信息如密钥、数据库密码等应通过环境变量管理:
bash
# .env.production
# Django设置
SECRET_KEY=your-very-secure-secret-key-here
DEBUG=False
ALLOWED_HOSTS=yourdomain.com,localhost,127.0.0.1
# 数据库配置
DB_NAME=mydatabase
DB_USER=mydbuser
DB_PASSWORD=mysecurepassword
DB_HOST=db
DB_PORT=5432
# Redis配置
REDIS_URL=redis://redis:6379/0
在Django设置中使用这些环境变量:
python
# settings/production.py
import os
SECRET_KEY = os.environ['SECRET_KEY']
DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
'PORT': os.environ.get('DB_PORT', '5432'),
}
}
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': os.environ['REDIS_URL'],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
7 完整示例代码
7.1 Flask应用完整示例
项目结构:
flask-docker-app/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ └── static/
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── entrypoint.sh
└── .env
app/init.py:
python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
# 配置
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get(
'DATABASE_URL', 'sqlite:///app.db'
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 初始化扩展
db.init_app(app)
# 注册蓝图
from .routes import main
app.register_blueprint(main)
return app
app/routes.py:
python
from flask import Blueprint, jsonify
from .models import db, Visit
main = Blueprint('main', __name__)
@main.route('/')
def index():
# 记录访问
visit = Visit()
db.session.add(visit)
db.session.commit()
# 获取总访问量
total_visits = Visit.query.count()
return jsonify({
'message': 'Hello from Dockerized Flask!',
'total_visits': total_visits
})
@main.route('/health')
def health():
return jsonify({'status': 'healthy'})
app/models.py:
python
from . import db
from datetime import datetime
class Visit(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
requirements.txt:
Flask==2.3.3
Flask-SQLAlchemy==3.0.5
Flask-Migrate==4.0.4
gunicorn==21.2.0
psycopg2-binary==2.9.7
python-dotenv==1.0.0
Dockerfile:
dockerfile
FROM python:3.10-slim
# 设置环境变量
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
FLASK_APP=app
WORKDIR /app
# 安装系统依赖
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc python3-dev libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非root用户
RUN useradd -m -u 1000 webuser && chown -R webuser:webuser /app
USER webuser
# 暴露端口
EXPOSE 5000
# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:create_app()"]
docker-compose.yml:
yaml
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- DATABASE_URL=postgresql://flaskuser:flaskpass@db:5432/flaskdb
- SECRET_KEY=your-production-secret-key
depends_on:
- db
volumes:
- ./app:/app/app # 开发时使用,便于代码热重载
restart: unless-stopped
db:
image: postgres:13
environment:
- POSTGRES_DB=flaskdb
- POSTGRES_USER=flaskuser
- POSTGRES_PASSWORD=flaskpass
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:
bash
#!/bin/bash
set -e
# 等待数据库就绪
echo "Waiting for database..."
while ! nc -z db 5432; do
sleep 0.1
done
echo "Database started"
# 运行数据库迁移
flask db upgrade
# 启动应用
exec "$@"
7.2 Django应用完整示例
项目结构:
django-docker-app/
├── myproject/
│ ├── __init__.py
│ ├── settings/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ └── production.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── entrypoint.sh
└── .env
myproject/settings/base.py:
python
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-dev-key')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'myproject.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
myproject/settings/production.py:
python
from .base import *
import os
DEBUG = False
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
'PORT': os.environ.get('DB_PORT', '5432'),
}
}
# 安全配置
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
# 静态文件
STATIC_ROOT = '/app/staticfiles'
MEDIA_ROOT = '/app/mediafiles'
Dockerfile:
dockerfile
FROM python:3.10-slim
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc python3-dev libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -m -u 1000 webuser && chown -R webuser:webuser /app
USER webuser
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "myproject.wsgi:application"]
docker-compose.yml:
yaml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DJANGO_SETTINGS_MODULE=myproject.settings.production
- DB_NAME=djangodb
- DB_USER=djangouser
- DB_PASSWORD=djangopass
- DB_HOST=db
- SECRET_KEY=your-django-production-secret
- ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
depends_on:
- db
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/mediafiles
command: >
sh -c "python manage.py migrate &&
python manage.py collectstatic --noinput &&
gunicorn --bind 0.0.0.0:8000 --workers 3 myproject.wsgi:application"
restart: unless-stopped
db:
image: postgres:13
environment:
- POSTGRES_DB=djangodb
- POSTGRES_USER=djangouser
- POSTGRES_PASSWORD=djangopass
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:
static_volume:
media_volume:
bash
#!/bin/bash
set -e
# 等待数据库就绪
echo "Waiting for PostgreSQL..."
while ! nc -z $DB_HOST $DB_PORT; do
sleep 0.1
done
echo "PostgreSQL started"
# 应用数据库迁移
echo "Applying database migrations"
python manage.py migrate
# 收集静态文件
echo "Collecting static files"
python manage.py collectstatic --noinput
exec "$@"
8 部署到云服务器
8.1 服务器准备
在部署到云服务器前,需要完成以下准备工作:
- 选择云服务商:AWS、Google Cloud、Azure、阿里云等
- 配置服务器:建议至少1GB内存,2核CPU
- 安装Docker:在服务器上安装Docker和Docker Compose
服务器初始化脚本:
bash
#!/bin/bash
# install-docker.sh
# 更新系统
apt-get update
apt-get upgrade -y
# 安装Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
# 添加用户到docker组
usermod -aG docker $USER
# 安装Docker Compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
# 启用防火墙
ufw allow OpenSSH
ufw allow 80
ufw allow 443
ufw --force enable
8.2 部署流程
手动部署步骤:
bash
# 1. 登录服务器
ssh user@server-ip
# 2. 创建项目目录
mkdir -p /opt/myapp
cd /opt/myapp
# 3. 上传代码(可以使用git、rsync等)
scp -r . user@server-ip:/opt/myapp
# 4. 设置环境变量
cp .env.production .env
# 编辑.env文件,填入实际值
# 5. 构建和启动服务
docker-compose -f docker-compose.prod.yml build
docker-compose -f docker-compose.prod.yml up -d
# 6. 检查服务状态
docker-compose ps
docker-compose logs web
8.3 使用CI/CD自动化部署
GitLab CI示例(.gitlab-ci.yml):
yaml
stages:
- test
- deploy
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_DRIVER: overlay2
test:
stage: test
image: python:3.10
before_script:
- pip install flake8 pytest
script:
- flake8 .
- python -m pytest
deploy:
stage: deploy
image: docker:latest
services:
- docker:dind
before_script:
- apk add --no-cache docker-compose
script:
- docker-compose -f docker-compose.prod.yml build
- docker-compose -f docker-compose.prod.yml down
- docker-compose -f docker-compose.prod.yml up -d
only:
- main
9 常见问题与解决方案
9.1 部署常见错误
-
数据库连接错误
- 问题:应用无法连接数据库
- 解决:检查数据库服务是否运行,环境变量配置是否正确,网络连接是否通畅
-
静态文件404错误
- 问题:CSS、JS等静态文件无法加载
- 解决:确保执行了
collectstatic
,Nginx配置正确指向静态文件目录
-
权限错误
- 问题:容器内应用没有文件写入权限
- 解决:确保使用非root用户运行应用,挂载卷权限正确
9.2 性能优化建议
-
数据库优化
yaml# docker-compose.yml中对PostgreSQL的优化配置 db: image: postgres:13 environment: - POSTGRES_DB=mydb - shared_buffers=256MB - effective_cache_size=1GB - work_mem=16MB command: > postgres -c shared_buffers=256MB -c effective_cache_size=1GB -c work_mem=16MB
-
Gunicorn优化
python# gunicorn.conf.py workers = (2 * cpu_count()) + 1 worker_class = 'gevent' worker_connections = 1000 max_requests = 1000 max_requests_jitter = 100 timeout = 30 keepalive = 2
-
Nginx优化
nginx# nginx.conf中的优化配置 worker_processes auto; worker_connections 1024; gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 静态文件缓存 location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 365d; add_header Cache-Control "public, immutable"; }
10 总结
通过本文的详细介绍,我们学习了如何将Django和Flask应用使用Docker容器化并部署到云服务器。容器化部署不仅解决了环境一致性问题,还大大简化了部署流程。
10.1 关键要点回顾
- Dockerfile是基础:正确编写Dockerfile是成功容器化的第一步
- 多服务编排:使用Docker Compose管理应用依赖的多个服务
- 生产就绪配置:使用Gunicorn作为WSGI服务器,Nginx作为反向代理
- 环境变量管理:敏感信息通过环境变量传递,提高安全性
- 持续部署:结合CI/CD工具实现自动化部署
10.2 后续学习方向
要进一步深入Docker和部署领域,可以学习:
- Kubernetes容器编排
- 微服务架构设计
- 监控和日志管理(Prometheus、ELK Stack)
- 服务网格(Istio、Linkerd)
- 云原生技术
容器化技术正在成为现代应用部署的标准,掌握这些技能将大大提升你的开发和运维能力。