Docker官方并没有提供docker registry的用户界面,对权限的控制粒度也比较粗。SUSE的Portus 很好地解决了这个问题。除了界面以外,它还提供了更细粒度的权限控制、用户认证等功能。本文尝试从零开始用容器搭建一个portus环境。
准备工作 我们需要先安装virtualBox 和vagrant 。通过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"
,在它的下面添加如下几行代码,相当于给它分配一台IP是192.168.33.18 的虚拟机。Registry配上portus会比较耗内存,所以我们给它2G内存,默认是512M。Vagrantfile 1
2
3
4
config.vm.network "private_network" , ip: "192.168.33.18"
config.vm.provider "virtualbox" do |v|
v.memory = 2048
end
这个vagrant镜像已经在ubuntu的基础上帮我们安装了docker,用起来很方便。然后在终端运行以下命令启动并连接虚拟机。virtual box host
搭建环境 我们将会把docker registry和portus都安装在同一台虚拟机上。一方面是比较方便,另一方面也避免了时钟同步问题 。为了启动一个带认证的docker registry,首先要生成自签名证书:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat << EOF > ssl.conf
[ req ]
prompt = no
distinguished_name = req_subj
x509_extensions = x509_ext
[ req_subj ]
CN = Localhost
[ x509_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:true
subjectAltName = @alternate_names
[ alternate_names ]
DNS.1 = localhost
IP.1 = 192.168.33.18
EOF
sudo mkdir /certs
sudo sh -c "openssl req -config ssl.conf \
-new -x509 -nodes -sha256 -days 365 -newkey rsa:4096 \
-keyout /certs/server-key.pem -out /certs/server-crt.pem"
证书生成好了,但是由于这是自签名证书,客户端还需要配置证书文件:1
2
3
sudo mkdir -p /etc/docker/certs.d/192.168.33.18:5000
sudo cp /certs/server-crt.pem /etc/docker/certs.d/192.168.33.18:5000/ca.crt
sudo service docker restart
接下来生成一个registry的配置文件,里面指定刚才的证书和token方式的认证。认证服务器设置到一会儿要启动的portus去: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
30
31
cat << EOF > config.yml
version: 0.1
loglevel: debug
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
tls:
certificate: /certs/server-crt.pem
key: /certs/server-key.pem
auth:
token:
realm: https://192.168.33.18/v2/token
service: 192.168.33.18:5000
issuer: 192.168.33.18
rootcertbundle: /certs/server-crt.pem
notifications:
endpoints:
- name: portus
url: https://192.168.33.18/v2/webhooks/events
timeout: 500ms
threshold: 5
backoff: 1s
EOF
然后就可以启动registry容器了:1
2
3
4
5
6
7
8
docker run -d \
--name registry \
-p 5000:5000 \
--restart=always \
-v /var/lib/registry:/var/lib/registry \
-v /certs:/certs \
-v `pwd `/config.yml:/etc/docker/registry/config.yml \
registry:2.3.0
Docker registry配置完成后,就该准备portus了。Portus需要一个数据库来存储信息,官方推荐MariaDB ,当然mysql也是没问题的。我们把数据库启动起来:1
2
3
4
5
6
7
docker run -d \
--name mariadb \
--net=host \
--restart=always \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TERM=xterm \
mariadb:10.1.10
等数据库启动完成,我们连接上去:1
docker exec -it mariadb mysql -uroot -p123456
为portus创建用户和数据库:sql 1
2
3
create database portus;
GRANT ALL ON portus.* TO 'portus' @'%' IDENTIFIED BY 'portus' ;
exit
万事俱备,让我们来启动portus: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
docker run -it -d \
--name portus \
--net host \
--restart=always \
-v /certs:/certs \
-v /usr/sbin/update-ca-certificates:/usr/sbin/update-ca-certificates \
-v /etc/ca-certificates:/etc/ca-certificates \
--env DB_ADAPTER=mysql2 \
--env DB_ENCODING=utf8 \
--env DB_HOST=192.168.33.18 \
--env DB_PORT=3306 \
--env DB_USERNAME=portus \
--env DB_PASSWORD=portus \
--env DB_DATABASE=portus \
--env RACK_ENV=production \
--env RAILS_ENV=production \
--env PUMA_SSL_KEY=/certs/server-key.pem \
--env PUMA_SSL_CRT=/certs/server-crt.pem \
--env PUMA_PORT=443 \
--env PUMA_WORKERS=4 \
--env MACHINE_FQDN=192.168.33.18 \
--env SECRETS_SECRET_KEY_BASE=secret-goes-here \
--env SECRETS_ENCRYPTION_PRIVATE_KEY_PATH=/certs/server-key.pem \
--env SECRETS_PORTUS_PASSWORD=portuspw \
h0tbird/portus:v2.0.2-1
启动完成后,在浏览器打开https://192.168.33.18/
,应该会看到证书不被浏览器所信任的提示。无视之,选择继续的话,应该就能看到注册页面啦:
权限管理 Portus现在只能管理一个私有库。它有一个团队的概念,每一个团队可以有多个命名空间,每个命名空间就是多个镜像的集合。每个团队有三种角色:
查看者(Viewer):只能pull镜像
贡献者(Contributor):除了pull,还可以push镜像
所有者(Owner):除了推拉镜像,还可以对团队成员进行管理
由于角色是定义在团队里的,所以命名空间就不需要再考虑权限问题了,它只是镜像的集合而已。命名空间也有三种类型:
全局(Global):只有管理员可以push,其他人只能pull
团队(Team):团队成员可以做自己角色支持的操作
个人(Personal):只有所有者和管理员可以推拉
命名空间还可以设置为public,这样不需要login也能pull。
说完一些基本概念,让我们来尝试一下。首先,portus需要配置一个用户,来调用docker registry的API,与其进行同步。同步 有两种方式 :一是在docker registry的配置文件里写的notifications
,这样每当有人push一个新镜像上去,docker registry将会通知portus修改数据库。可是时间长了,有可能数据库偶尔挂掉或是网络不稳定啥的导致两边数据不一致。Portus针对这种情况也提供了一个crono的job,设置定时运行即可,一会儿我们会试验。现在先让我们来创建这个用户:registry 1
docker exec portus bundle exec rake portus:create_api_account
接下来就可以在注册页面自行注册啦,注册完毕后会跳转到登记registry页面:
照上图填入registry,点击Create 按钮创建一个docker registry。接着创建一个新用户。点击左边的Admin ,再点击中间的Users ,然后点击右边的Create new user ,填写用户信息:
点击Add 按钮就可以创建一个新用户了。接下来创建一个团队。点击左边的Teams ,再点击右边的Create new team ,填写团队信息:
点击Add 按钮就可以创建一个新团队了。点击刚刚创建好的团队,再点击右边的Add namespace ,填写命名空间信息:
点击Add 按钮就可以创建一个新命名空间了。接下来把用户添加到这个团队中。点击右边的Add members ,填写刚才增加的用户信息:
点击Add 按钮就可以把用户加进来了。回到控制台,搞一个镜像,push一下:1
2
3
docker pull microbox/etcd:2.1.1
docker tag microbox/etcd:2.1.1 192.168.33.18:5000/microbox/etcd:2.1.1
docker push 192.168.33.18:5000/microbox/etcd:2.1.1
出错了:unauthorized: authentication required ,我们必须用docker先登录:1
docker login -u gggg -e gggg@123.com 192.168.33.18:5000
填上自己刚才设置的密码,登录成功之后,再试着push一下:1
docker push 192.168.33.18:5000/microbox/etcd:2.1.1
Bingo!换一个命名空间试试看:1
2
docker tag h0tbird/portus:v2.0.2-1 192.168.33.18:5000/h0tbird/portus:v2.0.2-1
docker push 192.168.33.18:5000/h0tbird/portus:v2.0.2-1
出错了:unauthorized: authentication required ,可见我们的权限控制确实起作用了。
镜像同步 接下来我们试试定时同步任务。首先需要在容器里信任我们的自签名证书:1
2
3
docker exec portus mkdir /usr/local /share/ca-certificates
docker cp /certs/server-crt.pem portus:/usr/local /share/ca-certificates/ca.crt
docker exec portus update-ca-certificates
然后启动定时同步任务,设置为每10秒钟同步一次:1
2
docker exec -it portus bash
RAILS_ENV=production CATALOG_CRON="10.seconds" bundle exec crono
等十秒钟,就会看到[catalog] Created the tag ‘2.1.1’ 的提示。如果先前没有信任自签名证书,同步的时候会报certificate verify failed 的错误。现在回到portus的界面,点击左边的Dashboard ,就能看到刚才push的microbox/etcd镜像已经显示在右边了:
最后一步就是自动同步了,先把刚才的crono给Ctrl+C掉,Ctrl+D退出portus容器。由于docker registry需要调用portus的API,所以我们需要在registry容器里也信任这个证书:1
2
3
docker cp /certs/server-crt.pem registry:/usr/local /share/ca-certificates/ca.crt
docker exec registry update-ca-certificates
sudo service docker restart
然后再push一个镜像:1
2
docker tag registry:2.3.0 192.168.33.18:5000/microbox/registry:2.3.0
docker push 192.168.33.18:5000/microbox/registry:2.3.0
到portus的dashboard刷新一下,搞定!在中间的Recent activities 还能看到是谁push的这个镜像,对审计、追踪来说很有帮助。