Skip to content

构建镜像规则

一、 概述

为保证平台容器正常启动运行,平台构建镜像时会为镜像封装SSH和SUDO软件,便于通过平台Shell操作容器或切换 Root 用户,组件适用场景如下:

1. 使用 SSH 登录容器时,需预装 SSH 和 SUDO

适用场景:创建 Notebook 实例后,使用 SSH 登录容器;创建容器实例后,通过 SSH 进入容器实例。为保证您可通过 SSH 登录并具有必要的操作权限,镜像中必须预装以下组件:

SSH 服务(如 openssh-server)

SUDO 工具

注意:若镜像中缺少 SSH 或 SUDO,实例可能无法正常启动或无法安装应用。

平台封装SSH和SUDO支持的源镜像版本如下:
CentOS: 7、8
Ubuntu: 14.04、16.04、18.04、20.04、22.04
其它平台不兼容版本如构建过程中安装SSH和SUDO失败,建议采用镜像包方式构建镜像(制作镜像Tar包时自行安装SSH和SUDO)

2. 若需打开“开发工具”,则需要预装开发工具

平台在创建 Notebook 或容器实例时,会根据用户选择的开发工具自动启动对应服务。因此,镜像中必须提前安装可用的 IDE。例如:在 Notebook 里使用“我的镜像”创建实例时,则需提前在镜像里安装 Jupyter;在容器实例里创建开发工具为“VSCode”的容器时,则需提前在镜像里安装 VSCode。

针对不同场景下需预装的 IDE 组件如下:

(1)创建 Notebook 时,应安装 Jupyter,启动路径支持:/opt/conda/bin/jupyter

(2)创建容器实例时,根据开发工具不同,启动路径不同:

a. 开发工具为Jupyter时,启动路径支持:/opt/conda/bin/jupyter

b. 开发工具为VS Code时,启动路径支持:/usr/lib/code-server/bin/code-server

c. 开发工具为RStudio时,启动路径支持:/usr/lib/rstudio-server/bin/rserver

注意

a. 实例启动时,会按启动路径进行扫描,若未找到对应路径下的 IDE,则创建实例将会失败。

b. 平台提供的基础镜像已默认安装上述IDE,如需自定义环境,可在基础镜像之上构建个人镜像。

3. 其他建议

建议基于平台提供的基础镜像进行扩展,避免遗漏必要依赖。

确保镜像中设置了默认用户及权限,以便在容器启动时正常加载 IDE 服务与 SSH 服务。

二、 构建镜像

构建镜像支持 3 种方式:镜像包、外部仓库、Dockerfile,如下将介绍如何使用镜像管理来构建镜像,以应对不同场景的示例。

1. 镜像包

当通过上传镜像包的方式进行构建时,需要确保镜像中预先安装了平台运行所需的工具和组件。否则,可能导致容器实例无法正常创建或运行。具体操作如下:

(1)加载或拉取源镜像

#源镜像为镜像包时执行命令

docker load -i 镜像包 

#源镜像为镜像仓库镜像时执行命令

docker pull 原始镜像

(2)运行镜像

docker run -it 镜像名 /bin/bash

(3)查看Linux系统版本

#查看Ubuntu/CentOS的方法
cat /etc/issue

(4)按不同操作系统添加SUDO

# 当操作系统为 ubuntu 时执行如下命令
sudo -V || /usr/bin/sudo -V || /usr/local/bin/sudo -V; if [ $? -ne 0 ]; then \
cd /tmp && dpkg --configure -a && dpkg -i sudo_1.8.16-0ubuntu1.9_amd64.deb ||  \
apt-get update && apt-get install -y sudo; fi

# 当操作系统为 centos 时执行如下命令
sudo -V || /usr/bin/sudo -V || /usr/local/bin/sudo -V; if [ $? -ne 0 ]; then \
yum clean all && yum makecache && yum install -y sudo; fi

(5)按不同操作系统添加SSH

# 当操作系统为 ubuntu 时执行如下命令
/usr/sbin/sshd -p 22; if [ $? -ne 0 ]; then \
apt-get update && apt-get dist-upgrade -y && apt-get install -y openssh-server; fi
mkdir -p /var/run/sshd /root/.ssh
# 不使用DNS
sed -i "s/#UseDNS .*/UseDNS no/" /etc/ssh/sshd_config
sed -i -r "s/^(.*pam_nologin.so)/#\1/" /etc/pam.d/sshd
ssh-keygen -A

# 当操作系统为 centos 时执行如下命令
/usr/sbin/sshd -p 22; if [ $? -ne 0 ]; then \
cd /tmp/Resource &&  rpm -ivh *.rpm \
    || yum clean all && yum makecache && yum install -y openssl openssh-server; fi
# 更新配置信息
sed -i "s/^\#PermitRootLogin/PermitRootLogin/" /etc/ssh/sshd_config && \
sed -i "s/^#PubkeyAuthentication/PubkeyAuthentication/" /etc/ssh/sshd_config && \
sed -i "s/^#RSAAuthentication/RSAAuthentication/" /etc/ssh/sshd_config
sed -i -r "s/^(.*pam_nologin.so)/#\1/" /etc/pam.d/sshd
ssh-keygen -A

