文章目录
  1. 1. 准备工作
  2. 2. 搭建环境
  3. 3. 界面
  4. 4. 认证

我们知道Docker官方提供了一个公有的registry叫做Docker Hub。但是企业内部可能有些镜像还是不方便放到公网上去,所以docker也提供了registry镜像来让需要的人自己搭建私有仓库。本文从零开始搭建Docker Registry的运行环境,并添加用户界面和认证功能。

准备工作

我们需要先安装virtualBoxvagrant。通过vagrant来驱动virtualBox搭建一个虚拟测试环境。首先在本地任意路径新建一个空文件夹比如test,运行以下命令:

virtual box host
1
2
3
4
mkdir test
cd test
vagrant init minimum/ubuntu-trusty64-docker
vi Vagrantfile

里面应该有一句config.vm.box = "minimum/ubuntu-trusty64-docker",在它的下面添加如下几行代码,相当于给它分配两台虚拟机,一台叫做registry,它的IP是192.168.33.18;另一台叫做client,它的IP是192.168.33.19。Registry配上界面会比较耗内存,所以我们给它1G内存,默认是512M。

Vagrantfile
1
2
3
4
5
6
7
8
9
10
11
12
config.vm.define "registry" do | host |
host.vm.hostname = "registry"
host.vm.network "private_network", ip: "192.168.33.18"
host.vm.provider "virtualbox" do |v|
v.memory = 1024
end
end
config.vm.define "client" do | host |
host.vm.hostname = "client"
host.vm.network "private_network", ip: "192.168.33.19"
end

这个vagrant镜像已经在ubuntu的基础上帮我们安装了docker,用起来很方便。然后分别在两个终端运行以下命令启动并连接两台虚拟机。

virtual box host terminal 1
1
2
vagrant up
vagrant ssh registry

virtual box host terminal 2
1
vagrant ssh client

搭建环境

启动一个registry是很容易的:

registry
1
2
3
4
5
6
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /var/lib/registry:/var/lib/registry \
registry:2.3.0

这里指定了一个/var/lib/registry的卷,是为了把真实的镜像数据储存在主机上,而别在容器挂掉之后丢失数据。就算这样,也还是不保险。要是主机挂了呢?Docker官方建议可以放到cephswift这样的存储里,或是亚马逊S3微软Azure谷歌GCS阿里云OSS之类的云商那里。Docker registry提供了配置文件,可以从容器里复制出来查看:

registry
1
2
docker cp registry:/etc/docker/registry/config.yml config.yml
cat config.yml

配置文件里有一个storage,按照这里写的配置,然后执行以下命令重新挂载这个文件来启动registry就可以了,有条件的话可以去试一试:

registry
1
2
3
4
5
6
7
8
docker rm -fv registry
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /var/lib/registry:/var/lib/registry \
-v `pwd`/config.yml:/etc/docker/registry/config.yml \
registry:2.3.0

Docker Registry配置完了,我们在client上传一个镜像试试:

client
1
2
3
docker pull busybox:1.24.1
docker tag busybox:1.24.1 192.168.33.18:5000/busybox:1.24.1
docker push 192.168.33.18:5000/busybox:1.24.1

结果push的时候就挂了。原来是我们没有配置认证信息,所以这是一个“不安全”的registry。Docker要求在docker daemon的启动参数里增加--insecure-registry,才能允许我们上传镜像:

client
1
2
3
sudo sh -c 'echo DOCKER_OPTS=\"--insecure-registry 192.168.33.18:5000\" >> /etc/default/docker'
sudo service docker restart
docker push 192.168.33.18:5000/busybox:1.24.1

这回就没问题啦。同样地在registry端也配置一下,然后把registry:2.3.0这个镜像上传:

registry
1
2
3
4
sudo sh -c 'echo DOCKER_OPTS=\"--insecure-registry 192.168.33.18:5000\" >> /etc/default/docker'
sudo service docker restart
docker tag registry:2.3.0 192.168.33.18:5000/library/registry:2.3.0
docker push 192.168.33.18:5000/library/registry:2.3.0

