- 后端
- 前端
- CMS
【免费下载链接】DjangoBlog
🍺基于Django的博客系统
本文以 DjangoBlog 官方的 Docker 部署文档(docs/docker-en.md)为主线,结合仓库内的 Dockerfile、docker-compose 配置、启动脚本 与 settings.py 源码,系统讲解如何用 Docker 在几分钟内完成博客的容器化部署。读完本文,你将掌握三种部署路径(docker-compose 一键部署、叠加 Elasticsearch 全文检索、独立镜像对接外部 MySQL),并彻底搞懂每一个DJANGO_*环境变量在源码层面如何生效,从而安全、正确地完成生产环境配置。
1. 部署前置条件
在开始之前,请确保本机已安装以下两样软件:
- Docker Engine:容器运行时,负责拉取镜像、构建镜像并运行容器;
- Docker Compose:容器编排工具,负责按
docker-compose.yml一次性拉起多服务栈。Docker Desktop(macOS / Windows)用户无需单独安装,已内置 Compose。
兼容性提示:本文所有命令均基于文档撰写时的 Compose V1 语法(
version: '3'、docker-compose子命令)与当前仓库中的 docker-compose 文件 实测结构;若你的环境使用 Compose V2,可将docker-compose替换为docker compose。
2. 推荐方式:docker-compose 一键部署基础服务栈
官方推荐使用docker-compose一键启动"应用 + 数据库 + 缓存 + 反向代理"的完整服务栈,它会自动完成镜像拉取、项目镜像构建与多容器编排,是上手最快、最省心的部署方式。
2.1 关于 compose 文件位置的说明
原文档中写明"在项目根目录执行docker-compose up -d --build",即假定根目录存在docker-compose.yml。在当前仓库快照中,两个 compose 文件均位于deploy/docker-compose/目录下(经仓库文件检索确认仅有这两份)。因此若从仓库根目录执行,请通过-f显式指定文件路径:
docker-compose -f deploy/docker-compose/docker-compose.yml up -d --build如果你将项目发布到服务器时习惯把 compose 文件放到根目录,也可以保持原文档的直接写法;二者的服务定义完全相同,只是文件位置不同。
2.2 服务栈拆解:这份 compose 到底编排了哪些容器
打开 deploy/docker-compose/docker-compose.yml 可以看到,基础栈共编排了 4 个服务:
| 服务名 | 镜像 | 职责 | 端口映射 | 关键配置 |
|---|---|---|---|---|
db | mysql:latest | 博客数据库 | 3306:3306 | 自动建库djangoblog,根密码QQQQwww123!@#,数据卷mysql_data:/var/lib/mysql |
redis | redis:latest | 缓存服务 | 6379:6379 | 无密码,供DJANGO_REDIS_URL=redis:6379连接 |
djangoblog | 本地构建(build: ../..) | Django 应用 | 8000:8000 | 启动命令执行 entrypoint.sh,挂载静态文件卷、日志与上传目录 |
nginx | nginx:latest | 反向代理 + 静态文件 | 80:80、443:443 | 挂载 deploy/nginx.conf,以只读方式共享静态文件卷 |
几个值得注意的实现细节:
- 应用镜像来自本地构建:
djangoblog服务的build.context指向../../(仓库根目录),dockerfile指定根目录的 Dockerfile,因此--build会先构建应用镜像; - 静态文件通过 named volume 共享:
static_files:/code/djangoblog/collectedstatic(djangoblog 容器可写、nginx 容器以:ro只读挂载),这是 nginx 直接服务静态资源、Django 只处理动态请求的基础; - 服务依赖关系:
djangoblog依赖db,db又依赖redis,保证了启动顺序。
2.3 启动命令与访问方式
# 构建并以后台模式启动容器(包含 Django 应用、MySQL、Redis、Nginx) docker-compose -f deploy/docker-compose/docker-compose.yml up -d --build- 访问博客:启动完成后,浏览器打开
http://127.0.0.1(Nginx 监听 80 端口并转发给容器内的 8000 端口); - 数据持久化:原文档描述为"MySQL 数据存放在项目根目录的
data/mysql中"。在当前仓库的 compose 文件中,db服务实际使用的是 Docker named volumemysql_data(挂载点为容器内/var/lib/mysql),数据同样在容器重启后不会丢失,且更便于用docker volume管理。若你确实想用宿主机目录,把该卷改成./data/mysql:/var/lib/mysql即可。
2.4 (可选) 叠加 Elasticsearch 启用全文搜索
默认情况下,DjangoBlog 使用 Whoosh 作为本地全文检索后端;如果你希望获得更强的全文搜索能力,可以在基础栈之上叠加 ES 覆盖文件:
docker-compose -f deploy/docker-compose/docker-compose.yml \ -f deploy/docker-compose/docker-compose.es.yml up -d --build-f可以多次使用,Compose 会将两个文件合并编排。查看 deploy/docker-compose/docker-compose.es.yml,它会额外引入两个服务:
es:使用liangliangyy/elasticsearch-analysis-ik:8.6.1镜像(已内置 IK 中文分词插件),以discovery.type=single-node单节点模式运行,ES_JAVA_OPTS限制 JVM 堆为 512MB,映射端口9200:9200;kibana:kibana:8.6.1,通过ELASTICSEARCH_HOSTS=http://es:9200连接 ES,映射端口5601:5601,便于可视化调试索引。
同时在djangoblog服务中注入DJANGO_ELASTICSEARCH_HOST=es:9200,这正是触发源码切换到 ES 后端的开关(详见第 6.5 节)。
数据持久化:原文档描述为"ES 数据存放在
data/elasticsearch",而当前仓库的 es 覆盖文件挂载的是./bin/datas/es/:/usr/share/elasticsearch/data/,部署时按仓库实际路径确认即可。版本一致性提醒:当前仓库的 es 覆盖文件中对
djangoblog服务的command与links仍引用旧版启动脚本(bin/docker_start.sh)和memcached服务,与主 compose 存在历史版本差异。若叠加启动报错,可参考第 7 节,直接在叠加命令中显式覆盖djangoblog.command为sh /code/djangoblog/deploy/entrypoint.sh。
3. 首次运行初始化:进入容器执行管理命令
当容器首次启动后,应用容器(服务名web,在仓库 compose 中实际名为djangoblog)会自动执行数据库迁移、静态文件收集等初始化工作(详见第 7 节),但你还需要手动创建管理员账号。
# 进入 djangoblog 应用容器 docker-compose exec djangoblog bash # 在容器内执行以下命令: # 创建超级管理员账户(按提示设置用户名、邮箱和密码) python manage.py createsuperuser # (可选) 创建一批测试数据 python manage.py create_testdata # (可选,如果启用了 ES) 重建搜索索引 python manage.py rebuild_index # 退出容器 exit这些命令对应仓库中的真实管理命令:create_testdata的实现位于 blog/management/commands/create_testdata.py,用于批量生成文章、分类、标签等演示数据;rebuild_index是 django-haystack 提供的标准索引重建命令,对应后端为 djangoblog/elasticsearch_backend.py 或 djangoblog/whoosh_cn_backend.py(由是否启用 ES 决定)。此外仓库还提供build_index(见 blog/management/commands/build_index.py),它会在容器启动时被 entrypoint 自动调用一次。
4. 备选方式:使用独立 Docker 镜像对接外部 MySQL
如果你已经有一套运行中的 MySQL,不需要 Compose 管理数据库,可以直接运行官方发布的应用镜像liangliangyy/djangoblog:
# 从 Docker Hub 拉取最新镜像 docker pull liangliangyy/djangoblog:latest # 运行容器,并通过环境变量连接你的外部数据库 docker run -d \ -p 8000:8000 \ -e DJANGO_SECRET_KEY='your-strong-secret-key' \ -e DJANGO_MYSQL_HOST='your-mysql-host' \ -e DJANGO_MYSQL_USER='your-mysql-user' \ -e DJANGO_MYSQL_PASSWORD='your-mysql-password' \ -e DJANGO_MYSQL_DATABASE='djangoblog' \ --name djangoblog \ liangliangyy/djangoblog:latest- 访问博客:启动完成后访问
http://127.0.0.1:8000(此时没有 Nginx,直接访问 Django 端口); - 创建管理员:
docker exec -it djangoblog python manage.py createsuperuser该镜像的构建入口与 Compose 完全一致(见第 7 节),因此容器首次启动时同样会自动执行迁移、静态文件收集与索引构建,只需把DJANGO_*数据库变量指向你的外部 MySQL 即可。
5. 配置总览:环境变量逐项解析
项目的大部分生产配置都通过环境变量驱动,你可以在 compose 文件的environment段修改,也可以在docker run时用-e传入。下表完整继承自官方文档,并补充了对应的源码影响位置:
| 环境变量 | 默认值 / 示例 | 说明 | 源码影响位置 |
|---|---|---|---|
DJANGO_SECRET_KEY | your-strong-secret-key | 务必改成随机复杂字符串!生产安全的核心 | settings.py L31-L32 |
DJANGO_DEBUG | False | 是否开启 Django 调试模式,生产必须False | settings.py L34 |
DJANGO_MYSQL_HOST | mysql | 数据库主机名(Compose 内为服务名db) | settings.py L114 |
DJANGO_MYSQL_PORT | 3306 | 数据库端口 | settings.py L115-L116 |
DJANGO_MYSQL_DATABASE | djangoblog | 数据库名称 | settings.py L111 |
DJANGO_MYSQL_USER | root | 数据库用户名 | settings.py L112 |
DJANGO_MYSQL_PASSWORD | djangoblog_123 | 数据库密码 | settings.py L113 |
DJANGO_REDIS_URL | redis:6379/0 | Redis 连接地址(用于缓存) | settings.py L295-L301 |
DJANGO_ELASTICSEARCH_HOST | elasticsearch:9200 | ES 主机地址,设置后切换全文检索后端 | settings.py L210-L233 |
DJANGO_EMAIL_HOST | smtp.example.org | 邮件服务器地址 | settings.py L311 |
DJANGO_EMAIL_PORT | 465 | 邮件服务器端口 | settings.py L312 |
DJANGO_EMAIL_USER | user@example.org | 发信邮箱账户 | settings.py L313 |
DJANGO_EMAIL_PASSWORD | your-email-password | 发信邮箱密码 | settings.py L314 |
DJANGO_EMAIL_USE_SSL | True | 是否启用 SSL | settings.py L310 |
DJANGO_EMAIL_USE_TLS | False | 是否启用 TLS | settings.py L309 |
DJANGO_ADMIN_EMAIL | admin@example.org | 接收异常报告的管理员邮箱 | settings.py L318 |
DJANGO_BAIDU_NOTIFY_URL | http://data.zz.baidu.com/... | 百度站长平台链接推送接口 | settings.py L304-L305 |
6. 环境变量在源码中如何生效
理解了环境变量表,再看它们在settings.py中真实的读取逻辑,你就能明白"改哪个变量会引发什么行为"。
6.1 布尔变量的解析规则
DJANGO_DEBUG、DJANGO_EMAIL_USE_SSL/TLS等布尔型变量并不是简单的字符串,而是经过env_to_bool统一解析(settings.py L19-L21):
def env_to_bool(env, default): str_val = os.environ.get(env) return default if str_val is None else str_val == 'True'即:变量未设置时返回默认值;设置时只有字符串字面量True才解析为真,其余任何写法(true、1、yes)都会被当作False。这一点在配置 compose 环境时很容易踩坑,务必写成True/False。
6.2 DEBUG 的默认值陷阱
注意 settings.py L34 的代码:
DEBUG = env_to_bool('DJANGO_DEBUG', True)若你不设置DJANGO_DEBUG,源码默认值是True(开发模式)——这与文档表格中的示例值False并不等价。生产部署时必须在 compose 或docker run中显式设置DJANGO_DEBUG=False,否则调试模式会把敏感信息暴露给访客。仓库的 docker-compose.yml 中已经显式写入了DJANGO_DEBUG=False,这是正确的生产姿势。
6.3 SECRET_KEY 与 MySQL 连接
SECRET_KEY在 settings.py L31-L32 通过os.environ.get('DJANGO_SECRET_KEY') or 'n9ceqv38...'读取——内置默认值仅用于本地开发,生产环境必须覆盖,否则所有部署此项目的站点将共享同一把密钥,存在被伪造签名会话的风险。
MySQL 连接(settings.py L109-L116)则完整读取DJANGO_MYSQL_DATABASE / USER / PASSWORD / HOST / PORT五个变量,并强制使用utf8mb4字符集以支持完整 Unicode(包括 emoji)存储。
6.4 Redis 缓存的切换
当设置DJANGO_REDIS_URL时(settings.py L295-L301),CACHES会切换到 Django 内置的redis.RedisCache后端,LOCATION被拼接为redis://<DJANGO_REDIS_URL>;未设置时则回退到项目默认的缓存方案。注意在 compose 中该变量的写法是redis:6379(不含redis://前缀和数据库编号),源码会自动补全协议头。
6.5 Elasticsearch 后端的自动切换
这是最值得关注的一处联动逻辑(settings.py L210-L250):
- 只要检测到
DJANGO_ELASTICSEARCH_HOST环境变量,就会构造ELASTICSEARCH_DSL配置(支持ELASTICSEARCH_VERIFY_CERTS、ELASTICSEARCH_USERNAME/PASSWORD等附加变量); - 随后
HAYSTACK_CONNECTIONS依据'ELASTICSEARCH_DSL' in locals()自动选择后端:启用 ES 时使用 djangoblog/elasticsearch_backend.py 的ElasticSearchEngine,否则回退到 djangoblog/whoosh_cn_backend.py 的WhooshEngine(索引目录whoosh_index)。
这解释了为什么第 2.4 节只需叠加一个 compose 文件、注入一个环境变量,全文检索后端就会从 Whoosh 平滑切换为 Elasticsearch。
6.6 邮件与错误报告
settings.py L308-L318 显示,邮件功能使用 SMTP 后端,EMAIL_USE_SSL默认True、EMAIL_USE_TLS默认False(两者互斥,同时为True会冲突);DJANGO_ADMIN_EMAIL会写入ADMINS,当DEBUG=False时 Django 会把未捕获异常以邮件形式发送给该管理员。也就是说,邮件变量不仅用于发送评论通知等业务邮件,也是生产环境异常告警的通道。
7. 镜像构建与容器启动的完整流程
理解了配置,再看应用镜像本身。根目录的 Dockerfile 采用两阶段构建,这是理解"为什么--build会比较慢"以及"静态资源从哪来"的关键。
7.1 阶段一:Node 前端构建
FROM node:20-alpine AS frontend-builder WORKDIR /app COPY frontend/package*.json ./frontend/ RUN cd frontend && npm config set registry https://registry.npmjs.org/ && npm ci COPY frontend/ ./frontend/ COPY templates/ ./templates/ RUN cd frontend && npm run build前端工程位于 frontend/,基于 Vite + Tailwind 构建(见 frontend/vite.config.js);由于模板中的 Tailwind 类名需要参与扫描,构建阶段同时拷贝了 templates/。构建产物输出到blog/static/blog/dist。
7.2 阶段二:Python 运行时
FROM python:3.11 RUN apt-get update && apt-get install default-libmysqlclient-dev gettext -y RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt \ && pip install --no-cache-dir gunicorn[gevent] && pip cache purge COPY . . RUN rm -rf /code/djangoblog/blog/static/blog/dist COPY --from=frontend-builder /app/blog/static/blog/dist /code/djangoblog/blog/static/blog/dist ENTRYPOINT ["/code/djangoblog/deploy/entrypoint.sh"]python:3.11基础镜像安装 MySQL 客户端库(用于django.db.backends.mysql驱动)和 gettext(用于compilemessages国际化编译);依赖安装完毕后,从第一阶段拷贝前端构建产物,并清掉源码树中可能残留的旧产物。
7.3 entrypoint:容器启动即自动初始化
容器启动后执行的 deploy/entrypoint.sh 会按顺序自动完成:
python manage.py makemigrations && \ python manage.py migrate && \ python manage.py collectstatic --noinput && \ python manage.py compress --force && \ python manage.py build_index && \ python manage.py compilemessages即:生成并执行数据库迁移、收集静态文件到collectedstatic、压缩静态资源、构建搜索索引、编译翻译文件——首次启动时这些步骤已经替你完成,这也是为什么第 3 节只需要创建超级管理员。全部成功后,最终以 Gunicorn 启动服务:
exec gunicorn djangoblog.wsgi:application \ --workers 1 --bind 0.0.0.0:8000 \ --worker-class gevent --threads 4采用 gevent 协程 worker + 每 worker 4 线程的组合(入口模块见 djangoblog/wsgi.py),在单 worker 情况下仍能并发处理请求。
7.4 Nginx:静态资源与反向代理
deploy/nginx.conf 中监听 80 端口:/static/请求通过alias直接命中collectedstatic目录(expires max设置长缓存);其余请求由proxy_pass http://djangoblog:8000转发给 Django,并透传X-Real-IP、X-Forwarded-For、Host头。静态文件之所以能被 nginx 读取,正是得益于 compose 中static_files命名卷在 djangoblog(读写)与 nginx(只读)两个容器之间的共享挂载。
8. 部署完成后的安全检查清单
部署完成后,请务必对照以下几点逐项确认(尤其是密钥与数据库、邮件相关项):
- 更换
DJANGO_SECRET_KEY为一个随机、复杂、足够长的字符串(可用python -c "import secrets; print(secrets.token_urlsafe(50))"生成); - 确认
DJANGO_DEBUG=False,并验证异常页面不再展示堆栈与调试工具栏; - 核对数据库变量与你的 MySQL 实例(用户名、密码、库名、主机、端口)完全一致,且数据库密码已从默认值
QQQQwww123!@#或djangoblog_123改为强密码; - 配置邮件变量(
DJANGO_EMAIL_*),否则生产环境的异常告警邮件无法送达DJANGO_ADMIN_EMAIL; - 如启用全文搜索,确认
DJANGO_ELASTICSEARCH_HOST指向可达的 ES 实例,并已在容器内执行过索引构建/重建; - 检查
http://127.0.0.1能正常访问博客,/admin/后台可用管理员账号登录。
完成以上步骤,你的 DjangoBlog 便已在 Docker 环境中稳定运行。若需要更完整的集群化部署方案,可继续阅读仓库中的 Kubernetes 部署指南 与中文版 Docker 部署文档。
- 后端
- 前端
- CMS
【免费下载链接】DjangoBlog
🍺基于Django的博客系统
相关推荐
DjangoBlog Docker 部署实战:docker-compose 一键搭建、Elasticsearch 全文搜索与完整环境变量配置
DjangoBlog Docker 部署实战:docker compose 一键搭建、Elasticsearch 全文搜索与完整环境变量配置 本指南以 Djan
后端前端CMSProxyPool 的 Docker 部署指南:镜像运行、docker-compose 编排与容器化实践
ProxyPool 的 Docker 部署指南:镜像运行、docker compose 编排与容器化实践 导读 本文围绕 proxy_pool(Python P
后端网页爬虫网络Sanic 应用 Docker 化部署实战:镜像构建、容器运行与 docker-compose 编排
Sanic 应用 Docker 化部署实战:镜像构建、容器运行与 docker compose 编排 导读 本文基于 Sanic 官方部署文档,完整讲解如何将一
后端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考