搭建docker内网私服的方法(docker-registry with nginx&ssl on centos)

本文介绍了搭建docker内网私服的方法,分享给大家。具体如下:

主要思路:

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私服

2.1 安装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-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

2.2 客户端使用

要从私服上获取镜像或向私服提交镜像,现在变得非常简单,只需要在仓库前面加上私服的地址和端口,形如172.29.88.222:5000/centos6。注意,这里可以选择不使用IP,而是用hostname,如registry.domain.com:5000,但不能仅用不带.的主机名registry,docker会认为registry是用户名,建议使用带域名的hostname加port来表示。

于是在另外一台要使用docker的主机上就可以通过这台私服拉取和推送镜像了:

从私服上搜索存在哪些可用镜像

代码如下:

# curl -X GET http://sean.domain.com:5000/v1/search
{"num_results": 2, "query": "", "results": [{"description": "", "name": "library/centos6"}, {"description": "", "name": "library/nginx"}]}

按条件搜索nginx

# curl -X GET http://sean.domain.com:5000/v1/search?q=centos6

拉取image到本地

docker pull library/centos6

## 本地对份镜像启动起来,形成container
## 给container去另外一个名字
# docker tag 68edf809afe7 registry.domain.com:5000/centos6-test

## 最后将新的docker images推送到私服上
docker push registry.domain.com:5000/centos6-test

第一次push到私服上时会提示用户名、密码和邮箱,创建即可。也可以在docker私服端加入认证机制。

3. 加入nginx认证

