Nvidia-NGC容器使用全过程
NGC镜像下载
-
注册账户
https://ngc.nvidia.com/signup注册,注意不要用google浏览器,否则收不到验证码
-
查看镜像仓库
https://ngc.nvidia.com/catalog/all
进入NGC界面即可看到由Nvidia官方封装的诸多镜像
-
查看所需镜像并拉取
以pytorch镜像为例
Terminal中下载该镜像
$ docker pull nvcr.io/nvidia/pytorch:19.09-py3
创建自定义镜像及自动备份
定制化容器为满足以下需求:
- 支持ssh进入容器(用于配置pycharm远程解释器)
- 设置entrypoint自动打开所需服务
构建自定义镜像
此过程采用Dockerfile实现,以nvcr.io/nvidia/pytorch:19.09-py3
为例
在宿主机内构建如下目录:
- ngc
- Dockerfile
- utils
- entrypoint.sh
- xxx.sh(其他脚本)
- utils.rar(把utils压缩成.rar)
建议把entrypoint.py
文件和其他启动脚本放到utils压缩包里,压缩命令tar -cvf utils.tar utils
。
在ngc
路径下执行docker build -t image_name .
命令即可创建自定义镜像,如:
docker build -t ngctorch_mine:1.0 .
Dockerfile
和entrypoint.sh
内容如下:
Dockerfile
FROM nvcr.io/nvidia/pytorch:19.09-py3
MAINTAINER yourname
# environment install
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
RUN apt-get update
RUN apt-get -y install sudo curl openssh-client openssh-server vim
# set root login
RUN echo "root:passwd123" | chpasswd
RUN sed -ri 's/^#PermitRootLogin\s+.*/PermitRootLogin yes/' /etc/ssh/sshd_config
# 网上搜到的多是下面这条命令,但是如果安装的ssh配置文件里面写的 #PermitRootLogin xxx 就会匹配不到,所以要加上面那句
RUN sed -ri 's/^PermitRootLogin\s+.*/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed -ri 's/UsePAM yes/#UsePAM yes/g' /etc/ssh/sshd_config
# port expose
EXPOSE 22 6006 8888
ADD utils.tar /root/
RUN chmod a+x /root/utils/entrypoint.sh
#python requirement list
RUN pip install numpy
RUN pip install opencv-python
ENTRYPOINT ["/root/utils/entrypoint.sh"]
entrypoint
#!/bin/bash
set -e
cat <<EOF
================
Your Name
===============
EOF
# jupyter 访问密码,自行修改
TOKEN='passwd123'
# 容器内jupyter代码存放路径,自行修改
JUPYTER_DIR="/code"
echo "总共参数: $#"
echo "脚本名字: $0"
service ssh start
nohup jupyter notebook --no-browser --ip=0.0.0.0 --allow-root --NotebookApp.token="$TOKEN" --notebook-dir="$JUPYTER_DIR" &
if [[ $# -eq 0 ]]; then
exec "/bin/bash"
else
exec "$@"
fi
容器定期备份与自启动
我们可以将代码文件和运行日志挂载到宿主机目录里,那为什么还要进行容器定期备份与自启动:
- 进行深度学习研究时经常需要额外装一些包,此部分无法挂载在外部,通过定期备份可依照装包之后的容器生成新的镜像。
- 服务器、工作站如果出现宕机、断电等情况,可以自动恢复容器,省去人工操作。
- 创建启动与动备份脚本,
ngc_backup.sh
# 镜像定期备份脚本
# 将该脚本添加到crontab命令中实现定时启动,如:
# 0 0 * * * /root/ngc_backup.sh
# 该命令可以让工作站每天0点执行一次备份
# 宿主机文件路径
DATA_DIR="/home/jupyter_data"
# 容器内文件路径
JUPYTER_DIR="/code"
# 查找复合筛选规则的最新的容器,可以自定义grep规则,我这里是用jupyter端口
ngctorchid=`docker ps | grep '9909' | awk '{print $1}'`
set -e
if [ -z $ngctorchid ]; then
# 说明容器不存在,使用最新image创建新容器
echo 'The ngctorch docker is not running, can not backup.'
# 查找最新image
latest_backup=`docker images | grep 'ngctorch' | awk '{print $3}' | head -n 1`
echo 'Trying to back it online... from' $latest_backup
# 创建容器
# 主机端口 | 容器端口 | 备注
# 9909 | 8888 | 用于浏览器访问jupyter
# 8422 | 22 | 用于ssh直接进入容器,可以使用pycharm远程解释器
# xxx | xxx | 按照自己需求可配置其他端口映射
nvidia-docker run --rm -it -p 9909:8888 -p 8422:22 -v $DATA_DIR:$JUPYTER_DIR $latest_backup
echo 'Done.'
exit 0
fi
# 容器正在运行,将当前容器备份为新镜像
docker commit $ngctorchid "ngctorch-backup:$(date +%m%d-%H%M)"
# 删除旧镜像
# 存档镜像数量设定为1,除了当前最新的镜像,其他全部删除(当前镜像的祖先节点不会被删除)
MAX_BACKUP_NUM=1
backupid=`docker images | grep 'ngctorch' | awk '{print $3}'`
backupnum=`echo $backupid | wc -w`
echo $backupid
echo $backupnum
if [ $backupnum -gt $MAX_BACKUP_NUM ]; then
echo 'Delete old backup...'
echo $backupid | tr ' ' '\n' | tail -n $(expr $backupnum - $MAX_BACKUP_NUM)
echo $backupid | tr ' ' '\n' | tail -n $(expr $backupnum - $MAX_BACKUP_NUM) | xargs docker rmi
fi
echo 'Done.'
在容器未打开时可以直接运行该脚本以打开容器,运行该命令后,将直接进入容器的/bin/bash
,可以按Ctrl+p+q
退回宿主机切保持容器不关闭。
如果在
/bin/bash
中输入exit
将使得终端窗口关闭,entrypoint运行结束,容器直接关闭。
- 创建crontab定时命令(每天备份一次)
$ crontab -e
#在下面添加
m h dom mon dow command
0 0 * * * /root/ngc_backup.sh
$ service cron restart # 重启crontab
$ service cron status # 查看crontab服务状态,active即为启动
这样系统每天会在半夜0点自动检查容易是否运行,如果不存在将自动创建容器。如果存在容器则将根据该容器生成docker 镜像,并删除当前使用镜像及其父节点以外的历史存储镜像。
- 什么是父节点镜像?
假如容器a生成于镜像A,现在使用容器a执行commit命令将生成镜像B。镜像A是B父节点。- 镜像删除规则:
如果镜像A是镜像B的父节点,则在B删除之前是无法删除镜像A的。因此上述脚本执行rmi命令时,由于最新镜像不会被删除,因此其祖先节点镜像将被全部保留- 保留如此多的镜像,是否会浪费过多存储空间:
不会,按上述方法新镜像的生成是增量的,都是在原镜像基础上铺上了一层,因此实际存储空间近似于最新的镜像大小。
Tips: 可通过docker system df
命令查看总Images、Containers所占空间