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
我在项目中遇到过,日志不限制大小,结果磁盘被撑爆了。所以日志配置一定要加上。
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:安全考虑,最后切换到普通用户。
再看一个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"' |
resources.limits 和 resources.requests 来设置的。但底层原理和Docker一样。所以理解Docker的资源限制,对后面学K8s调度很有帮助。
知识体系总览
下面这张图,把本章的核心逻辑串起来了。从安装配置到资源限制,每一步都是环环相扣的。
好了,这一章的内容就到这里。Docker的安装、Dockerfile编写、镜像构建推送、资源限制,这些是容器化的基本功。你在实际项目中多练几次,就会形成肌肉记忆。
想要更多资料,联系可可