Docker实战:将Django应用容器化的完整指南
本文将带你从零开始,一步步将Django应用容器化,包括Dockerfile编写、镜像优化和容器部署的完整流程。
一、Dockerfile核心指令快速掌握
Dockerfile是构建镜像的"食谱",包含了一系列构建指令。在开始实战前,我们先掌握这些最常用的核心指令:
指令 | 作用说明 | 实战价值 |
---|---|---|
FROM |
指定基础镜像(必须是第一条指令) | 站在巨人的肩膀上,无需从零构建操作系统环境 |
WORKDIR |
设置工作目录(后续命令的执行目录) | 避免使用复杂的绝对路径,让Dockerfile更清晰 |
COPY |
复制本地文件到镜像中 | 将应用代码和配置文件打包到镜像 |
RUN |
执行命令(构建镜像时运行) | 安装依赖、编译代码等构建阶段操作 |
ENV |
设置环境变量 | 配置应用运行参数,避免硬编码敏感信息 |
EXPOSE |
声明容器运行时监听的端口 | 文档化端口信息,提醒使用者需要映射的端口 |
CMD |
容器启动命令(可被docker run 参数覆盖) |
定义应用的启动方式 |
ENTRYPOINT |
容器入口点(不可被覆盖,常与CMD配合) | 固定应用的启动流程,仅动态参数通过CMD传递 |
小贴士:
COPY
与ADD
的区别:COPY
仅用于复制本地文件,ADD
还支持URL下载和自动解压压缩包。实际开发中,优先使用COPY
,它更直观且避免意外行为。
二、Django应用容器化实战步骤
我们以一个典型的Django博客应用为例,演示完整的容器化过程。
2.1 项目结构准备
首先确保你的Django项目结构如下(关键文件必须包含):
myblog/
├── Dockerfile # 核心构建文件
├── requirements.txt # Python依赖列表
├── run.sh # 应用启动脚本
├── myblog.conf # Nginx配置文件
└── 其他Django项目文件 # 包括manage.py、应用代码等
其中几个关键文件的内容参考:
requirements.txt(列出项目依赖):
Django==3.2.16
djangorestframework==3.13.1
pymysql==1.0.2
uwsgi==2.0.21
run.sh(启动脚本,负责启动Nginx和uWSGI):
#!/bin/bash
# 启动Nginx
nginx
# 启动uWSGI服务
uwsgi --ini uwsgi.ini
2.2 编写基础Dockerfile
创建Dockerfile
文件,逐步构建我们的镜像:
# 1. 选择基础镜像(CentOS 7.5,稳定性好)
FROM centos:centos7.5.1804
# 2. 设置维护者信息(可选,但推荐)
LABEL maintainer="your_email@example.com"
# 3. 配置环境变量(解决中文乱码等问题)
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
# 4. 配置国内YUM源(加速依赖安装)
RUN curl -so /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 5. 安装系统依赖(Python3、编译工具等)
RUN yum install -y python36 python3-devel gcc pcre-devel zlib-devel make net-tools
# 6. 设置工作目录(后续命令将在此目录执行)
WORKDIR /opt/myblog
# 7. 复制项目文件到镜像中
COPY . .
# 8. 安装Nginx(从源码编译,可指定版本)
RUN tar -zxf nginx-1.13.7.tar.gz -C /opt && \
cd /opt/nginx-1.13.7 && \
./configure --prefix=/usr/local/nginx && \
make && make install && \
ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx # 创建软链接方便调用
# 9. 配置Nginx(复制应用专属配置)
RUN cp myblog.conf /usr/local/nginx/conf/myblog.conf
# 10. 安装Python依赖(使用阿里云PyPI镜像加速)
RUN pip3 install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt
# 11. 赋予启动脚本执行权限,并清理缓存
RUN chmod +x run.sh && rm -rf ~/.cache/pip
# 12. 声明应用监听端口
EXPOSE 8002
# 13. 容器启动命令(执行启动脚本)
CMD ["./run.sh"]
关键说明:
- 选择
centos7.5.1804
而非latest
,是为了保证构建环境的一致性- 所有
RUN
命令尽量合并成一行(用&&
连接),可以减少镜像层数- 安装依赖时使用国内镜像源(阿里云),大幅提升构建速度
- 最后清理缓存(
rm -rf ~/.cache/pip
),减小镜像体积
2.3 构建并测试镜像
镜像编写完成后,执行以下命令构建:
# 构建镜像(-t指定名称和标签,.表示当前目录为构建上下文)
docker build . -t myblog:v1
# 查看构建好的镜像
docker images | grep myblog
# 预期输出:myblog v1 xxxxxxxxxx 2 minutes ago 890MB
构建成功后,我们需要先启动依赖的MySQL容器,再启动Django应用:
# 1. 启动MySQL容器(数据持久化到宿主机/opt/mysql/mysql-data目录)
docker run -d -p 3306:3306 --name mysql \
-v /opt/mysql/mysql-data/:/var/lib/mysql \
-e MYSQL_DATABASE=myblog \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
# 2. 启动Django应用容器(连接到MySQL)
docker run -d -p 8002:8002 --name myblog \
-e MYSQL_HOST=172.17.0.2 # 替换为实际的MySQL容器IP或使用--link
-e MYSQL_USER=root \
-e MYSQL_PASSWD=123456 \
myblog:v1
# 3. 查看容器运行状态
docker ps | grep -E "mysql|myblog"
连接数据库技巧:在生产环境中,更推荐使用Docker网络(
--network
)让容器通过服务名通信,而不是硬编码IP。例如:# 创建自定义网络 docker network create my-network # 启动MySQL时加入网络 docker run ... --network my-network --name mysql ... # 启动应用时加入同一网络,直接用mysql作为主机名 docker run ... --network my-network -e MYSQL_HOST=mysql ...
最后执行数据库迁移并创建管理员用户:
# 执行数据库迁移
docker exec -ti myblog python3 manage.py migrate
# 创建超级用户(按提示输入用户名、邮箱、密码)
docker exec -ti myblog python3 manage.py createsuperuser
现在访问宿主机的8002端口,就能看到你的Django应用了!
三、镜像优化:更小、更快、更高效
上面的基础镜像可以工作,但还有优化空间。主要问题是:每次代码修改都要重新安装所有依赖,构建速度慢;镜像体积较大(接近1GB)。
3.1 优化思路:提取基础镜像
将不常变化的部分(系统依赖、Nginx、Python环境)构建成基础镜像,应用代码和依赖作为上层镜像,这样每次代码更新时,只需重新构建上层镜像。
创建基础镜像的Dockerfile(Dockerfile-base):
FROM centos:centos7.5.1804
LABEL maintainer="your_email@example.com"
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
# 配置YUM源并安装系统依赖
RUN curl -so /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum install -y python36 python3-devel gcc pcre-devel zlib-devel make net-tools
# 提前下载Nginx源码包(避免每次构建重新下载)
COPY nginx-1.13.7.tar.gz /opt/
# 安装Nginx
RUN tar -zxf /opt/nginx-1.13.7.tar.gz -C /opt && \
cd /opt/nginx-1.13.7 && \
./configure --prefix=/usr/local/nginx && \
make && make install && \
ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx && \
rm -f /opt/nginx-1.13.7.tar.gz # 清理安装包
构建基础镜像:
docker build -f Dockerfile-base -t centos-django-base:v1 .
3.2 基于基础镜像构建应用镜像
创建应用镜像的Dockerfile(Dockerfile-app):
# 基于我们构建的基础镜像
FROM centos-django-base:v1
WORKDIR /opt/myblog
# 先复制requirements.txt并安装依赖(利用Docker缓存)
COPY requirements.txt .
RUN pip3 install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt && \
rm -rf ~/.cache/pip
# 再复制其他项目文件(代码变动频繁,放在后面不破坏前面的缓存)
COPY . .
# 配置Nginx
RUN cp myblog.conf /usr/local/nginx/conf/myblog.conf
# 赋予执行权限
RUN chmod +x run.sh
EXPOSE 8002
CMD ["./run.sh"]
关键优化点:
- 先复制
requirements.txt
并安装依赖,只有依赖变化时才会重新执行这一步- 最后复制应用代码,代码修改不会影响前面步骤的缓存
- 基础镜像只需构建一次,后续构建应用镜像速度提升50%以上
构建优化后的应用镜像:
docker build -f Dockerfile-app -t myblog:v2 .
对比优化前后的效果:
- 构建时间:从5分钟缩短到1分钟(代码修改时)
- 镜像体积:从890MB减小到650MB(去除重复的基础组件)
四、总结与最佳实践
总结几个关键经验:
Dockerfile编写原则:
- 指令顺序:从少变到多变(利用缓存)
- 合并命令:减少镜像层数(用
&&
和\
换行) - 清理冗余:每次安装后清理缓存和临时文件
生产环境建议:
- 不要使用
latest
标签,固定具体版本(如centos:7.5.1804
) - 避免在镜像中存储敏感信息,通过环境变量或Docker Secrets注入
- 以非root用户运行容器(在Dockerfile中添加
USER
指令)
- 不要使用