VPSKnow

Docker 容器化部署完全指南

中级
45分钟

在 VPS 上折腾各种软件环境,最怕的就是依赖地狱、版本冲突和难以卸载。Docker 将应用及其全部依赖打包成隔离的容器,实现了"一次配置,到处运行"。本指南从基础概念到完整 LEMP 栈实战,带您掌握现代服务器运维最核心的容器化技能。

🐳 什么是 Docker?核心概念

Docker 是一种轻量级容器化技术,将应用程序及其所有依赖项(库、环境变量、配置文件)打包成标准化的容器(Container),确保它在任何 Linux 环境下都能以完全相同的方式运行。

📦

环境隔离

MySQL、Redis、Nginx 各自运行在独立容器中,互不干扰。不同项目可以使用不同版本的同一软件(如 PHP 7.4 + PHP 8.3 并存)

🚀

秒级启动

容器共享宿主机内核,没有传统虚拟机的系统引导过程。启动一个 Nginx 容器只需约 0.3 秒

♻️

一键迁移

换服务器只需复制 docker-compose.yml 和数据目录,执行一条命令即可完整恢复所有服务

📖 三个核心概念

镜像 (Image)

只读模板,相当于安装光盘。从 Docker Hub 拉取(如 nginx:alpine)或通过 Dockerfile 构建。镜像本身不运行,用来创建容器。

容器 (Container)

镜像运行后的实例,相当于已安装好的虚拟机。容器是可读写的,但内部变更在容器删除后消失(数据持久化靠挂载卷)。

仓库 (Registry)

存储和分发镜像的服务。Docker Hub 是最大的公共仓库(hub.docker.com),也可以搭建私有仓库(Harbor)。

⚔️ Docker vs 传统虚拟机

很多新手会混淆 VPS(虚拟机)和 Docker 容器。理解它们的区别,是掌握容器化思维的关键。

对比维度 传统虚拟机(KVM/VMware) Docker 容器 ⭐
隔离层级 硬件级(含完整 Guest OS) 进程级(共享宿主机内核)
资源占用 极大(数 GB 内存/磁盘) 极小(数十 MB 起)
启动速度 分钟级 秒级/毫秒级
镜像大小 数 GB(含完整 OS) 数十 MB 到数百 MB
可移植性 受限于 Hypervisor 类型 任意支持 Docker 的 Linux 环境
安全隔离 强(内核完全隔离) 较弱(共享内核,但 namespace 隔离)
适用场景 强隔离需求、运行不同操作系统 微服务、快速部署、开发环境统一
💡 关系理解: VPS 是您租的服务器(一台虚拟机),Docker 运行在 VPS 上。VPS 提供计算资源,Docker 负责管理这些资源上运行的各个应用服务。两者是上下层关系,不是竞争关系。

⚙️ 一键安装 Docker 环境

官方一键安装(Ubuntu / Debian / CentOS)
# ── 官方一键安装脚本(适用于 Ubuntu / Debian / CentOS)────────────────────
# 自动检测发行版并安装最新稳定版 Docker Engine + Docker Compose 插件
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# 启动并设置开机自启
sudo systemctl enable --now docker

# 验证安装
docker --version          # 应输出:Docker version 27.x.x
docker compose version    # 应输出:Docker Compose version v2.x.x

# ── 可选:允许普通用户运行 Docker(无需每次 sudo)──────────────────────────
# 将当前用户加入 docker 组,重新登录后生效
sudo usermod -aG docker $USER
newgrp docker              # 临时生效,或重新 SSH 登录

💡 新版本变化: Docker 已将 docker-compose 作为插件集成到 CLI 中。现在推荐使用 docker compose(中间是空格)而非旧版的 docker-compose(连字符)。两者功能相同,但新版性能更好。

⌨️ Docker 基础命令速查

命令 功能描述
docker ps 查看正在运行的容器
docker ps -a 查看所有容器(含已停止)
docker images 查看本地已下载的镜像列表
docker pull nginx:latest 从 Docker Hub 拉取指定镜像
docker run -d --name app -p 80:80 nginx 后台运行容器并映射端口
docker stop app 优雅停止容器(发送 SIGTERM)
docker start app 重新启动已停止的容器
docker restart app 重启容器(等同于 stop + start)
docker rm app 删除已停止的容器
docker rm -f app 强制删除运行中的容器
docker rmi nginx:latest 删除本地镜像
docker logs -f --tail 100 app 实时查看最近 100 行日志
docker exec -it app /bin/sh 进入容器内部交互式终端
docker inspect app 查看容器详细配置(JSON 格式)
docker system prune -a --volumes 清理所有未使用资源(镜像/容器/卷)⚠️ 谨慎执行

