溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何通過自己build構(gòu)建docker的私有倉庫

發(fā)布時間:2021-12-13 17:49:51 來源:億速云 閱讀:157 作者:小新 欄目:云計算

這篇文章將為大家詳細講解有關(guān)如何通過自己build構(gòu)建docker的私有倉庫,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

  1. Docker Registry 說明

(注意,我是ubuntu14.04構(gòu)建的,修改過/etc/default/docker文件,添加

 DOCKER_OPTS="$DOCKER_OPTS -- insecure-registry=10.32.170.108:5000",然后service restart docker,可能可以解決https證書錯誤問題。)

關(guān)于如何創(chuàng)建和使用本地倉庫,其實已經(jīng)有很多文章介紹了。因為docker技術(shù)正處于發(fā)展和完善階段,所以有些文章要么內(nèi)容已經(jīng)過時,要么給出了錯誤的配置,導(dǎo)致無法正常創(chuàng)建倉庫。本文記錄的是個人完整的搭建過程,docker version為1.1.2。

官方提供了Docker Hub網(wǎng)站來作為一個公開的集中倉庫。然而,本地訪問Docker Hub速度往往很慢,并且很多時候我們需要一個本地的私有倉庫只供網(wǎng)內(nèi)使用。

Docker倉庫實際上提供兩方面的功能,一個是鏡像管理,一個是認證。前者主要由docker-registry項目來實現(xiàn),通過http服務(wù)來上傳下載;后者可以通過docker-index(閉源)項目或者利用現(xiàn)成認證方案(如nginx)實現(xiàn)http請求管理。

