1. 介绍 Docker 和 Conda
Conda
Conda 是一个开源的包管理器和环境管理器,主要用于安装和管理来自于 Python 和 R 的软件包和环境。使用 Conda 的主要场景包括:
- 科学计算:Conda 特别适合于科学计算和数据科学领域,因为它可以轻松管理具有复杂依赖关系的包。
- 版本和环境管理:如果您需要在同一台机器上维护多个隔离的 Python/R 环境,Conda 是一个很好的选择。它可以帮助您避免不同项目间的依赖冲突。
- 跨平台:Conda 支持多平台(Windows、macOS、Linux),适合于需要在不同操作系统上进行开发和测试的场景。
Docker
Docker 是一个开源的容器化平台,用于自动化应用程序的部署。它包装软件及其依赖项到一个标准化的单元中,用于软件开发。使用 Docker 的主要场景包括:
- 应用程序的打包和部署:当您需要在不同的环境中一致地部署应用程序时,Docker 是一个理想的选择。它通过容器来确保应用程序在不同的系统和平台上表现一致。
- 微服务架构:对于采用微服务架构的系统,Docker 提供了隔离、快速部署和伸缩性,非常适合于管理和部署微服务。
- CI/CD 流程:Docker 可以很好地集成到持续集成和持续部署(CI/CD)的流程中,实现自动化测试和部署。
为什么用 Docker?
- Docker提供了更高级别的隔离(操作系统级别),而 Conda 提供了较低级别(Python/R 环境级别)的隔离。
- 适合部署深度学习环境:服务器CUDA版本不允许升级或降级时,使用Docker可以解决。只要宿主机的 NVIDIA 驱动与容器内部的 CUDA 版本兼容即可正常运行使用GPU的docker容器。
- 思路:在Windows上搭建基础镜像,连进容器配置环境,通过docker commit保存镜像,再通过docker save导出,迁移到服务器上。
- 应用部署需求:有些应用需要在Docker部署,比如coffee AI。
- 镜像共享:网络问题,有了镜像就可以共享给其他人,不需要其他人再下载。
容器和镜像
- 镜像(Image) 和 容器(Container) 的关系,就像是面向对象程序设计中的类和实例一样。
- 镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
Dockerfile
Docker 可以通过读取 Dockerfile 创建一个镜像,Dockerfile 是一个文本文档,其中包含用户可以在命令行上调用和组合镜像的所有命令。常见命令包括:
FROM
:Dockerfile 必须从 From 开始,它为容器设置最基础的镜像。WORKDIR
:设置工作目录,为后面的 RUN 等指令设置工作目录。RUN
:运行指令。COPY
:把 Dockerfile 所在目录的一些文件拷贝到工作空间。EXPOSE
:声明容器运行时需要监听的端口号,使用 docker run 命令的 -p 参数来将容器端口映射到宿主机上。例如-p 8080:80
,表示将容器的 80 端口映射到宿主机的 8080 端口上。HEALTHCHECK
:告诉 Docker 如何测试容器以检查它是否仍在工作。ENTRYPOINT
:配置容器,里面包括了可以 run 的 py 文件,也包括了 run 指令,可以让容器创建时去运行某些指令。
写 Dockerfile 的注意事项
FROM
的镜像可以选择更基础的镜像。- 在
pip
后面增加--no-cache-dir
,减少缓存。 - 在同一个
RUN
里不同的命令经常用&&
来连接,这是一种常见的做法,主要有以下几个原因:- 减少图层:Dockerfile 中的每个 RUN 指令都会创建一个新的图层。通过使用 && 将多个命令连接在一起,可以减少生成的图层的数量,这样做的好处是创建更小、更简洁的镜像,并且可能提高构建速度。
- 确保所有命令都成功执行:当使用 && 时,如果一个命令失败(返回非零退出状态),整个 RUN 指令将失败并停止执行。这是一种保护措施,以确保不会在部分更新的或不一致的状态下构建镜像。
- 清洁和优化:通过在一个 RUN 指令中连接多个命令,您可以在完成必要的安装和配置后立即进行清理(例如,删除临时文件或清除缓存)。这有助于保持镜像的大小尽可能小。
- 在
apt install
后面加上rm -rf /var/lib/apt/lists/*
来清理安装后的无用文件。
2. 常用指令
查看docker所有命令
1 | docker commond --help |
镜像操作
查看所有镜像
1 | docker images |
下载镜像,Tag表示版本,有些镜像的版本显示latest,为最新版本
1 | docker pull 镜像名:TAG |
使用国内源来拉取镜像,将registry.docker-cn.com填写到镜像名前。
- Docker中国区官方镜像:https://registry.docker-cn.com
- 网易:http://hub-mirror.c.163.com
- ustc:https://docker.mirrors.ustc.edu.cn
- 中国科技大学:https://docker.mirrors.ustc.edu.cn
- 阿里云容器 生成自己的加速地址:登录:cr.console.aliyun.com
windows 可以直接在设置里填入加速的地址。
1 | {"registry-mirrors":["https://reg-mirror.qiniu.com/"]} |
删除镜像,删除指定本地镜像 -f 表示强制删除
1 | docker rmi -f 镜像ID或者镜像名:TAG |
获取镜像的元信息,获取镜像的详细信息,包括存放地址等等
1 | docker inspect 镜像ID或者镜像名:TAG |
从本地的压缩包里导入镜像
1 | docker load < 压缩包所在路径 |
使用 Dockerfile 构建镜像
1 | docker build -t test:v1.0 . |
如果 Dockerfile 文件不在当前目录中,或者 Dockerfile 文件的名称不是 Dockerfile,则可以使用 -f 参数来指定 Dockerfile 文件的路径和名称。
容器操作
运行容器
1 | docker run --name 容器名 -i -t -p 主机端口:容器端口 -d -v 主机目录:容器目录:ro 镜像ID或镜像名:TAG |
容器列表
1 | docker ps -a -q |
启动容器
1 | docker start 容器ID或容器名 |
停止容器
1 | docker stop 容器ID或容器名 |
删除容器
1 | docker rm -f 容器ID或容器名 |
进入运行容器
1 | docker exec -it 容器ID或者容器名 /bin/bash |
查看容器使用的资源
docker stats 命令会每隔 1 秒钟刷新一次输出的内容直到按下 ctrl + c
输出的主要内容:
- [CONTAINER]:以短格式显示容器的 ID。
- [NAME]:容器名称
- [CPU %]:CPU 的使用情况。
- [MEM USAGE / LIMIT]:当前使用的内存和最大可以使用的内存。
- [MEM %]:以百分比的形式显示内存使用情况。
- [NET I/O]:网络 I/O 数据。
- [BLOCK I/O]:磁盘 I/O 数据。
- [PIDS]:PID 号。
1 | docker stats |
3. CentOS8安装Docker
部署环境:
- Linux:Linux 操作系统,以 CentOS Stream 8 为例。
- Docker:容器管理,以Docker CE 24.0.7为例。
安装
卸载旧版本
1 | sudo yum remove docker \ |
卸载后将保留 /var/lib/docker 的内容(镜像、容器、存储卷和网络等),也删除。
1 | rm -rf /var/lib/docker |
更新 yum 源
1 | yum makecache |
设置 Docker 仓库
1 | sudo yum install -y yum-utils |
安装 docker-ce
1 | yum install docker-ce docker-ce-cli containerd.io |
查看 Docker 版本
1 | docker -v |
启动 Docker
1 | systemctl start docker |
检查docker是否安装成功,打印出:Hello from Docker! 说明安装成功。
1 | docker run hello-world |
设置 Docker 开机自启动
1 | systemctl enable docker |
4. Ubuntu20.04安装Docker
自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装,另外可以通过 --mirror
选项使用国内源进行安装:
1 | curl -fsSL get.docker.com -o get-docker.sh |
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。
安装 NVIDIA Docker
但是上面的脚本没有安装 NVIDIA Docker 支持, 如果运行需要GPU的容器会报如下错误:
1 | root@dell:~# docker run -it --rm --gpus all --net host -v /home/dell/lqm/aigc/Diffusion/Difftraj chengdu:/difftraj difftraj:2.0.1-py3.10.11-cuda11.8.0-ubuntu22.04 |
如果要在 Docker 容器中使用 NVIDIA GPU 需要安装 NVIDIA Docker 支持,即 nvidia-docker
,我们还需要进行如下操作:
- 确保nvidia驱动和docker安装好,下面两行命令能够成功输出。
1 | nvcc --version |
- 添加 NVIDIA Docker 仓库:
- 对于 Ubuntu/Debian 系统,运行以下命令:
1 | distribution=$(. /etc/os-release;echo $ID$VERSION_ID) |
- 对于 RHEL/CentOS 系统,运行以下命令:
1 | distribution=$(. /etc/os-release;echo $ID$VERSION_ID) |
- 安装 NVIDIA Docker:
- 更新包管理器的索引并安装 NVIDIA Docker 包:
- 对于 Ubuntu/Debian:
1 | sudo apt-get update |
- 对于 RHEL/CentOS:
1 | sudo yum clean expire-cache |
- 重新启动 Docker 服务:
- 安装完成后,您需要重启 Docker 服务来应用更改:
1 | sudo systemctl restart docker |
- 验证安装
- 运行一个测试容器以验证 NVIDIA Docker 是否安装正确:
1 | docker run --rm --gpus all nvidia/cuda:11.0.3-base nvidia-smi |
- 这个命令会运行一个具有 CUDA 支持的容器,并在容器内执行 nvidia-smi。如果一切正常,将看到 GPU 的信息。
手动安装
首先卸载旧版本,确保卸载任何冲突的软件包(也就是旧版本的Docker组件)。Ubuntu在apt仓库中提供了Docker软件包的非官方分发版,该版本由Ubuntu负责维护和发行,必须先卸载这些软件包,然后才能安装Docker Engine的官方版本。
1 | for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done |
卸载了这四个包:
- docker.io
- docker-compose
- docker-doc
- podman-docker
添加 Docker 官方仓库的 GPG key
1 | sudo install -m 0755 -d /etc/apt/keyrings |
apt 安装 Docker Engine
1 | sudo apt-get update |
配置 Docker 仓库
1 | echo \ |
接着安装 NVIDIA Docker,见自动安装部分
5. Windows安装Docker Desktop
Win10
下载:https://docs.docker.com/desktop/install/windows-install/
参考:https://zhuanlan.zhihu.com/p/441965046
Win11-家庭版
安装问题
- Docker desktop第一次启动一直在转圈,显示starting the Docker Engine
可能原因:
- 没有Hyper-V内置虚拟机,需要手动安装
https://www.baiyunxitong.com/bangzhu/6775.html
- 还需要安装wsl(适用于linux的windows子系统)
https://zhuanlan.zhihu.com/p/667495068
以管理员的身份打开CMD或PowerShell运行以下命令
1 | netsh winsock reset |
更新 WSL
1 | wsl --update |
在控制面板-程序-启用或关闭windows功能勾选上以下三个内容
Docker Desktop 设置容器资源限制
有时候Docker容器里的大模型会出现爆内存等问题,可能是容器资源设置了限制。
6. 制作Docker镜像
6.1 根据已有镜像使用docker commit构建
这一方法的核心是docker commit
- docker commit可以从容器创建一个新的镜像。
- 通过对运行中的容器进行更改,然后使用 docker commit 命令,可以将容器的当前状态保存为新镜像。
- 这种方法适用于快速的实验,但不推荐用于生产环境,因为:
- docker commit不会明确记录构建过程,缺乏可重复性和透明性,会产生所谓的黑箱镜像。
- 在容器中执行命令,会有很多文件被改动或添加。安装软件包、编译构建,那会有大量的无关内容被添加进来,将会导致镜像极为臃肿。
- 简单的Python训练环境,可以用这个方法图方便,快速构建镜像。
思路:
- 先拉取已有的镜像。
- 使用镜像运行容器后,在容器内安装项目需要的Python依赖。
- 将整个容器通过docker commit指令制作成镜像。
- 导出镜像,在服务器上导入。
拉取已有镜像
官方Pytorch镜像:https://github.com/pytorch/pytorch#docker-image
也可以从docker hub里找到官方Pytorch镜像:https://hub.docker.com/r/pytorch/pytorch/tags
同样的pytorch和cuda版本会有两种镜像,分别是 devel
和 runtime
镜像,区别如下:
devel
镜像:
- 用途:
devel
(开发)镜像包含了编译和运行 CUDA 应用所需的所有依赖,包括编译器和开发工具。 - 适用场景:如果您需要编译使用 CUDA 的自定义操作或者需要编译整个 PyTorch 源代码,那么
devel
镜像是必需的。 - 大小:由于包含更多的开发工具和库,
devel
镜像通常比runtime
镜像大很多。
runtime
镜像:
- 用途:
runtime
(运行时)镜像仅包含运行基于 CUDA 的应用程序所必需的库和工具。 - 适用场景:如果您只需要运行已经编译好的 CUDA 应用程序,而不需要进行额外的编译或开发工作,
runtime
镜像就足够了。 - 大小:相较于
devel
镜像,runtime
镜像更小,因为它不包含额外的编译工具和库。