有时在 docker 中产生的数据,我们需要进行相应的备份和迁移到另一台服务器上,并在另一台服务器上进行数据恢复,docker 容器备份与迁移是在 docker 的镜像层级操作,我们介绍了三种容器备份与迁移的方法:

  • 离线迁移
  • DockerHub
  • 私有镜像仓库

首先我们需要将需要备份的容器打包成镜像。假设我们有一个容器,名为 nvidia/cuda:11.6.0-cudnn8-devel-ubuntu18.04,首先停止容器:

1
docker stop nvidia_cuda

使用 docker commit 命令将该容器打包成镜像

1
docker commit -m "nvidia_cuda" nvidia_cuda my_container:1.0

可以看到我们生成的镜像信息,已成功制作镜像 my_container:1.0

离线迁移

镜像文件经常有在服务器之间传输的需求,为此 docker 提供了镜像打包和镜像加载的命令,docker save 命令可将镜像打包成 tar 压缩文件,使用示例

1
docker save -o my_container:1.0.tar my_container:1.0

在当前目录下能生成 7.8G 的镜像压缩包 my_container:1.0.tar

image-20230525111125136

之后需要将文件传输到其它主机上,在局域网内可实现高速传输,在压缩包所在目录打开 http 端口

1
python3 -m http.server 9000

监听服务器的 9000 号端口,如果显示端口被占用,换一个数字即可。

在浏览器中输入10.24.83.40:9000,找到我们的镜像压缩文件 my_container:1.0.tar,右键复制链接地址

在另一台主机上执行

1
wget ${刚才复制的地址}

文件开始传输(如果卡住刷新下浏览器就行,这种端口映射不支持并行传输)

至此,镜像压缩文件从一台主机传输到了另一台主机,之后需要从tar文件载入镜像。

docker load 命令可以从tar文件载入镜像,执行示例:

1
docker load -i my_container:1.0.tar

查看镜像是否添加进 docker 里面:

然后使用 docker run 创建容器

1
docker run -it --gpus all --name my_container -v /mnt/data:/data -p 40000:40000 -p 40001:40001 -p 9000:22 my_container:1.0 /bin/bash

可能能用上的参数说明:

  • –gpus:容器内能使用GPU
  • –name:容器名称
  • -v:文件挂载,通常需要将主机上的机械硬盘目录挂载进容器内
  • -p:端口映射,9000:22表示将容器的22号端口映射到主机的9000号端口,用于容器的Shell连接,40000:40000表示将容器的40000号端口映射到主机的40000的端口,便于容器的局域网络服务

容器启动成功:

在主机上运行设置容器自启动

1
2
docker start my_container
docker update --restart=always my_container

Docker Hub

我们可以将自己制作的 docker 镜像发布至 DockerHub 公共仓库,需要科学上网才能进入,使用这种方式的核心命令:

  • docker push:用于将本地 docker 镜像上传到远程仓库,让其它用户可以使用
  • docker pull:用于从 DockerHub 或其它镜像仓库中下载镜像到本地 docker 环境

首先注册一个 DockerHub 账号,然后 docker login 命令使用 docker ID 和密码登录:

推送镜像至仓库,我们将 my_container:1.0 镜像拉取至本地,然后再上传至 DockerHub 仓库中:

1
2
docker tag my_container:1.0 lizhongliang123/my_container:1.0
docker push lizhongliang123/my_container:1.0

可以看到镜像已经被push上去了:

我们在另一台主机上拉取镜像,测试镜像能否被拉取

1
docker pull lizhongliang123/my_container:1.0

使用完退出当前账号登录

1
docker logout

后续容器的构建可以参考离线迁移后半部分的内容。

私有镜像仓库

像 DockerHub、阿里云这样的公共镜像仓库有时候用起来不太方便,DockerHub 网速太慢,阿里云需要花钱买云主机;另外,涉及内部资源的保密性,有的机构不太可能将镜像提供给公网,因此需要创建一个基于内部项目的镜像,构造本地私人仓库供给团队使用。因此,docker 提供了 docker-registry 工具,可以用于构建私有镜像仓库。

