文章

Docker实验五:Docker 仓库管理

Docker 仓库管理

使用仓库(Repository)可以集中存放和管理镜像。

本实验包含三部分内容:

  • 如何使用公共的 Docker 仓库。
  • 如何使用 Registry 搭建 Docker 仓库。
  • 如何使用 VMWare Harbor 搭建自己的Docker仓库。

1 Docker Hub

目前 Docker 官方维护了一个公共仓库 Docker Hub

大部分需求都可以通过在 Docker Hub 中直接下载镜像实现。从 Docker Hub 上下载镜像时,不需要注册账号。

以 hello-world 为关键词进行搜索:

1
docker search hello-world

可以看到Docker Hub给出的 hello-world 镜像列表,这里选择第一个镜像。

1
docker pull hello-world

但是,如果用 Docker Hub 存放(push)自己的镜像时,需要首先在Docker Hub上注册账号。

1.1 注册

https://hub.docker.com 免费注册一个 Docker 账号。打开官网后,点击 “Sign Up Docker Hub”注册账号,注册完毕后,点击“Sign In”登录网站。

1.2 登录

登录需要输入用户名和密码,登录成功后,我们就可以往自己账号下的推送镜像了。

使用 docker login 登录 Docker Hub。

1
docker login 

输入在Docker Hub网站上注册的账号和密码后,会提示登录成功(Login Succeeded)。

1.3 退出

退出 docker hub 可以使用 docker logout 命令:

1
docker logout

1.4 推送(push)

如果当前处于登出状态,需要重新登录。

登录后,通过 docker push 命令将自己的镜像推送到 Docker Hub。

1
2
3
docker login
docker tag hello-world:latest jiongjiong/hello-world:latest
docker push jiongjiong/hello-world:latest

推送结束后,可以在官网上点击 Repositories 查看自己账号下的镜像。

2 基于 Registry 搭建仓库

在 Docker 中,当执行 docker pull image_name 时 ,实际上是从 registry.hub.docker.com 这个地址去查找,这就是 Docker 公司提供的公共仓库。

在工作中,不可能把企业项目push到公有仓库进行管理。为了更好的管理镜像,Docker不仅提供了一个中央仓库,同时也允许用户搭建本地私有仓库。本节介绍如何使用registry搭建私有仓库,下节介绍如何使用VMWare Harbor搭建仓库。

registry搭建仓库的实验分为两部分:单机版仓库和分布式仓库。

2.1 registry 本地仓库

2.1.1 搭建

Docker 官方提供了一个搭建私有仓库的镜像 registry ,只需把镜像下载下来,运行容器并暴露 5000 端口,就可以使用了。

Registry服务默认会将上传的镜像保存在容器的/var/lib/registry,我们将主机的/opt/registry目录挂载到该目录,即可实现将镜像保存到主机的/opt/registry目录了。

1
2
3
docker pull registry:2
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --name myregistry registry:2
docker ps -l

浏览器访问http://127.0.0.1:5000/v2/_catalog,出现下面情况说明registry运行正常。

可以看到,当前还没有上传任何镜像。

2.1.2 验证

现在通过 push hello-world 镜像验证 registry 是否正常。

注意在推送前,需要将镜像做一个新的标记(tag),标记的格式为:

仓库地址/镜像名:版本号

使用 push 命令时,push的语法为:

docker push 仓库地址/镜像名:版本号

1
2
docker tag hello-world:latest localhost:5000/hello-world:latest
docker push localhost:5000/hello-world:latest

可以看出,hello-world 镜像推送成功。

通过浏览器验证 hello-world 镜像推送成功。

可以看到仓库中已显示 hello-world 镜像。

接着,使用私有仓库下载镜像,首先移除本地的 hello-world 镜像:

然后,通过pull下载镜像,pull命令的格式为:

docker pull 仓库地址/镜像名:版本号

1
2
3
4
5
docker images
docker rmi hello-world jiongjiong/hello-world localhost:5000/hello-world
docker images
docker pull localhost:5000/hello-world:latest
docker images

可以看到 hello-world 镜像已被成功下载。

对镜像做一个 hello-world:latest 的标记。