💾 必学:数据持久化与挂载

⚠️ 新手最常踩的坑: 容器是"用完即抛"的无状态单元。执行 docker rm 容器名 后,容器内部的数据(数据库文件、上传的图片、配置变更)全部永久消失!必须通过挂载将数据存储在宿主机上。

两种挂载方式对比
# ════════════════════════════════════════════════════════════
#  数据持久化:两种挂载方式对比
# ════════════════════════════════════════════════════════════

# ── ❌ 错误做法(容器删除 = 数据消失)────────────────────────────────────────
docker run -d --name mysql_bad   -e MYSQL_ROOT_PASSWORD=secret   mysql:8.0
# 执行 docker rm mysql_bad 后,数据库数据完全丢失!

# ── ✅ 方式一:Bind Mount(绑定宿主机目录)推荐用于开发和生产 ────────────────
# 格式:-v 宿主机绝对路径:容器内路径
docker run -d --name mysql_good   -v /opt/mysql/data:/var/lib/mysql       # 数据目录映射
  -v /opt/mysql/conf:/etc/mysql/conf.d   # 配置目录映射
  -e MYSQL_ROOT_PASSWORD=secret   -p 127.0.0.1:3306:3306                # 只绑定本地,不对外暴露
  --restart unless-stopped              # 意外崩溃自动重启
  mysql:8.0

# ── ✅ 方式二:Named Volume(命名卷)推荐用于数据库等需要高 I/O 的场景 ─────
# Docker 管理存储位置(在 /var/lib/docker/volumes/ 下),性能略优于 Bind Mount
docker volume create mysql_data
docker run -d --name mysql_vol   -v mysql_data:/var/lib/mysql   -e MYSQL_ROOT_PASSWORD=secret   mysql:8.0

# 查看所有命名卷
docker volume ls
# 查看卷详情(包含宿主机实际路径)
docker volume inspect mysql_data

📁Bind Mount(绑定挂载)

  • 路径直观,宿主机直接访问修改
  • 适合配置文件、网站源码
  • 迁移时直接打包目录

路径强耦合,可移植性略差

🗄️Named Volume(命名卷)

  • Docker 统一管理,性能略优
  • 适合数据库等高 I/O 场景
  • 支持 volume driver 对接云存储

默认路径在 /var/lib/docker/,不直观

🌐 进阶:Docker 网络模式详解

理解 Docker 网络是实现容器间安全通信的关键。不同网络模式适用于不同场景:

🌉 bridge(默认)

容器获得独立虚拟 IP,通过 docker0 网桥与宿主机通信。推荐使用自定义 bridge 网络——容器间可直接用服务名通信(内置 DNS)。

🏠 host

容器直接使用宿主机网络,无独立 IP,性能最好(无 NAT 开销),但失去网络隔离,需注意端口冲突。适合对延迟极敏感的场景。

🔇 none

完全禁用网络,容器没有网络接口。适合数据处理、批量计算等完全不需要网络的任务,安全隔离最彻底。

Docker 网络实战命令
# ════════════════════════════════════════════════════════════
#  Docker 网络模式详解
# ════════════════════════════════════════════════════════════

# ── 默认:bridge 模式(最常用)──────────────────────────────────────────────
# 每个容器分配独立虚拟 IP(172.17.0.x),通过 docker0 网桥与宿主机通信
# 容器间通信需要通过 IP 或 --link(已废弃,推荐自定义网络)
docker run -d --name app1 --network bridge nginx

# ── 自定义 bridge 网络(推荐!容器间可直接用服务名通信)────────────────────
docker network create myapp_net

docker run -d --name web   --network myapp_net nginx
docker run -d --name db    --network myapp_net mysql:8.0

# 在 web 容器内可直接 ping db(用容器名作为 DNS)
# docker exec web ping db   → 可以 ping 通

