前言
使用docker官方的registry下载镜像速度很慢,下载一次push到自己的搭建的registry中,再使用时就方便很多了,下面就是自己搭建私有registry的过程,记录一下。
环境
主机:10.1.1.40
OS:CentOS 7.3
Dokcer:1.12.6
Nginx:1.10.3
Registry:V2,容器化
# 搜索50个星以上的镜像,从描述可以看出已经是V2版本了
docker search --filter=stars=50 registry
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/registry The Docker Registry 2.0 implementation for... 1369 [OK]
docker.io docker.io/konradkleine/docker-registry-frontend Browse and modify your Docker registry in ... 140 [OK]
docker.io docker.io/atcol/docker-registry-ui A web UI for easy private/local Docker Reg... 88 [OK]
docker.io docker.io/hyper/docker-registry-web Web UI, authentication service and event r... 79 [OK]
# 下载官方的registry镜像
dokcer pull docker.io/registry
registry的默认配置文件为/etc/docker/registry/config.yml,image默认存放位置为/var/lib/registry/,通过卷保存在本地存储上
# 建立目录
mkdir -pv /mydata/registry/{conf,data}
# 建立配置文件
vim /mydata/registry/conf/config.yml
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
secret: admin
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
# 启动容器
docker run -d -p 4000:5000 --restart=always --name registry \
-v /mydata/registry/conf/config.yml:/etc/docker/registry/config.yml \
-v /mydata/registry/data:/var/lib/registry \
docker.io/registry:latest
# 查看容器
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7350a38dc313 docker.io/registry:latest "/entrypoint.sh /etc/" 19 seconds ago Up 18 seconds 0.0.0.0:4000->5000/tcp registry
接下来,把下载下来的registry镜像push到私有的repository中
# 查看images
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/registry latest 047218491f8c 9 days ago 33.17 MB
# 给image打tag
docker tag 047218491f8c 10.1.1.40:4000/registry:v2
# push
docker push 10.1.1.40:4000/registry:v2
The push refers to a repository [10.1.1.40:4000/registry]
Get https://10.1.1.40:4000/v1/_ping: http: server gave HTTP response to HTTPS client
push的时候报错了。自建v2版的registry需要启用TLS认证,否则就会报错。
如果本地安装registry,可以通过修改配置文件/etc/sysconfig/docker
加上INSECURE_REGISTRY='--insecure-registry 10.1.1.40:4000'
来解决,registry容器化后,没有/etc/sysconfig/docker
,只能使用TLS证书来解决。
生成自签名证书
# 创建ssl目录
mkdir -p /etc/ssl
# 生成证书
cd /etc
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ssl/ivixq.com.key -x509 -days 365 -out ssl/ivixq.com.crt
Generating a 4096 bit RSA private key
......................++
..........................................................................................++
writing new private key to 'ssl/ivixq.com.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) []:GD
Locality Name (eg, city) [Default City]:GZ
Organization Name (eg, company) [Default Company Ltd]:IV
Organizational Unit Name (eg, section) []:IV
Common Name (eg, your name or your server's hostname) []:registry.ivixq.com
Email Address []:admin@ivixq.com
# 证书和私钥文件
ll ssl/
total 8
-rw-r--r-- 1 root root 2074 Mar 13 10:14 ivixq.com.crt
-rw-r--r-- 1 root root 3272 Mar 13 10:14 ivixq.com.key
重新启动容器
# 删除刚才启动的registry,加上REGISTRY_HTTP_TLS_CERTIFICATE、REGISTRY_HTTP_TLS_KEY环境变量,支持证书
docker rm -f registry
docker run -d -p 4000:5000 --restart=always --name registry \
-v /mydata/registry/conf/config.yml:/etc/docker/registry/config.yml \
-v /mydata/registry/data:/var/lib/registry \
-v /etc/ssl:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/ivixq.com.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/ivixq.com.key \
docker.io/registry:latest
# 证书不支持IP地址,必须使用域名进行申请,故签名域名为registry.ivixq.com
,编辑/etc/hosts
文件,添加域名解析
vim /etc/hosts
10.1.1.40 registry.ivixq.com
# registry打tag,并push
docker tag 047218491f8c registry.ivixq.com:4000/registry
docker push registry.ivixq.com:4000/registry
The push refers to a repository [registry.ivixq.com:4000/registry]
Get https://registry.ivixq.com:4000/v1/_ping: x509: certificate signed by unknown authority
又有报错信息Get https://registry.ivixq.com:4000/v1/_ping: x509: certificate signed by unknown authority
,docker client认为registry传过来证书由一个未知的授权机构签署的证书,验证失败。
解决方法:
为docker client安装证书,前面我们创建了自签名证书,将自签名的证书拷贝到docker client目录的下/etc/docker/certs.d/
注意:存放证书的文件夹名称必须是证书中的域名+registry的端口号
# 建立目录
mkdir -pv /etc/docker/certs.d/registry.ivixq.com:4000
# 拷贝证书
cp /etc/ssl/ivixq.com.crt /etc/docker/certs.d/registry.ivixq.com:4000/ivixq.com.crt
# 重启docker
systemctl restart docker
# 再次push
docker push registry.ivixq.com:4000/registry
The push refers to a repository [registry.ivixq.com:4000/registry]
0912b310db10: Pushed
6767cac03a2d: Pushed
f38182d44088: Pushed
b5aac7bb5fdf: Pushed
9f8566ee5135: Pushed
latest: digest: sha256:437df2cf9a6553a91552f716e7b51f696e98aae6e961bf74e113b0363e913480 size: 1364
终于push成功了。
注意:其他docker主机要使用这个自建registry,也需要为docker client导入证书
在其他HOST使用自建registry
# 在其他host上直接pull,会发生报错
docker pull 10.1.1.40:4000/registry:v2
Trying to pull repository 10.1.1.40:4000/registry ...
Get https://10.1.1.40:4000/v1/_ping: x509: cannot validate certificate for 10.1.1.40 because it doesn't contain any IP SANs
# 添加域名解析,再pull,还会报错
vim /etc/hosts
10.1.1.40 registry.ivixq.com
docker pull registry.ivixq.com:4000/registry:v2
Trying to pull repository registry.ivixq.com:4000/registry ...
Get https://registry.ivixq.com:4000/v1/_ping: x509: certificate signed by unknown authority
# 添加证书,重启docker服务后,再pull,成功
mkdir -pv /etc/docker/certs.d/registry.ivixq.com:4000
scp /etc/docker/certs.d/registry.ivixq.com\:4000/ivixq.com.crt root@10.1.1.50:/etc/docker/certs.d/registry.ivixq.com\:4000/
systemctl restart docker
docker pull registry.ivixq.com:4000/registry
Using default tag: latest
Trying to pull repository registry.ivixq.com:4000/registry ...
latest: Pulling from registry.ivixq.com:4000/registry
12a7970a6783: Pull complete
bb9291d659e1: Pull complete
c71426f9b69b: Pull complete
2e70e7c5f4fd: Pull complete
267774bac577: Pull complete
Digest: sha256:437df2cf9a6553a91552f716e7b51f696e98aae6e961bf74e113b0363e913480
# 查看images,发现image已经下载到本地
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.ivixq.com:4000/registry latest 047218491f8c 9 days ago 33.17 MB
这样一个本地的registry服务就可以正常使用了,但是如此任何人都可以任意访问私有仓库的images,这样不安全,我想只有授权的用户才能访问pull和push。
我这里使用nginx反向代理client的请求,并用nginx的basic认证来限定用户的访问
删除刚才启动的registry
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
84995f349ade docker.io/registry:latest "/entrypoint.sh /etc/" 17 hours ago Up 15 hours 0.0.0.0:4000->5000/tcp registry
docker rm -f registry
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
创建启动新容器
docker run -d -p 4000:5000 --restart=always --name registry \
-v /mydata/registry/conf/config.yml:/etc/docker/registry/config.yml \
-v /mydata/registry/data:/var/lib/registry \
docker.io/registry:latest
打tag,push
docker tag c981855ea126 127.0.0.1:4000/centos:lasest
docker tag push 127.0.0.1:4000/centos:lasest
Error response from daemon: no such id: push
[root@cinder ~]# docker push 127.0.0.1:4000/centos:lasest
The push refers to a repository [127.0.0.1:4000/centos]
34e7b85d83e4: Pushed
lasest: digest: sha256:c5c9a0dd49f7a06ba7c298c498f310924d567b33c8e9bcb97c32ab89a448b3e6 size: 529
可以看出我们这次push的地址127.0.0.1
,成功push,如果换成10.1.1.40
呢?
docker tag c981855ea126 10.1.1.40:4000/centos:lasest
[root@cinder ~]# docker push 10.1.1.40:4000/centos:lasest
The push refers to a repository [10.1.1.40:4000/centos]
Get https://10.1.1.40:4000/v1/_ping: http: server gave HTTP response to HTTPS client
可以看出使用10.1.1.40
地址会报错,和最开始时的报错信息相同,也就是说如果没有证书,是无法从远程主机push和pull的,但是使用127.0.0.1的地址就可以,
# 安装nginx
yum install niginx
# 重新生成自签证书
mkdir -pv /etc/nginx/ssl
cd /etc/nginx/ssl
openssl req -newkey rsa:4096 -nodes -sha256 -keyout iflys.cn.key -x509 -days 365 -out iflys.cn.crt
Generating a 4096 bit RSA private key
.........................................++
..................................................................++
writing new private key to 'iflys.cn.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) []:GD
Locality Name (eg, city) [Default City]:GZ
Organization Name (eg, company) [Default Company Ltd]:GZ
Organizational Unit Name (eg, section) []:GZ
Common Name (eg, your name or your server's hostname) []:www.iflys.cn
Email Address []:admin@iflys.cn
# 在nginx.conf中配置全局参数
vim nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
# 配置虚拟主机
vim /etc/nginx/conf.d/registry.conf
upstream registry {
server 127.0.0.1:4000;
}
server {
listen 443;
server_name www.iflys.cn;
ssl on;
ssl_certificate /etc/nginx/ssl/iflys.cn.crt;
ssl_certificate_key /etc/nginx/ssl/iflys.cn.key;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_ciphers 'EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5';
#ssl_stapling on;
#ssl_stapling_verify on;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
chunked_transfer_encoding on; # required to avoid HTTP 411
location /v2/ {
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;
proxy_pass http://registry;
proxy_set_header Host $http_host; # required for docker client‘s sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client‘s IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
auth_basic "Registry realm";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
}
}
# 生成dhparam.pem文件
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
# 生成密码文件
yum install httpd-tools
htpasswd -cb /etc/nginx/conf.d/.htpasswd admin admin
# 重启nginx服务
nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx -s reload
# 添加域名解析
vim /etc/hosts
10.1.1.40 www.iflys.cn
验证服务
# 登录成功
curl -i -k https://admin:admin@www.iflys.cn/v2/
HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Tue, 14 Mar 2017 09:28:14 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2
Connection: keep-alive
Docker-Distribution-Api-Version: registry/2.0
X-Content-Type-Options: nosniff
Docker-Distribution-Api-Version: registry/2.0
HTTP/1.1 200 OK
验证成功
# 直接tag,push
docker tag c981855ea126 www.iflys.cn/centos:latest
docker push www.iflys.cn/centos:latest
The push refers to a repository [www.iflys.cn/centos]
Get https://www.iflys.cn/v1/_ping: x509: certificate signed by unknown authority
有报错信息,也是因为无法验证registry发来的证书,我们需要给docker daemon设置一个证书
# 拷贝证书
mkdir /etc/docker/certs.d/www.iflys.cn
cp /etc/nginx/ssl/iflys.cn.crt /etc/docker/certs.d/www.iflys.cn/
# 重启服务
systemctl restart docker
直接push
docker push www.iflys.cn/centos:latest
docker push www.iflys.cn/centos:latest
The push refers to a repository [www.iflys.cn/centos]
no basic auth credentials
提示没有认证的凭据
我们登录一下
docker login https://www.iflys.cn/v2/
Username: admin
Password:
Login Succeeded
再push
docker push www.iflys.cn/centos:latest
The push refers to a repository [www.iflys.cn/centos]
0912b310db10: Pushed
6767cac03a2d: Pushed
f38182d44088: Layer already exists
b5aac7bb5fdf: Pushed
9f8566ee5135: Pushed
latest: digest: sha256:437df2cf9a6553a91552f716e7b51f696e98aae6e961bf74e113b0363e913480 size: 1364
哈,终于push成功了。
那么用户的认证信息保存在什么位置呢?当登录成功后,会在用户的家目录下面建立一个.docker文件夹并在该文件夹下有一个config.json,在这个文件内保存用户的凭据
cat .docker
.docker/ .docker.bak/
[root@cinder ~]# cat .docker/config.json
{
"auths": {
"https://www.iflys.cn/v2/": {
"auth": "YWRtaW46YWRtaW4="
}
}
}
重新创建一个用户
htpasswd -m /etc/nginx/conf.d/.htpasswd yxq
New password:
Re-type new password:
Adding password for user yxq
查看用户的密码
cat /etc/nginx/conf.d/.htpasswd
admin:$apr1$9i03xbwl$FPxFrmTX3d.93lvPVqZbx0
yxq:$apr1$Dw1tr.qw$KvONLqO.S5Zpa6Rm5O6Xk0
重新登录
docker login https://www.iflys.cn/v2/
Username (admin): yxq
Password:
Login Succeeded
再tag,push一个image
docker tag 6b914bbcb89e www.iflys.cn/nginx:latest
docker pull www.iflys.cn/nginx:latest
Trying to pull repository www.iflys.cn/nginx ...
latest: Pulling from www.iflys.cn/nginx
Digest: sha256:7f9c22c6b2ba14c609588a794fb40366c5d1eea2c70b8bb7474583994dab9e70
再查看用户的凭据
cat .docker/config.json
{
"auths": {
"https://www.iflys.cn/v2/": {
"auth": "eXhxOnRvbnk="
}
}
}
最后,如果其他docker主机需要使用registry,必须将ca证书放置在/etc/dokcer/certs.d/yourdomain/
目录下,然后重新启动docker。
至此registry就安装完毕。