Bootstrap

docker全流程使用指南

1 安装Docker及前期配置

1.1 安装docker

注:本部分内容参照自Ubuntu - Docker — 从入门到实践

卸载旧版本

sudo apt-get remove docker \
               docker-engine \
               docker.io

使用脚本自动安装

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装,另外可以通过 --mirror 选项使用国内源进行安装:

curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun

执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。

1.2 启动Docker

# 启动docker
sudo systemctl enable docker
sudo systemctl start docker

# 设置docker开机自启动
sudo systemctl enable docker.service
sudo systemctl enable containerd.service

1.3 建立Docker用户组

默认情况下,docker命令会使用Unix socketDocker引擎通讯。而只有root用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。

  • 建立 docker 组:
sudo groupadd docker
  • 将当前用户加入 docker 组:
sudo usermod -aG docker $USER

退出当前终端并重新登录,进行如下测试。

1.4 测试 Docker 是否安装正确

docker run --rm hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:308866a43596e83578c7dfa15e27a73011bdd402185a84c5cd7f32a88b501a24
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

若能正常输出以上信息,则说明安装成功。

2 镜像获取

2.1 从docker hub从下载镜像

使用docker pull命令,下面给出几个例子

# 下载最新的配置了pytorch的镜像
sudo docker pull pytorch/pytorch:latest  

2.2 物理机文件镜像制作

配置Dockerfile文件

先用touch Dockerfile在当前目录创建一个Dockerfile文件,然后用sudo vim Dockerfile编辑Dockerfile文件:

# FROM ubuntu:2.04
# FROM python:3.8
FROM continuumio/anaconda3
WORKDIR /home
COPY . .

# pip配置清华镜像
RUN pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip3 install -r requirements.txt
RUN apt-get update && apt-get install sudo -y

# 配置阿里云镜像
RUN sudo cp -a /etc/apt/sources.list /etc/apt/sources.list.bak
RUN sudo sed -i "s@http://.*archive.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list
RUN sudo sed -i "s@http://.*security.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list

# 下载GPU工具用的
RUN distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
            sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
            sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

RUN apt-get update && apt-get install -y \
        passwd \
        openssl \
        openssh-server \
        openssh-client \
        wget \
        nano \
        net-tools \
        vim-gtk \
        iputils-ping \
        nvidia-container-toolkit

# CMD ["bash", "sample2.sh"]
# CMD ["python3", "run.py"]
# ENTRYPOINT service ssh start && bash

注释:

  • FROM:指定一个基础镜像 (base image);

  • WORKDIR:指定这个命令之后的所有Docker命令 (比如RUN, COPY等等)的工作路径 (working directory),如果指定的路径在镜像中不存在则会自动创建;

  • COPY:复制文件,格式为COPY <物理机路径> <镜像中的目标路径>,这里使用.表示指定WORKDIR下的所有文件;

  • RUN:在创建镜像时运行shell命令;

  • CMD:指定当Docker容器运行起来之后要执行的命令

创建镜像

sudo docker build --no-cache -t image-name .

注释:

  • -ttag,指的是要给镜像起的标签名,这里为image-name名字必须要是小写

  • .:表示在当前路径下搜索Dockerfile文件;

3.3 已保存容器制作

具体参见5.2的容器导入部分。

3 创建容器

使用docker run命令便可创建容器。

3.1 使用docker hub中的镜像。

此时需要额外设置工作路径等。

sudo docker run -itd --gpus all -w /home -p 18080:22 \
             --name container_name pytorch/pytorch:latest /bin/bash

解释:这会创建一个名为container_name的容器,并将它存储在物理机的 path_to_project 目录下。此外,该容器会将主机的 18080 端口映射到容器的 22 端口上。其中

  • --gpus all 表示开启 GPU;

  • -v (volume,数据卷) 表示挂载一个主机目录 。-v /path_to_project:/home (慎用)。这里将物理机的/path_to_project路径映射为容器中的/home路径。可以把它当做是一个在物理机和不同容器中共享的文件夹,比如在一个容器中修改了volume的数据,会同时反应在其它容器上。也可以使用docker volume create path_to_volume创建数据卷,这里因为我已经直接指定了-v参数,是会默认创建volume的,因此无需再create一个;

  • -w 表示指定容器工作目录 (与Dockerfile中的WORKDIR一样),-p 表示映射主机端口到容器端口(port);

  • --name 表示指定容器名称;

  • -itd中的-d表示detached即后台运行,-i (--interactive) 表示保留交互界面,-t表示分配一个虚拟的终端 (allocate a pseudo-TTY),经常与-i一起出现,合起来就是“以交互的方式打开终端”;

  • pytorch/pytorch:latest为前面用docker pull拉取的镜像名字。

  • /bin/bash:指bash文件的编译地址。

