适用:所有 Linux 耗时:约 35 分钟 前置:S1(会起服务)、E2(懂服务管理)
Docker 解决的是一个很具体的问题:这个软件在我机器上能跑,在你机器上跑不起来。
这一篇只讲"怎么用它部署东西",不讲"怎么构建镜像"(那是开发的事)。
一、它到底解决什么
没有 Docker 的时候
"这个程序需要 Python 3.9、特定版本的库 A、库 B 要 2.1 版"
↓
你在机器上装 Python 3.9 → 和系统的 Python 3.8 冲突
↓
装库 A 的版本 → 把别的程序依赖搞坏了
↓
最后:这台机器只能跑这一个程序
这叫"依赖地狱"。
有 Docker 的时候
程序 + 它需要的一切 → 打包成一个镜像 → 在任何装了 Docker 的机器上跑
镜像里自带操作系统、语言运行时、所有依赖。 和宿主机完全隔离。
一句话:Docker 让"环境"变成可以复制的文件。
二、三个核心概念
| 概念 | 是什么 | 类比 |
|---|---|---|
| 镜像(image) | 一个只读的"模板" | 光盘 / 装机盘 |
| 容器(container) | 镜像跑起来的实例 | 装好的那台电脑 |
| 仓库(registry) | 存镜像的地方 | 应用商店 |
镜像 --run--> 容器
(模板) (实例,可以跑很多个)
一个镜像可以起多个容器,就像一张装机盘可以装很多台电脑。
三、安装
方式 1:官方脚本(快,但要注意来源)
curl -fsSL https://get.docker.com | sudo sh
curl | sh有风险——等于把网上的脚本直接当 root 跑。只在你信任来源时用。
方式 2:发行版仓库(稳,版本可能旧)
sudo apt install docker.io # Debian 系
sudo dnf install docker # RPM 系
方式 3:官方仓库(推荐,版本新且可控)
# 按官方文档加源,然后
sudo apt install docker-ce docker-ce-cli containerd.io
国内网络建议先配镜像加速(见第十二节),否则拉镜像会很慢。
装完:让普通用户也能用 docker
sudo usermod -aG docker $USER
# 必须重新登录(或 newgrp docker)才生效
⚠️ 这等于给了这个用户 root 级别的权限(Docker 能挂载宿主机目录)。只在个人机器上这么做,多用户服务器上要谨慎。
验证
docker --version
docker run --rm hello-world
看到 “Hello from Docker!” 就成了。
四、最常用的命令(够用 90%)
拉镜像
docker pull nginx # 拉最新的
docker pull nginx:1.24 # 指定版本(推荐)
docker pull mysql:8.0
生产环境一定要指定版本。
latest今天和明天可能不一样,升级会发生在你不知情的时候。
跑容器
docker run -d --name mysite -p 8080:80 nginx
参数解释:
| 参数 | 作用 |
|---|---|
-d | 后台运行(detach) |
--name mysite | 给容器起名(不起名就是随机名) |
-p 8080:80 | 端口映射:宿主机 8080 → 容器 80 |
nginx | 用哪个镜像 |
-p 宿主:容器 的顺序不能反。 这是最容易搞错的地方。
看状态
docker ps # 正在跑的
docker ps -a # 所有(含已停止)
docker logs mysite # 看日志
docker logs -f mysite # 实时跟踪
docker stats # 资源占用(像 top)
进入容器
docker exec -it mysite bash
# 或(镜像里没有 bash)
docker exec -it mysite sh
-it = 交互 + 伪终端。 出来按 Ctrl+D 或 exit。
停止 / 删除
docker stop mysite # 停止
docker start mysite # 再启动
docker restart mysite # 重启
docker rm mysite # 删除(必须先停)
docker rm -f mysite # 强制删除(运行中也删)
清理(磁盘满了必用)
docker system df # 看占了多少
docker system prune # 清理停止的容器和悬空镜像
docker system prune -a # 清理所有未使用的镜像 ⚠️
⚠️
prune -a会删掉所有"没有被容器使用"的镜像。下次用要重新下载(几百 MB 到几 GB)。 先docker system df看清楚再动手。
五、五个真实部署例子
例 1:nginx 静态站
docker run -d --name web \
-p 8080:80 \
-v /var/www/mysite:/usr/share/nginx/html:ro \
--restart unless-stopped \
nginx:1.24
-v 宿主路径:容器路径:ro 把本地目录挂进容器,:ro 是只读。
--restart unless-stopped = 挂了自动重启、开机自动启动。部署服务一定要加。
例 2:MySQL
docker run -d --name mysql \
-p 127.0.0.1:3306:3306 \
-e MYSQL_ROOT_PASSWORD=你的强密码 \
-e MYSQL_DATABASE=myapp \
-v /data/mysql:/var/lib/mysql \
--restart unless-stopped \
mysql:8.0
三个关键点:
-p 127.0.0.1:3306:3306—— 只绑本地,不暴露到公网-e传环境变量(数据库密码、库名)-v把数据目录挂出来 —— 不挂出来,删了容器数据就没了
⚠️ 这是 Docker 最大的坑:容器是无状态的,删了数据就没了。 所有需要保留的数据,必须
-v挂到宿主机。
例 3:用 docker compose 管理多个服务
一步步敲 docker run 很快就乱了。 用 compose:
sudo apt install docker-compose-plugin # 新版是 docker compose(无横线)
docker-compose.yml:
services:
web:
image: nginx:1.24
ports:
- "8080:80"
volumes:
- /var/www/mysite:/usr/share/nginx/html:ro
restart: unless-stopped
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 强密码
MYSQL_DATABASE: myapp
volumes:
- /data/mysql:/var/lib/mysql
restart: unless-stopped
一条命令起全部:
docker compose up -d # 后台启动
docker compose ps # 看状态
docker compose logs -f # 看日志
docker compose down # 停止并删除容器
docker compose restart # 重启
这个文件可以放到 Git 里——换台机器 docker compose up -d 就还原了全部环境。
例 4:看容器占多少空间
docker system df -v
例 5:容器里的服务连不上外面
容器里的 127.0.0.1 是容器自己,不是宿主机。
- 容器 → 宿主机:用宿主机 IP,或者 Linux 上可以用
172.17.0.1(docker0 网关) - 宿主机 → 容器:
-p映射,或直接用容器 IP - 容器 → 容器(同 compose):用服务名当主机名(
db:3306)
这是新手最常踩的坑。
六、镜像加速(国内必配)
不配的话拉镜像可能很慢或失败。
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info | grep -A3 "Registry Mirrors"
镜像加速地址会变。 失效了就搜"docker 镜像加速 2026"找当前的可用地址。
七、安全要点(别不当回事)
| 要点 | 说明 |
|---|---|
别用 -p 0.0.0.0:3306:3306 暴露数据库 | 用 127.0.0.1:3306:3306 |
| 容器默认以 root 跑 | 生产环境加 --user 1000:1000 或用镜像自带的非 root 用户 |
-v /:/host 这种挂载 = 给宿主机 root | 绝不这么干 |
| 镜像要固定版本 | nginx:1.24 而不是 nginx:latest |
| 及时更新 | 老版本镜像有漏洞 |
--privileged 慎用 | 等于给容器全部权限 |
一条判断:你
-p后面写0.0.0.0或者省略主机地址,就是暴露到所有网络接口。 只给自己用的服务,一律写127.0.0.1:端口:端口。
八、动手:五个练习
练习 1:跑 hello-world
docker run --rm hello-world
练习 2:跑 nginx 并映射端口
docker run -d --name test-web -p 8080:80 nginx:1.24
curl -I http://127.0.0.1:8080
docker logs test-web | head -5
练习 3:进容器看看
docker exec -it test-web bash
# 在里面
ls /usr/share/nginx/html
cat /etc/os-release
exit
你会发现容器里是一个独立的系统。
练习 4:挂载本地目录
mkdir -p /tmp/webroot
echo "<h1>来自宿主机</h1>" > /tmp/webroot/index.html
docker run -d --name test-mount -p 8081:80 \
-v /tmp/webroot:/usr/share/nginx/html:ro \
nginx:1.24
curl http://127.0.0.1:8081
# 应该看到"来自宿主机"
改宿主机上的文件,刷新页面就变——这就是挂载。
练习 5:清理
docker rm -f test-web test-mount
docker system df
docker system prune -f
九、验证:你过关了吗
- 能说清"镜像"和"容器"的区别
- 会
docker run -d -p 宿主:容器起服务 - 知道
-p的顺序不能反 - 知道数据必须
-v挂出来,否则删容器就丢 - 会
docker logs/exec -it/ps -a - 会写
docker-compose.yml起多服务 - 知道容器里的
127.0.0.1不是宿主机 - 会配镜像加速
- 知道数据库要绑
127.0.0.1不暴露公网
十、不行怎么办
Q1:permission denied while trying to connect to the Docker daemon
用户不在 docker 组:
sudo usermod -aG docker $USER
newgrp docker # 当前终端立即生效
或者重新登录。
Q2:Cannot connect to the Docker daemon
服务没起来:
sudo systemctl status docker
sudo systemctl start docker
Q3:拉镜像超时 配镜像加速(第六节),或者检查网络/代理。
Q4:port is already allocated
端口被占:
sudo ss -ltnp | grep 8080
换一个端口,或者停掉占用者。
Q5:容器起来就退出(docker ps -a 显示 Exited)
看日志:
docker logs 容器名
常见原因:配置错、缺环境变量、命令不存在。
docker run -it 镜像 bash 可以进去手动排查。
Q6:改了容器里的文件,重启就没了
容器是无状态的。 要持久化的东西必须 -v 挂到宿主机。
Q7:磁盘被 Docker 占满了
docker system df -v
docker system prune -a --volumes # ⚠️ 连数据卷一起删,先确认
--volumes 会删数据卷——有数据库的话先备份。
Q8:容器里连不上宿主机的服务
容器内 127.0.0.1 是它自己。用:
- 宿主机 IP
- 或
--add-host=host.docker.internal:host-gateway - 或
172.17.0.1(Linux 默认网桥网关)
Q9:docker compose 报 command not found
老版本是 docker-compose(有横线):
docker-compose up -d
装新版插件:sudo apt install docker-compose-plugin,之后用 docker compose。
十一、一句话总结
镜像是模板,容器是实例,
-p映射端口,-v挂载数据。数据不挂载 = 删容器就丢。
数据库绑
127.0.0.1,镜像固定版本,清理前先df看。
← 上一篇 S2|数据库入门 下一篇 → S4|反向代理与 HTTPS