3、Docker基础:Docker的安装与配置、Dockerfile编写、镜像构建与仓库管理
聊到云原生CI/CD,Docker绝对是绕不开的基石。说实话,没有容器化,后面那些Kubernetes、微服务什么的,玩起来都会很别扭。我最早接触Docker是在2016年,那时候还在用笨重的虚拟机做环境隔离,每次部署都像开盲盒——开发环境跑得好好的,一到测试环境就崩。后来切到Docker,整个世界清净了。
这一章,咱们就踏踏实实把Docker的基础打牢。从安装配置开始,到写Dockerfile,再到构建镜像和推送到仓库。嗯,这些都是你后面搭建流水线时,每天都要打交道的活儿。
3.1 Docker的安装与配置
安装Docker其实没什么难度,但不同操作系统有些小差异。我个人习惯在Linux上玩,毕竟生产环境基本都是Linux。
3.1.1 在Ubuntu上安装
官方推荐用apt安装,但别直接用系统自带的旧版本。我曾经踩过这个坑——系统源里的Docker版本太老,导致后面很多新特性用不了。
# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc
# 安装依赖
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 设置稳定版仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
装完之后,记得把当前用户加到docker组里,不然每次都得sudo,烦得很。
sudo usermod -aG docker $USER
newgrp docker
3.1.2 配置镜像加速器
国内拉取镜像,你懂的,速度感人。我建议第一时间配置镜像加速器。这里以阿里云为例,你也可以用腾讯云、华为云的。
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://你的加速器地址.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
配置完跑一下 docker info,看看Registry Mirrors那行有没有生效。嗯,这一步很多人会忘,结果后面拉镜像慢到怀疑人生。
3.2 Dockerfile编写
Dockerfile说白了就是一份镜像的「菜谱」。你告诉Docker要用什么基础镜像、装什么软件、复制什么文件、启动什么命令。我见过不少新手把Dockerfile写得又大又乱,一个镜像几个G,部署起来慢得要命。
3.2.1 核心指令
| 指令 | 作用 | 使用频率 |
|---|---|---|
| FROM | 指定基础镜像 | 必用 |
| RUN | 执行命令(构建时) | 高频 |
| COPY | 复制文件到镜像 | 高频 |
| ADD | 复制文件(支持URL和解压) | 中频 |
| CMD | 容器启动时的默认命令 | 高频 |
| ENTRYPOINT | 容器启动入口(不可覆盖) | 中频 |
| ENV | 设置环境变量 | 高频 |
| WORKDIR | 设置工作目录 | 高频 |
| EXPOSE | 声明容器端口 | 中频 |
3.2.2 一个实战例子
假设我们要打包一个Node.js应用。你想想看,如果直接把整个项目复制进去,然后npm install,那镜像里会塞满node_modules,体积大得吓人。我建议用多阶段构建来瘦身。
# 第一阶段:构建
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 第二阶段:运行
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
3.2.3 编写技巧与避坑
- 层数要少: 每个RUN、COPY都会产生一层。我习惯把多个命令用
&&串起来,减少层数。 - 注意缓存: Docker会缓存每一层。把变化少的指令放前面,比如先COPY package.json,再COPY源码。这样改代码时不用重新装依赖。
- 别用latest: 基础镜像指定具体版本,比如
node:18-alpine而不是node:latest。否则哪天latest更新了,你的构建可能就炸了。
docker build --target builder -t myapp:build .。这样能快速定位问题,不用每次都从头构建。
3.3 镜像构建与仓库管理
Dockerfile写好了,下一步就是构建镜像。构建本身很简单,但怎么管理镜像、怎么打标签、怎么推送到仓库,这里面有不少门道。
3.3.1 构建镜像
# 基本构建
docker build -t myapp:v1.0 .
# 指定Dockerfile路径
docker build -f ./docker/Dockerfile.prod -t myapp:prod .
# 带构建参数
docker build --build-arg NODE_ENV=production -t myapp:latest .
构建的时候,. 表示上下文路径。注意,Docker会把上下文里所有文件都发给守护进程。如果你的项目里有node_modules、.git这些大目录,记得写个 .dockerignore 文件。
# .dockerignore
node_modules
.git
*.log
dist
.cache
我曾经见过一个同事没写.dockerignore,构建上下文有2个多G,每次构建都要等半天。后来加上忽略文件,构建时间从5分钟降到了30秒。
3.3.2 镜像标签与版本管理
标签这东西,看似简单,但团队里经常因为标签不规范出问题。我建议用语义化版本号,再加一些元信息。
| 标签格式 | 示例 | 适用场景 |
|---|---|---|
| 语义版本 | v1.2.3 | 正式发布 |
| 分支+提交 | feature-abc123 | 开发测试 |
| 构建编号 | build-456 | CI流水线 |
| latest | latest | 仅用于开发环境 |
# 打标签
docker tag myapp:v1.0 registry.example.com/myapp:v1.0
docker tag myapp:v1.0 registry.example.com/myapp:latest
# 查看本地镜像
docker images
3.3.3 镜像仓库管理
镜像仓库分两种:公有和私有。公有仓库最常用的是Docker Hub,但国内访问慢。私有仓库可以用Harbor、Nexus,或者各大云厂商的镜像服务。
推送到仓库的流程很简单:
# 登录
docker login registry.example.com -u username -p password
# 推送
docker push registry.example.com/myapp:v1.0
# 拉取
docker pull registry.example.com/myapp:v1.0
在CI/CD流水线里,我一般会把镜像推送到私有仓库,然后部署时从私有仓库拉取。这样有几个好处:一是速度快,内网传输;二是安全,镜像不会暴露到公网;三是可以配合镜像扫描工具做安全检测。
3.3.4 镜像清理与维护
时间一长,本地会堆积大量无用的镜像和容器。我习惯定期清理:
# 清理所有停止的容器
docker container prune
# 清理所有未使用的镜像
docker image prune -a
# 一键清理(慎用)
docker system prune -a --volumes
好了,Docker基础这部分就聊到这儿。安装配置、Dockerfile编写、镜像构建与仓库管理,这三块是你在云原生CI/CD路上必须掌握的硬功夫。下一章咱们会把这些知识串起来,搭建一条完整的流水线。到时候你会发现,今天打下的基础,全都能用上。