3.2 使用物理机镜像

此时无需设置工作路径以及挂载路径等。

sudo docker run -itd --gpus all -p 18080:22 --name container_name \
                                               image_name /bin/bash

其中-v /path_to_project:/home慎加,可能会导致容器中没有文件; -w /home可以不用加了。

示例:

sudo docker run -itd --gpus all -p 18080:22 --name ffjord_v1 ffjord /bin/bash

sudo docker run -itd -v /home/cw/scire_solver --gpus all -p 18080:22 --name scire_solver_1 scire_solver /bin/bash

3.3 可使用jupyterlab

参考自How to run JupyterLab on Docker - DEV Community

sudo docker run -itd -v /home/cw/scire_solver --gpus all --shm-size 50G --privileged -p 8899:8899 -e JUPYTER_ENABLE=yes -e JUPYTER_TOKEN=docker --name scire_solver_2 scire_solver_jupyter /bin/bash

其中:

-e指的是设定容器的环境变量,其中JUPYTER_ENABLE=yes是让容器可使用jupyter_labJUPYTER_TOKEN=docker是设定jupyter_labtoken,在后面登录的时候要用,-v指的是设定容器保存在物理机上的地址,8899:8899指的是将容器的8899端口(:后面的,这个是要在jupyter_lab_config.py文件中设定的)映射到物理机的8899端口(:前面的)。--shm-size设定的是交换区内容大小,这个会影响data_loader等的性能(调整容器shm大小)--privileged是获取容器的root权限,此时可以用root权限操控容器。

设定好之后,就可以用http://localhost:8899?token=docker远程连接了,注意,这里面的localhost换成容器所挂载的物理机的ip地址。8899也是物理机的端口号,但因为我们将物理机的8899端口映射到容器的8899端口了,而容器的8899端口被用于jupyter_lab的远程连接服务,因此意味着连物理机的8899等价于连接容器的jupyter_labtoken=docker是前面设置的JUPYTER_TOKEN=docker决定的。

4 启动并进入容器

  • 先启动容器:
sudo docker start container_name
# 示例:sudo docker start scire_solver_2
  • 接着进入容器:
sudo docker exec -it container_name /bin/bash
# 示例:sudo docker exec -it scire_solver_2 /bin/bash

其中/bin/bashbash文件的编译地址,与前面一致。

5 容器备份与迁移

5.1 用容器构建镜像

本节内容主要参考自利用 commit 理解镜像构成

当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个 docker commit 命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。

docker commit 的语法格式为:

docker commit [options] <container_ID或container_name> [<new_image_name>[:<label>]]

我们可以用下面的命令将容器保存为镜像:

docker commit \
    --author "XX" \
    --message "XX" \
    container_name \
    new_image_name:label

其中 --author 是指定修改的作者,而 --message 则是记录本次修改的内容。这点和 git 版本控制相似,不过这里这些信息可以省略留空。

我们可以在 docker image ls 中看到这个新定制的镜像。我们还可以用 docker history image_name[:label] 具体查看镜像内的历史记录。

5.2 导入和导出容器

参考自导出和导入 - Docker — 从入门到实践

导出容器

如果要导出物理机某个容器,可以使用 docker export 命令。

$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
7691a814370e        ubuntu:18.04        "/bin/bash"         36 hours ago        Exited (0) 21 hours ago                       test
$ docker export 7691a814370e > ubuntu.tar

这样将导出容器快照到物理机文件。

导入容器快照

注:下面用到的ubuntu.tar根据自己情况修改成其他名字

可以使用 docker import 从容器快照文件中再导入为镜像,例如

$ cat ubuntu.tar | docker import - test/ubuntu:v1.0
$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
test/ubuntu         v1.0                9d37a6082e97        About a minute ago   171.3 MB

这里的cat命令是ubuntu中用来显示文件内容用的,这里必须要用。或者也可以用

docker import ubuntu.tar test/ubuntu:v1.0

docker import之后可以用docker image ls查看镜像,但查看容器是看不到的

此外,也可以通过指定 URL 或者某个目录来导入,例如

$ docker import http://example.com/exampleimage.tgz example/imagerepo

注:用户既可以使用 *docker load* 来导入镜像存储文件到物理机镜像库,也可以使用 *docker import* 来导入一个容器快照到物理机镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

6 开启ssh服务

在此之前需要先安装好Linux必备软件。具体过程见Linux使用ssh服务并保持长时间连接进入容器。

