Docker 还是 systemd.service?重新审视 Linux 上的 Web 应用部署策略

近年来,“部署 = Docker + 容器编排(Kubernetes、ECS 等)”的说法几乎成了常识。正因如此,直接把 Web 应用以 进程 + systemd 服务 的方式部署在 Linux 服务器上,往往会被视为过时。

但在实际场景中:

  • 单一 Web 应用
  • 小型团队 / 简单基础设施
  • 本地部署或监管严格的环境

时,用 systemd 服务部署往往更简单、更稳定、更易运维

本文将整理在 Linux 上使用 systemd.service 部署 Web 应用时,相较 Docker 的优势以及 哪些情况下更适合使用 systemd


1. 简要对比 systemd 与 Docker



先把概念说得简短一点:

  • Docker
  • 把应用打包成镜像
  • 以容器方式运行
  • “把整个环境封装起来 → 在任何地方都能一致运行”是其强项

  • systemd

  • 现代 Linux 发行版的默认 init 系统
  • 在启动时启动服务(守护进程),服务挂掉后自动重启,管理日志
  • *.service 单元文件定义并管理进程

Docker 是封装应用环境的工具,而 systemd 是管理 Linux 进程的工具

两者并非竞争关系,常见的做法是:在 Docker 容器内部使用 systemd,或者让 systemd 管理 Docker 守护进程本身。

但本文聚焦于 完全不使用 Docker,只用 systemd 进行部署 的场景。


2. 用 systemd.service 替代 Docker 的优势

2-1. 简单:层级减少

使用 Docker 时,部署栈会多出以下层级:

  • Docker 守护进程
  • 镜像构建流水线
  • 镜像仓库(Registry)
  • 容器运行时的权限/安全管理

而 systemd 部署只需:

  • 在 OS 上安装所需运行时(Python/Node/Java 等)
  • 部署应用代码
  • 用 systemd 服务注册并启动

这是一种相对更简洁的结构。

在小型项目或内部服务中,

  • “构建镜像 → 推送 → 拉取 → 重新部署” 的流程往往更繁琐
  • 直接 SSH 进入服务器,执行 git pull + systemctl restart 更快、更直观

2-2. 与 Linux 的天然集成

systemd 与 Linux OS 的各项功能天然耦合:

  • 日志journalctl -u myapp.service 直接查看
  • 开机自启systemctl enable myapp.service 一次即可
  • 资源限制MemoryMaxCPUQuota 等选项
  • 依赖管理After=network.target / After=postgresql.service

使用 Docker 时,需要分别查看容器内外的日志、资源、网络,判断问题是容器层还是宿主机层。

若只运行一两个 Web 服务,直接在宿主机上运行往往更直观。

2-3. 资源占用更低

Docker 本身的开销不大,但往往伴随:

  • 多个镜像/层导致磁盘占用增加
  • 未停止的容器占用资源
  • 容器日志/卷管理

systemd 部署只需 OS + 运行时 + 应用代码,在磁盘/内存受限的环境(如嵌入式或低配服务器)更轻量。

2-4. 网络结构更直观

Docker 需要理解:

  • 容器内部 IP 与端口
  • 主机端口映射
  • 桥接网络 / 覆盖网络

而 systemd 服务直接绑定宿主机 IP/端口,网络调试更简单

  • 端口是否开放?
  • 防火墙是否拦截?
  • 与同一主机的其他服务是否冲突?

2-5. 某些环境无法使用 Docker

在金融、公共、医疗等监管严格的本地环境,或

  • 容器运行时被禁止
  • 外部镜像仓库不可访问

此时,唯一可行的方案往往是 OS + systemd。掌握 systemd 后,便可实现自动重启、日志管理、资源限制、健康检查等功能。


3. systemd.service 示例:Web 应用部署



下面以 gunicorn 运行 Django/Flask 为例。

3-1. 单元文件示例

/etc/systemd/system/myapp.service

[Unit]
Description=My Web Application (Gunicorn)
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/usr/bin/gunicorn \
    --workers 4 \
    --bind 0.0.0.0:8000 \
    config.wsgi:application

# 进程崩溃时自动重启
Restart=on-failure
RestartSec=5

# 资源限制示例(可选)
# MemoryMax=512M
# CPUQuota=50%

[Install]
WantedBy=multi-user.target

环境变量放在 /etc/myapp.env

DJANGO_SETTINGS_MODULE=config.settings.prod
SECRET_KEY=super-secret-key
DATABASE_URL=postgres://...

3-2. 常用命令

# 注册服务并设置开机自启
sudo systemctl enable myapp.service

# 启动 / 停止 / 重启
sudo systemctl start myapp.service
sudo systemctl restart myapp.service
sudo systemctl stop myapp.service

# 查看状态 / 日志
sudo systemctl status myapp.service
sudo journalctl -u myapp.service -f

熟悉 Linux 服务器的运维团队可以在不增加学习曲线的情况下直接使用。


4. 何时更倾向于 systemd 而非 Docker

总结如下,

4-1. 单一/小型服务,且不需要复杂编排

  • 1~2 个 Web 应用
  • 数据库使用 RDS 等托管服务
  • 服务器数量不多(1~5 台)

此时 Docker + 编排的成本可能超过收益,systemd + 简单脚本(Ansible、Fabric 等)即可满足需求。

4-2. 运维团队熟悉 Linux + systemd

  • 现有系统大多基于 systemd
  • 运维人员已熟练使用 systemctljournalctlrsysloglogrotate

在这种环境下,直接在宿主机上部署更高效。

4-3. 监管严格或 Docker 被禁止

  • 金融、公共、国防、医疗等
  • 内部网络/隔离网络
  • 容器安全评估/认证繁琐

此时 Docker 的引入本身就是风险,OS + systemd 是更安全、可控的方案。

4-4. 需要直接调试宿主机资源

  • 需要使用 straceperf/proc 等工具
  • 想一次性查看网络/文件系统/资源问题

在容器中调试会多一层抽象,直接在宿主机进程上调试更方便。


5. 当然,Docker 仍有其适用场景

虽然 systemd 有诸多优势,但 Docker 也不可忽视:

  • 镜像构建 → 任何地方一致运行
  • 本地/预发布/生产环境差异最小化
  • 与 CI/CD 流水线天然集成
  • 多服务(Web + worker + cron + DB)组合

当需要在多台服务器/多环境中统一部署同一堆栈,或团队内部环境差异大时,Docker 可能是更好的选择。

最终,关键是:

“在我们的规模、团队、基础设施下,哪种工具更简单、更稳定、更易运维?”


image

6. 结语:工具不是目的,情境才是关键

在 Linux 上部署 Web 应用时,不是“一定要 Docker”,也不是“Docker 就好”

  • 单一服务、简单基础设施、监管严格 → systemd 更现实
  • 多服务、频繁部署、环境多样 → Docker 更有价值

如果你已经在使用 Linux 服务器,值得认真思考:

  • “这项服务真的需要 Docker 吗?”
  • “用 systemd 能否更简洁?”

工具只是实现目标的手段,简洁与易运维才是长期生产力的关键。