1. Docker Registry 说明
关于如何创建和使用本地仓库,其实已经有很多文章介绍了。因为docker技术正处于发展和完善阶段,所以有些文章要么内容已经过时,要么给出了错误的配置,导致无法正常创建仓库。本文记录的是个人完整的搭建过程, docker version
为1.1.2。
官方提供了 Docker Hub 网站来作为一个公开的集中仓库。然而,本地访问Docker Hub速度往往很慢,并且很多时候我们需要一个本地的私有仓库只供网内使用。
Docker仓库实际上提供两方面的功能,一个是镜像管理,一个是认证。前者主要由docker-registry 项目来实现,通过http服务来上传下载;后者可以通过docker-index(闭源)项目或者利用现成认证方案(如nginx)实现http请求管理。
docker-registry既然也是软件应用,自然最简单的方法就是使用官方提供的已经部署好的镜像registry。官方文档中也给出了建议,直接运行 sudo docker run -p 5000:5000 registry
命令。这样确实能启动一个registry服务器,但是所有上传的镜像其实都是由docker容器管理,放在了/var/lib/docker/....某个目录下。而且一旦删除容器,镜像也会被删除。因此,我们需要想办法告诉docker容器镜像应该存放在哪里。registry镜像中启动后镜像默认位置是 /tmp/registry
,因此直接映射这个位置即可,比如到本机的 /opt/data/registry
目录下。
2. 在CentOS上搭建docker私服
安装 docker-registry
的方法有多种。
直接运行下面的命令:
# docker run -d -e SETTINGS_FLAVOR=dev -e STORAGE_PATH=/tmp/registry -v /opt/data/registry:/tmp/registry -p 5000:5000 registry
# docker run -d -e SETTINGS_FLAVOR=dev -e STORAGE_PATH=/tmp/registry -v /opt/data/registry:/tmp/registry -p 5000:5000 registry
如果本地没有拉取过docker-registry,则首次运行会pull registry,运行时会映射路径和端口,以后就可以从 /opt/data/registry
下找到私有仓库都存在哪些镜像,通过主机的哪个端口可以访问。
你也可以把项目 https://github.com/docker/docker-registry.git 克隆到本地,然后使用Dockerfile来build镜像:
# git clone https://github.com/docker/docker-registry.git
# cd docker-registry && mkdir -p /opt/data/registry
# docker build -t "local-sean" .
build完成后,就可以运行这个docker-registry
我们先配置自己的config.yml文件,第一种方法是直接在run的时候指定变量
# cp config/config_sample.yml /opt/data/registry/config.yml
# vi /opt/data/registry/config.yml
##这里可以设置本地存储SETTINGS_FLAVOR=dev,local STORAGE_PATH:/tmp/registry等待
# docker run -d -v /opt/data/registry:/tmp/registry -p 5000:5000 -e DOCKER_REGISTRY_CONFIG=/tmp/registry/config.yml registry
或
docker run -d -e SETTINGS_FLAVOR=dev -e STORAGE_PATH=/tmp/registry -v /db/docker-images:/tmp/registry -p 5000:5000 registry
# git clone https://github.com/docker/docker-registry.git
# cd docker-registry && mkdir -p /opt/data/registry
# docker build -t "local-sean" .
build完成后,就可以运行这个docker-registry
我们先配置自己的config.yml文件,第一种方法是直接在run的时候指定变量
# cp config/config_sample.yml /opt/data/registry/config.yml
# vi /opt/data/registry/config.yml
##这里可以设置本地存储SETTINGS_FLAVOR=dev,local STORAGE_PATH:/tmp/registry等待
# docker run -d -v /opt/data/registry:/tmp/registry -p 5000:5000 -e DOCKER_REGISTRY_CONFIG=/tmp/registry/config.yml registry
或
docker run -d -e SETTINGS_FLAVOR=dev -e STORAGE_PATH=/tmp/registry -v /db/docker-images:/tmp/registry -p 5000:5000 registry
2.2 客户端使用
要从私服上获取镜像或向私服提交镜像,现在变得非常简单,只需要在仓库前面加上私服的地址和端口,形如 172.29.88.222:5000/centos6
。注意,这里可以选择不使用IP,而是用hostname,如registry.example.com:5000,但不能仅用不带 .
的主机名registry,docker会认为registry是用户名,建议使用带域名的hostname加port来表示。
于是在另外一台要使用docker的主机上就可以通过这台私服拉取和推送镜像了:
从私服上搜索存在哪些可用镜像
# curl -X GET http://sean.example.com:5000/v1/search
{"num_results": 2, "query": "", "results": [{"description": "", "name": "library/centos6"}, {"description": "", "name": "library/nginx"}]}
按条件搜索nginx
# curl -X GET http://sean.example.com:5000/v1/search?q=centos6
拉取image到本地
docker pull library/centos6
## 本地对份镜像启动起来,形成container
## 给container去另外一个名字
# docker tag 68edf809afe7 registry.example.com:5000/centos6-test
## 最后将新的docker images推送到私服上
docker push registry.example.com:5000/centos6-test
第一次push到私服上时会提示用户名、密码和邮箱,创建即可。也可以在docker私服端加入认证机制。
3. 加入nginx认证
3.1 安装及配置nginx
从上面的过程可以看到,除非防火墙限制,否则任何主机可以创建账号并想私服推送镜像,更安全的做法是在外层加入登录认证机制。
最好安装1.4.x版本,不然下面的有些配置可能会不兼容
# yum install nginx
创建两个登录用户
# htpasswd -c /etc/nginx/docker-registry.htpasswd sean
New password:
Re-type new password:
Adding password for user sean
# htpasswd -c /etc/nginx/docker-registry.htpasswd itsection
最好安装1.4.x版本,不然下面的有些配置可能会不兼容
# yum install nginx
创建两个登录用户
# htpasswd -c /etc/nginx/docker-registry.htpasswd sean
New password:
Re-type new password:
Adding password for user sean
# htpasswd -c /etc/nginx/docker-registry.htpasswd itsection
为了让nginx使用这个密码文件,并且转发8080端口的请求到Docker Registry,新增nginx配置文件
vi /etc/nginx/sites-enabled/docker-registry
:
# For versions of Nginx > 1.3.9 that include chunked transfer encoding support
# Replace with appropriate values where necessary
upstream docker-registry {
server localhost:5000;
}
server {
listen 8080;
server_name sean.example.com; -- your registry server_name
# ssl on;
# ssl_certificate /etc/ssl/certs/docker-registry;
# ssl_certificate_key /etc/ssl/private/docker-registry;
proxy_set_header Host $http_host; # required for Docker client sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client IP
client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads
# required to avoid HTTP 411: see Issue #1486 (https://github.com/dotcloud/docker/issues/1486)
chunked_transfer_encoding on;
location / {
# let Nginx know about our auth file
auth_basic "Restricted";
auth_basic_user_file docker-registry.htpasswd;
proxy_pass http://docker-registry;
}
location /_ping {
auth_basic off;
proxy_pass http://docker-registry;
}
location /v1/_ping {
auth_basic off;
proxy_pass http://docker-registry;
}
}
# For versions of Nginx > 1.3.9 that include chunked transfer encoding support
# Replace with appropriate values where necessary
upstream docker-registry {
server localhost:5000;
}
server {
listen 8080;
server_name sean.example.com; -- your registry server_name
# ssl on;
# ssl_certificate /etc/ssl/certs/docker-registry;
# ssl_certificate_key /etc/ssl/private/docker-registry;
proxy_set_header Host $http_host; # required for Docker client sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client IP
client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads
# required to avoid HTTP 411: see Issue #1486 (https://github.com/dotcloud/docker/issues/1486)
chunked_transfer_encoding on;
location / {
# let Nginx know about our auth file
auth_basic "Restricted";
auth_basic_user_file docker-registry.htpasswd;
proxy_pass http://docker-registry;
}
location /_ping {
auth_basic off;
proxy_pass http://docker-registry;
}
location /v1/_ping {
auth_basic off;
proxy_pass http://docker-registry;
}
}
让nginx来使用这个virtual-host
# ln -s /etc/nginx/sites-enabled/docker-registry /etc/nginx/conf.d/docker-registry.conf
重启nginx来激活虚拟主机的配置
# service nginx restart
3.2 加入认证后使用docker-registry
此时主机的5000端口应该通过防火墙禁止访问(或者在 docker run
端口映射时只监听回环接口的IP -p 127.0.0.1:5000:5000
)。
# curl localhost:5000
"docker-registry server (dev) (v0.8.1)"
如果直接访问访问将得到未授权的信息:
# curl localhost:8080
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.4.7</center>
</body>
</html>
带用户认证的docker-registry:
# curl http://sean:sean@sean.example.com:8080/v1/search
{"num_results": 2, "query": "", "results": [{"description": "", "name": "library/centos6"}, {"description": "", "name": "library/nginx"}]}
# docker login registry.example.com:8080
Username: sean
Password:
Email: zhouxiao@example.com
Login Succeeded
# docker pull registry.example.com:8080/library/centos6
# curl http://sean:sean@sean.example.com:8080/v1/search
{"num_results": 2, "query": "", "results": [{"description": "", "name": "library/centos6"}, {"description": "", "name": "library/nginx"}]}
# docker login registry.example.com:8080
Username: sean
Password:
Email: zhouxiao@example.com
Login Succeeded
# docker pull registry.example.com:8080/library/centos6
另外还可以加入SSL来加密连接,如有需要见参考[1]部分。
TO-DO:
上面的 docker pull
可能会出现 问题(3)
,暂未解决。
3.3 问题
(1) docker后台进程意外中断后,重新 docker start <container_id>
报错
# docker start b36bd796bd3d
Error: Cannot start container b36bd796bd3d: Error getting container b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652
from driver devicemapper: Error mounting '/dev/mapper/docker-253:0-787676-b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652'
on '/var/lib/docker/devicemapper/mnt/b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652': device or resource busy
2014/11/08 15:14:57 Error: failed to start one or more containers
# docker start b36bd796bd3d
Error: Cannot start container b36bd796bd3d: Error getting container b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652
from driver devicemapper: Error mounting '/dev/mapper/docker-253:0-787676-b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652'
on '/var/lib/docker/devicemapper/mnt/b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652': device or resource busy
2014/11/08 15:14:57 Error: failed to start one or more containers
经分析产生这个问题的原因是做了一个操作:在docker后台进程启动的终端,继续回车后会临时退出后台进程的日志输出,我就在这个shell下使用yum安装软件包,但由于网络原因yum卡住不动,于是我就另起了一个终端kill了这个yum进程,不知为何会影响到表面已经退出前台输出的docker。解决办法是umount容器的挂载点:(见 这里 )
# umount /var/lib/docker/devicemapper/mnt/b36bd796bd3d463c4fedb70d98621e7318ec3d5cd14b2f60b1d182ad3cbcc652
# service docker start 正常
能想到的另外一个办法是,启动docker后台进程时,重定向输出 docker -d > /dev/null 2>&1
(/var/log/docker已自动记录了一份日志)。
(2) 配置完nginx的docker-registry.conf后启动报错
# service nginx start
[emerg] 14714#0: unknown directive "upstream" in /etc/nginx/conf.d/docker-registry.conf:4
# service nginx start
[emerg] 14714#0: unknown directive "upstream" in /etc/nginx/conf.d/docker-registry.conf:4
原因是nginx版本太低,一些配置指令不兼容,使用 yum install nginx
默认安装了1.0.x,卸载重新下载 nginx-1.4.7-1.el6.ngx.x86_64.rpm
安装解决。
(3) 加入nginx认证以后,pull出现下面的问题
# docker pull registry.example.com:8080/library/centos6
Pulling repository registry.example.com:8080/library/centos6
2014/11/11 21:00:25 Could not reach any registry endpoint
# docker push registry.example.com:8080/ubuntu:sean
The push refers to a repository [registry.example.com:8080/ubuntu] (len: 1)
Sending image list
Pushing repository registry.example.com:8080/ubuntu (1 tags)
2014/11/12 08:11:32 HTTP code 401, Docker will not send auth headers over HTTP.
nginx日志
2014/11/12 07:03:49 [error] 14898#0: *193 no user/password was provided for basic
authenticatGET /v1/repositories/library/centos6/tags HTTP/1.1", host: "registry.example.com:8080"
查过一些资料但没有一个定论,又看到说继续安装SSL,通过https来访问便正常。