6.1 前期准备

# add root passward* 记住自己设置的密码,后面ssh连接要用
sudo passwd root  
# New passwrd: # 输入root新密码
# Retype new password: # 再次输入root密码
# passwd: password updated successfully # 密码更新成功

apt update
apt install passwd openssl openssh-server openssh-client -y

# 检查ssh服务是否启动成功
sudo ps -e | grep ssh
# 如果有sshd则说明ssh服务已启动,如果没有启动,输入下边命令启动ssh服务
sudo service ssh start

# 配置ssh文件
vi /etc/ssh/sshd_config
# PasswordAuthentication no         # 设置为no才可以使用sftp传文件
# port 22
# PermitRootLogin yes

# 重启ssh
service ssh restart   或   /etc/init.d/ssh restart

# 查看ssh状态
service ssh status

# 设置开机自启动
systemctl enable ssh 
# 取消开机自启
systemctl disable ssh 

实际服务器环境下机器是很少重启的,所以最好再手动配置一个启动脚本。

# 设置打开shell自启动
sudo nano ssh_auto.sh

添加以下内容:

#!/bin/bash

LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$LOGTIME] startup run..." >>/root/run.log
service ssh start >>/root/run.log

赋予权限:

chmod +x ssh_auto.sh

添加到.bashrc文件中去:

# 编辑.bashrc文件
sudo vim /root/.bashrc

# 添加以下内容
. /root/ssh_auto.sh

# 让.bashrc生效
source .bashrc

6.2 远程连接

ssh root@ip -p 18080-o ServerAliveInterval=20

远程连接ip是重点,这里ip不是容器内部的ip而是物理机的ip。此外,root指的是容器中用户的名字,而非物理机中用户的名字,千万不要搞混了。

  • -o ServerAliveInterval=20表示每隔20秒发送一次信息告诉服务器我还在线。

  • -p是端口号,指的是在使用docker run的时候物理机映射到容器中的ip,比如18080:22的话ip=18080,可以用

docker port container_name 22

在物理机看容器端口映射。

在输入密码的时候,填的是容器的密码,而不是物理机的密码,一定要注意!

6.3 补充

  • 使用sudo systemctl status ssh仍然会报错,无需理会

    $ sudo systemctl status ssh
    
    System has not been booted with systemd as init system (PID 1). Can't operate.
    Failed to connect to bus: Host is down
    

7 补充

7.1 为Docker配置GPU

解决TensorFlow出现的Could not load dynamic library ‘libcurand.so.10‘等类似的问题_三只佩奇不结义的博客-CSDN博客

本节内容参考自nvidia-container-toolkit,可解决docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]].。注意,下面的命令都是在物理机上执行的,而非在容器里。

  • 1、设置软件包存储库和▁GPG▁密钥 (直接复制粘贴过去即可):

    distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
          && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
          && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
                sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
                sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    
  • 2、 在更新软件包列表后安装 Nvidia-container-Toolkit 软件包(和依赖项):

    sudo apt-get update
    sudo apt-get install -y nvidia-container-toolkit
    
  • 3、配置Docker daemon以识别 NVIDIA Container Runtime

    sudo nvidia-ctk runtime configure --runtime=docker
    
  • 4、在设置默认运行时后重新启动Docker daemon以完成安装:

    sudo systemctl restart docker
    

之后便可继续运行docker run了。

7.2 删除或停止容器

  • 获取容器ID:一般使用 docker ps 命令查看 Docker 进程。但是,由于这个进程没有正常启动,所以,此时没有显示出来。因此,改用 docker ps -l 命令,其中-l表示显示最新创建的容器 (latest)。

  • 删除对应容器:拿到了容器ID,现在只需要执行 docker rm container_ID 指令删除容器即可。

  • 停止对应容器:同理,只需执行docker stop container_ID或者docker stop container_name便可关闭容器。

7.3 Docker常用命令

查看所有镜像:docker images
查看运行中的容器:docker ps
查看所有容器:docker ps -a

启动容器:docker start 容器ID
重启容器:docker restart 容器ID
停止容器:docker stop 容器ID
进入容器:docker exec -it 容器ID /bin/bash
退出容器:exit

构建镜像:docker build -f Dockerfile -t 镜像名:V1  .
创建并运行容器:docker run -d -p 端口 镜像名:V1
删除容器:docker rm 容器ID
删除镜像:docker image rm 镜像ID
复制jar到容器中:docker cp XXX.jar 容器ID:/opt  

7.4 清理容器存储目录