# ── host 模式(高性能,容器直接使用宿主机网络)───────────────────────────────
# 容器不再有独立 IP,直接监听宿主机端口
# 性能最好,但失去网络隔离,端口冲突风险高
docker run -d --name fast_app --network host nginx
# 注意:host 模式下不需要 -p 端口映射,容器直接使用宿主机 80 端口

# ── none 模式(完全隔离网络,适合数据处理任务)───────────────────────────────
docker run -d --name isolated --network none alpine sleep 3600

# 网络管理常用命令
docker network ls                        # 列出所有网络
docker network inspect myapp_net         # 查看网络详情
docker network connect myapp_net app1    # 将已有容器加入网络

🎼 Docker Compose:多容器编排

当应用需要多个容器协同工作时(数据库 + Web 服务器 + 缓存),用命令行逐个 docker run 既繁琐又难以维护。Docker Compose 用一个 yaml 文件声明所有服务的配置关系,一条命令启动全部。

基础 docker-compose.yml 示例

/opt/myapp/docker-compose.yml
# 文件路径:/opt/myapp/docker-compose.yml
# 最基础的 Nginx + PHP-FPM 组合示例

services:
  web:
    image: nginx:alpine           # 使用轻量级 alpine 版本
    container_name: myapp_nginx
    restart: unless-stopped       # 除非手动停止,否则崩溃或开机自动重启
    ports:
      - "80:80"                   # 宿主机端口:容器端口
      - "443:443"
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d    # Nginx 配置目录
      - ./html:/var/www/html              # 网站文件目录
      - ./logs/nginx:/var/log/nginx       # 日志目录(方便在宿主机查看)
    networks:
      - app_net
    depends_on:
      - php                       # 确保 php 服务先启动

  php:
    image: php:8.3-fpm-alpine
    container_name: myapp_php
    restart: unless-stopped
    volumes:
      - ./html:/var/www/html      # 与 Nginx 挂载相同目录(共享网站文件)
    networks:
      - app_net

# 自定义网络(容器间用服务名通信,如 nginx 配置中 fastcgi_pass php:9000)
networks:
  app_net:
    driver: bridge

Docker Compose 核心命令速查

docker compose up -d

后台启动所有服务(自动拉取镜像)

docker compose down

停止并删除容器(保留挂载数据)

docker compose down -v

停止并删除容器及命名卷⚠️ 数据会删除

docker compose ps

查看所有服务的运行状态

docker compose logs -f

实时查看所有服务的合并日志

docker compose logs -f web

只看指定服务的日志

docker compose pull

拉取最新镜像(之后需 up -d 重建)

docker compose restart web

重启指定服务

docker compose exec web sh

进入指定服务容器内部

docker compose config

验证并查看最终合并的配置

🏗️ 实战:LEMP 栈完整部署

LEMP(Linux + Nginx + MySQL + PHP)是部署 WordPress 等 PHP 应用的经典组合。以下是一套完整的生产级 Compose 配置,包含 Redis 缓存和安全最佳实践。

docker-compose.yml(完整 LEMP + Redis)

/opt/lemp/docker-compose.yml
# 文件路径:/opt/lemp/docker-compose.yml
# 完整 LEMP 栈:Linux + Nginx + MySQL + PHP-FPM + Redis

services:

  # ── Nginx 反向代理 ─────────────────────────────────────────────────────────
  nginx:
    image: nginx:alpine
    container_name: lemp_nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./www:/var/www/html
      - ./nginx/ssl:/etc/nginx/ssl
    networks:
      - lemp_net
    depends_on:
      - php
      - mysql

  # ── PHP-FPM ────────────────────────────────────────────────────────────────
  php:
    image: php:8.3-fpm-alpine
    container_name: lemp_php
    restart: unless-stopped
    volumes:
      - ./www:/var/www/html       # 与 Nginx 共享网站目录
    environment:
      - PHP_MEMORY_LIMIT=256M
    networks:
      - lemp_net

  # ── MySQL 8 ────────────────────────────────────────────────────────────────
  mysql:
    image: mysql:8.0
    container_name: lemp_mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}   # 从 .env 文件读取密码
      MYSQL_DATABASE:      ${MYSQL_DATABASE}
      MYSQL_USER:          ${MYSQL_USER}
      MYSQL_PASSWORD:      ${MYSQL_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql                    # 使用命名卷保存数据
    networks:
      - lemp_net
    # 不对外暴露端口,只在内部网络访问(安全!)

  # ── Redis 缓存 ──────────────────────────────────────────────────────────────
  redis:
    image: redis:7-alpine
    container_name: lemp_redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD}  # 启用密码认证
    volumes:
      - redis_data:/data
    networks:
      - lemp_net

