玩转Docker镜像

前言Docker是Docker.Inc公司开源的一个基于轻量级虚拟化技术的容器引擎项目,整个项目基于Go语言开发,并遵从Apache 2.0协议。通过分层镜像标准化和内核虚拟化技术,Docker使得应用开发者和运维工程师可以以统一的方式跨平台发布应用,并且以几乎没有额外开销的情况下提供资源隔离的应用运行环境。由于众多新颖的特性以及项目本身的开放性,Docker在不到两年的时间里迅速获得诸多IT厂商的参与,其中更是包括Google、Microsoft、VMware等业界行业领导者。同时,Docker在开发者社区也是一石激起千层浪,许多如我之码农纷纷开始关注、学习和使用Docker,许多企业,尤其是互联网企业,也在不断加大对Docker的投入,大有掀起一场容器革命之势。Docker镜像命名解析镜像是Docker最核心的技术之一,也是应用发布的标准格式。无论你是用docker pull image,或者是在Dockerfile里面写FROM image,从Docker官方Registry下载镜像应该是Docker操作里面最频繁的动作之一了。那么在我们执行docker pull image时背后到底发生了什么呢?在回答这个问题前,我们需要先了解下docker镜像是如何命名的,这也是Docker里面比较容易令人混淆的一块概念:Registry,Repository, Tag and Image。下面是在本地机器运行docker images的输出结果:

我们可以发现我们常说的“ubuntu”镜像其实不是一个镜像名称,而是代表了一个名为ubuntu的Repository,同时在这个Repository下面有一系列打了tag的Image,Image的标记是一个GUID,为了方便也可以通过Repository:tag来引用。

那么Registry又是什么呢?Registry存储镜像数据,并且提供拉取和上传镜像的功能。Registry中镜像是通过Repository来组织的,而每个Repository又包含了若干个Image。

Registry包含一个或多个RepositoryRepository包含一个或多个ImageImage用GUID表示,有一个或多个Tag与之关联那么在哪里指定Registry呢?让我们再拉取一个更完整命名的镜像吧:

上面我试图去拉取一个ubuntu镜像,并且指定了Registry为我本机搭建的私有Registry。下面是Docker CLI中pull命令的代码片段 (docker/api/client/command.go中的CmdPull函数)

在运行时,上面的taglessRemote变量会被传入localhost:5000/ubuntu。上面代码试图从taglessRemote变量中解析出Registry的地址,在我们的例子中,它是localhost:5000。

那我们回过头再来看看下面这个耳熟能详的pull命令背后的故事吧:

我们跟着上面的示例代码,进一步进入解析函数ResolveRepositoryName的定义代码片段(docker/registry/registry.go)

我们发现,Docker CLI会判断传入的taglessRemote参数的第一部分中是否包含’.’或者':’,如果存在则认为第一部分是Registry地址,否则会使用Docker官方默认的Registry(即index.docker.io其实这里是一个Index Server,和Registry的区别留在后面再去深究吧),即上面代码中高亮的部分。背后的故事还没有结束,如果你向DockerHub上传过镜像,应该记得你上传的镜像名称格式为user-name/repository:tag,这样用户Bob和用户Alice可以有相同名称的Repository,通过用户名前缀作为命名空间隔离,比如Bob/ubuntu和Alice/ubuntu。官方镜像是通过用户名library来区分的,具体代码片段如下(docker/api/client/command.go中的CmdPull函数)

我们回过头再去看Docker命令行中解析Tag的逻辑吧(docker/api/client/command.go中的CmdPull函数):

代码会试着在用户输入的Image名称中找’ : ‘后面的tag,如果不存在,会使用默认的‘DEFAULTTAG’,即‘latest’。

也就是说在我们的例子里面,命令会被解析为下面这样(注意,下面的命令不能直接运行,因为Docker CLI不允许明确指定官方Registry地址)

