这是「把自己部署到互联网上」系列的第 19 篇。
上一篇,我把 Conda 和 Docker 放在个人博客生产部署场景里做了一次对比。结论不是 Conda 不好,也不是 Docker 永远更高级,而是:如果只是本地开发、数据分析、短期实验,Conda 很舒服;但如果是长期运行、多服务组合、多项目共存,并且后续要迁移和维护的个人博客,Docker 更适合我的目标。
这一篇不再泛泛对比,而是从自己的过程出发,复盘为什么我最终放弃了 Conda 部署。
一开始,我确实想用 Conda。长期写 Python 的人,很容易把 Conda 当成自然选择。本地开发时,它管理 Python 版本和依赖很方便:
conda create -n blog python=3.11
conda activate blog
pip install -r requirements.txt
如果只是为了第一天跑起来,这条路很直接:服务器上装 Miniconda,创建环境,安装依赖,启动项目,再用 Nginx 代理出去。不用写 Dockerfile,不用理解容器网络,不用处理数据卷,也不用写 Docker Compose。对快速验证来说,它很有吸引力。
但真正开始想生产部署时,问题接踵而至。
原因一:环境不只等于 Python 依赖
一个博客项目要长期运行,除了 Python 包,还会涉及系统依赖、环境变量、数据库、静态资源、服务启动方式、进程守护、日志路径、Nginx 代理、HTTPS 证书、上传目录和备份目录。Conda 能很好地管理 Python 版本和一部分依赖,但它不负责整个服务运行环境。
这意味着我需要额外补很多东西。
服务怎么后台运行?
用 nohup、screen、tmux、systemd,还是 supervisor?
数据库怎么跑?
装在系统里,单独用 Docker,还是作为系统服务?
Nginx、证书、日志、上传目录又放在哪里?
这些都可以做,但会依赖大量手动约定。
而手动约定最大的问题,写在 README.md文档里面还好,单纯靠记性,几个月后被自己忘掉落。
原因二:启动方式越来越像补丁
本地开发时,启动项目很简单:
conda activate blog
python app.py
或者:
uvicorn main:app --host 0.0.0.0 --port 8000
但生产环境和开发环境不一样,不能只靠一个前台命令长期跑。要考虑服务崩了怎么办,服务器重启后怎么办,日志写到哪里,环境变量怎么加载,多个服务的启动顺序怎么处理。
如果继续用 Conda,这些问题通常要交给其他工具,
比如 systemd。systemd 很稳定,也适合管理 Linux 服务,但我就需要把 Conda 环境路径、项目目录、启动命令、用户权限和日志配置都写进 service 文件。后面如果还有第二个、第三个项目,每个项目都要类似处理。
最后部署结构会变成:
- Conda 管 Python 环境
- systemd 管进程
- Nginx 管入口
- 数据库另管
- 日志另管
- 配置文件另管
这套“组合拳”可以工作,但在个人维护场景里,多少有点杂乱。
过段时间,回头看项目时,想能在一个地方看到它需要哪些服务、端口、环境变量、数据目录和启动方式。这也是我转向 Docker Compose 的原因之一。
原因三:是多项目共存
个人博客只是第一步。后面还有个人官网、作品站,也可能部署小工具或实验项目。如果每个项目都用 Conda 环境,理论上没问题:
blog 环境
site 环境
tool 环境
api 环境
但项目不只是 Python 环境。每个项目还会有启动脚本、环境变量、日志目录、上传目录、数据库连接、Nginx 配置、静态资源路径和备份方式。
如果这些都散落在服务器不同位置,多项目共用一台服务器时就会越来越难维护。我希望每个项目都有清晰边界:配置在哪里,数据在哪里,日志在哪里,怎么启动和停止,依赖哪些服务。Conda 可以隔离 Python 包,但它不是完整的项目部署边界。
原因四:迁移
在创建项目前期,个人博客是长期项目,服务器以后可能会迁移。可能是续费太贵,可能是配置不够,可能是换云厂商,也可能是系统需要重做。
如果一年后换服务器,我希望能快速地把博客重新拉起来。使用 Conda 部署时,我要重新安装 Miniconda、创建环境、安装依赖、补系统依赖、恢复环境变量、恢复数据库和上传文件、恢复 Nginx 配置、恢复 systemd 或其他启动脚本,还要确认端口和防火墙。
这当然可以通过写文档解决,但文档容易滞后。实际环境里手动改过什么,有时候就懒得记,过一段时间可能自己都忘了。
Docker 也不是免迁移。数据卷、配置文件、环境变量、证书、数据库备份一样要处理。但如果 Dockerfile 和 Docker Compose 写得清楚,应用运行环境、服务关系和启动方式更容易固化。迁移时,我更像是在恢复一套声明好的项目结构,而不是回忆服务器上曾经手动装过什么。
原因五:部署过程能不能沉淀
这个合集系列不只是为了把博客跑起来,也是在把过程沉淀成文章、经验和后续可复用的资产。如果部署大量依赖手工操作,文章会写得很散,读者难以复用,我自己以后也难复盘。
如果部署过程可以文件化,比如 Dockerfile、docker-compose.yml、.env 示例、Nginx 配置、目录结构说明、数据备份策略,它就更容易沉淀。文章也不只是记录“我在服务器上做了什么”,而是输出一套更清晰的部署结构。
不是因为 Conda 不能用才放弃。Conda 能用,而且在本地开发、数据分析、内部工具、小脚本和轻量实验里很好用。我放弃它,是因为它不再是这个场景里的最优选择。
转向 Docker 后,解决几个问题:
- 通过 Dockerfile 记录项目运行依赖
- 通过 Compose 记录服务关系
- 让应用、数据库、Nginx 有更清晰的边界
- 用
docker compose up -d、docker compose down、docker compose logs统一管理启停和日志 - 让多个项目更容易共存
- 让迁移不完全依赖记忆。
当然,Docker 也会带来新的问题,比如镜像构建、数据卷、网络、端口映射、容器日志、权限和备份。但这些问题更符合我后续长期维护的方向。
小结
这次选择也给我一个提醒:不要只用开发习惯决定生产部署。
- 本地开发看重方便、快速、灵活;
- 生产部署看重稳定、可复现、可维护、可迁移。
目标不同,工具选择就可能不同。
下一篇,我会继续拆一个基础问题:Docker 和 Docker Compose 到底分别解决什么问题?在真正写部署文件之前,先把这两个概念讲清楚。
本文由 楸木 原创,转载请注明出处。