(6)提交容器更改为镜像

docker commit 容器id 镜像名称:tag

(7)保存镜像为归档Tar包

#压缩包格式为:.tar或.tar.gz。
docker save 镜像名称:tag 镜像Tar包.tar

(8)上传镜像Tar包到平台,添加镜像时选择此镜像包

2. 外部仓库

使用docker pull命令拉取外部镜像仓库中的镜像,不需要自己上传镜像包或写 Dockerfile。目前只支持外部公开的镜像库(例如:Dockerhub、其他云厂商等),暂不支持私有的镜像库。

注意:根据Docker公司政策,Docker Hub对匿名和免费用户实施速率和拉取请求次数限制。所以,构建服务拉取Docker Hub镜像时,可能受此影响导致构建失败,建议通过可拉取镜像环境制作镜像并保存Tar包,在平台采用镜像包方式构建镜像。

(1)源镜像拉取命令
  必须填写源镜像拉取命令,否则会提示 不可为空,可以是 外部镜像仓库地址/命名空间/镜像名。
  格式为:docker pull <name>[:tag]
  例如:docker pull image.sourcefind.cn:5000/gpu/admin/base/jupyterlab-pytorch:2.7.0-py3.11-cuda11.8-ubuntu22.04-devel、docker pull elasticsearch:9.0.7

(2)镜像名称 <name>
  可以是 Docker Hub 上的官方镜像,例如:python、nginx、ubuntu

(3)镜像标签 [:tag]
  若不写 :tag,默认拉取 :latest
  推荐显式写明版本
  例如 :3.10、2.7.0-py3.11-cuda11.8-ubuntu22.04

3. Dockerfile

当使用 Dockerfile 方式构建镜像时,需提前准备好 Dockerfile 文件。如有 COPY 或 ADD 操作,请将所需文件放到家目录 dockerFileTemp 文件夹下。

存放路径如 /public/home/${username}/dockerFileTemp。
#Dockerfile内容
FROM ...
# ......
# 复制 /public/home/${username}/dockerFileTemp/tmp.txt 到 /root/
COPY tmp.txt /root/

如下完整 Dockerfile 示例:

# 使用 Ubuntu 20.04 基础镜像
FROM ubuntu:20.04

# 添加镜像标签信息
LABEL module="jupyter"

# 设置非交互式安装模式
ARG DEBIAN_FRONTEND=noninteractive

# 设置系统时区为中国上海
ENV TZ=Asia/Shanghai

# 切换到 root 用户
USER root

# Bash 的语法和功能
SHELL ["/bin/bash","-c"]

# 更新软件包列表 && 安装 HTTPS 根证书
RUN apt-get update && apt-get install -y ca-certificates

# 备份源文件
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak && \
    mkdir -p /etc/apt/sources.list.d.bak && \
    mv /etc/apt/sources.list.d/* /etc/apt/sources.list.d.bak/ || true

# 获取当前系统 codename(如 jammy)
RUN version_id=$(cat /etc/os-release | grep VERSION_CODENAME | cut -d= -f2) && \
    echo "Setting up mirrors for Ubuntu ${version_id}" && \
    echo -e "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id} main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-security main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-updates main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-proposed main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-backports main restricted universe multiverse\n\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id} main restricted universe multiverse\n\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-security main restricted universe multiverse\n\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-updates main restricted universe multiverse\n\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-proposed main restricted universe multiverse\n\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ ${version_id}-backports main restricted universe multiverse" > /etc/apt/sources.list

# 更新包索引并安装基础工具
RUN apt-get update -y && \
    apt-get install --no-install-recommends -y \
        vim \
        openssl \
        libssl-dev \
        net-tools \
        locales \
        wget \
        sudo \
        openssh-client \
        openssh-server \
        python3.10 \
        python3-pip && \
    locale-gen en_US.UTF-8 && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 恢复原始源(可选)
RUN mv /etc/apt/sources.list.bak /etc/apt/sources.list && \
    mv /etc/apt/sources.list.d.bak /etc/apt/sources.list.d

# 安装 JupyterLab
RUN pip3 install jupyterlab==4.0.0

# 软连接IDE到平台指定路径
RUN jupytersite="$(python3 -m pip show jupyterlab | grep -i '^location' | awk '{print $2}')" \ 
    && JUPYTERLAB_DIR=$(echo ${jupytersite%%/lib/python*}) \
    && if [[ ${JUPYTERLAB_DIR}/bin/jupyter != "/opt/conda/bin/jupyter" ]]; \
    then mkdir -p /opt/conda/bin; \
    ln -sf ${JUPYTERLAB_DIR}/bin/jupyter /opt/conda/bin/jupyter;fi 

# 启动命令
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root"]

# 暴露端口
EXPOSE 8888