1
2
docker tag localhost:5000/hello-world:latest hello-world:latest
docker images

使用本地镜像的另一个好处是,一般局域网的速度要远快于互联网,因此,push和pull的速度都较快。

2.2 registry 远程仓库

到此为止,已经在本地系统上完成了registry仓库的搭建。然而,一般镜像仓库是需要被远程访问,即仓库服务器搭建好了之后,在其他docker客户端上可以将镜像推送到这个镜像仓库,或者从这个镜像仓库下载镜像。

由于我们的实验环境只有当前桌面环境这一台服务器,为了模拟多台服务器,这里,借助于 dind 镜像。

dind 镜像的功能是在 Docker 容器中运行 Docker 容器,可以用dind创建一个 registry_server 容器,作为镜像仓库;再创建一个 registry_client 容器,作为普通的docker服务器,然后从这个 docker服务器上向registry_server推送镜像或者从registry_server上下载镜像。这样就实现了,镜像仓库被远程访问的功能。

首先下载dind镜像,然后创建registry_server 和 registry_client,并为这两台服务器分配IP地址。

1
2
3
docker pull jpetazzo/dind
docker network create registry_net --subnet=172.20.0.0/16
docker run -itd --privileged --name registry_server --hostname server --network registry_net --ip 172.20.1.1 jpetazzo/dind

上述命令分别创建了 registry_server(172.20.1.1) 和 registry_client(172.20.1.2) ,registry_server 为仓库服务器, registry_client 为用于访问仓库服务器的远程机。

在registry_server上部署registry:2服务:

1
2
3
docker exec -it registry_server /bin/bash
docker pull registry:2
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --name myregistry registry:2

打开Chrome浏览器,输入地址:http://172.20.1.1:5000/v2/_catalog,查看服务是否启动。

可见,服务已正常启动。

新建一个终端标签。

在新打开的终端里,进入 registry_client 。

1
docker exec -it registry_client /bin/bash

首先修改/etc/hosts文件,添加内容到该文件尾部:

172.20.1.1      server

然后,下载 hello-world 镜像,并推送给 registry_server

1
2
3
docker pull hello-world
docker tag hello-world server:5000/hello-world:latest
docker push server:5000/hello-world:latest

可以看到推送失败了。这是因为从 Docker 1.13.2 版本开始,使用 registry 时,必须使用TLS保证其安全。

有两种方法,可以让镜像顺利推送到仓库服务器上。一种是修改仓库服务器的Docker配置文件 daemon.json ,将仓库服务器配置为非安全服务器。另一种方式是配置TLS认证。

这里,分别用这两种方式进行配置。

2.2.1 修改仓库服务器的 Docker 配置

编辑 /etc/docker/daemon.json 文件,添加如下信息:

1
2
3
{
    "insecure-registries":["server:5000","172.20.1.1:5000"]
}

修改完毕后,重启Docker。在 dind 中,第一次重启 Docker 的方式为:

1
2
3
4
ps -ef | grep dockerd
kill -9 58
ps -ef | grep dockerd
service docker start

在后续的实验中,可采用如下方式在 dind 中重启 Docker

1
2
service docker stop
service docker start

通过 docker info 查看 insecure-registies 是否正确设置:

1
docker info

可以看到,insecure-registies 已被正确设置。

接下来,重新推送 hello-world 镜像:

1
docker push server:5000/hello-world

通过 Chrome 验证 hello-world 镜像推送成功。

可见,hello-world 镜像已成功推送。

2.2.2 配置TLS

接下来使用配置TLS(安全传输层协议)认证的方式配置仓库服务器和 Docker 客户端。

首先,将 Docker 客户端的 daemon.json 配置文件移除,并重启Docker。

1
2
3
4
mv /etc/docker/daemon.json /etc/docker/daemon.json.bak
service docker stop
service docker start
docker ps

下载 nginx 镜像, 并尝试推送镜像仓库,确认 Docker 镜像仓库无法推送。

1
2
3
docker pull nginx
docker tag nginx server:5000/nginx
docker push server:5000/nginx

首先在仓库服务器上,生成带有自签名的证书:

