4、容器化基础:Docker安装与配置、Dockerfile编写、镜像构建与推送、容器资源限制

聊到集群部署和GPU调度,Docker是绕不开的一环。我个人习惯把Docker看作「轻量级虚拟机」,但它比虚拟机快得多、灵活得多。说白了,它就是给应用打包了一个完整的环境,让你在任意机器上都能跑起来。

这一章,我会带你走一遍Docker的核心操作。从安装配置开始,到写Dockerfile、构建镜像、推送仓库,最后聊聊资源限制——这部分在GPU集群里尤其重要。

4.1 Docker安装与配置

安装Docker其实很简单。我建议你用官方脚本,省心。

# 一键安装Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# 启动并设置开机自启
sudo systemctl enable docker
sudo systemctl start docker

# 验证安装
docker --version

装完之后,记得把当前用户加入docker组。不然每次都要sudo,很烦。

sudo usermod -aG docker $USER
# 退出重新登录,或者执行 newgrp docker 生效

嗯,这里要注意:加入docker组后,用户就有了root权限。生产环境要谨慎,别随便加人。

配置方面,我通常会改一下镜像加速器。国内拉镜像慢,你懂的。

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://mirror.ccs.tencentyun.com"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

我在项目中遇到过,日志不限制大小,结果磁盘被撑爆了。所以日志配置一定要加上。

小技巧: 如果你用NVIDIA GPU,还需要安装nvidia-docker2。否则容器里用不了GPU。
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update
sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker

4.2 Dockerfile编写

Dockerfile就是构建镜像的「配方」。你想想看,它告诉Docker一步步怎么组装你的应用环境。

先看一个简单的Python应用示例:

# 基础镜像,选alpine版本更小
FROM python:3.9-slim

# 维护者信息
LABEL maintainer="keke@example.com"

# 设置工作目录
WORKDIR /app

# 复制依赖文件
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8080

# 启动命令
CMD ["python", "app.py"]

写Dockerfile有几个原则,我总结一下:

  • 层数越少越好:每个RUN、COPY都会产生一层。能用&&合并就合并。
  • 基础镜像选小的:alpine、slim版本优先。我见过一个镜像2GB,里面全是没用的工具。
  • 利用缓存:把不常变动的指令放前面,比如安装依赖。这样改代码时不用重装依赖。
  • 不要用root:安全考虑,最后切换到普通用户。
重点: 我曾经在项目里踩过一个坑——Dockerfile里写了ADD去下载一个压缩包,结果每次构建都重新下载,构建时间从2分钟变成20分钟。后来改成先下载到本地再COPY,配合缓存,速度就回来了。

再看一个GPU场景的Dockerfile:

FROM nvidia/cuda:11.8-runtime-ubuntu22.04

RUN apt-get update && apt-get install -y \
    python3 python3-pip \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /workspace
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt

COPY train.py .

# 告诉Kubernetes这个容器需要GPU
ENV NVIDIA_VISIBLE_DEVICES all
ENV NVIDIA_DRIVER_CAPABILITIES compute,utility

CMD ["python3", "train.py"]

4.3 镜像构建与推送

Dockerfile写好了,接下来就是构建镜像。命令很简单:

# 构建镜像,-t 指定标签
docker build -t myapp:v1.0 .

# 查看本地镜像
docker images

# 给镜像打标签,准备推送到仓库
docker tag myapp:v1.0 registry.example.com/myapp:v1.0

构建的时候,我习惯加一个--no-cache参数来强制重新构建。但平时不用,因为缓存能省很多时间。

推送镜像到仓库,需要先登录:

# 登录到镜像仓库
docker login registry.example.com -u username -p password

# 推送镜像
docker push registry.example.com/myapp:v1.0

如果你用私有仓库,记得配置HTTPS。不然Docker会拒绝推送。我曾经因为这个折腾了半天,最后发现是证书问题。

注意: 镜像标签要有规范。我建议用 项目名-环境-版本 的格式,比如 ai-train-prod-v2.3.1。别用 latest,它会让你的部署变得不可控。

4.4 容器资源限制

在集群里跑容器,资源限制是必须的。不然一个容器能把整台机器的CPU吃满,其他服务全挂掉。

Docker支持CPU、内存、GPU等资源的限制。看几个例子:

# 限制内存
docker run -d --memory="512m" --memory-swap="1g" myapp:v1.0

# 限制CPU
docker run -d --cpus="1.5" myapp:v1.0

# 限制CPU核心绑定
docker run -d --cpuset-cpus="0-2" myapp:v1.0

对于GPU,需要加上--gpus参数:

# 使用所有GPU
docker run -d --gpus all myapp:v1.0

# 使用指定GPU
docker run -d --gpus '"device=0,1"' myapp:v1.0

# 限制GPU内存(需要NVIDIA容器工具包支持)
docker run -d --gpus '"device=0,memory=4096MiB"' myapp:v1.0

为什么需要限制资源?我举个例子:

有一次,团队里有人跑了一个训练任务,没加任何限制。结果这个容器把32核CPU全占满了,其他服务的响应时间从10ms飙升到5秒。后来我们规定:所有容器必须设置资源限制,否则不允许上线。

资源限制的常用参数总结一下:

参数 作用 示例
--memory 限制内存上限 --memory="512m"
--memory-swap 限制内存+交换分区上限 --memory-swap="1g"
--cpus 限制CPU核心数(可小数) --cpus="2.5"
--cpuset-cpus 绑定到指定CPU核心 --cpuset-cpus="0-3"
--gpus 指定GPU设备 --gpus '"device=0"'
经验之谈: 在Kubernetes里,资源限制是通过 resources.limits 和 resources.requests 来设置的。但底层原理和Docker一样。所以理解Docker的资源限制,对后面学K8s调度很有帮助。

知识体系总览

下面这张图,把本章的核心逻辑串起来了。从安装配置到资源限制,每一步都是环环相扣的。

容器化基础:Docker核心流程 安装与配置 编写Dockerfile 构建镜像 推送仓库 资源限制 运行容器 核心要点 • 安装配置是基础,GPU场景需额外安装nvidia-docker2 • Dockerfile要精简层数、利用缓存、避免root • 资源限制是集群稳定的关键,CPU/内存/GPU都要设

好了,这一章的内容就到这里。Docker的安装、Dockerfile编写、镜像构建推送、资源限制,这些是容器化的基本功。你在实际项目中多练几次,就会形成肌肉记忆。

想要更多资料,联系可可