# ── 命名卷(Docker 管理,高 I/O 性能)──────────────────────────────────────
volumes:
  mysql_data:
  redis_data:

# ── 自定义内部网络 ────────────────────────────────────────────────────────────
networks:
  lemp_net:
    driver: bridge

.env 配置文件(敏感信息隔离)

/opt/lemp/.env
# 文件路径:/opt/lemp/.env
# 敏感配置统一放在 .env 文件,不提交到 Git(在 .gitignore 中添加 .env)

MYSQL_ROOT_PASSWORD=强密码_至少16位
MYSQL_DATABASE=myapp_db
MYSQL_USER=myapp_user
MYSQL_PASSWORD=另一个强密码

REDIS_PASSWORD=Redis访问密码

# 启动命令:
# cd /opt/lemp && docker compose up -d
# 查看所有服务状态:
# docker compose ps
💡 安全提示: .env 文件包含数据库密码等敏感信息,必须在 .gitignore 中添加 .env 防止提交到版本控制系统。可以提交一个 .env.example 模板(清空密码值)供团队参考。

📝 进阶:编写自定义 Dockerfile

当 Docker Hub 上的现成镜像不满足需求时,可以编写 Dockerfile 构建自定义镜像。多阶段构建是生产环境的最佳实践——在构建阶段安装编译工具,最终镜像只保留运行时必需的文件,显著减小镜像体积。

多阶段构建示例(Node.js 生产镜像)

/opt/myapp/Dockerfile
# 文件路径:/opt/myapp/Dockerfile
# 示例:为 Node.js 应用构建生产镜像(多阶段构建,减小最终镜像体积)

# ════ 阶段一:构建(Builder Stage)════════════════════════════════════════════
FROM node:20-alpine AS builder
WORKDIR /app

# 先复制 package.json,利用 Docker 层缓存(依赖不变时跳过 npm install)
COPY package*.json ./
RUN npm ci --only=production

# 再复制源码并构建
COPY . .
RUN npm run build

# ════ 阶段二:生产镜像(只包含运行时必需文件)══════════════════════════════════
FROM node:20-alpine AS production
WORKDIR /app

# 创建非 root 用户运行应用(安全最佳实践)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 只从 builder 阶段复制构建产物
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .

# 设置文件所有权
RUN chown -R appuser:appgroup /app
USER appuser

# 暴露端口(文档说明,不实际发布)
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3   CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "dist/server.js"]
构建与推送镜像
# 在 Dockerfile 所在目录执行构建
docker build -t myapp:v1.0 .

# 打标签(为推送到 Docker Hub 或私有仓库做准备)
docker tag myapp:v1.0 yourusername/myapp:v1.0
docker tag myapp:v1.0 yourusername/myapp:latest

# 推送到 Docker Hub(需要先 docker login)
docker push yourusername/myapp:v1.0

# 查看镜像层信息(了解每层的大小,优化 Dockerfile)
docker history myapp:v1.0

🧹 进阶:限制容器日志大小

Docker 默认将容器的标准输出无限期保存在 /var/lib/docker/containers/ 下。高流量服务的日志可能在几周内积累到数十 GB,直接把 VPS 磁盘占满导致服务崩溃。

日志大小限制配置
# ── 方案一(推荐):全局配置,对所有新容器生效 ─────────────────────────────
# 编辑或创建 /etc/docker/daemon.json

# 配置内容(JSON 格式):
# {
#   "log-driver": "json-file",
#   "log-opts": {
#     "max-size": "20m",
#     "max-file": "3"
#   }
# }

# 含义:每个容器日志文件最大 20MB,最多保留 3 个滚动文件
# 即最多占用 60MB 磁盘空间(20MB × 3)

# 保存后重启 Docker 守护进程(仅对新创建的容器生效)
sudo systemctl restart docker

# ── 方案二:在 docker-compose.yml 中单独配置特定服务 ─────────────────────────
# services:
#   web:
#     image: nginx
#     logging:
#       driver: json-file
#       options:
#         max-size: "50m"    # 高流量服务可以设大一些
#         max-file: "5"