docker-registry 工具也是个 docker 镜像,它的功能就是用于创建私服版的 DockerHub,使用 docker-compose 部署带有图形界面的 docker-registry,首先编写 credentials.yml

1
2
3
mkdir registry-ui
cd registry-ui
vim credentials.yml

设置容器开机自启动,文件的内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version: '2.0'
services:
registry:
image: registry:2.7
volumes:
- /mnt/data/registry:/var/lib/registry
- ./registry-config/credentials.yml:/etc/docker/registry/config.yml
- ./registry-config/htpasswd:/etc/docker/registry/htpasswd
networks:
- registry-ui-net
restart: always

ui:
image: joxit/docker-registry-ui:latest
ports:
- 8080:80
environment:
- REGISTRY_TITLE=厦门大学私有镜像仓库
- NGINX_PROXY_PASS_URL=http://registry:5000
- SINGLE_REGISTRY=true
- DELETE_IMAGES=true
- SHOW_CONTENT_DIGEST=true
depends_on:
- registry
networks:
- registry-ui-net
restart: always
networks:
registry-ui-net:

新建鉴权配置文件:

1
2
3
mkdir registry-config
cd registry-config
vim credentials.yml

配置文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: 0.1
log:
fields:
service: registry
storage:
delete:
enabled: true
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ['http://localhost']
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
Access-Control-Allow-Headers: ['Authorization', 'Accept']
Access-Control-Max-Age: [1728000]
Access-Control-Allow-Credentials: [true]
Access-Control-Expose-Headers: ['Docker-Content-Digest']
auth:
htpasswd:
realm: basic-realm
path: /etc/docker/registry/htpasswd

添加密码文件,需要安装 passwd

1
sudo apt install apache2-utils

然后执行

1
htpasswd -Bbn admin admin > ./registry-config/htpasswd

启动Registry服务:

1
docker-compose -f credentials.yml up -d

registry 映射到了 8080 号端口,访问 http://localhost:8080/ 即可访问镜像仓库,默认用户名为 admin,密码为 admin

接下来需要向镜像仓库推送镜像,首先登录,用户名为 admin,密码为 admin

1
2
# login后面如果不加地址默认是登录DockerHub
docker login 10.24.83.22:8080

一个bug:输入用户名和密码后出现错误


解决方法:https://blog.csdn.net/qcdh1234/article/details/100639420,但是它是docker-compose的依赖库,需要login的时候就remove,不需要的时候就装回去:

1
2
3
4
# docker login
sudo apt-get remove golang-docker-credential-helpers
# docker-compose
sudo apt-get install docker-compose

接下来就是镜像推送,以registry镜像为例

首先打标签

1
docker tag registry:latest 10.24.83.22:8080/registry:latest

然后就可以推送镜像了

1
docker push 10.24.83.22:8080/registry:latest

在局域网主机上使用docker pull可以从私有仓库中拉取镜像,在拉取镜像前,由于私服采用的是http协议,默认不被Docker信任,需要进行配置,改为https协议,使用docker pull的主机都需要修改

1
2
3
4
5
6
7
8
9
10
11
# 打开docker配置文件
vim /etc/docker/daemon.json

# 添加内容
"insecure-registries": ["https://10.24.83.22:8080"],

# 重加载
systemctl daemon-reload

# 重启docker
systemctl restart docker

然后使用docker pull从私有仓库中拉取镜像

1
docker pull 10.24.83.22:8080/registry:latest

鉴权

若要修改用户名和密码,执行以下命令

1
htpasswd -Bbn admin admin > ./registry-config/htpasswd

指定需要修改的用户名和密码。

清空

删除镜像在网页端操作,如果某个repos下面一个镜像都没有,需要采用删除文件夹的方式将0镜像的repos去除,镜像文件夹存储位置/mnt/data/registry/docker/registry/v2/repositories/

批量删除打标签10.24.83.22:8080”的镜像

1
docker rmi $(docker images | grep 10.24.83.22:8080 | awk '{name=$1":"$2;print name}')