Nvidia-NGC容器配置全过程+ssh配置+镜像定时备份

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

创建自定义镜像及自动备份

相关文件地址:https://github.com/y18810919727/Dgx-station_forum/

定制化容器为满足以下需求:

支持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 <

================

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所占空间