如何在阿里雲上部署私有的Docker Registry
關於什麼是Docker,為什麼要使用Docker,使用Docker的基礎知識這裡就先不贅述了,有很多的參考資料都有了詳盡的介紹,比如說這本Gitbook:《 Docker —— 從入門到實踐》。
這裡先簡要介紹一下為什麼要在阿里雲上部署私有的Docker Registry:
- 使用Docker Hub來存放Docker Image,經常會出現Push/Pull timeout,你們懂的;
- 我司現在各個Server都是放在阿里雲上的,如果我們把Docker Registry也放在阿里雲上,那麼我們做release的速度就會相當快;
背景介紹完了,下面我們就來看看具體如何部署吧。#READMORE#
什麼是Docker Registry
也許一些Docker的新人,對於什麼是Registry還不太清楚,這裡我大概講解一下,了解的人可以直接略過這一部分了。
Docker Registry就是可以存放很多Docker Repository的伺服器。舉個例子,比如我們在內網192.168.0.1的5000埠上創建了一個Registry,並且其中有一個ubuntu 12.04的Image,那麼我們就可以用下面這個命令來獲取它:
$ docker pull 192.168.0.1:5000/ubuntu:12.04n
其中192.168.0.1:5000就是Registry的伺服器地址和埠,ubuntu就是Repository的名字,12.04指示了版本號,也具體指向了一個Image。所以也可以這麼理解:定位一個Image的方式是Registry + Repository + Version。
Docker Registry主要有兩種:公開的和私有的。最大的公開Registry就是Docker Hub,不過他也提供了私有Registry的服務,每個帳號可以有一個免費的Private Image,如果多了就要付費。但是對於國內來說他是基本很難連上的。私有Registry就是個人或者公司搭建的,通過網路隔離或者某種認證手段,只允許內部訪問。
在阿里雲上安裝Docker
由於我們的Registry會使用最新的2.0版本,所以安裝的Docker也必須是最新的1.6版本,apt-get還是1.5,所以這裡我們使用官方的腳本進行安裝:
wget -qO- https://get.docker.com/ | sh。n
安裝完成以後你會發現,再啟動Docker的時候有報錯:Could not find a free IP address range for xxx。沒錯,這就是阿里雲的坑,具體原因和解決方案可以參考這裡,簡單來說的話就是:修改 /etc/network/interface,去掉172那段的路由,然後運行 $ route del -net 172.16.0.0/12。
現在運行 $ service docker start 就可以啟動Docker了。
安裝並運行Docker Registry
在伺服器上安裝Docker Registry主要有兩種方式:本地安裝;通過Image安裝。這裡我推薦用Image安裝,因為安裝最快,啟動也方便。
Docker官方已經很貼心的將一個完整的Docker Registry打包成了一個Image,我們只需要把它run起來就「可以了」:
$ docker run -d -p 5000:5000 registry:2.0n
然後Docker會檢查你本地有沒有registry:2.0這個鏡像,如果沒有的話它就會默認從Docker Hub上面Pull下來,然後就會run起來了。
安裝和啟動完成以後,可以訪問一下http://localhost:5000/v2/,如果看到伺服器返回了一個空的JSON Object,那麼說明運行已經成功了。大家以為大功就要告成了嗎?其實征途才剛剛開始啊!
從本地把Image Push到Docker Registry中
我是萬萬沒有想到,這臨門一腳的一步,卻是最難的一步,也是最費時間精力的一步,我為什麼要寫這篇博客,就是希望大家可以在這一步少走彎路。
假設我們現在本地有一個叫做hello-world的Image,而我們阿里雲上的Registry的IP是120.1.1.1,埠是5000。當我們想要把hello-world Push到阿里雲的Registry中時,首先我們要指定它的Registry:
$ docker tag hello-world:latest 120.0.0.1:5000/hello-world:latestn
然後我們很自然的就會去運行Push命令:
$ docker push 120.0.0.1:5000/hello-world:latestn
於是你就看到下面這個錯誤了:
FATA[0000] Error response from daemon: v1 ping attempt failed with error: Get https://120.0.0.1:5000/v1/_ping: tls: oversized record received with length 20527. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add --insecure-registry 120.0.0.1:5000 to the daemons arguments. In the case of HTTPS, if you have access to the registrys CA certificate, no need for the flag; simply place the CA certificate at /etc/docker/certs.d/120.0.0.1:5000/ca.crt
這是由於我們並沒有把一個通過認證的安全證書加到Registry伺服器中。這裡就涉及到如何添加安全證書,以及如何設置安全認證,關於這兩點官方都有很詳盡的文檔,可以參考Configure TLS on a registry server,以及Registry Configuration Reference。但是還是有一些場景是不需要安全證書以及安全認證的,關於如何繞過這些安全配置,我就沒有找到一個很好的教程了。下面就是我自己摸索出來的配置方式,總得來說就是我們要在執行Pull和Push的地方配置好insecure-registry這個參數:
對於開發環境(Windows,OSX)
一般我們都使用了boot2docker,所以這裡是基於boot2docker的配置。
- $ boot2docker ssh 進入到運行Docker的虛擬機中;
- $ sudo vi /var/lib/boot2docker/profile 添加配置 EXTRA_ARGS="--insecure-registry 120.0.0.1:5000",這裡的120.0.0.1:5000就是你的Registry所在伺服器的IP和埠號。如果你需要向多個Registry Push,或者從多個Registry Pull,那麼你可以添加多個insecure-registry,例如:EXTRA_ARGS="--insecure-registry 120.0.0.1:5000 --insecure-registry 120.0.0.2:5000"
- $ exit 退出以後,重啟Docker $ boot2docker restart
- 現在終於可以在本地環境build鏡像,然後往我們搭建起來的Registry Push了。
對於生產環境(Ubuntu,CentOS)
跟開發環境差別不大,目的都是一樣的,只是手段不同。
- ssh到我們需要部署鏡像的生產伺服器上
- $ sudo vi /etc/default/docker 添加 DOCKER_OPTS="--insecure-registry 120.0.0.1:5000"
- $ service docker restart
- 現在可以在生產伺服器上Pull放在我們私有Registry中的Image了。
總結
到這裡整個配置就完成了,我感覺最坑爹的地方在於,這個insecure-registry的配置其實是針對Pull這個操作的,但是Push也需要這個配置,而且這個配置在Push/Pull的時候不能指定,必須在啟動Docker的時候指定,每次改了還得重啟Docker……社區對於這個喪病的行為已經諸多意見了,例如這個issue:--insecure-registry should be on "docker pull",但是目前為止Docker還沒有修改。甚至有人還在這個issue裡面貼出了更加喪病的work around,就是使用ssh tunnel:
$ docker pull host:5000/image #failsn$ ssh -N -L 5000:host:5000 user@hostn$ docker pull localhost:5000/image #worksn
希望Docker的後續版本可以更加方便的向私有Registry Pull和Push,或者是有更加方便的配置安全證書和安全認證的方式。
推薦閱讀:
※阿里雲發布固定公網IP升級為彈性公網IP功能
※【互聯網安全知多少】阿里安全專家帶你深入背後的技術
※阿里巴巴王堅博士學心理學的,是怎麼與計算機扯上關係的?
※網易蜂巢 靈雀雲 daocloud 時速雲 區別?
※馬雲將城市大腦帶到澳門,貝索斯今夜無眠!