1
2
mkdir -p /opt/docker/registry/certs
openssl req -newkey rsa:4096 -nodes -sha256 -keyout /opt/docker/registry/certs/domain.key -x509 -days 365 -out /opt/docker/registry/certs/domain.crt

根据提示信息输入自己的信息,在路径 /opt/docker/registry/certs 下生成签名证书。

删除之前创建的 myregistry 容器,重新创建带有 TLS 认证的 registry 容器。

1
2
3
docker stop myregistry
docker rm myregistry
docker run -d --name myregistry -p 5000:5000 -v /opt/docker/registry/certs:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key registry:2

然后回到 Client 端,首先需要创建/etc/docker/certs.d/目录。

然后再该目录下创建与这个registry服务器域名一致的目录:server:5000

1
2
3
mkdir /etc/docker/certs.d
cd /etc/docker/certs.d/
mkdir server:5000

然后将证书 domain.crt 复制到每一个 Client 的 /etc/docker/certs.d/server:5000/ 目录下。

这里,采用scp复制,复制前需要在 server 端安装 ssh 服务器,在 client 端安装 ssh 客户端。

首先在 server 端配置 ssh 服务器:

1
2
apt-get update
apt-get install -y openssh-server

ssh 安装完毕后,需要允许root登录,修改 /etc/ssh/sshd_config 文件,将 PermitRootLogin 这一行改为:

1
PermitRootLogin yes

修改完毕后,重启 ssh 服务器,修改过程如下所示:

1
2
3
vi /etc/ssh/sshd_config 
cat /etc/ssh/sshd_config | grep PermitRoot
service ssh restart

为仓库服务器设置root密码:

1
passwd root

接着回到 Client 端安装 ssh 客户端。

1
2
apt-get update
apt-get install -y openssh-client

安装完毕后,将认证文件从仓库服务器拷贝到本地。

1
scp -p [email protected]:/opt/docker/registry/certs/domain.crt /etc/docker/certs.d/server\:5000/ca.crt

现在重新推送 nginx 镜像,输出信息如下:

1
docker push server:5000/nginx

使用 Chrome 查看镜像列表(在提示页面点击:高级->继续):

可以看到 nginx 已被成功推送于仓库服务器上。

从仓库服务器下载 ngnix 镜像进一步验证仓库服务器已正确配置。

1
2
3
4
5
docker images
docker rmi nginx:latest
docker rmi server:5000/nginx
docker pull server:5000/nginx
docker images

可见,可以顺利地从仓库服务器下载到 nginx 镜像。

2.3 基于 VMWare Harbor 搭建仓库

docker 官方提供的私有仓库 registry,用起来虽然简单 ,但在管理的功能上存在不足。 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,harbor在实现上使用了官方的docker registry v2(v2命名是distribution)服务。harbor在docker distribution的基础上增加了一些安全、访问控制、管理的功能以满足企业对于镜像仓库的需求。

2.3.1 搭建本地仓库

首先,进入~/course/docker/harbor/目录, 安装 docker-compose, 将文件 docker-compose-Linux-x86_64 拷贝于目录 /usr/local/bin/ 下,并重命名为:docker-compose

1
2
cd ~/course/docker/harbor/
cp docker-compose-Linux-x86_64 /usr/local/bin/docker-compose

然后解压 harbor-offline-installer-v1.2.2.tgz 压缩包,修改 harbor.cfg 将 hostname 的值修改为 127.0.0.1。

1
2
3
4
5
6
tar -zxf harbor-offline-installer-v1.2.2.tgz
ls -l
cd harbor
ls
vim harbor.cfg 
cat harbor.cfg | grep hostname

为install.sh添加执行权限,执行 install.sh。

1
2
chmod +x install.sh 
./install.sh 

安装完毕后,可使用 Chrome 浏览器访问 harbor 服务,在地址栏输入:127.0.0.1,可打开如下图所示页面。

输入账号/密码:admin/Harbor12345,以管理员身份登陆到 harbor 管理页面。

可以看到,当前存在一个library的目录,且该目录为空。

在推送镜像到服务器之前,需要首先用 docker login 登陆仓库服务器。

登陆账号/密码为:admin/Harbor12345