配置Registry MirrorDocker之所以这么吸引人,除了它的新颖的技术外,围绕官方Registry(Docker Hub)的生态圈也是相当吸引人眼球的地方。在Docker Hub上你可以很轻松下载到大量已经容器化好的应用镜像,即拉即用。这些镜像中,有些是Docker官方维护的,更多的是众多开发者自发上传分享的。而且你还可以在Docker Hub中绑定你的代码托管系统(目前支持Github和Bitbucket)配置自动生成镜像功能,这样Docker Hub会在你代码更新时自动生成对应的Docker镜像,是不是很方便?

不幸的是Docker Hub并没有在国内放服务器或者用国内的CDN,下载个镜像20分钟最起码,我等码农可耗不起这么长时间,老板正站在身后催着我们搬运代码呢。为了克服跨洋网络延迟,一般有两个解决方案:一是使用私有Registry,另外是使用Registry Mirror,我们下面一一展开聊聊.

方案一就是搭建或者使用现有的私有Registry,通过定期和Docker Hub同步热门的镜像,私有Registry上保存了一些镜像的副本,然后大家可以通过docker pull private-registry.com/user-name/ubuntu:latest,从这个私有Registry上拉取镜像。因为这个方案需要定期同步Docker Hub镜像,因此它比较适合于使用的镜像相对稳定,或者都是私有镜像的场景。而且用户需要显式的映射官方镜像名称到私有镜像名称,私有Registry更多被大家应用在企业内部场景。私有Registry部署也很方便,可以直接在Docker Hub上下载Registry镜像,即拉即用,具体部署可以参考官方文档。

方案二是使用Registry Mirror,它的原理类似于缓存,如果镜像在Mirror中命中则直接返回给客户端,否则从存放镜像的Registry上拉取并自动缓存在Mirror中。最酷的是,是否使用Mirror对Docker使用者来讲是透明的,也就是说在配置Mirror以后,大家可以仍然输入docker pull ubuntu来拉取Docker Hub镜像,除了速度变快了,和以前没有任何区别。

了以更便捷的方式对接Docker Hub生态圈,使用Registry Mirror自然成为我的首选。接下来我就和大家一起看看Docker使用Mirror来拉取镜像的过程。下面的例子,我使用的是由DaoCloud提供的Registry Mirror服务,在申请开通Mirror服务后你会得到一个Mirror地址,然后我们要做的就是把这个地址配置在Docker Server启动脚本中,重启Docker服务后Mirror配置就生效了(如何获得Mirror服务可以参考本篇文章的附录)

Ubuntu下配置Docker Registry Mirror的命令如下:

sudo echo “DOCKER_OPTS=\”\$DOCKER_OPTS –registry-mirror=http://your-id.m.daocloud.io -d\”” >> /etc/default/docker

sudo service docker restart

如果你是用的Boot2Docker,配置命令为:

# 进入Boot2Docker Start Shell,并执行

sudo su

echo “EXTRA_ARGS=\”–registry-mirror=http://your-id.m.daocloud.io\”” >> /var/lib/boot2docker/profile

exit

# 重启Boot2Docker

配置好Registry Mirror后,就可以拉取Docker镜像了,经我测试,使用DaoCloud的Mirror后,拉取常见镜像的速度可以达到1.5M左右,具体速度在你的网络环境可能会略有不同。

我们来看看配置了Registry Mirror后,Docker拉取镜像的过程吧。首先是CLI拉取镜像命令代码片段(docker/api/client/command.go中的CmdPull函数)

首先,Docker CLI会试图获得授权,在我们的例子中会向https://index.docker.io/v1请求认证,认证完成后,认证服务器会返回一个对应的Token。注意,这里用户认证与配置的Registry Mirror完全无关,这样我们就不用担心使用Mirror的安全问题了。接着Docker CLI会调用Docker Server(即Docker daemon程序)的创建镜像命令,Docker Server随之会执行具体的拉取镜像动作,代码片段如下(docker/graph/pull.go的pullRepository函数)

