Docker 容器化部署实战指南:从入门到生产环境
作为一个草根站长,我最早接触 Docker 是在一次服务器迁移中。那时我需要把一套 LAMP 环境从旧服务器搬到新服务器,各种依赖冲突、PHP 版本不兼容、MySQL 编码问题让我折腾了两天。后来学会了 Docker,同样的迁移工作只用了一小时。这篇文章就把我这两年使用 Docker 的经验完整地分享给大家。
一、为什么个人站长需要 Docker?
很多个人站长觉得 Docker 是大厂才用的技术,小网站用不上。这个想法其实不对。Docker 对个人站长有几个特别实用的好处,我逐个来说明。
环境一致性:你在本地开发好的网站,部署到服务器上经常出现"明明本地好好的,怎么一上服务器就报错"的情况。原因就是两边的环境不一致——PHP 版本不同、扩展没装、MySQL 字符集设置不一样。Docker 把整个运行环境打包在一起,本地和服务器用同一个镜像,彻底杜绝了环境差异问题。我自己的博客从部署到现在,迁移过三次服务器,每次都是 docker-compose up -d 一行命令搞定,再也没有出现过环境问题导致的报错。
快速迁移:服务器到期换机房、从国内搬到国外、从单机扩展到多机,Docker 容器直接导出导入就行,不用重新配置环境。以前换个服务器,从安装 Nginx、PHP、MySQL 到配置每个网站的 vhost,折腾下来至少半天。现在只需要把 docker-compose.yml 和挂载目录打个包,新服务器上一解压、一启动,十分钟全部搞定。
隔离性强:如果你像我一样,一台服务器上跑着两三个网站,每个网站依赖不同的 PHP 版本或 MySQL 版本,Docker 可以让它们互不干扰地运行在同一台机器上。我现在一台 2 核 4G 的云服务器上跑了三个网站,一个用 PHP 7.4、一个用 PHP 8.0、一个用 PHP 8.1,各自在独立的容器里运行,互不干扰。这在传统环境下几乎不可能实现,或者说维护成本太高了。
回滚简单:升级某个服务之前打个快照,升级出问题了一行命令就能回滚到之前的状态。我以前有一次升级 PHP 版本,结果网站全挂了,折腾了两个小时才恢复。用 Docker 之后,升级前 docker commit 一下当前容器,出了问题 docker run 旧镜像就行了,前后不到一分钟。
二、Docker 核心概念速览
对于没接触过 Docker 的朋友,先理解这几个核心概念。网上很多教程讲得太复杂,我用最通俗的方式给你讲明白:
- 镜像(Image):可以理解成一个操作系统的安装包或者光盘镜像。它是一个只读的模板文件,里面包含了操作系统、运行环境和应用程序。比如
nginx:1.24-alpine这个镜像,就包含了 Alpine Linux 操作系统和 Nginx 1.24 版本的程序。镜像可以从 Docker Hub 上拉取,也可以自己用 Dockerfile 构建。 - 容器(Container):镜像运行起来后的实例。你可以把容器理解成一台已经装好系统的虚拟机。镜像和容器的关系,就像程序和进程的关系——镜像是静态的程序文件,容器是正在运行的进程。你可以启动、停止、删除容器,对容器的修改不会影响原始镜像。
- Dockerfile:一个文本文件,里面按照特定格式写的是"如何构建一个镜像"的步骤说明。比如先装什么软件包、复制什么文件进去、设置什么环境变量、暴露哪个端口。每次修改 Dockerfile 后重新构建,就能生成一个新的镜像版本。
- 数据卷(Volume):容器被删除后,里面的一切数据也会消失,包括数据库、上传的文件、日志等。Volume 就是为了解决这个问题而存在的,它把数据持久化到宿主机上,即使容器被删除,数据也还在。新容器可以挂载同一个 Volume 继续使用之前的数据。
- Docker Compose:一个基于 YAML 格式的工具,用来定义和运行多个容器。比如你有一个网站需要同时运行 Nginx、PHP-FPM、MySQL 三个容器,用 docker-compose.yml 把它们定义在一起,一条命令就能同时启动三个容器,还会自动创建网络让它们互相通信。
三、安装 Docker
在 Ubuntu 22.04 系统上安装 Docker 非常简单,按照以下步骤即可:
# 更新系统包
apt update && apt upgrade -y
# 安装依赖
apt install -y apt-transport-https ca-certificates curl software-properties-common
# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加 Docker 仓库(新版 Docker 推荐的方式)
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker Engine
apt update && apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 设置开机自启并启动
systemctl enable docker && systemctl start docker
# 验证安装
docker --version
docker compose version建议安装完成后将当前用户加入 docker 组,这样不用每次都加 sudo,日常操作方便很多:
usermod -aG docker $USER
# 退出重新登录后生效,或者执行 newgrp docker 立即生效四、用 Docker 部署一个 Typecho 博客(完整实战)
接下来我以部署 Typecho 博客为例,带大家走一遍完整的 Docker 部署流程。这个例子非常典型,包含了 Nginx、PHP-FPM、MySQL 三个服务的编排,你以后部署其他网站也是类似的思路。
第一步,创建项目目录并进入:
mkdir -p ~/typecho-docker && cd ~/typecho-docker第二步,创建一个 docker-compose.yml 文件:
version: '3.8'
services:
nginx:
image: nginx:1.24-alpine
container_name: typecho-nginx
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./typecho:/var/www/html
depends_on:
- php
restart: always
networks:
- typecho-net
php:
image: php:8.1-fpm-alpine
container_name: typecho-php
volumes:
- ./typecho:/var/www/html
restart: always
networks:
- typecho-net
mysql:
image: mysql:8.0
container_name: typecho-mysql
environment:
MYSQL_ROOT_PASSWORD: your_root_password
MYSQL_DATABASE: typecho
MYSQL_USER: typecho
MYSQL_PASSWORD: your_typecho_password
volumes:
- mysql_data:/var/lib/mysql
restart: always
networks:
- typecho-net
volumes:
mysql_data:
networks:
typecho-net:
driver: bridge第三步,创建 Nginx 配置文件 nginx.conf:
server {
listen 80;
server_name _;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}这里 fastcgi_pass php:9000 中的 php 就是 docker-compose.yml 里定义的服务名,Docker 内置的 DNS 会自动把它解析为 php 容器的 IP 地址。
第四步,下载 Typecho 源码并启动:
# 下载 Typecho 最新版
wget https://github.com/typecho/typecho/releases/latest/download/typecho.zip
unzip typecho.zip -d typecho
chmod -R 755 typecho
chown -R 1000:1000 typecho
# 启动所有容器
docker compose up -d
# 查看运行状态
docker compose ps
# 查看日志(确认没有报错)
docker compose logs -f访问 http://你的服务器IP:8080 即可进入 Typecho 安装向导。在这里有一个关键点需要注意:在安装数据库配置步骤中,数据库地址要填容器名称 typecho-mysql,而不是 localhost 或者 127.0.0.1。因为 PHP 容器和 MySQL 容器是两个独立的容器,它们之间通过容器名进行 DNS 解析通信。
五、日常 Docker 运维命令汇总
以下是我日常运维中用得最多的 Docker 命令,建议收藏:
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 进入容器内部操作
docker exec -it typecho-nginx sh
# 查看容器日志
docker logs -f typecho-nginx
# 重启单个容器
docker restart typecho-nginx
# 重启所有服务
docker compose restart
# 停止并删除所有容器
docker compose down
# 重新构建并启动(修改过 Dockerfile 或 compose 配置后使用)
docker compose up -d --build
# 查看资源占用
docker stats
# 清理未使用的镜像、容器、网络(释放磁盘空间)
docker system prune -a -f六、Docker 安全与性能注意事项
安全方面有几个容易被忽视的要点。首先,不要以 root 用户运行容器内的进程。在 Dockerfile 中通过 USER 指令切换到普通用户,可以避免容器被攻破后攻击者直接获得 root 权限。其次,Docker 镜像也需要定期更新,建议每两个月执行一次 docker pull 拉取最新版本,及时获取安全补丁。还有就是不要把 Docker 的 /var/run/docker.sock 套接字挂载到容器内部,这是一个非常危险的操作,相当于把宿主机 root 权限交给了容器。
磁盘管理也是一个常见问题。Docker 默认把容器日志全部保存到磁盘上,时间长了几个 G 的日志文件很常见。我建议在 /etc/docker/daemon.json 中配置日志轮转:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}配置好之后重启 Docker 服务:systemctl restart docker。
另一个常见问题是时区。Docker 容器默认使用 UTC 时区,中国站长会发现容器内的日志时间比实际时间晚了 8 个小时。在 docker-compose.yml 中配置一下就好了:
environment:
- TZ=Asia/Shanghai七、踩坑记录
两年用下来,有几次印象深刻的问题值得分享。
磁盘空间爆满:运行半年后突然发现网站访问变慢,排查发现是 /var/lib/docker 目录占用了 30 多 G 空间。除了上面说的日志问题,还有一个原因是每次 docker pull 都会下载新镜像层,但旧的镜像层不会自动删除。养成定期执行 docker system prune 的习惯可以避免这个问题。
数据库连接问题:第一次用 Docker 部署时,Typecho 安装一直报"无法连接数据库"。排查半天才发现,数据库主机要填容器名而不是 localhost。因为 PHP 和 MySQL 运行在不同的容器里,localhost 指向的是 PHP 容器本身而不是 MySQL 容器。这个坑很多新手都会踩到。
网络问题:如果修改了 docker-compose.yml 中的 network 配置,记得 docker compose down 再 docker compose up -d,而不是直接 docker compose restart。因为网络配置变更需要重建容器才能生效,只重启不会应用新的网络设置。
镜像版本:生产环境不要使用 latest 标签。latest 指向的是最新版本,但"最新"的含义在不同时间点是不一样的。两个月前拉取的 latest 和现在拉取的 latest 可能是两个不同的版本。建议始终使用具体的版本号,如 nginx:1.24.0-alpine。
八、总结
Docker 的学习曲线确实比直接用 apt 安装软件要陡一些,但一旦上手,它对服务器管理效率的提升是巨大的。本文从安装到实战再到运维踩坑,覆盖了个人站长使用 Docker 的完整路径。建议你先在一个低风险的网站(比如个人博客)上实践,熟悉之后再逐步把其他服务也容器化。
如果你在实践过程中遇到问题,欢迎留言交流。作为一个同样从零开始学习 Docker 的草根站长,我很乐意分享更多的实战经验。