Docker系列(四):私有仓库(一)
简介
有些私有镜像不方便传输到公共镜像库中,或者内网环境,可以搭建一个私有Registry作为镜像仓库。
Docker Registry
Registry是用于存储和交付Docker镜像的系统。 和本地镜像管理中存储的镜像一样,可以使用不同的标签版本。
1. 使用docker-distribution
启动Registry
可以直接安装docker组件distribution来启动Registry。
- 安装
对于CentOS系统,直接使用yum
安装即可:
$ yum install docker-distribution
- 启动
通过systemctl
启动Registry服务:
$ systemctl start docker-distribution
- 配置说明
安装好后的Registry的配置文件可以正常启动应用,修改/etc/docker-distrbution/registry/config.yml
文件来修改默认配置:
version: 0.1
log:
fields:
service: registry
storage:
cache:
layerinfo: inmemory
filesystem:
rootdirectory: /var/lib/registry #镜像文件存储的目录
http:
addr: :5000 #对外服务的端口
后面会继续说明一些用到的配置。
2. 使用已有的镜像启动Registry
官方文档都是通过下载已经配置好的Registry的镜像,通过容器启动此镜像,来提供Registry的服务。
- 下载官方镜像
直接拉取官方镜像:
$ docker pull registry:2
2: Pulling from library/registry
49388a8c9c86: Pull complete
e4d43608dd22: Pull complete
3a41740f900c: Pull complete
e16ef4b76684: Pull complete
65f212f7c778: Pull complete
Digest: sha256:d837de65fd9bdb81d74055f1dc9cc9154ad5d8d5328f42f57f273000c402c76d
Status: Downloaded newer image for registry:2
- 通过镜像启动Registry服务
通过官方镜像启动容器:
$ docker run -d -p 5000:5000 --name registry registry:2
4199973ca1c7511fd608da534570375023fa69715948b13f4d9b3a3c277d3536
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4199973ca1c7 registry:2 "/entrypoint.sh /e..." 5 seconds ago Up 4 seconds 0.0.0.0:5000->5000/tcp registry
其实启动容器时如果没有对应的镜像,会自动下载:
$ docker run -d -p 5000:5000 --name registry registry:2
Unable to find image 'registry:2' locally #提示在本地镜像库中没有找到镜像
2: Pulling from library/registry #开始从公共镜像库下载镜像
49388a8c9c86: Pull complete
e4d43608dd22: Pull complete
3a41740f900c: Pull complete
e16ef4b76684: Pull complete
65f212f7c778: Pull complete
Digest: sha256:d837de65fd9bdb81d74055f1dc9cc9154ad5d8d5328f42f57f273000c402c76d
Status: Downloaded newer image for registry:2 #镜像下载完成
6dabd62f77e8e2079bed029599aea96b65a551bcdb517a4adb24630828dea761 #启动容器
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry 2 a07e3f32a779 5 days ago 33.3MB
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6dabd62f77e8 registry:2 "/entrypoint.sh /e..." 5 minutes ago Up 5 minutes 0.0.0.0:5000->5000/tcp registry
使用容器启动Registry时注意将存储镜像的目录挂载到本地硬盘,如果存储镜像在容器中,容器销毁时,所有镜像也一起销毁:
$ docker run -d -p 5000:5000 --name registry -v /mnt/registry:/var/lib/registry registry:2
3. 访问无验证的Registry
默认的docker client访问无认证的Registry可能会出现错误:
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
Get https://10.0.2.15:5000/v2/: http: server gave HTTP response to HTTPS client
docker client客户端默认需要访问https
的地址,需要增加配置,重启docker:
$ echo "{\"insecure-registries\":[\"10.0.2.15:5000\"]}" >> /etc/docker/daemon.json
$ systemctl restart docker
重启后重新推送镜像:
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
3c133a51bc00: Pushed
a2717186d7dd: Pushed
656c7684d0bd: Pushed
7683d4fcdf4e: Pushed
ef763da74d91: Pushed
2: digest: sha256:435db1be85c6c10b2f506516aa14d8c485c1f1bd5f4a941a637808b085f294b6 size: 1364
如果是通过二进制程序启动的docker,直接在启动时增加参数即可:
$ dockerd --insecure-registry 10.0.2.15:5000 & #如已启动docker,请先停止已启动的进程
4. 查看私有库中的镜像
Registry没有图形界面,只能通过命令访问接口:
$ curl http://10.0.2.15/v2/_catalog
{"repositories":["registry"]}
5. 其它
以上2种配置启动Registry的方法,对比来说第一种方法(直接安装docker-distribution
包)更为方便简洁,后期也较好维护(官网只有第二种方法,根据情况选择适合自己的方法来启动Registry)。
安全的Registry
Docker官方是推荐采用带有认证的Registry,传输采用tls。
1. 制作自签署证书
制作证书前需要在openssl.cnf
配置中加入证书绑定的域名(或主机名或IP)。否则推送镜像时会差生以下错误:
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
Get https://10.0.2.15:5000/v2/: x509: cannot validate certificate for 10.0.2.15 because it doesn't contain any IP SANs
修改配置文件,加入IP:
$ cp /etc/pki/tls/openssl.cnf /tmp/
$ vim /tmp/openssl.cnf
......
[v3_ca]
subjectAltName = IP: 10.0.2.15
修改后保存退出即可。继续使用openssl
来制作自签署的证书,注意需要指定刚才修改的openssl.cnf
配置文件:
$ mkdir /etc/docker-distribution/registry/certs
$ cd /etc/docker-distribution/registry/certs
$ openssl req -newkey rsa:2048 -nodes -sha256 -keyout domain.key -x509 -days 365 -out domain.crt -config /tmp/openssl.cnf
Generating a 2048 bit RSA private key
.............+++
...............................+++
writing new private key to 'domain.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:BJ
Organization Name (eg, company) [Default Company Ltd]:ZL
Organizational Unit Name (eg, section) []:ZL
Common Name (eg, your name or your server's hostname) []:registry
Email Address []:
$ ls
domain.crt domain.key
2. 修改配置文件
修改Registry的配置文件,添加tls
证书:
$ vim /etc/docker-distribution/registry/config.yml
version: 0.1
log:
fields:
service: registry
storage:
cache:
layerinfo: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
#增加以下tls的配置
tls:
certificate: /etc/docker-distribution/registry/certs/domain.crt
key: /etc/docker-distribution/registry/certs/domain.key
重启Registry服务:
$ systemctl restart docker-distribution
3. 客户端证书配置
Registry服务配置好后,需要将证书配置到客户端,否则会产生以下错误:
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
Get https://10.0.2.15:5000/v2/: x509: cannot validate certificate for 10.0.2.15 because it doesn't contain any IP SANs
将证书配置到客户端,并重启客户端:
$ mkdir -p /etc/docker/certs.d/10.0.2.15:5000
# 注意,本文档测试时客户端与私有库是同一台服务器,以下这个证书应该是拷贝到真实的客户端服务器中。
$ cp /etc/docker-distribution/registry/certs/domain.crt /etc/docker/certs.d/10.0.2.15\:5000/ca.crt
$ systemctl restart docker
测试是否正常访问私有镜像库:
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
3c133a51bc00: Pushed
a2717186d7dd: Pushed
656c7684d0bd: Pushed
7683d4fcdf4e: Pushed
ef763da74d91: Pushed
2: digest: sha256:435db1be85c6c10b2f506516aa14d8c485c1f1bd5f4a941a637808b085f294b6 size: 1364
Registry鉴权管理
Registry提供了基础的鉴权方式,可以像公有镜像库一样先登录,再提交镜像。
1. 生成鉴权密码文件
在Registry服务器上,增加一个admin
用户,密码为admin123
:
$ mkdir /etc/docker-distribution/registry/auth
$ docker run --entrypoint htpasswd registry:2 -Bbn admin admin123 > /etc/docker-distribution/registry/auth/htpasswd
2. 修改配置并重启服务
增加对应配置:
$ vim /etc/docker-distribution/registry/config.yml
version: 0.1
log:
fields:
service: registry
storage:
cache:
layerinfo: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
tls:
certificate: /etc/docker-distribution/registry/certs/domain.crt
key: /etc/docker-distribution/registry/certs/domain.key
#增加以下配置:
auth:
htpasswd:
realm: basic-realm
path: /etc/docker-distribution/registry/auth/htpasswd
重启服务:
$ systemctl restart docker-distribution
测试推送镜像:
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
3c133a51bc00: Preparing
a2717186d7dd: Preparing
656c7684d0bd: Preparing
7683d4fcdf4e: Preparing
ef763da74d91: Preparing
no basic auth credentials
推送失败,尝试登录后再次推送:
$ docker login 10.0.2.15:5000
Username: admin
Password:
Login Succeeded
$ docker push 10.0.2.15:5000/registry:2
The push refers to a repository [10.0.2.15:5000/registry]
3c133a51bc00: Layer already exists
a2717186d7dd: Layer already exists
656c7684d0bd: Layer already exists
7683d4fcdf4e: Layer already exists
ef763da74d91: Layer already exists
2: digest: sha256:435db1be85c6c10b2f506516aa14d8c485c1f1bd5f4a941a637808b085f294b6 size: 1364
成功登录后,推送镜像成功(因之前已推送过此镜像,所以提示镜像已存在)。
使用容器启动的Registry的安全和鉴权配置
使用容器启动的Registry可以通过多种方法进行配置:
- 使用Dockerfile将修改好的配置文件、证书及密码文件打入启动镜像。
如Dockerfile加入下列几行后重新制作镜像:
COPY config.yml /etc/docker/registry/config.yml
COPY domain.crt /etc/docker/registry/domain.crt
COPY domain.key /etc/docker/registry/domain.key
COPY htpasswd /etc/docker/registry/htpasswd
- 将修改好的配置文件、证书及密码文件的目录挂载到镜像对应目录。
启动镜像时将配置目录重新挂载:
$ docker run -d -p 5000:5000 --name registry \
-v /mnt/registry:/var/lib/registry \
-v /config:/etc/docker/registry \
registry:2
- 启动容器时使用特定环境变量指定修改。
启动容器是通过环境变量也可以修改Registry的配置:
$ docker run -d -p 5000:5000 --restart=always --name registry \
-v `pwd`/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v `pwd`/data:/var/lib/registry \
-v `pwd`/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2