从代码中可以发现,如果配置了Registry Mirror,Docker Server会首先从Mirror中拉取镜像,如果Mirror拉取失败会退而求其次从镜像中指定的Registry拉取。大家又可以松口气了,就算配置的Registry Mirror失效,也不会影响用户拉取镜像,只不过速度就。。。

镜像拉下来后,就可以运行容器了

附录下面我简单介绍下如何在DaoCloud申请一个Mirror服务,首先登陆DaoCloud主页

点击”立刻注册“,简单填写个人信息后,随即登陆并自动跳转到”控制台“,按照提示点击”启动你的加速器“按钮。

启动成功后,你就拥有了一个你专用的Registry Mirror地址了,加速器链接就是你要设置”--registry-mirror“的地址。目前每个用户有10G的加速流量(Tips:如果流量不够用可以邀请好友获得奖励流量,邀请越多奖励越多哦)

最后,要感谢国内存储行业领先企业七牛云存储在存储和CDN方面提供的大力支持,正因为有了像七牛这样技术领先又热心促进互联网生态发展的企业的积极参与,我们才能给开发者提供更多高质量的服务。

结语今天和大家一起聊了聊Docker在拉取镜像时如何解析镜像和执行拉取动作的,以及如何通过设置Registry Mirror克服网络延时,加速拉取过程。涉及到的代码只集中在Docker CLI和Docker Server,在很多方面并没有展开,比如Registry是如何响应以及如何和Index Server联动的,只能留给下次再和大家详细探讨了。

作者简介

孙宏亮,DaoCloud初创团队成员,软件工程师,浙江大学计算机科学专业应届毕业研究生。读研期间活跃在PaaS和Docker开源社区,对Cloud Foundry有深入研究和丰富实践,擅长底层平台代码分析,对分布式平台的架构有一定经验,撰写了大量有深度的技术博客。2014年末以合伙人身份加入DaoCloud团队,致力于传播以Docker为主的容器的技术,推动互联网应用的容器化步伐。

如需要了解更多Docker相关的资讯或是技术文档可访问Docker技术社区;如有更多的疑问请在Dcoker技术论坛提出,我们会邀请专家回答。CSDN Docker技术交流QQ群:303806405。

时间: 2024-09-09 14:32:32

玩转Docker镜像的相关文章

最小的镜像 - 每天5分钟玩转Docker容器技术(9)

镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器. 本章内容安排如下: 首先通过研究几个典型的镜像,分析镜像的内部结构. 然后学习如何构建自己的镜像. 最后介绍怎样管理和分发镜像. 镜像的内部结构 为什么我们要讨论镜像的内部结构? 如果只是使用镜像,当然不需要了解,直接通过 docker 命令下载和运行就可以了. 但如果我们想创建自己的镜像,或者想理解 Docker 为什么是轻量级的,就非常有必要学习这部分知识了. 我们从一个最小的镜像开始吧. hello-world

Docker 镜像小结 - 每天5分钟玩转 Docker 容器技术(21)

本节我们对 Docker 镜像做个小结. 这一部分我们首先讨论了镜像的分层结构,然后学习了如何构建镜像,最后实践使用 Docker Hub 和本地 registry. 下面是镜像的常用操作子命令: images    显示镜像列表 history   显示镜像构建历史 commit    从容器创建新镜像 build     从 Dockerfile 构建镜像 tag       给镜像打 tag pull      从 registry 下载镜像 push      将 镜像 上传到 regi

莫源:像搭积木一样玩转Docker的持续交付

云栖TechDay活动第十八期中,阿里云的高级研发工程师莫源带来了题为<像搭积木一样玩转Docker的持续交付>的分享,主要讲解了阿里云容器服务实现基于Docker的持续交付.容器持续交付的设计思路和未来发展反向. 幻灯片下载地址:https://yq.aliyun.com/attachment/download/?filename=dbf464e5883344e9dd010214576889bf.pdf 以下为现场分享观点整理. 最近Docker越来越火,持续交付的概念也随着被大家越炒越火.