# ── 查看当前容器日志占用空间 ─────────────────────────────────────────────────
# 查看所有容器日志总大小
du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -rh | head -10

# 手动清空某个容器的日志(不停服务)
truncate -s 0 /var/lib/docker/containers/容器ID/容器ID-json.log

📋 /etc/docker/daemon.json 完整配置示例

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "3"
  },
  "dns": ["1.1.1.1", "8.8.8.8"]
}

保存后执行 sudo systemctl restart docker 生效。注意:只对之后新创建的容器有效,存量容器需重建。

🗼 进阶:Watchtower 容器自动更新

每次应用发布新版本都要手动 pullup -d 很麻烦?Watchtower 会监控您的容器,发现镜像有新版本时自动拉取、重建、清理旧镜像,实现完全无人值守的容器更新。

Watchtower 部署与配置
# ── Watchtower:自动监控并更新所有 Docker 容器 ────────────────────────────
docker run -d   --name watchtower   --restart always   -v /var/run/docker.sock:/var/run/docker.sock   # 需要 socket 权限来管理其他容器
  containrrr/watchtower   --cleanup                     # 更新后自动删除旧镜像,释放磁盘
  --schedule "0 3 * * *"         # Cron 格式:每天凌晨 3 点检查更新

# ── 进阶:只更新特定容器(打标签)──────────────────────────────────────────
# 在需要自动更新的容器上加 label:
# docker run -d --label=com.centurylinklabs.watchtower.enable=true --name app nginx

# 然后以 --label-enable 模式运行 Watchtower(只更新打了标签的容器)
# docker run -d --name watchtower #   -v /var/run/docker.sock:/var/run/docker.sock #   containrrr/watchtower --label-enable --cleanup

# ── 查看 Watchtower 的更新日志 ────────────────────────────────────────────
docker logs -f watchtower
⚠️ Watchtower 注意事项: 不建议对数据库容器(MySQL/PostgreSQL)启用自动更新——大版本升级(如 MySQL 8.0 → 8.4)可能需要手动执行数据迁移,自动更新可能导致数据损坏。建议用 --label-enable 模式,只对无状态服务(Nginx、API 服务等)开启自动更新。

常见问题解答

docker compose up -d 运行后容器立刻退出,怎么排查?

排查步骤:① docker compose ps 查看哪个服务的状态是 "Exited";② docker compose logs 服务名 查看退出前的日志输出——通常会有明确的报错信息(如配置文件格式错误、端口冲突、缺少环境变量);③ 常见原因:.env 文件不存在导致必需的环境变量为空(MySQL 的 MYSQL_ROOT_PASSWORD 未设置会立即退出)、挂载的宿主机目录不存在、端口已被其他进程占用(ss -tlnp | grep 端口号)。

容器内的应用如何访问宿主机上的服务(如宿主机的 MySQL)?

在 bridge 网络模式下,容器内使用特殊地址 host.docker.internal 访问宿主机(Linux 需要在 docker run 时加 --add-host host.docker.internal:host-gateway)。或者,直接使用宿主机的内网 IP(通常是 172.17.0.1,即 docker0 网桥地址,可用 ip addr show docker0 查看)。更推荐的做法:将宿主机的 MySQL 也迁移到 Docker,用自定义 bridge 网络实现容器间通信,彻底容器化管理。

docker system prune -a 和 docker system prune 有什么区别?执行前要注意什么?

docker system prune:清理已停止的容器、悬空镜像(dangling images,即无 tag 的中间层镜像)、未使用的网络。docker system prune -a:在此基础上额外删除所有未被任何容器使用的镜像(包括有 tag 的镜像)。--volumes 参数还会删除未使用的命名卷——这个参数极其危险,会删除数据库数据,千万不要在生产环境随意执行。建议只用 docker system prune(不加 -a),或精确指定要删除的资源(docker image prune / docker container prune)。

Docker 容器占用了多少内存?怎么限制单个容器的资源使用?

查看各容器实时资源占用:docker stats(类似 top,实时刷新)。在 docker-compose.yml 中限制资源
services: web: deploy: resources: limits: memory: 512m cpus: '0.5'
这样该容器最多使用 512MB 内存和 50% 单核 CPU。典型参考值:Nginx 约 20-50MB,PHP-FPM(含业务)约 100-300MB/进程,MySQL 约 300-500MB(取决于 buffer_pool 配置),Redis 约 20-200MB(取决于数据量)。1GB 内存的 VPS 跑 LEMP 全栈会比较吃力,建议 2GB 起步。

