从 Conda 到 Docker,再到全局 Nginx,我终于理清了部署架构

预计阅读时间:10 分钟

这是「把自己部署到互联网上」系列的第 25 篇。

从第 18 篇到第 24 篇,我一直在处理一个问题:

个人博客到底应该怎么部署

这个问题看起来只是技术选型,但会直接影响后续维护。如果部署架构一开始就很散,后面新增项目、修改配置、迁移服务器、排查故障,都会消耗大量精力。所以这一阶段我没有急着把博客跑起来,而是先把部署方式理清楚。

这几篇大致走过三步

  • 先在 Conda 和 Docker 之间做选择
  • 再复盘为什么放弃 Conda 部署,转向 Docker
  • 最后确定用全局 Nginx 统一管理多个项目入口

到现在,我的基本方案可以概括为一句话:

Docker 管项目运行,Docker Compose 管项目内部服务,全局 Nginx 管公网入口

动机是什么?

服务器安全阶段结束后,接下来考虑项目部署。但部署不是把代码拉到服务器上、执行一条启动命令这么简单。对一个准备长期运行的项目来说,至少要考虑应用运行环境、数据库、多服务启动、项目隔离、端口暴露、Nginx 入口、多项目共存、配置迁移和故障排查。

如果这些问题不提前想,很容易出现一个现象:

第一天项目跑起来了,一个月后配置开始分散,三个月后新增项目开始冲突,半年后自己也忘了当时怎么部署。到最后变得越来越不想维护了。

最早的选择是 Conda 和 Docker。我一开始挺喜欢用 Conda 管理环境。

它在本地开发和 Python 环境管理里很舒服,创建环境、切换版本、安装依赖都很直观。

如果只是临时跑一个 Python 项目,或者做数据分析、实验脚本,Conda 仍然很好用。

但我的个人博客不是临时脚本。它是要长期运行的项目,要有数据库,要通过 Nginx 对外访问,要配置 HTTPS,后面还要和个人官网、作品站共存。

Conda 与 Docker

Conda 管的是 Python 环境,但我的部署问题不只是 Python 环境。服务启动、数据库、日志、配置、环境变量、迁移、多项目组织,都需要另外处理。

所以我 不是因为 Conda 不能用才放弃它,而是因为它不匹配这次的长期目标

转向 Docker 后,我看重的也不是“更高级”,而是它能把应用运行环境固化下来。

Dockerfile 记录项目如何构建,镜像记录运行环境,容器提供隔离边界,Compose 文件记录一组服务如何一起运行。

这比在服务器上手工创建环境、安装依赖、写启动脚本,更适合长期维护。它能让我更清楚地回答:

  1. 项目需要哪些服务
  2. 哪个服务对外暴露
  3. 数据库数据放在哪里
  4. 环境变量从哪里来
  5. 服务如何启动和停止
  6. 日志怎么看
  7. 以后换服务器怎么恢复

当然,Docker 也有成本。需要理解镜像、容器、网络、数据卷、端口映射和 Compose。

但这些成本换来的是更清楚的部署结构

只用 Docker 还不够。一个真实项目往往不止一个容器。博客至少会有应用和数据库,后面还可能有缓存、后台任务、定时任务等。如果每个容器都用 docker run 手动启动,命令会越来越长,关系也很难维护。

Docker Compose

Docker Compose 的价值就是把项目内部服务组织起来。

应用、数据库、数据卷、环境变量、网络,都可以写在一个文件里。

这样项目不再是一堆手工命令,而是一个可描述的服务组。

以后回头看博客项目时,我能知道它有哪些服务、服务之间怎么连接、数据在哪里、端口怎么处理、启动命令是什么。

当项目用 Docker 和 Docker Compose 管起来后,下一个问题就是公网流量怎么进来。

Nginx 的位置

如果只有一个项目,可以用系统 Nginx,也可以用 Nginx 容器。但我的场景设计是多项目。

博客、官网、作品站后面都可能在同一台服务器上。

如果每个项目都自己暴露端口,入口会越来越乱;如果每个项目都自己管理 Nginx 和证书,维护会越来越分散。

所以我最后确定:

公网入口统一交给全局 Nginx。它负责接管 80 和 443,根据域名转发到不同项目,集中处理 HTTPS 相关配置,并通过公共 Docker 网络访问项目容器。每个项目内部仍然独立。

结构大概是:

公网用户
  -> 全局 Nginx
  -> 项目应用容器
  -> 项目数据库容器

公网只认 Nginx,项目只提供内部服务,数据库只服务项目内部。

现在的部署架构可以总结为:

服务器
  ├── 全局 Nginx 容器
  │   ├── 监听 80 / 443
  │   ├── 管理域名配置
  │   ├── 引用 HTTPS 证书
  │   └── 代理到不同项目
  │
  ├── 博客项目
  │   ├── app 容器
  │   ├── db 容器
  │   ├── compose.yml
  │   └── 数据卷
  │
  ├── 官网项目
  │   ├── app 或静态服务
  │   ├── compose.yml
  │   └── 构建产物
  │
  └── 公共 Docker 网络
      ├── global-nginx
      ├── blog-app
      └── site-app

这个架构不复杂,但对我的个人服务器已经足够清楚。它解决了几个核心问题:

  • 环境用 Docker 管
  • 多服务用 Docker Compose 管
  • 入口用全局 Nginx 管
  • 数据库不暴露公网
  • 项目之间保持边界
  • 新增项目有固定接入方式
  • 迁移时有目录和配置可依赖

小结:

回头看,这个阶段主要踩过三个判断坑。

第一个坑,是只看当前能不能跑

如果只看最快上线,Conda 很可能是最短路径。但个人博客不是只跑一天,不能只问今天怎么最快上线,还要问半年后怎么维护。

第二个坑,是把所有项目都当成单项目看

只有一个博客时,很多方案都能用。但以后如果还有官网、作品站和小工具,就要提前考虑入口统一、端口管理和证书集中,否则第一个项目图省事,后面会补债。

第三个坑,是以为容器化就是把所有东西都塞进容器

Docker 有用,但关键是边界清楚。项目服务容器化,数据库容器化但数据持久化,Nginx作为全局入口容器化,证书和配置挂载到宿主机目录。组合起来,才是可维护方案。

这一阶段开始前,我的目标是“把项目跑起来”。

现在目标变成了“以可维护、可迁移、可扩展的方式把项目跑起来”。前者追求速度,后者追求结构。

如果只是练手项目,速度优先没问题;但这次我要搭的是长期个人技术阵地,结构更重要。

下一阶段要解决 HTTPS。部署架构解决的是项目怎么跑,HTTPS 解决的是网站如何更可信地对外访问。

接下来会涉及为什么个人网站需要 HTTPS、SSL 证书怎么申请和部署、Nginx 如何配置 HTTPS、通配符证书和 acme.sh 怎么管理多域名证书,以及证书续期怎么处理。

到这里,服务器安全边界有了,部署架构也有了。

下一步,就是让这个入口具备 HTTPS 访问能力。


本文由 楸木 原创,转载请注明出处。

相关推荐

发现更多