@Last Update: 2022/10/31
注: 如需在容器内使用显卡,需要安装好NVIDIA显卡驱动、cuda、nvidia-docker[方法见下文]。
0.运行环境
Docker 引擎支持在x86_64
(或amd64
), armhf
, and arm64
上运行.
1.卸载旧版本docker
sudo apt-get remove docker docker-engine docker.io containerd runc
执行以上命令将会卸载docker,但是docker本地保存的images, containers, volumes, and networks将会保存。
使用一下命令将清除本地保存的内容:
sudo apt-get purge docker-ce docker-ce-cli containerd.io
sudo rm -rf /var/lib/docker
2.安装docker
参考官方教程:https://docs.docker.com/engine/install/ubuntu/#uninstall-docker-engine
设置仓库
-
安装环境:
sudo apt-get update sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common
-
添加Docker官方GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
-
设置稳定版仓库.
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
3.安装docker引擎
-
使用以下命令安装最新版docker。
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io
-
以下是安装指定版本docker的方法:
a. 试用一下命令查看可安装的版本:
apt-cache madison docker-ce
docker-ce | 5:18.09.13-0ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable amd64 Packages
docker-ce | 5:18.09.03-0ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable amd64 Packages
docker-ce | 18.06.1ce3-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable amd64 Packages
docker-ce | 18.06.0ce3-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable amd64 Packages
...b. 使用以下命令,安装指定版本的docker
5:18.09.1~3-0~ubuntu-xenial
.sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
-
运行
hello-world
.sudo docker run hello-world
4.[可选]授权多用户使用docker服务
1.创建docker组:sudo groupadd docker
2.将当前用户加入docker组:sudo gpasswd -a [授权的用户名] docker
3.重启服务:sudo service docker restart
4.刷新docker成员:newgrp - docker
5.[可选]安装nvidia-docker
参考来源:https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#getting-started
执行以下命令添加仓库:
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
curl -s -L https://nvidia.github.io/nvidia-container-runtime/experimental/$distribution/nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
安装 nvidia-docker2
:
sudo apt-get update
sudo apt-get install -y nvidia-docker2
重启docker守护进程
sudo systemctl restart docker
测试:
sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi
6.[可选]修改docker文件存储位置
1、停止docker服务运行
2、在Ubuntu中,需要修改以下文件:/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
后面新加
--graph=/data/docker
/data/docker 是指新的存储位置
3、转移原先的docker的文件到新的文件夹
4、重新载入配置并重启:
sudo systemctl daemon-reload
sudo systemctl restart docker.service
7.[可选]添加国内加速源
修改/etc/docker/daemon.json(没安装过nvidia-docker,可能需要创建本文件),并加入registry-mirrors项。
一定要注意格式!!!!简单方法请参考这里!
示例(安装过nvidia-docker的情况下):
{
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
},
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://docker.mirrors.ustc.edu.cn"]
}
重新载入配置并重启:
sudo systemctl daemon-reload
sudo systemctl restart docker.service
8.[可选]Docker容器日志查看与清理
docker容器日志导致主机磁盘空间占用严重。很占用空间,不用的日志可以清理掉了。
解决方法
8.1 找出Docker容器日志
在linux上,容器日志一般存放在/var/lib/docker/containers/container_id/
下面, 以json.log结尾的文件(业务日志)很大,查看各个日志文件大小的脚本docker_log_size.sh,内容如下:
#!/bin/sh
echo "======== docker containers logs file size ========"
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
ls -lh $log
done
chmod +x docker_log_size.sh
./docker_log_size.sh
8.2 清理Docker容器日志(治标)
如果docker容器正在运行,那么使用rm -rf
方式删除日志后,通过df -h
会发现磁盘空间并没有释放。原因是在Linux或者Unix系统中,通过rm -rf
或者文件管理器删除文件,将会从文件系统的目录结构上解除链接(unlink)。如果文件是被打开的(有一个进程正在使用),那么进程将仍然可以读取该文件,磁盘空间也一直被占用。正确姿势是cat /dev/null > *-json.log
,当然你也可以通过rm -rf
删除后重启docker。接下来,提供一个日志清理脚本clean_docker_log.sh
,内容如下:
#!/bin/sh
echo "======== start clean docker containers logs ========"
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
echo "clean logs : $log"
cat /dev/null > $log
done
echo "======== end clean docker containers logs ========"
chmod +x clean_docker_log.sh
./clean_docker_log.sh
但是,这样清理之后,随着时间的推移,容器日志会像杂草一样,卷土重来。
8.3 设置Docker容器日志大小
- 设置一个容器服务的日志大小上限
上述方法,日志文件迟早又会涨回来。要从根本上解决问题,需要限制容器服务的日志大小上限。这个通过配置容器docker-compose的max-size选项来实现
nginx:
image: nginx:1.12.1
restart: always
logging:
driver: “json-file”
options:
max-size: “5g”
重启nginx容器之后,其日志文件的大小就被限制在5GB,再也不用担心了。
- 全局设置
新建/etc/docker/daemon.json,若有就不用新建了。添加log-dirver和log-opts参数,样例如下:
vim /etc/docker/daemon.json
{
"log-opts": {"max-size":"500m", "max-file":"3"}
}
max-size=500m,意味着一个容器日志大小上限是500M,
max-file=3,意味着一个容器有三个日志,分别是id+.json、id+1.json、id+2.json。
// 重启docker守护进程
# systemctl daemon-reload
# systemctl restart docker
注意:设置的日志大小,只对新建的容器有效。
8.4 本节参考文章
https://blog.csdn.net/xunzhaoyao/article/details/72959917
https://www.cnblogs.com/testzcy/p/7904829.html
9.[可选]在容器内安装指定版本tf/torch环境
部分低版本 TensorFlow/Pytorch无法在最新的cuda版本下运行【尤其是tf1.15以下版本,无法使用cuda11】,并且最新的显卡并没有低版本的cuda支持,因此,如需要使用显卡运行低版本的TensorFlow/Pytorch,可借助nvidia官方容器。
使用方法:
- 打开英伟达NGC NVIDIA NGC
- 搜索TensorFlow(以TensorFlow为例)
- 打开搜索的结果,如TensorFlow | NVIDIA NGC
- 打开页面中Container Release Notes(可以在页面中搜索下release note)
- 点击左侧,选择对应的Container Release 版本,每个页面中都会包含该版本所包含的系统版本、cuda版本、tf版本等内容。
- 选择适合的版本,并记录其容器版本,如
18.02-py2
- 使用以下命令下载并启动容器
docker run --gpus all -it --rm nvcr.io/nvidia/tensorflow:xx.xx-tfx-py3
其中xx.xx-tfx-py3为以上版本号,如18.02-py2
- 将代码移入docker内运行
10. Dataloader中的num_workers设置与docker的shared memory相关问题
错误一
RuntimeError: DataLoader worker (pid 53617) is killed by signal: Bus error. It is possible that dataloader's workers are out of shared memory. Please try to raise your shared memory limit.
错误二
ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm).
产生错误的原因
由于在docker镜像中默认限制了shm(shared memory),然而数据处理时pythorch则使用了shm。这就导致了在运行多线程时会将超出限制的DataLoader并直接被kill掉。dataloader从RAM中找本轮迭代要用的batch,如果找到了就使用。如果没找到,就要num_worker个worker继续加载batch到内存,直到dataloader在RAM中找到目标batch。num_worker设置得大,好处是寻batch速度快,因为下一轮迭代的batch很可能在上一轮/上上一轮迭代时已经加载好了。坏处是内存开销大,也加重了CPU负担(worker加载数据到RAM的进程是CPU复制的)。
num_workers的经验设置值是自己电脑/服务器的CPU核心数,如果CPU很强、RAM也很充足,就可以设置得更大些。
解决办法
- 在Dataloader中将num_worker设置为0。意味着每一轮迭代时,dataloader不再有自主加载数据到RAM这一步骤(因为没有worker了),而是在RAM中找batch,找不到时再加载相应的batch。
- 在起Docker容器时,设置 --ipc=host 或 --shm-size 或者
docker run --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=2,3 --shm-size 8G -it --rm dev:v1 /bin/bash
11.使用Docker训练模型挂载数据集相关的问题
Docker容器启动的时候,如果要挂载宿主机的一个目录,可以用-v参数指定。
比如启动一个centos容器,宿主机的/test目录挂载到容器的/soft目录,可通过以下方式指定:# docker run -it -v /test:/soft centos /bin/bash
这样在容器启动后,容器内会自动创建/soft的目录。通过这种方式,可以明确一点,即-v参数中,冒号":"前面的目录是宿主机目录,后面的目录是容器内目录。
一、容器目录不可以为相对路径
[root@localhost ~]# docker run -it -v /test:soft centos /bin/bash
invalid value "/test:soft" for flag -v: soft is not an absolute path
See 'docker run --help'.
直接报错,提示soft不是一个绝对路径,所谓的绝对路径,必须以下斜线“/”开头。
二、宿主机目录如果不存在,则会自动生成
如果宿主机中存在/test目录,首先删除它
[root@localhost ~]# rm -rf /test
[root@localhost ~]# ls /
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
启动容器
[root@localhost ~]# docker run -it -v /test:/soft centos /bin/bash
[root@a487a3ca7997 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin soft srv sys tmp usr var
查看宿主机,发现新增了一个/test目录
[root@localhost ~]# ls /
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys test tmp usr var
三、宿主机的目录如果为相对路径时
# docker run -it -v test1:/soft centos /bin/bash
再到宿主机上查看是否新增了一个/test1目录,结果没有,查看test1目录是否在当前目录下,结果发现还是没有。
通过docker inspect命令,查看容器“Mounts”那一部分,可以看出,容器内的/soft目录挂载的是宿主机上的/var/lib/docker/volumes/test1/_data目录
"Mounts": [
{
"Name": "test1",
"Source": "/var/lib/docker/volumes/test1/_data",
"Destination": "/soft",
"Driver": "local",
"Mode": "z",
"RW": true
}
],
所谓的相对路径指的是/var/lib/docker/volumes/,与宿主机的当前目录无关。
四、如果只是-v指定一个目录
启动一个容器
[root@localhost ~]# docker run -it -v /test2 centos /bin/bash
[root@ea24067bc902 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys test2 tmp usr var
同样使用docker inspect命令查看宿主机的挂载目录
"Mounts": [
{
"Name": "96256232eb74edb139d652746f0fe426e57fbacdf73376963e3acdb411b3d73a",
"Source": "/var/lib/docker/volumes/96256232eb74edb139d652746f0fe426e57fbacdf73376963e3acdb411b3d73a/_data",
"Destination": "/test2",
"Driver": "local",
"Mode": "",
"RW": true
}
],
可以看出,同3中的结果类似,只不过,它不是相对路径的目录名,而是随机生成的一个目录名。
五、如果在容器内修改了目录的属主和属组,那么对应的挂载点也会修改
在容器内修改/soft的属主和属组,与UID有关系,UID,即“用户标识号”,是一个整数,系统内部用它来标识用户。一般情况下它与用户名是一一对应的。
六、容器销毁了,在宿主机上新建的挂载目录是否会消失?
在这里,主要验证两种情况:一、指定了宿主机目录,即 -v /test:/soft。二、没有指定宿主机目录,即-v /soft
第一种情况:
[root@localhost ~]# rm -rf /test --首先删除宿主机的/test目录
[root@localhost ~]# ls / --可以看到,宿主机上无/test目录
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@localhost ~]# docker run -it --name=centos_test -v /test:/soft centos /bin/bash --启动容器,为了删除方便,我用--name参数指定了容器的名字
[root@82ad7f3a779a /]# exit
exit
[root@localhost ~]# docker rm centos_test --删除容器
centos_test
[root@localhost ~]# ls / --发现 /test目录依旧存在
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys test tmp usr var
可以看出,即便容器销毁了,新建的挂载目录不会消失。进一步也可验证,如果宿主机目录的属主和属组发生了变化,容器销毁后,宿主机目录的属主和属组不会恢复到挂载之前的状态。
第二种情况,通过上面的验证知道,如果没有指定宿主机的目录,则容器会在/var/lib/docker/volumes/随机配置一个目录,那么我们看看这种情况下的容器销毁是否会导致相应目录的删除
七、挂载宿主机已存在目录后,在容器内对其进行操作,报“Permission denied”。
可通过两种方式解决:
1> 关闭selinux。
临时关闭:# setenforce 0
永久关闭:修改/etc/sysconfig/selinux文件,将SELINUX的值设置为disabled。
2> 以特权方式启动容器
指定--privileged参数
如:# docker run -it --privileged=true -v /test:/soft centos /bin/bash
标签:容器,宿主机,--,sudo,nvidia,相关,Docker,安装,docker From: https://www.cnblogs.com/yeahchen/p/17491104.html