4. Docker容器技术:从安装到生产实践
Docker 这东西,说白了就是把你的应用连同环境一起打包。我刚开始接触时也觉得不就是个轻量级虚拟机吗?后来线上踩过几次坑才明白——容器和虚拟机的思维模式完全不同。这一章,我把这几年在生产环境折腾 Docker 的经验梳理出来,从安装到镜像管理、Dockerfile 编写、私有仓库搭建,一条线讲清楚。
4.1 Docker安装与架构
安装 Docker 其实不难,但不同发行版有细微差别。我个人习惯用官方脚本,干净利落:
# Ubuntu / Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# CentOS / RHEL
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
装完后记得把当前用户加入 docker 组,不然每次都要 sudo:
sudo usermod -aG docker $USER
newgrp docker
Docker 的架构其实就三块:客户端、守护进程、镜像仓库。客户端发指令,守护进程干活,仓库存镜像。我画了张图帮你理解:
4.2 镜像与容器生命周期管理
镜像和容器的关系,你可以理解成程序和进程。镜像是静态的只读模板,容器是运行中的实例。我经常看到新手把镜像当容器用,直接在镜像里改东西——这是个大坑。
镜像操作
拉取、查看、删除,三板斧:
# 拉取镜像
docker pull nginx:1.25-alpine
# 列出本地镜像
docker images
# 删除镜像(先删依赖的容器)
docker rmi nginx:1.25-alpine
# 查看镜像分层
docker history nginx:1.25-alpine
容器生命周期
容器的状态流转其实就几个:Created → Running → Paused → Stopped → Deleted。我整理了一张表:
| 命令 | 作用 | 常用参数 |
|---|---|---|
docker run |
创建并启动容器 | -d 后台运行,-p 端口映射,-v 挂载卷 |
docker start/stop |
启动/停止已有容器 | --time 等待时间(默认10秒) |
docker pause/unpause |
暂停/恢复进程 | 使用 cgroups freezer |
docker rm |
删除已停止的容器 | -f 强制删除运行中的 |
docker exec |
进入运行中的容器 | -it 交互模式 |
举个例子,启动一个 Nginx 并挂载配置:
docker run -d \
--name my-nginx \
-p 8080:80 \
-v /data/nginx/html:/usr/share/nginx/html:ro \
-v /data/nginx/conf:/etc/nginx/conf.d:ro \
--restart always \
nginx:1.25-alpine
--restart=always 配合 -d,结果容器因为配置错误不断重启,日志刷爆了磁盘。建议先用 --rm 调试,确认没问题再改成 --restart。
4.3 Dockerfile编写最佳实践
Dockerfile 写得好不好,直接影响镜像大小和构建速度。我总结了几个核心原则:
- 选择合适的基础镜像:能用 alpine 就别用 ubuntu,能指定版本就别用 latest
- 减少层数:每个 RUN 指令都会产生一层,能用
&&合并就合并 - 利用构建缓存:把不常变的指令放前面,经常变的放后面
- 多阶段构建:编译环境和运行环境分离
看一个实际例子,构建一个 Go 应用:
# 第一阶段:编译
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
# 第二阶段:运行
FROM alpine:3.19
RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /app/myapp /usr/local/bin/
EXPOSE 8080
USER nobody
ENTRYPOINT ["myapp"]
这个 Dockerfile 有几个好处:最终镜像只有 15MB 左右,没有 Go 编译工具链;用 nobody 用户运行,安全;时区和证书都配好了。
Dockerfile 指令速查
| 指令 | 用途 | 注意事项 |
|---|---|---|
FROM |
指定基础镜像 | 尽量用官方镜像,指定精确版本 |
RUN |
执行命令 | 用 && 合并,清理缓存 |
COPY |
复制文件 | 优先于 ADD,ADD 有自动解压行为 |
CMD |
默认启动命令 | 可以被 docker run 参数覆盖 |
ENTRYPOINT |
入口点 | 与 CMD 配合使用更灵活 |
EXPOSE |
声明端口 | 只是文档作用,实际映射靠 -p |
USER |
指定运行用户 | 不要用 root,创建专用用户 |
4.4 私有仓库搭建
生产环境不可能每次都从 Docker Hub 拉镜像,太慢了,也不安全。私有仓库是必需品。我推荐用 Harbor,功能全、有 Web UI、支持镜像复制和漏洞扫描。
快速部署 Harbor
# 下载离线安装包
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar xzf harbor-offline-installer-v2.10.0.tgz
cd harbor
# 复制配置模板
cp harbor.yml.tmpl harbor.yml
# 修改配置(关键项)
# hostname: registry.yourcompany.com
# harbor_admin_password: YourStrongPassword
# 如果使用 HTTP,需要配置 insecure-registries
# 安装
sudo ./install.sh
安装完成后,访问 http://registry.yourcompany.com 就能看到 Web 界面。默认管理员账号 admin,密码在 harbor.yml 里配置。
推送和拉取镜像
# 登录
docker login registry.yourcompany.com
# 打标签
docker tag nginx:1.25-alpine registry.yourcompany.com/library/nginx:1.25-alpine
# 推送
docker push registry.yourcompany.com/library/nginx:1.25-alpine
# 拉取
docker pull registry.yourcompany.com/library/nginx:1.25-alpine
/: 的格式。比如 infra/nginx:1.25、app/user-service:v2.1.0。项目多了你就知道规范有多重要。
配置 HTTPS 和清理策略
生产环境必须配 HTTPS,不然密码明文传输。可以用 Let's Encrypt 免费证书:
# 在 harbor.yml 中配置
certificate: /data/cert/server.crt
private_key: /data/cert/server.key
# 重启 Harbor
sudo docker-compose down
sudo ./install.sh
镜像多了会占磁盘,我习惯设置自动清理:
- 保留最近 30 天的版本
- 每个项目最多保留 10 个标签
- 未被任何容器引用的镜像自动删除
嗯,Docker 这块内容不少,但核心就这些:装好环境、管好镜像和容器、写好 Dockerfile、搭好私有仓库。把这些基础打牢,后面讲编排和监控才能站得住脚。