(请在实际操作以前,先阅读完本节,再确定是否在前端加入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 /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.domain.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.domain.com:8080/v1/search
{"num_results": 2, "query": "", "results": [{"description": "", "name": "library/centos6"}, {"description": "", "name": "library/nginx"}]}

# docker login registry.domain.com:8080
Username: sean
Password:
Email: zhouxiao@domain.com
Login Succeeded

# docker pull registry.domain.com:8080/library/centos6

不出意外的话,上面的docker pull会失败:

# docker pull registry.domain.com:8080/library/centos6
Pulling repository registry.domain.com:8080/library/centos6
2014/11/11 21:00:25 Could not reach any registry endpoint

# docker push registry.domain.com:8080/ubuntu:sean
The push refers to a repository [registry.domain.com:8080/ubuntu] (len: 1)
Sending image list
Pushing repository registry.domain.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.domain.com:8080"

本文后的第1篇参考文档没有出现这个问题,但评论中有提及。

有人说是backend storage的问题,这里是本地存储镜像,不应该。经过查阅大量资料,并反复操作验证,是docker-registry版本的问题。从v0.10.0开始,docker login虽然Succeeded,但pull或push的时候,~/.dockercfg下的用户登录信息将不允许通过HTTP明文传输。(如果你愿意可以查看v0.10.0的源码 registry.go,在分支v0.9.1及以前是没有HTTP code 401, Docker will not send auth headers over HTTP的)

目前的办法三个:

  1. 撤退,这就是为什么先说明在操作前线查看到这的原因了
  2. 换成v0.9.1及以下版本。现在都v1.3.1了,我猜你不会这么做
  3. 修改源码session.go,去掉相应的判断行,然后git下来重新安装。我猜你更不会这么做
  4. 安装SSL证书,使用HTTPS传输。这是明智的选择,新版本docker也推荐我们这么做,往下看。

3.3 为nginx安装ssl证书

首先打开nginx配置文件中ssl的三行注释

# vi /etc/nginx/conf.d/docker-registry.conf
...
server {
 listen 8000;
 server_name registry.domain.com;

 ssl on;
 ssl_certificate /etc/nginx/ssl/nginx.crt;
 ssl_certificate_key /etc/nginx/ssl/nginx.key;
...

保存之后,nginx会分别从/etc/nginx/ssl/nginx.crt和/etc/nginx/ssl/nginx.key读取ssl证书和私钥。如果你自己愿意花钱买一个ssl证书,那就会变得非常简单,把证书和私钥拷贝成上面一样即可。关于SSL以及签署ssl证书,请参考其他文章。

这里我们自签署一个ssl证书,把当前系统作为(私有)证书颁发中心(CA)。

创建存放证书的目录

# mkdir /etc/nginx/ssl
确认CA的一些配置文件

# vi /etc/pki/tls/openssl.cnf
...
[ CA_default ]

dir    = /etc/pki/CA   # Where everything is kept
certs   = $dir/certs   # Where the issued certs are kept
crl_dir   = $dir/crl    # Where the issued crl are kept
database  = $dir/index.txt  # database index file.
#unique_subject = no     # Set to 'no' to allow creation of
          # several ctificates with same subject.
new_certs_dir = $dir/newcerts   # default place for new certs.

certificate  = $dir/cacert.pem  # The CA certificate
serial   = $dir/serial   # The current serial number
crlnumber  = $dir/crlnumber  # the current crl number
          # must be commented out to leave a V1 CRL
crl    = $dir/crl.pem   # The current CRL
private_key  = $dir/private/cakey.pem # The private key
RANDFILE  = $dir/private/.rand # private random number file
...
default_days = 3650     # how long to certify for
...
[ req_distinguished_name ]
countryName      = Country Name (2 letter code)
countryName_default    = CN
countryName_min     = 2
countryName_max     = 2

stateOrProvinceName    = State or Province Name (full name)
stateOrProvinceName_default  = GD
...[ req_distinguished_name ]部分主要是颁证时一些默认的值,可以不动

(1) 生成根密钥

# cd /etc/pki/CA/
# openssl genrsa -out private/cakey.pem 2048

为了安全起见,修改cakey.pem私钥文件权限为600或400,也可以使用子shell生成( umask 077; openssl genrsa -out private/cakey.pem 2048 ),下面不再重复。

(2) 生成根证书

# openssl req -new -x509 -key private/cakey.pem -out cacert.pem

会提示输入一些内容,因为是私有的,所以可以随便输入,最好记住能与后面保持一致。上面的自签证书cacert.pem应该生成在/etc/pki/CA下。

(3) 为我们的nginx web服务器生成ssl密钥

# cd /etc/nginx/ssl
# openssl genrsa -out nginx.key 2048

我们的CA中心与要申请证书的服务器是同一个,否则应该是在另一台需要用到证书的服务器上生成。

(4) 为nginx生成证书签署请求

 # openssl req -new -key nginx.key -out nginx.csr
...
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:GD
Locality Name (eg, city) []:SZ
Organization Name (eg, company) [Internet Widgits Pty Ltd]:COMPANY
Organizational Unit Name (eg, section) []:IT_SECTION
Common Name (e.g. server FQDN or YOUR name) []:your.domain.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
...

同样会提示输入一些内容,其它随便,除了Commone Name一定要是你要授予证书的服务器域名或主机名,challenge password不填。

(5) 私有CA根据请求来签发证书

# openssl ca -in nginx.csr -out nginx.crt

上面签发过程其实默认使用了-cert cacert.pem -keyfile cakey.pem,这两个文件就是前两步生成的位于/etc/pki/CA下的根密钥和根证书。

到此我们已经拥有了建立ssl安全连接所需要的所有文件,并且服务器的crt和key都位于配置的目录下,唯有根证书cacert.pem位置不确定放在CentOS6下的哪个地方。

经验证以下几个位置不行:(Adding trusted root certificates to the server
/etc/pki/ca-trust/source/anchors、/etc/pki/ca-trust/source、/etc/pki/ca-trust/extracted、
/etc/pki/ca-trust/extracted/pem/、/etc/pki/tls/certs/cacert.crt

都会报错:

# docker login https://registry.domain.com:8000
Username (sean): sean
2014/11/14 02:32:48 Error response from daemon: Invalid Registry endpoint: Get https://registry.domain.com:8000/v1/_ping: x509: certificate signed by unknown authority

# curl https://sean:sean@registry.domain.com:8000/
curl: (60) Peer certificate cannot be authenticated with known CA certificates
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

(6) 目前让根证书起作用的只发现一个办法:

# cp /etc/pki/tls/certs/ca-bundle.crt{,.bak} 备份以防出错
# cat /etc/pki/CA/cacert.pem >> /etc/pki/tls/certs/ca-bundle.crt

# curl https://sean:sean@registry.domain.com:8000
"docker-registry server (dev) (v0.8.1)"

cacert.pem根证书追加到ca-bundle.crt后一定要重启docker后台进程才行。

如果docker login依然报错certificate signed by unknown authority,参考Running Docker with https,启动docker后台进程时指定信任的CA根证书:

 # docker -d --tlsverify --tlscacert /etc/pki/CA/cacert.pem

或者将cacert.pem拷贝到~/.docker/ca.pem
# mkdir ~/.docker && cp /etc/pki/CA/cacert.pem ~/.docker/ca.pem
# docker -d
最好重启一下registry
# docker restart <registry_container_id>

上面用“如果”是因为一开始总提示certificate signed by unknown authority,有人说将根证书放在/etc/docker/certs.d下,还有人说启动docker daemon收加入--insecure-registry .. 但终究是因为版本差异不成功。但后来又奇迹般的不需要--tlscacert就好了。
这个地方挣扎了很久,重点关注一下这个下面几个issue:

  1. https://github.com/docker/docker-registry/issues/82
  2. https://github.com/docker/docker/pull/2687
  3. https://github.com/docker/docker/pull/2339

(7) 最终搞定:

# docker login https://registry.domain.com:8000
Username: sean
Password:
Email: zhouxiao@domain.com
Login Succeeded

# curl https://sean:sean@registry.domain.com:8000
"docker-registry server (dev) (v0.8.1)"

# docker push registry.domain.com:8000/centos6:test_priv
The push refers to a repository [registry.domain.com:8000/centos6] (len: 1)
Sending image list
Pushing repository registry.domain.com:8000/centos6 (1 tags)
511136ea3c5a: Image successfully pushed
5b12ef8fd570: Image successfully pushed
68edf809afe7: Image successfully pushed
40627956f44c: Image successfully pushed
Pushing tag for rev [40627956f44c] on {https://registry.domain.com:8000/v1/repositories/centos6/tags/test_priv}

但还有一个小问题没解决,虽然已经可以正常使用,但每次请求在nginx的error.log中还是会有[error] 8299#0: *27 no user/password was provided for basic authentication,应该是这个版本docker暂未解决的bug。

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后台进程启动的终端,继续回车后会临时退出后台进程的日志输出,我就在这个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

原因是nginx版本太低,一些配置指令不兼容,使用yum install nginx默认安装了1.0.x,卸载重新下载nginx-1.4.7-1.el6.ngx.x86_64.rpm安装解决。

(3) 网络设置代理问题

pull, push官网的镜像时由于GFW的原因需要设置代理,但不是http_proxy而是HTTP_PROXY,对于docker来说同时设置这两个值就会出问题,有时出于安装软件包的需要设置http_proxy,就会导致冲突。在docker-registry中如果忘记了当前哪一个在起作用,找遍所有问题都发现不了原因,而docker返回给我们的错误也难以判断。切记~

TO-DO
如何删除docker-registry的里的镜像

4. 参考

部署自己的私有 Docker Registry [英文]
Official docker-registry README
How To Set Up a Private Docker Registry on Ubuntu 14.04
The Docker Hub and the Registry spec

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Centos7下安装与卸载docker应用容器引擎的方法

    Docker 是一个开源的应用容器引擎,基于Go 语言并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. 容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低. Docker的应用场景 Web 应用的自动化打包和发布. 自动化测试和持续集成.发布. 在服务型环境中部署和调整数据库或其他的后台应用. 从头编译或者扩展现

  • centos7更改docker仓库的方法

    我们知道,大多数情况下,我们安装完docker之后,会直接去启动docker,这种情况一般也没什么问题,但是和github一样,如果使用官方的仓库,服务器在国外,由于qiang的原因,不是很稳定,于是,我们可以将仓库改成国内的,比如阿里的,下面来介绍下如何去更改配置文件 首先进入到路径/lib/systemd/system下,直接vim docker.service 进入编辑该配置文件,然后找到ExecStart这项,将阿里云的加速器地址拷贝到截图这个地方 --registry-mirror=h

  • Centos7+Docker+Jenkins+ASP.NET Core 2.0自动化发布与部署的实现

    前言 Docker一直很火热,一直想把原本的Jenkins自动部署工具搬到Docker上面,无奈今年一直忙于各种事情,迟迟未实施这个事情,正好迎来了dotnet core 2.0 的正式发布,升级项目的同时,顺便直接将Jenkins搬到Docker上.为什么要写这篇文章呢?因为找过相关的资料,大多数文章都是基于Ubuntu 安装.net core 又或者 GitLab 进行持续集成 自动部署等等等,并未有人尝试过Centos7.3 上部署 Jenkins 并且 构建 ASP.NET CORE 2

  • CentOS版本问题安装Docker报错的解决方案

    1. 版本信息 # cat /etc/system-release CentOS Linux release 7.2.1511 (Core) # uname -a Linux k8s-daniel-3 3.10.0-327.28.3.el7.x86_64 #1 SMP Thu Aug 18 19:05:49 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux 2. Docker的安装和错误 直接使用yum -y install docker进行安装, 然后无法启动.

  • CentOS7虚拟机安装并配置docker套件

    CentOS7比ubuntu的一键式安装要稍微复杂一些, 有些小伙伴按照下一步, 下一步的套路安装完成, 发现没有图像化界面, 在纯粹的命令行里面, 很多小伙伴是不适应的, 这里我把centos7在vmware里面的安装过程记录一下, 没有centos7安装经验的小伙伴可以参考一下 1. 打开vmware, 创建虚拟机, 选择光盘, 下一步 2. 选择传统BIOS 3.自定设置 4.选择存储虚拟机的位置,存储 5. 自定义内存为2G, 磁盘为40GB 6. 开机,选择install CentOS

  • CentOS7.2服务器上搭建Docker私有镜像仓库操作示例

    本文实例讲述了CentOS7.2服务器上搭建Docker私有镜像仓库操作.分享给大家供大家参考,具体如下: 鉴于国内pull镜像的速度较慢,很有必要搭建docker私有或者本地镜像仓库. 安装docker # yum -y install docker # systemctl start docker && systemctl enable docker 使用自签名进行安全认证 创建存放证书和密钥的certs目录 # mkdir -p /docker/certs # chcon -Rt s

  • centos 下docker 安装方法

    这里只介绍比较简易的安装方式: 一.使用yum安装 最好更新一下yum sudo yum update 直接安装 sudo yum install -y docker 此方法最简单,但是版本比较老: sudo docker version Client: Version: 1.13.1 API version: 1.26 Package version: docker-1.13.1-75.git8633870.el7.centos.x86_64 Go version: go1.9.4 Git c

  • Centos7使用docker搭建gitlab服务器

    了解到docker的优点,搭建快,运行要求资源低,最重要的是实现的功能和效果都能达到预期,于是决定使用docker来搭建gitlab服务器. 效果图如下: 系统环境:CentOS Linux release 7.1.1503 (Core) git版本:/gitlab/gitlab-ce 一.安装和启动docker 安装:yum -y install docker 启动:systemctl start docker 开机启动:systemctl enable docker 二.拉取镜像文件 doc

  • Centos7上安装docker的方法

    Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如经过官方测试认证过的基础设施.容器.插件等. 社区版按照stable和edge两种方式发布,每个季度更新stable版本,如17.06,17.09:每个月份更新edge版本,如17.09,17.10.  一.安装docker 1.Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的Cent

  • CentOS 7上安装Docker 1.8 的步骤详解

    Docker支持运行在以下CentOS版本: •CentOS 7.X 安装在二进制兼容的EL7版本如 Scientific Linux也是可能成功的,但是Docker 没有测试过并且不官方支持. 此文带你通过使用Docker管理的发行包和安装机制来安装.使用这些报能确保你使用最新的Docker版本. 如果你希望使用CentOS管理的包,请阅读你的CentOS文档. 要求 不过你的系统版本是多少,Docker都要求64位.并且当CentOS7时你的内核必须不小于3.10. 检查当前内核版本: #

随机推荐