适用:所有 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

三个关键点:

  1. -p 127.0.0.1:3306:3306 —— 只绑本地,不暴露到公网
  2. -e 传环境变量(数据库密码、库名)
  3. -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