docker-registry既然也是軟件應(yīng)用,自然最簡單的方法就是使用官方提供的已經(jīng)部署好的鏡像registry。官方文檔中也給出了建議,直接運行sudo docker run -p 5000:5000 registry命令。這樣確實能啟動一個registry服務(wù)器,但是所有上傳的鏡像其實都是由docker容器管理,放在了/var/lib/docker/....某個目錄下。而且一旦刪除容器,鏡像也會被刪除。因此,我們需要想辦法告訴docker容器鏡像應(yīng)該存放在哪里。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(此為鏡像名字,上面是local-sean,可修改其tag為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
docker run -d -e SETTINGS_FLAVOR=dev -e STORAGE_PATH=/tmp/registry -v /opt/data/registry:/tmp/registry -p 5000:5000 registry

2.2 客戶端使用

要從私服上獲取鏡像或向私服提交鏡像,現(xiàn)在變得非常簡單,只需要在倉庫前面加上私服的地址和端口,形如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到私服上時會提示用戶名、密碼和郵箱,創(chuàng)建即可。也可以在docker私服端加入認證機制。

3. 加入nginx認證

(請在實際操作以前,先閱讀完本節(jié),再確定是否在前端加入nginx)

3.1 安裝及配置nginx

從上面的過程可以看到,除非防火墻限制,否則任何主機可以創(chuàng)建賬號并想私服推送鏡像,更安全的做法是在外層加入登錄認證機制。

最好安裝1.4.x版本,不然下面的有些配置可能會不兼容
# yum install nginx 創(chuàng)建兩個登錄用戶 # 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使用這個密碼文件,并且轉(zhuǎn)發(fā)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 necessaryupstream 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端口應(yīng)該通過防火墻禁止訪問(或者在docker run端口映射時只監(jiān)聽回環(huán)接口的IP -p 127.0.0.1:5000:5000)。

# curl localhost:5000"docker-registry server (dev) (v0.8.1)"

如果直接訪問訪問將得到未授權(quán)的信息:

# curl localhost:8080<html><head><title>401 Authorization Required</title></head><body bgcolor="white"><center><h2>401 Authorization Required</h2></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:8080Username: seanPassword: Email: zhouxiao@domain.comLogin Succeeded# docker pull registry.domain.com:8080/library/centos6

不出意外的話,上面的docker pull會失?。?/p>

# docker pull registry.domain.com:8080/library/centos6Pulling repository registry.domain.com:8080/library/centos62014/11/11 21:00:25 Could not reach any registry endpoint# docker push registry.domain.com:8080/ubuntu:seanThe 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篇參考文檔沒有出現(xiàn)這個問題,但評論中有提及。
有人說是backend storage的問題,這里是本地存儲鏡像,不應(yīng)該。經(jīng)過查閱大量資料,并反復(fù)操作驗證,是docker-registry版本的問題。從v0.10.0開始,docker login雖然Succeeded,但pullpush的時候,~/.dockercfg下的用戶登錄信息將不允許通過HTTP明文傳輸。(如果你愿意可以查看v0.10.0的源碼 registry.go,在分支v0.9.1及以前是沒有HTTP code 401, Docker will not send auth headers over HTTP的
目前的辦法三個:

  • 撤退,這就是為什么先說明在操作前線查看到這的原因了

  • 換成v0.9.1及以下版本?,F(xiàn)在都v1.3.1了,我猜你不會這么做

  • 修改源碼session.go,去掉相應(yīng)的判斷行,然后git下來重新安裝。我猜你更不會這么做

  • 安裝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證書,那就會變得非常簡單,把證書和私鑰拷貝成上面一樣即可。關(guān)于SSL以及簽署ssl證書,請參考其他文章。
這里我們自簽署一個ssl證書,把當(dāng)前系統(tǒng)作為(私有)證書頒發(fā)中心(CA)。

創(chuàng)建存放證書的目錄

# mkdir /etc/nginx/ssl

確認CA的一些配置文件

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

dir             = /etc/pki/CA           # Where everything is keptcerts           = $dir/certs            # Where the issued certs are keptcrl_dir         = $dir/crl              # Where the issued crl are keptdatabase        = $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 certificateserial          = $dir/serial           # The current serial numbercrlnumber       = $dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRLcrl             = $dir/crl.pem          # The current CRLprivate_key     = $dir/private/cakey.pem # The private keyRANDFILE        = $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                 = 2countryName_max                 = 2stateOrProvinceName             = 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私鑰文件權(quán)限為600或400,也可以使用子shell生成( umask 077; openssl genrsa -out private/cakey.pem 2048 ),下面不再重復(fù)。

(2) 生成根證書

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

會提示輸入一些內(nèi)容,因為是私有的,所以可以隨便輸入,最好記住能與后面保持一致。上面的自簽證書cacert.pem應(yīng)該生成在/etc/pki/CA下。

(3) 為我們的nginx web服務(wù)器生成ssl密鑰

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

我們的CA中心與要申請證書的服務(wù)器是同一個,否則應(yīng)該是在另一臺需要用到證書的服務(wù)器上生成。

(4) 為nginx生成證書簽署請求

# openssl req -new -key nginx.key -out nginx.csr...Country Name (2 letter code) [AU]:CNState or Province Name (full name) [Some-State]:GDLocality Name (eg, city) []:SZOrganization Name (eg, company) [Internet Widgits Pty Ltd]:COMPANYOrganizational Unit Name (eg, section) []:IT_SECTIONCommon Name (e.g. server FQDN or YOUR name) []:your.domain.comEmail Address []:Please enter the following 'extra' attributes
to be sent with your certificate requestA challenge password []:An optional company name []:...

同樣會提示輸入一些內(nèi)容,其它隨便,除了Commone Name一定要是你要授予證書的服務(wù)器域名或主機名,challenge password不填。

(5) 私有CA根據(jù)請求來簽發(fā)證書

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

上面簽發(fā)過程其實默認使用了-cert cacert.pem -keyfile cakey.pem,這兩個文件就是前兩步生成的位于/etc/pki/CA下的根密鑰和根證書。

到此我們已經(jīng)擁有了建立ssl安全連接所需要的所有文件,并且服務(wù)器的crt和key都位于配置的目錄下,唯有根證書cacert.pem位置不確定放在CentOS6下的哪個地方。
經(jīng)驗證以下幾個位置不行:(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:8000Username (sean): sean2014/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.htmlcurl 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) 目前讓根證書起作用的只發(fā)現(xiàn)一個辦法:

# 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就好了。
這個地方掙扎了很久,重點關(guān)注一下這個下面幾個issue:

  • https://github.com/docker/docker-registry/issues/82

  • https://github.com/docker/docker/pull/2687

  • https://github.com/docker/docker/pull/2339

(7) 最終搞定:

# docker login https://registry.domain.com:8000Username: 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_privThe push refers to a repository [registry.domain.com:8000/centos6] (len: 1)
Sending image listPushing 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}

但還有一個小問題沒解決,雖然已經(jīng)可以正常使用,但每次請求在nginx的error.log中還是會有[error] 8299#0: *27 no user/password was provided for basic authentication,應(yīng)該是這個版本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 busy2014/11/08 15:14:57 Error: failed to start one or more containers

經(jīng)分析產(chǎn)生這個問題的原因是做了一個操作:在docker后臺進程啟動的終端,繼續(xù)回車后會臨時退出后臺進程的日志輸出,我就在這個shell下使用yum安裝軟件包,但由于網(wǎng)絡(luò)原因yum卡住不動,于是我就另起了一個終端kill了這個yum進程,不知為何會影響到表面已經(jīng)退出前臺輸出的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) 網(wǎng)絡(luò)設(shè)置代理問題
pull, push官網(wǎng)的鏡像時由于GFW的原因需要設(shè)置代理,但不是http_proxy而是HTTP_PROXY,對于docker來說同時設(shè)置這兩個值就會出問題,有時出于安裝軟件包的需要設(shè)置http_proxy,就會導(dǎo)致沖突。在docker-registry中如果忘記了當(dāng)前哪一個在起作用,找遍所有問題都發(fā)現(xiàn)不了原因,而docker返回給我們的錯誤也難以判斷。切記~

關(guān)于“如何通過自己build構(gòu)建docker的私有倉庫”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI