事情是这样的:朋友买了一台新的 VPS,让我帮他搭个 WordPress。我 SSH 上去一看,PHP 版本不对,MySQL 没装,Nginx 缺模块。光配环境就搞了半小时——然后他说“诶我另外一台机器上还有个 Node.js 项目,能一起跑吗”。
这就是为什么每个开发者都需要学 Docker 入门——把环境和应用一起打包,换服务器像换 U 盘一样简单。每换一台服务器就要重装一遍依赖,版本冲突、路径错误、缺库少包,折腾半天。Docker 就是来解决这个问题的:把应用和它需要的一切打包成一个集装箱,到哪都能跑。
本文从零开始,装 Docker、跑容器、写 Compose 文件,最后用一条命令起一个完整的 WordPress 站点。
Docker 是什么
别去看那些“容器化”“微服务”“编排”的八股文。Docker 本质上就做了两件事:
- 打包:把你的代码 + PHP + Nginx + 配置文件 + 所有依赖,打成一个镜像(Image)。这个镜像可以在任何装了 Docker 的机器上跑,无视系统差异
- 隔离:每个容器(Container)有自己独立的文件系统、进程空间、网络。你在容器里 rm -rf / 不会影响宿主机,两个容器之间默认也互不干扰
类比一下:镜像像 Ghost 系统盘,容器像用这个 Ghost 盘装好的电脑。一个镜像可以启动无数个容器,每个容器都是独立运行的实例。
Docker vs 虚拟机:虚拟机需要模拟整个操作系统(包括内核),一个 VM 动辄占几个 G。Docker 直接共享宿主机的 Linux 内核,只打包应用层,一个容器几十 MB 就够了,启动不到一秒。
安装 Docker(CentOS 7/8,一行命令)
官网的安装步骤很长,对新手不太友好。用 Docker 官方的一键脚本最快:
curl -fsSL https://get.docker.com | bash
装完后启动 Docker 并设为开机自启:
systemctl start docker
systemctl enable docker
验证一下:
docker version
如果输出 Client 和 Server 两段信息,说明装好了。
不想每次敲 docker 前面都加 sudo?把当前用户加进 docker 组:
usermod -aG docker $USER
# 退出 SSH 重新登录生效
第一个容器:跑个 Nginx
Docker 最神奇的地方在于:跑一个 Nginx 只需要一条命令,不需要 apt install、不需要改配置、不需要创建 www 目录。
docker run -d -p 8080:80 --name my-nginx nginx:latest
拆解一下:
-d:后台运行-p 8080:80:把宿主机的 8080 端口映射到容器的 80 端口。访问http://你的IP:8080就能看到 Nginx 欢迎页了--name my-nginx:给容器起个名字,方便后续管理nginx:latest:镜像名和标签。Docker 会自动从 Docker Hub 拉取最新版
用浏览器打开 http://你的服务器IP:8080,你能看到 Nginx 的默认欢迎页面。整个过程不过 5 秒——这就是 Docker 的威力。
如果你用的是宝塔面板或者云服务商的安全组,记得先去放行 8080 端口。具体操作见本站 Linux 放行端口指南。
常用命令速查
上面跑起来之后,几个最常用的操作:
# 查看正在运行的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 停止容器
docker stop my-nginx
# 启动已停止的容器
docker start my-nginx
# 删除容器(先停止)
docker rm my-nginx
# 查看本地已有的镜像
docker images
# 删除镜像
docker rmi nginx:latest
# 进入容器的终端(调试用)
docker exec -it my-nginx /bin/bash
# 查看容器日志
docker logs my-nginx
# 实时跟踪日志
docker logs -f my-nginx
新手最容易忘的是 docker ps -a 里的 -a——不加的话只显示运行中的容器,已停止的不显示。以为自己把容器删了,其实还在占着磁盘。
实战:用 Docker Compose 一键部署 WordPress
单个容器没什么意思。实际项目中一个应用通常需要多个服务配合——比如 WordPress 需要 PHP-FPM + MySQL + Nginx。Docker Compose 就是用来定义和管理这种多容器应用的。
创建一个 docker-compose.yml 文件:
version: '3.8'
services:
db:
image: mysql:8.0
container_name: wp-db
restart: always
environment:
MYSQL_ROOT_PASSWORD: your_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_password
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
container_name: wp-app
restart: always
ports:
- "8081:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: wp_password
WORDPRESS_DB_NAME: wordpress
depends_on:
- db
volumes:
- wp_data:/var/www/html
volumes:
db_data:
wp_data:
在文件所在目录执行:
docker compose up -d
30 秒后,打开 http://你的IP:8081,WordPress 的安装向导就出来了。MySQL 容器和 WordPress 容器自动组网,你不需要手动配置数据库连接——容器之间通过服务名(db)互相发现。
要停掉整个项目:
docker compose down
数据在 volumes 里,下次 docker compose up -d 数据还在。除非你加了 -v 参数(docker compose down -v),那样会连数据卷一起删掉。
踩过的坑
1. 容器重启后数据丢了
容器的文件系统是临时的,容器删掉数据就没了。但凡需要持久化的数据(数据库、上传文件、配置文件),必须挂载 volume 或 bind mount。上面 Compose 文件里的 volumes: 配置就是干这个的。
2. 端口冲突
宿主机上一个端口只能被一个服务占用。如果你之前用宝塔装了 Nginx 监听 80 端口,Docker 里再映射 80 就会报错。换个端口就行,比如 -p 8080:80。
3. 镜像拉不动
Docker Hub 在国内有时很慢甚至超时。配置镜像加速器:
# 编辑 /etc/docker/daemon.json,没有就新建
{
"registry-mirrors": ["https://docker.1ms.run"]
}
# 重启 Docker
systemctl restart docker
4. 用 root 跑容器的安全风险
默认情况下容器内进程以 root 运行。虽然容器有隔离,但一旦逃逸就可能拿到宿主机权限。生产环境建议在 Dockerfile 里指定非 root 用户,或者用 --user 参数启动。
下一步学什么
到此你已经能装 Docker、跑容器、写 Compose、部署 WordPress 了。接下来三条路:
- 写自己的 Dockerfile:把你自己写的项目打包成镜像,不再依赖“别人的镜像有没有装对版本”
- 学 Docker 网络:bridge、host、overlay 三种模式的区别,容器间怎么通信
- 上 k8s:如果你有 3 台以上服务器,就该学容器编排了。但个人项目用 Docker Compose 就够了,别被 k8s 的复杂度劝退
Docker 核心概念就三个(镜像、容器、仓库),常用命令不超过 20 个。花一个下午实战一遍,第二天就能用它部署项目了。
相关阅读:Linux 放行端口、Nginx 配置详解、WordPress 多站点