文章目录
  1. 1. 准备工作
  2. 2. 搭建环境
  3. 3. 权限管理
  4. 4. 镜像同步

Docker官方并没有提供docker registry的用户界面,对权限的控制粒度也比较粗。SUSE的Portus很好地解决了这个问题。除了界面以外,它还提供了更细粒度的权限控制、用户认证等功能。本文尝试从零开始用容器搭建一个portus环境。

准备工作

我们需要先安装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",在它的下面添加如下几行代码,相当于给它分配一台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
1
2
vagrant up
vagrant ssh

搭建环境

我们将会把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的这个镜像,对审计、追踪来说很有帮助。

文章目录
  1. 1. 准备工作
  2. 2. 搭建环境
  3. 3. 权限管理
  4. 4. 镜像同步