如何让你的 Docker 镜像更小

Docker是个好东西毋庸置疑,甚至可以称其为万金油,什么场合都看到他的身影.自14年底开始,小到防污染的DNS.CoreOS的socks5代理,大点到开发团队的CI系统,一些Web项目等等,都有在用,并且稳定性非常好,使用起来也方便,但是最近经常发现各大论坛.网站.文档在使用Docker镜像的时候常常发现的一个误区,谨以此文抛砖引玉. 让我们从一个dockerfile说起,缘起我5月写的一个2048的Docker镜像,当时是在csphere的群里,以游戏的形式,教人快速的集成Web服务,提供服

写在最前面 - 每天5分钟玩转Docker容器技术(1)

写在最前面 <每天5分钟玩转Docker容器技术>是一个有关容器技术的教程,有下面两个特点: 系统讲解当前最流行的容器技术 从容器的整个生态环境到各种具体的技术,从整体到细节逐一讨论. 重实践并兼顾理论 从实际操作的角度带领大家学习容器技术. 为什么要写这个 简单回答是:容器技术非常热门,但门槛高. 容器技术是继大数据和云计算之后又一炙手可热的技术,而且未来相当一段时间内都会非常流行. 对 IT 行业来说,这是一项非常有价值的技术.而对 IT 从业者来说,掌握容器技术是市场的需要,也是提升自我

Docker 的两类存储资源 - 每天5分钟玩转 Docker 容器技术(38)

我们从本章开始讨论 Docker 存储. Docker 为容器提供了两种存放数据的资源: 由 storage driver 管理的镜像层和容器层. Data Volume. 我们会详细讨论它们的原理和特性. storage driver 在前面镜像章节我们学习到 Docker 镜像的分层结构,简单回顾一下. 容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中.这样的分层结构最大的特性是 Copy-on-Write: 新数据会直接存放在最上面的容器层. 修改现有数据

Secret 的使用场景 - 每天5分钟玩转 Docker 容器技术(109)

我们可以用 secret 管理任何敏感数据.这些敏感数据是容器在运行时需要的,同时我们不又想将这些数据保存到镜像中. secret 可用于管理: 用户名和密码. TLS 证书. SSH 秘钥. 其他小于 500 KB 的数据. secret 只能在 swarm service 中使用.普通容器想使用 secret,可以将其包装成副本数为 1 的 service. 这里我们再举一个使用 secret 的典型场景. 数据中心有三套 swarm 环境,分别用于开发.测试和生产.对于同一个应用,在不同的

如何使用 Secret?- 每天5分钟玩转 Docker 容器技术(108)

我们经常要向容器传递敏感信息,最常见的莫过于密码了.比如: docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql 在启动 MySQL 容器时我们通过环境变量 MYSQL_ROOT_PASSWORD 设置了 MySQL 的管理员密码.不过密码是以明文的形式写在 docker run 命令中,有潜在的安全隐患. 为了解决这个问题,docker swarm 提供了 secret 机制,允许将敏感信息加密后保存到 secret 中,用户可以指定哪

Docker Swarm 中最重要的概念- 每天5分钟玩转 Docker 容器技术(94)

从主机的层面来看,Docker Swarm 管理的是 Docker Host 集群.所以先来讨论一个重要的概念 - 集群化(Clustering). 服务器集群由一组网络上相互连接的服务器组成,它们一起协同工作.一个集群和一堆服务器最显著的区别在于: 集群能够像 单个 系统那样工作,同时提供高可用.负载均衡和并行处理. 如果我们部署应用和服务时选择的是多个独立的服务器而非集群,资源的整体利用率则很难达到最优,因为我们无法提前知道如何分布这些应用才能达到资源利用的最大化.而且,应用使用资源的趋势是