可以用sudo du -sh /var/lib/docker指令查看物理机中存储docker相关文件的文件夹的大小。接着运行以下指令便可清除不必要的文件:

docker system prune --all --force
docker system prune --all --force --volumes

7.5 下载Linux必备软件

  • 下载wget, vim等必备基础软件
apt-get update 
apt-get install sudo

# 配置阿里云镜像
sudo cp -a /etc/apt/sources.list /etc/apt/sources.list.bak
sudo sed -i "s@http://.*archive.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list
sudo sed -i "s@http://.*security.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list
apt-get update

# 下载必备软件
sudo apt-get install wget
sudo apt-get install nano
sudo apt install net-tools
sudo apt-get install vim-gtk
apt install iputils-ping
  • 下载并配置anaconda3
# 下载anaconda
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2023.03-1-Linux-x86_64.sh

# 安装anaconda,默认安装在/root/anaconda3
bash Anaconda3-2023.03-1-Linux-x86_64.sh

# 普通用户登陆后,需要执行以下指令使conda的路径等系统环境变量信息写入当前用户的 ~/bashrc 文件中:
/root/anaconda3/bin/conda init bash

# 刷新环境变量
source .bashrc

# pip配置清华镜像源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple 

7.6 修改docker镜像的存储路径

参考自Docker----如何更改docker镜像的存储路径_docker修改镜像存储位置_redrose2100的博客-CSDN博客

  • 首先查看当前docker镜像默认的存储位置,如下命令
docker info|grep "Docker Root Dir"

一般情况下,在没有特意设置的情况下,默认的保存路径为 /var/lib/docker

  • 关闭所有运行的docker容器
docker ps | awk '{print $1}' |xargs docker stop
  • 停止docker服务
systemctl stop docker
  • 在新新增的磁盘挂载点上新建目录,并将原有的docker容器和镜像全部拷贝过来,比如这里新增磁盘的挂载点为 /data/(这个看自己需求,可自行设置,比如我的为/home/cw/),则参照如下命令操作
mkdir -p /data/var/lib/docker/
cd /data/var/lib/docker/
cp -r /var/lib/docker/* /data/var/lib/docker/
  • 设置docker的配置文件,并指定存储路径,如果文件不存在则直接创建一个
vi /etc/docker/daemon.json

添加如下内容

{
    "data-root": "/data/var/lib/docker",
    // 可有可无,如果不需要记得把`data-root`后面的`,`删掉
    "registry-mirrors": ["https://ooe7wn09.mirror.aliyuncs.com"]  
    }
  • 然后重启docker服务
systemctl daemon-reload
systemctl start docker

至此就完成了docker容器和镜像默认路径的修改。

8 实例

这是我拉取pytorch,然后创建容器的命令,创建完后可以配置vscode直接远程该镜像,端口为18080

sudo docker pull pytorch/pytorch:latest
sudo docker run -itd --gpus all -v /data/chumei:/home -w /home -p 18080:22 --name chumei pytorch/pytorch:latest /bin/bash
sudo docker start chumei
sudo docker exec -it chumei /bin/bash
/etc/init.d/ssh start

你的容器打包好后,在新系统创建你的容器,需要

  • 改变拉取镜像名:pytorch/pytorch:latest

  • 改变容器存储在系统上的文件夹:/data/chumei

  • 改变你想开通的端口号:18080

具体解释:

1、首先使用以下命令拉取 PyTorch 镜像:

sudo docker pull pytorch/pytorch:latest

这将会从 Docker Hub 上下载最新版本的 PyTorch 镜像,并在物理机存储。

2、接下来,使用以下命令创建容器:

sudo docker run -itd --gpus all -v /data/chumei:/home -w /home -p 18080:22 --name chumei pytorch/pytorch:latest /bin/bash

这会创建一个名为 chumei 的容器,并将它存储在 /data/chumei 目录下。此外,该容器会将主机的 18080 端口映射到容器的 22 端口上。其中 --gpus all 表示开启 GPU,-v 表示挂载一个主机目录,-w 表示指定容器工作目录,-p 表示映射主机端口到容器端口,--name 表示指定容器名称。

3、启动容器:

sudo docker start chumei

这会启动名为 chumei 的容器。

4、进入容器:

sudo docker exec -it chumei /bin/bash

这会打开一个新的终端,进入正在运行的容器 chumei 中。

5、启动 SSH 服务:

/etc/init.d/ssh start

这会启动容器内的 SSH 服务。

完成以上步骤后,就可以使用 VS Code 等工具通过远程连接访问容器,开发和运行代码了。注意,在使用 VS Code 配置远程连接时,需要指定容器的 IP 地址和端口号。

;