前言
概念懂了,开始动手装 Docker。目标:装好、跑起第一个容器、掌握镜像与容器的日常操作。
一、安装与加速
# 1. 卸载旧版本
dnf remove -y docker docker-client docker-common
# 2. 配置国内 yum 源(阿里云)
dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 3. 安装
dnf install -y docker-ce docker-ce-cli containerd.io
# 4. 配置镜像加速器(国内拉 Docker Hub 很慢)
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<'EOF'
{
"registry-mirrors": ["https://docker.m.daocloud.io"],
"log-driver": "json-file",
"log-opts": {"max-size": "50m", "max-file": "3"}
}
EOF
# 5. 启动
systemctl enable --now docker
docker version # Client + Server 都有输出即成功
daemon.json里顺手配了日志上限——容器 stdout 日志不加限制,迟早把磁盘写爆(血泪教训)。
二、第一个容器
# 跑个 Nginx(本地没有镜像会自动 pull)
docker run -d --name web -p 8080:80 nginx:alpine
# 参数拆解:
# -d 后台运行
# --name web 容器命名
# -p 8080:80 端口映射: 宿主机8080 -> 容器80
# nginx:alpine 精简版镜像
curl -I http://127.0.0.1:8080 # 200 OK 🎉
数据持久化——数据卷挂载:
docker run -d --name web \
-p 8080:80 \
-v /opt/www:/usr/share/nginx/html:ro \
nginx:alpine
# -v 宿主机路径:容器路径[:ro]
# 容器删了, /opt/www 的文件还在 —— 数据不进容器是黄金法则
三、镜像操作
docker pull python:3.11-slim # 拉取(不写 tag 默认 latest, 生产禁用)
docker images # 本地镜像列表
docker rmi python:3.11-slim # 删除镜像
docker tag nginx:alpine reg.local/mynginx:v1 # 打标签
docker push reg.local/mynginx:v1 # 推到私有仓库
docker save -o nginx.tar nginx:alpine # 导出离线包
docker load -i nginx.tar # 导入
docker history nginx:alpine # 看镜像分层
docker inspect nginx:alpine # 镜像详情(JSON)
镜像分层:镜像是只读层的堆叠(每条 Dockerfile 指令一层),多个镜像共享基础层,省空间、拉取快。
四、容器生命周期
docker ps # 运行中的容器
docker ps -a # 包括已停止的
docker stop web && docker start web
docker restart web
docker rm web # 删除(停止的)容器
docker rm -f web # 强删(运行中的)
docker container prune # 清理所有停止的容器
# 进入容器排查(比 attach 安全, 退出不带走容器)
docker exec -it web sh
# 看日志
docker logs -f --tail 100 web
# 拷文件(双向)
docker cp web:/etc/nginx/nginx.conf ./
docker cp ./app.conf web:/etc/app/
# 查看资源占用
docker stats --no-stream
docker top web # 容器内进程
五、容器 ↔ 进程的对应关系
# 容器本质是宿主机上的进程
docker inspect -f '{{.State.Pid}}' web # 拿到容器主进程 PID, 假设 9876
ps -p 9876 # 宿主机上能看到
ls /proc/9876/ns/ # namespace 隔离证据
六、动手练习:跑一个 Python 应用
mkdir -p /opt/pyapp && cd /opt/pyapp
cat > app.py <<'EOF'
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "hello from container\n"
app.run(host="0.0.0.0", port=5000)
EOF
docker run -d --name pyapp \
-v /opt/pyapp:/app -w /app \
-p 5000:5000 \
python:3.11-slim \
sh -c "pip install -q flask -i https://mirrors.aliyun.com/pypi/simple/ && python app.py"
curl http://127.0.0.1:5000
这个例子把代码挂载、工作目录、端口映射、启动命令四个高频点全串起来了。
七、常见坑速查
| 现象 | 原因与解法 |
|---|---|
| 拉镜像超时 | 没配 registry-mirrors,或镜像源挂了换一个 |
| 端口映射后外部不通 | 云安全组没放行;或容器内服务只监听 127.0.0.1 |
| 容器一启动就退出 | 前台没有常驻进程;看 docker logs |
| 磁盘被吃满 | /var/lib/docker 膨胀,docker system prune + 日志限额 |
exec 进不去 |
精简镜像(alpine/scratch)没有 bash,用 sh |
# 大扫除(谨慎: 会删掉未使用的镜像/容器/网络)
docker system df # 先看占用
docker system prune -a
小结
| 操作 | 命令 |
|---|---|
| 跑容器 | docker run -d --name x -p 宿:容器 -v 宿:容器 镜像 |
| 进容器 | docker exec -it x sh |
| 看日志 | docker logs -f x |
| 清理 | docker rm / docker rmi / system prune |
牢记两条黄金法则:数据不进容器(用 -v)、生产不用 latest(锁版本)。下一篇写 Dockerfile,把"怎么做出自己的镜像"补上。
本文是「云原生」系列第 2 篇。