1
docker login 127.0.0.1

现在将 nginx 镜像上传至 harbor 仓库。

1
2
3
docker pull nginx
docker tag nginx 127.0.0.1/library/nginx
docker push 127.0.0.1/library/nginx

可以看到,镜像已成功推送到 harbor 仓库上。

使用 Chrome 查看所推送的镜像,刷新 harbor 管理页面后,点击library:

可以看到 nginx 镜像已被成功推送到 harbor 仓库上。

使用 docker pull 进一步验证 harbor 仓库服务。

首先删除本地的 nginx 镜像,然后从 harbor 仓库服务器上拉取。

1
2
3
docker rmi nginx 127.0.0.1/library/nginx
docker pull 127.0.0.1/library/nginx
docker images

可以看到,ngnix 已从 harbor仓库成功下载。

本地仓库在实际环境中很少使用,更常使用的仓库的远程仓库。

现在基于 dind 模拟 harbor 远程仓库。

基于 dind 创建两台服务器 harbor_server 和 harbor_client , IP 地址分别设置为 172.20.2.1,172.20.2.2。

1
2
docker run -itd --privileged --name harbor_server --hostname server --network registry_net --ip 172.20.2.1 jpetazzo/dind
docker run -itd --privileged --name harbor_client --hostname client --network registry_net --ip 172.20.2.2 jpetazzo/dind

将 docker-compose 和 harbor 安装包拷贝到 harbor_server 中,然后进入 harbor_server 安装 docker-compose 并解压 harbor 安装包。

1
2
3
4
5
6
7
8
9
10
cd ..
ls
docker cp docker-compose-Linux-x86_64 harbor_server:/home
docker cp harbor-offline-installer-v1.2.2.tgz harbor_server:/home
docker exec -it harbor_server /bin/bash
cd /home
ls
mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
tar -zxf harbor-offline-installer-v1.2.2.tgz
ls

进入harbor目录,将harbor.cfg中的IP地址改为:172.20.2.1,然后分别为/usr/local/bin/docker-compose和./install.sh 添加执行权限。

1
2
3
4
vi harbor.cfg 
cat harbor.cfg | grep hostname
chmod +x /usr/local/bin/docker-compose 
chmod +x install.sh 

执行 install.sh 安装 harbor。

1
./install.sh

从浏览器上查看 Harbor 仓库服务,打开 Chrome 浏览器,输入地址:172.20.2.1,使用 admin/Harbor12345 登录,可以看到当前 library 仓库为空。

在终端另一个tab页上进入 harbor_client, 尝试推送 hello-world 镜像到 harbor 仓库服务器。

1
2
3
4
docker exec -it harbor_client /bin/bash
docker pull hello-world
docker tag hello-world 172.20.2.1/library/hello-world
docker login 172.20.2.1

可以看到,远程方式访问 harbor 仓库时,访问失败。

和registry:2一样,可以通过两种方式使得远程机可以推送镜像到Harbor服务器,一种是配置 daemon.json 文件,告知 Docker 客户端,所要使用的仓库时不安全的;另一种是配置TLS认证。

下面分别使用这两种方式来配置 harbor 仓库。

2.3.2 修改 daemon.json 配置文件

编辑修改 /etc/docker/daemon.json 文件,添加相关内容:

1
2
3
{
    "insecure-registries":["172.20.2.1"]
}

1
2
3
ps -ef | grep dockerd
kill -9 58
service docker start

使用docker info确认配置已生效:

可以在 Insecure Registries 中看到 172.20.2.1,因此,配置已生效。

再次使用 docker login 登录 harbor 仓库服务器,

1
docker login 172.20.2.1

提示登录已成功。

再次推送 hello-world 镜像,

1
docker push 172.20.2.1/library/hello-world

可以看到,镜像已成功推送。

通过浏览器确认镜像推送成功,切换到 Chrome 浏览器,刷新 harbor 管理页面,可以看到 hello-world 镜像已被成功推送。

2.4 基于 TLS 配置安全性更高的 harbor 仓库

首先在 Client 上移除 /etc/docker/daemon.json 文件,并重启 Dcoker, 确认关闭不安全的配置方式。

