# 第8章 存儲Docker鏡像
如果讀者已經在開發環境或生產環境中使用過Docker就會知道,使用Docker鏡像可以很簡單地完成存儲鏡像的任務。Docker從創建的那天起就有一個中央倉庫可以讓用戶非常方便地存儲鏡像。這個中央模式簡化了鏡像的推送和拉取,同時方便工程師將代碼和服務變得高度可移植。存儲Docker鏡像有3種方式:公共的、私有的、保存/載入。每個選項都有其優缺點,因此選用何種方式取決于所處環境類型、哪個最管用以及公司的安全性要求。
對于開源或公共項目,建議使用公共倉庫。如果需要更高的安全性和更佳的性能,建議使用私有registry。如果需要定制某些東西,可以使用保存/載入。企業還應該考慮所存儲鏡像的數量和大小。在存儲器中鏡像大小通常有幾百兆,因此需要確保在配備新容器時倉庫具有高性能。
在使用Docker拉取或推送鏡像時,除非指定了本地倉庫,否則默認是Docker Hub。例如,以下命令會將鏡像直接推送到Docker Hub上。
`- docker push redis`如果在鏡像名稱之前指定命名空間,就可以重定向到一個內部私有倉庫。例如,如果repo.domain.com托管在內部,以下命令將推送到一個本地倉庫中。
`- docker push repo.domain.com/redis`讓我們來詳細了解一下存儲鏡像的各種方式。
對于開發環境和公共用途而言,存儲Docker鏡像最常見的方法是使用默認倉庫hub.docker.com(Docker Hub)。可以將Docker Hub當作Docker鏡像的GitHub。它提供了一個查看不同類型鏡像的極佳途徑,可以關注、收藏最好鏡像,查看Dockerfile的內容,甚至是查看對該鏡像用途的描述和評論。使用Docker Hub啟動和運行非常簡單。只需要創建一個賬號,就能獲得一個可以立即使用的單一倉庫。完成賬號設置后,就可以通過這個命令將新構建的鏡像推送到Dokcer Hub中。
`- docker push -t newrepository/webimage`從Docker Hub拉取鏡像也非常簡單:
`- docker pull newrepository/webimage`在使用公共倉庫時,需要注意幾個安全設置。在使用Docker Hub時,鏡像可以簡單地置為公共或私有狀態。如果在鏡像中存儲了源代碼、安全密鑰或環境細節,那么將鏡像設置為公開狀態應該非常慎重。如果用戶的鏡像包含敏感信息,Docker Hub能通過私有化倉庫為鏡像進行加固(只能通過管理員或協作賬號訪問)。Docker Hub提供了認證服務以保護可以對用戶的倉庫進行修改的人,還可以為用戶的倉庫分配協作者。
如果對Docker Hub背后的技術感興趣,可以看一下Jér?me Petazzoni的\[演講視頻\](http://blog.heavybit. com/blog/2015/3/23/dockermeetup)。
如果剛開始使用Docker,可嘗試一些[官方鏡像](https://registry.hub.docker.com/search?q=library&f=official)。
Docker Hub提供了一個不太出名但卻非常有用的功能,用戶可以使用Docker Hub的服務器自動構建容器鏡像。要設置自動化構建,將Docker Hub倉庫指向一個包含Dockerfile的GitHub、Bitbucket倉庫或倉庫的一個路徑。
一旦設置了自動化構建,每當修改所配置的源代碼時,Docker Hub就會自動化構建新容器鏡像。接著,新構建的容器將被推送到registry中,并被標記為自動構建(automated build)以供下載。
自動化構建有以下優點:
- 減少用戶或用戶的基礎設施工作量;
- 自動化構建可以使用安全補丁自動更新基礎Docker庫鏡像;
- 事件驅動方法(通過Webhooks)——鏡像反映了應用程序代碼的最新版本——對于開源項目這尤其有用。
存儲Docker鏡像的另一個常見方法是使用私有registry。Docker提供了一個開源服務器來存儲鏡像。私有registry讓企業可以安全地將鏡像保存在防火墻和VPN之后,以確保代碼及鏡像倉庫的安全。啟動并運行私有registry也非常簡單。這是一個入門鏈接:http://docs.docker.com/docker-hub-enterprise/install/。
在Docker剛起步時,私有registry就已經是Docker主代碼的一部分。由于Docker registry是其生態系統中極其重要的一部分,他們決定將私有registry抽出來作為獨立產品。Docker自此將代碼移動到自己的分支上,甚至將代碼轉化為可下載的Docker鏡像。在過去一年中,私有registry得到了更好的發展。如果讀者從早期就開始接觸Docker,會發現私有registry已經從原先的非常不穩定變成了現在具有多種改進的穩定狀態。
目前的私有倉庫已經相當穩定,很多公司因為其性能提升和更高的安全要求已經開始使用自有的內部registry。如果你剛剛上手,打算運行自己的私有registry時,應考慮幾個架構決策。需要考慮網絡帶寬、登錄憑證、SSL安全性、監控以及磁盤存儲要求。
私有倉庫有以下優點:
- 速度——將倉庫放置在自有網絡內部可加快鏡像的推送與拉取;
- 安全性。
企業剛開始使用私有registry時,將其快速安裝在服務器上后就放任不管了,任其運行。很快,企業就意識到鏡像會占用大量存儲空間、消耗大量網絡帶寬,并將遇到很多Docker所使用的不同類型文件系統所帶來的文件系統問題(見4.3節)。如果計劃在自有網絡中運行私有Docker registry,應將其作為最高等級的服務器來對待。
在運行自己的內部私有registry時,建議使用基于網絡的存儲,并對倉庫服務器做負載均衡以達成冗余。讓我們來看一個現實中生產環境的私有倉庫。
這個環境具有一個負載均衡器、兩個設置成自動擴展組中的倉庫Web服務器,并使用S3作為后端存儲。這個環境包含了倉庫中所有526 751個對象。對象由存儲在倉庫中的鏡像及標簽組成。這個環境的總大小是2 678 702 030 780字節,即可使用的存儲空間為2.43 TB。
這個環境能應對的突發網絡流量可以達到1 Gbit/s,不過通常在300 Mbit/s左右。這有采集Web服務器兩周進出的網絡吞吐量的多個鏡像。
擴展私有registry并不難,不過要長期持續使用Docker,應考慮好存儲及網絡吞吐量。希望讀者在實現自己的環境時,能從本書中得到一些與環境相關指標的靈感。讓我們來探索一些更深的領域。
閱讀Docker提供的[管理員手冊](http://docs.docker.com/docker-hub-enterprise/adminguide/)或[部署手冊](https://docs.docker.com/registry/deploying/)也大有裨益。
我們看到運行私有registry的大部分公司都使用S3來存儲自己的鏡像。Docker Hub也使用S3來存儲鏡像。其最大的優勢在于其幾乎無限的存儲以及管理的簡易性。如果使用的是AWS基礎設施,其速度也將非常快,因為流量將通過本地路由到S3服務上。因為這個配置的持久性存儲器是S3,這使得用戶的私有倉庫服務器保持不變,也可以對registry的Web部分進行自動擴展和負載均衡。在配置私有registry的設置時,可以使用S3存儲驅動程序。
本地存儲是運行私有registry的另一個常用方法。如果用戶更傾向這個選項或沒有亞馬遜賬號,可以將registry文件存儲在本地掛載點上,不過我們建議使用基于NFS或NAS的掛載點,以便在持續存儲新鏡像時能擴展讀、寫及容量。使用基于網絡的存儲也允許用戶對registry的Web部分進行擴展。容量要求可能很快就會失控,因此應確保做相應計劃。
由于網絡帶寬的要求,單一的Docker倉庫服務器可能逐漸不滿足要求。Docker非常聰明,決定在私有registry中提供一個可插拔的存儲驅動程序架構。可以在一個基于網絡的可擴展文件存儲器(如S3)中存儲鏡像,因此可以對倉庫的Web部分做負載均衡。企業可以將registry鏡像放置在用戶選定的負載均衡器之后。將倉庫放置在Web負載均衡器之后,可以輕松地擴展網絡帶寬,并減少單一倉庫服務器失敗帶來的單點故障。
隨著時間推移,用戶可能不再需要使用舊的鏡像及標簽。目前Docker倉庫還沒有自動清除的功能,因此可操作的最佳實踐是,定期清理不再使用的標簽和鏡像。鏡像或標簽的刪除無法通過[Docker API](https://docs.docker.com/registry/spec/api/)進行(截至1.6版本),因此需要使用SSH登錄到機器上,然后通過Docker CLI命令清除舊的鏡像。
還需要注意的是,Docker registry是個非常活躍的項目,因此需要留意其升級和新功能。請查閱最新文檔以使用正確的方法升級Docker倉庫。
Docker私有registry的網絡加固很簡單,因為用戶只需開放5000端口。不過,由于registry是個標準的Web服務器,將其重新配置到80或443端口上很容易。建議遵循公司的最佳實踐來配置防火墻,阻止非必需端口的訪問。
用戶可以使用SSL證書來保護鏡像,使其免于受到中間人攻擊。使用SSL證書加固registry傳輸有多種方法。用戶可以使用內置的Nginx服務器、配置TLS,或將證書部署在負載均衡器上。例如,如果用戶使用AWS,可以在彈性負載均衡器(ELB)上配置SSL證書,然后以http的方式傳輸到registry的Web服務器上。在Docker registry上安裝SSL證書十分簡單。這個鏈接可以帶讀者入門:https://docs.docker. com/registry/deploying/。
認證對于保護registry非常重要,可防止非法或不安全的鏡像被上傳。它同樣可保護源代碼的知識產權或鏡像所提供的信息。對于高保密性環境,這是需要考慮的一個重要因素。目前私有registry提供了兩種認證方式:silly和令牌(tohen)。[\[1\]](part0014.xhtml#anchor81)
基于令牌的認證方式是唯一可供選擇的安全選項。它是一個具有高度安全性的成熟范例,目前有很多公司正在使用。silly認證正如其名所暗示的那樣不安全。它只在HTTP請求中檢查是否存在Authorization頭。如果未提供頭信息,它依然需要認證。
存儲鏡像還有另外一種方法,使用Docker在1.0版本之前就已經實現的保存/載入功能。因為早期私有registry不穩定,有些公司采用了[Dogestry](https://github.com/dogestry)模式并一直使用它。如今,這是移動鏡像時最不受歡迎的方法,不過如果它適合用戶的環境,當然也是可以使用的。用戶可以通過Docker的內置命令使用其保存/載入功能。例如,可以這么做:
- `docker build redis`
- `docker save redis > /tmp/redis_docker_save.tar`
- 將鏡像復制到遠程服務器中(或在本地使用)
- `docker load < /tmp/redis_docker_save.tar`
通過使用`save/load`命令,用戶可以擁有足夠的靈活度。可以將鏡像保存為一個tar包,并上傳到倉庫或網絡共享中,以便集中使用。需要注意的是,用戶可以使用Docker的`export`命令。它跟`save`相比有輕微區別。`export`命令會合并鏡像,這意味著將丟失歷史和元數據。它可以將鏡像體積變得更小。在移動鏡像使用保存/載入方法時,應牢記這一點。
由于用于構建鏡像的依賴項不同,Docker鏡像體積可能會變得很大。例如,用戶使用Ubuntu作為基礎鏡像,然后使用apt-get更新了任何一些庫文件,同時安裝了一個軟件包,如nginx。apt-get將安裝一堆容器構建完成后不需要的緩存庫文件和依賴項。一個通用模式是刪除這些緩存文件和庫以盡量減小鏡像。如果用戶發現自己需要最小化Docker鏡像,那可以使用一個名為[docker-squash](https://github.com/jwilder/docker-squash)的優秀社區項目。以下是如何使用它的一個簡單示例。
`- docker save <鏡像id> | sudo docker-squash -t newtag | docker load`我們對mesosphere/marathon里的一個公共鏡像運行docker-squash,可以將其大小縮小11%。拉取下來的鏡像初始大小是831.7 MB。在對該鏡像運行docker-squash后,我們創建了一個大小是736.2 MB的新鏡像。隨著時間的累加空間性能逐步提升,同時節省了網絡寬帶,這將改善倉庫的存儲和性能。
如果想了解更多關于鏡像壓縮的信息,推薦看一下這篇博客文章:https://blog.jtlebi.fr/2015/04/25/how-i-shrunk-a-docker-image-by-98-8-featuring-fanotify/。
隨著Docker生態系統的不斷成長,在探索運行Docker的新環境時,讀者應留意一下其他的鏡像倉庫:
- [Artifactory](https://www.jfrog.com/confluence/display/RTF/Docker+Repositories);
- [Quay](http://quay.io);
- 由New Relic更新的[Dogestry](https://github.com/dogestry);
- [Google容器倉庫](http://googlecloudplatform.blogspot.ca/2015/01/secure-hosting-of-private-Docker-repositories-in-Google-Cloud-Platform.html);
- Azure上的[Docker](http://azure.microsoft.com/blog/2014/10/15/new-windows-server-containers-and-azure-support-for-docker/)。
在第9章中,我們將講述如何結合Docker鏡像使用CI/CD系統。
- - - - - -
[\[1\]](part0014.xhtml#ac81) 在2.1.0版本中增加了htpasswd認證方式。——譯者注
- 版權信息
- 版權聲明
- 內容提要
- 對本書的贊譽
- 譯者介紹
- 前言
- 本書面向的讀者
- 誰真的在生產環境中使用Docker
- 為什么使用Docker
- 開發環境與生產環境
- 我們所說的“生產環境”
- 功能內置與組合工具
- 哪些東西不要Docker化
- 技術審稿人
- 第1章 入門
- 1.1 術語
- 1.1.1 鏡像與容器
- 1.1.2 容器與虛擬機
- 1.1.3 持續集成/持續交付
- 1.1.4 宿主機管理
- 1.1.5 編排
- 1.1.6 調度
- 1.1.7 發現
- 1.1.8 配置管理
- 1.2 從開發環境到生產環境
- 1.3 使用Docker的多種方式
- 1.4 可預期的情況
- 為什么Docker在生產環境如此困難
- 第2章 技術棧
- 2.1 構建系統
- 2.2 鏡像倉庫
- 2.3 宿主機管理
- 2.4 配置管理
- 2.5 部署
- 2.6 編排
- 第3章 示例:極簡環境
- 3.1 保持各部分的簡單
- 3.2 保持流程的簡單
- 3.3 系統細節
- 利用systemd
- 3.4 集群范圍的配置、通用配置及本地配置
- 3.5 部署服務
- 3.6 支撐服務
- 3.7 討論
- 3.8 未來
- 3.9 小結
- 第4章 示例:Web環境
- 4.1 編排
- 4.1.1 讓服務器上的Docker進入準備運行容器的狀態
- 4.1.2 讓容器運行
- 4.2 連網
- 4.3 數據存儲
- 4.4 日志
- 4.5 監控
- 4.6 無須擔心新依賴
- 4.7 零停機時間
- 4.8 服務回滾
- 4.9 小結
- 第5章 示例:Beanstalk環境
- 5.1 構建容器的過程
- 部署/更新容器的過程
- 5.2 日志
- 5.3 監控
- 5.4 安全
- 5.5 小結
- 第6章 安全
- 6.1 威脅模型
- 6.2 容器與安全性
- 6.3 內核更新
- 6.4 容器更新
- 6.5 suid及guid二進制文件
- 6.6 容器內的root
- 6.7 權能
- 6.8 seccomp
- 6.9 內核安全框架
- 6.10 資源限制及cgroup
- 6.11 ulimit
- 6.12 用戶命名空間
- 6.13 鏡像驗證
- 6.14 安全地運行Docker守護進程
- 6.15 監控
- 6.16 設備
- 6.17 掛載點
- 6.18 ssh
- 6.19 私鑰分發
- 6.20 位置
- 第7章 構建鏡像
- 7.1 此鏡像非彼鏡像
- 7.1.1 寫時復制與高效的鏡像存儲與分發
- 7.1.2 Docker對寫時復制的使用
- 7.2 鏡像構建基本原理
- 7.2.1 分層的文件系統和空間控管
- 7.2.2 保持鏡像小巧
- 7.2.3 讓鏡像可重用
- 7.2.4 在進程無法被配置時,通過環境變量讓鏡像可配置
- 7.2.5 讓鏡像在Docker變化時對自身進行重新配置
- 7.2.6 信任與鏡像
- 7.2.7 讓鏡像不可變
- 7.3 小結
- 第8章 存儲Docker鏡像
- 8.1 啟動并運行存儲的Docker鏡像
- 8.2 自動化構建
- 8.3 私有倉庫
- 8.4 私有registry的擴展
- 8.4.1 S3
- 8.4.2 本地存儲
- 8.4.3 對registry進行負載均衡
- 8.5 維護
- 8.6 對私有倉庫進行加固
- 8.6.1 SSL
- 8.6.2 認證
- 8.7 保存/載入
- 8.8 最大限度地減小鏡像體積
- 8.9 其他鏡像倉庫方案
- 第9章 CI/CD
- 9.1 讓所有人都進行鏡像構建與推送
- 9.2 在一個構建系統中構建所有鏡像
- 9.3 不要使用或禁止使用非標準做法
- 9.4 使用標準基礎鏡像
- 9.5 使用Docker進行集成測試
- 9.6 小結
- 第10章 配置管理
- 10.1 配置管理與容器
- 10.2 面向容器的配置管理
- 10.2.1 Chef
- 10.2.2 Ansible
- 10.2.3 Salt Stack
- 10.2.4 Puppet
- 10.3 小結
- 第11章 Docker存儲引擎
- 11.1 AUFS
- 11.2 DeviceMapper
- 11.3 BTRFS
- 11.4 OverlayFS
- 11.5 VFS
- 11.6 小結
- 第12章 Docker 網絡實現
- 12.1 網絡基礎知識
- 12.2 IP地址的分配
- 端口的分配
- 12.3 域名解析
- 12.4 服務發現
- 12.5 Docker高級網絡
- 12.6 IPv6
- 12.7 小結
- 第13章 調度
- 13.1 什么是調度
- 13.2 調度策略
- 13.3 Mesos
- 13.4 Kubernetes
- 13.5 OpenShift
- Red Hat公司首席工程師Clayton Coleman的想法
- 第14章 服務發現
- 14.1 DNS服務發現
- DNS服務器的重新發明
- 14.2 Zookeeper
- 14.3 基于Zookeeper的服務發現
- 14.4 etcd
- 基于etcd的服務發現
- 14.5 consul
- 14.5.1 基于consul的服務發現
- 14.5.2 registrator
- 14.6 Eureka
- 基于Eureka的服務發現
- 14.7 Smartstack
- 14.7.1 基于Smartstack的服務發現
- 14.7.2 Nerve
- 14.7.3 Synapse
- 14.8 nsqlookupd
- 14.9 小結
- 第15章 日志和監控
- 15.1 日志
- 15.1.1 Docker原生的日志支持
- 15.1.2 連接到Docker容器
- 15.1.3 將日志導出到宿主機
- 15.1.4 發送日志到集中式的日志平臺
- 15.1.5 在其他容器一側收集日志
- 15.2 監控
- 15.2.1 基于宿主機的監控
- 15.2.2 基于Docker守護進程的監控
- 15.2.3 基于容器的監控
- 15.3 小結
- DockOne社區簡介
- 看完了