# 第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社区简介
- 看完了