1
2
3
4
mv /etc/docker/daemon.json /etc/docker/daemon.json.bak
service docker stop
service docker start
docker login 172.20.1.1

可以看到使用 docker login 时,无法登录,说明不安全的配置方式已关闭。

回到 harbor 仓库服务器的终端,开始为 harbor 配置 https 认证。

2.4.1 创建证书

首先创建证书的存放目录:

1
2
3
mkdir /root/ca -p
cd /root/ca
openssl req  -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 365 -out ca.crt

其中,

  • req:申请证书签署请求
  • -newkey:新密钥
  • -x509:可以用来显示证书的内容,转换其格式,给CSR签名等X.509证书的管理工作,这里用来自签名。

按照提示信息输入相应内容,注意在 Common Name 提示信息处输入 harbor 服务器的仓库地址。

2.4.2 生成证书签名请求

1
openssl req  -newkey rsa:4096 -nodes -sha256 -keyout 172.20.2.1.key -out 172.20.2.1.csr

按照自己的信息填写上述内容。注意在 Common Name 处需要填写 harbor 仓库服务器的 IP 地址。

2.4.3 生成证书

habor仓库服务器默认只能通过域名访问,不能通过IP地址访问,这里对其进行配置,使得可以通过IP访问仓库服务器。

1
2
echo subjectAltName = IP:172.20.2.1 > extfile.cnf
openssl x509 -req -days 365 -in 172.20.2.1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile extfile.cnf -out 172.20.2.1.crt

2.4.4 配置harbor.cfg

配置 harbor.cfg 文件,

  • 将协议改为 https 协议,uiurlprotocol = https
  • 设置 ssl_cert 文件路径为:/root/ca/172.20.2.1.crt
  • 设置 ssl_cert_key 文件路径为:/root/ca/172.20.2.1.key

使用vi,按如下方式编辑harbor.cfg文件。

2.4.5 重新启动harbor

使用 docker-compose down 命令停止当前的harbor服务,使用 prepare 脚本使得新配置的 harbor.cfg 生效,使用 docker-compose up 命令启动新配置下的 habor 服务。

1
2
3
docker-compose down -v
./prepare
docker-compose up -d

接下来需要将 harbor 仓库服务器的认证文件拷贝到 Client 远程机上。

按照 registry TLS 配置实验中的方法分别为 harbor 仓库服务器和 Client 客户端安装 SSH Server 和 SSH Client,安装完毕后,将 server 端的 root 密码重置为 coursegrading。

server端的 ssh 配置流程如下:

1
2
3
4
5
6
apt-get update
apt-get install -y openssh-server
vi /etc/ssh/sshd_config 
cat /etc/ssh/sshd_config | grep PermitRootLogin
service ssh restart
passwd root 

client端的 ssh 配置流程如下:

1
2
apt-get update
apt-get install -y openssh-client

然后将 server 端制作的 ca 证书拷贝到 client 端,并添加到信任。

1
2
mkdir -p /etc/docker/certs.d/172.20.2.1
scp [email protected]:/root/ca/ca.crt /etc/docker/certs.d/172.20.2.1

然后重启 client 端的 Docker 服务:

1
2
service docker stop
service docker start

2.4.6 测试

重新使用 docker login 登录 172.20.2.1 仓库服务器:

1
docker login 172.20.2.1

由于之前登陆时,账号/密码已被系统记录,所以可以直接登录。

这里,首先从 docker 官方下载 mysql 镜像,然后推送到 harbor 仓库服务器上。

1
2
3
docker pull mysql
docker tag mysql 172.20.2.1/library/mysql
docker push 172.20.2.1/library/mysql

可见,mysql镜像已成功推送。

通过Chrome浏览器查看该镜像,首先在地址栏输入:https://172.20.2.1,登录

可以看到 mysql 镜像已被成功推送。

使用docker pull 再次测试:

1
2
docker rmi 172.20.2.1/library/mysql mysql
docker pull 172.20.2.1/library/mysql

查看镜像列表:

1
docker images

可见,带有 https 认证的harbor仓库已配置成功。

本文由作者按照 CC BY 4.0 进行授权