如果是没有用户的镜像(通常是官方镜像),打标签和上传都需要加一个library/。客户端必须再配置一个参数--registry-mirror才能在我们自己的私有registry里下载镜像:

client
1
2
3
4
sudo sed -i '$d' /etc/default/docker
sudo sh -c 'echo DOCKER_OPTS=\"--insecure-registry 192.168.33.18:5000 --registry-mirror http://192.168.33.18:5000\" >> /etc/default/docker'
sudo service docker restart
docker pull registry:2.3.0

应该有飞一般的感觉了吧。如果镜像不在registry里,客户端会自动去docker hub下载。但是每次打标签再上传岂不是很麻烦?所幸docker提供了一个proxy的功能。只要在config.yml里增加如下配置,重启registry容器即可。这样,客户端pull的镜像,也会自动同步到registry里去。

1
2
proxy:
remoteurl: https://registry-1.docker.io

界面

Docker官方只提供了REST API,并没有给我们一个界面。好在有热心人士出马,所以我们只需执行以下命令就可以给我们的私有库提供一个UI了:

registry
1
2
3
4
5
6
docker run -d \
-p 8080:8080 \
--name web \
-e REGISTRY_HOST=172.17.0.1 \
-e REGISTRY_PORT=5000\
hyper/docker-registry-web

然后打开http://192.168.33.18:8080,应该就能看到如下界面:

上面是个简易版,如果有更深入的需求,可以尝试SUSE的Portus。除了界面以外,它还提供了更细粒度的权限控制、用户认证等功能。

认证

我们刚刚配好的insecure registry是不支持认证的,如果要上产品环境,找CA申请一个证书吧。我们自己测试的话,可以用自签名证书。我们准备使用IP代替域名,所以需要在证书里面包含我们的IP:

registry
1
2
3
4
5
sudo mkdir /certs
sudo sed -i '/^\[ v3_ca \]$/a subjectAltName = IP:192.168.33.18' /etc/ssl/openssl.cnf
sudo sh -c "openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout /certs/domain.key \
-x509 -days 365 -out /certs/domain.crt"

随便填点值完成这繁琐的流程,就能看见certs里面多了两个文件。现在可以用以下命令来启动registry:

registry
1
2
3
4
5
6
7
8
9
10
docker rm -f registry
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /var/lib/registry:/var/lib/registry \
-v /certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2.3.0

客户端现在就不需要--insecure-registry了,但是由于这是自签名证书,客户端还需要把证书文件复制过去:

client
1
2
3
4
sudo sed -i '$d' /etc/default/docker
sudo mkdir -p /etc/docker/certs.d/192.168.33.18:5000/
sudo scp vagrant@192.168.33.18:/certs/domain.crt /etc/docker/certs.d/192.168.33.18:5000/ca.crt
sudo service docker restart

注意vagrant的默认密码也是vagrant。现在push就没有问题了:

client
1
docker push 192.168.33.18:5000/busybox:1.24.1

提示镜像已经存在,并没有阻止我们提交。接下来我们加上认证。首先在registry生成用户名hello和密码world:

registry
1
2
sudo mkdir /auth
sudo sh -c "docker run --entrypoint htpasswd registry:2.3.0 -Bbn hello world > /auth/htpasswd"

还得指定认证方式和认证文件等参数,重新启动registry容器:

registry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
docker rm -f registry
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /var/lib/registry:/var/lib/registry \
-v /auth:/auth \
-v /certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:2.3.0

这回客户端用docker push 192.168.33.18:5000/busybox:1.24.1来尝试push就会失败啦。但是我们可以用用户名hello和密码world登录啦:

client
1
docker login -u hello -p world -e email_whatever 192.168.33.18:5000

再次push,就没有问题了:

client
1
docker push 192.168.33.18:5000/busybox:1.24.1

文章目录
  1. 1. 准备工作
  2. 2. 搭建环境
  3. 3. 界面
  4. 4. 认证