Dockerfile 中 RUN、CMD 和 ENTRYPOINT 有什么区别?

RUN:构建镜像时执行(安装软件、创建目录等),结果被固化到镜像层中。每条 RUN 命令创建一个新镜像层,建议用 && 合并多条命令减少层数。CMD:容器启动时的默认命令,可以被 docker run 命令行参数覆盖。一个 Dockerfile 只有最后一条 CMD 生效。ENTRYPOINT:容器的入口点,不会被命令行参数覆盖(除非 --entrypoint)。常用组合:ENTRYPOINT 定义固定执行程序,CMD 提供默认参数——docker run image 新参数 时 CMD 被替换而 ENTRYPOINT 保持不变。

如何将整个 Docker 应用迁移到新服务器?

标准迁移流程:① 在新服务器安装 Docker(官方脚本一键安装);② 将配置目录(docker-compose.yml.env、Nginx 配置等)和数据目录(MySQL 数据、网站文件等)打包传输:rsync -avz /opt/myapp/ root@新服务器IP:/opt/myapp/;③ 如果使用 Named Volume,需要先导出:docker run --rm -v mysql_data:/data -v /tmp:/backup alpine tar czf /backup/mysql_data.tar.gz /data,传输后在新机器解压;④ 在新服务器执行 docker compose up -d,镜像会自动从 Docker Hub 重新拉取;⑤ 验证服务正常后切换 DNS,保持旧服务器再运行 24-48 小时作为备用。

Docker 容器如何配置时区?容器内时间和宿主机不一致怎么办?

容器默认使用 UTC 时区,日志时间戳会与宿主机不一致(如宿主机是 UTC+8,日志会差 8 小时)。解决方案:在 docker-compose.yml 的服务配置中添加:environment: - TZ=Asia/Shanghai,并挂载宿主机时区文件:volumes: - /etc/localtime:/etc/localtime:ro。两种方案选一即可,推荐 TZ 环境变量(更简洁)。对于已运行的容器需重建才能生效(docker compose up -d --force-recreate)。

我已经用了 1Panel 面板管理 Docker,还需要学命令行操作吗?

强烈建议学。理由:① 面板异常时的应急手段:1Panel 本身也是一个 Docker 容器,如果面板出问题,只能用命令行操作其他容器;② 面板的应用商店不能覆盖所有场景:定制化的 docker-compose.yml、多阶段 Dockerfile 构建、网络配置调试都需要命令行;③ CI/CD 流水线中没有 GUI:自动化部署脚本必须用命令行;④ 面板是加速器而非替代品:理解了命令行原理,才能看懂面板操作背后发生了什么,出问题时不慌乱。第 13 篇的 1Panel 和本篇是互补关系,两者都学效果最好。

学完 Docker 后,下一步应该按什么顺序继续?

按本站 30 篇路径,第 15 篇(本篇)→ 第 16 篇(database-setup)→ 第 17 篇(personal-cloud-storage)是最顺畅的进阶链条。关联逻辑:第 16 篇的 MySQL/PostgreSQL/Redis 部署会大量用到本篇的 Compose 和数据持久化知识——事实上本篇的 LEMP 栈实战已经包含了 MySQL + Redis 的 Compose 配置,第 16 篇会深入讲解这些数据库的内部配置和安全加固;第 17 篇的 Nextcloud/AList 私有云盘则是 Docker 最典型的应用场景之一,一条 docker compose up -d 即可部署。

Docker 和 Kubernetes(K8s)是什么关系?什么时候需要 K8s?

Docker 是单机容器运行时,管理一台服务器上的容器。Kubernetes(K8s)是容器编排平台,管理跨多台服务器的容器集群,提供自动扩缩容、故障自愈、滚动更新、服务发现等能力。什么时候需要 K8s:① 需要横向扩展到 3 台以上服务器;② 需要零停机滚动发布;③ 有复杂的微服务架构(20+ 个服务);④ 企业级可靠性要求。个人 VPS / 小型项目完全不需要 K8s——Docker Compose 足够应对 95% 的个人和中小企业场景,学习成本远低于 K8s,且不需要额外的 Master 节点(K8s 的控制面本身就需要消耗约 4GB 内存)。