本章中,我们会讲解几个服务,如Docker Hub,可用于存储镜像,还有Docker私有仓库(Docker Registry),我们可以使用它来运行本地存储的Docker容器。我们还将回顾这些服务间的不同以及在何时、怎样使用这些服务。本章还将涵盖如何使用Webhooks来设置自动化构建,以及进行这一设置的各个组成部分。
我们来快速看下本章将要学习的主要内容:
- 掌握Docker Hub
- 部署Docker自有仓库
- 了解第三方仓库
- 了解Microbadger
本章中,我们将使用我们的Docker安装来构建镜像。和之前一样,虽然本章中的截图来自我个人偏爱的操作系统macOS,我们所运行的命令在前述的三个操作系统中都可以生效。
访问如下视频来查看实现代码的运行:https://bit.ly/3iaKo9I
掌握Docker Hub
我们在前两章中都介绍到了Docker Hub,但我们除了使用docker image pull
来下载远程镜像外并没有与其进行任何其它交互。
这一部分中,我们会集中讲解 Docker Hub,它既有免费选项,在其上我们仅能托管公开访问的镜像,也有一个订阅选项,允许我们托管私有镜像。我们会着重讲解Docker Hub网页方面的内容以及通过它所能进行的管理。
其首页为https://hub.docker.com/,在右上角包含一个Sign Up注册表单,以及一个Sign In 登录选项。大概率是你已经涉足过Docker,那么你就已经有Docker ID了。如果没有,则可通过首页右上角的Sign Up来创建一个账号。如果已有Docker ID,只需点击Sign In进行登录。
登录后,会看到主仪表盘界面。
Docker Hub仪表盘
在登入Docker Hub之后,你会进入到如下的落脚页。该页面被称为Docker Hub的仪表盘:
图3.1 Docker Hub初始仪表盘界面
从这里,你可以进入Docker Hub的所有其它子页面。但是,在查看其它部分之前,我们先来说说仪表盘。在这里,你可以查看自己所有的镜像,包括公有的和私有的。它们的排序首先是star数,然后是拉取的数量,这一排序无法修改。
在接下来的小节中,我们将一起来了解仪表盘上所能看到的所有内容,先从顶部的淡蓝色菜单开始。
发现
Explore发现选项会列出官方的Docker镜像,像仪表盘一样,它们以星标数和拉取数进行排序(排序规则已调整)。可以从下图中看出我选择了基础镜像。每个高人气官方镜像都有上千万次下载和上千个星标:
图3.2 – 探秘Docker Hub
Docker现在集成了Docker商店,提供了一站式购买所有 Docker 相关内容的地方,
仓库
我们会在本章创建自动化构建一节中更深入地讲解如何创建仓库,所以这里不会涉及细节。本节说明在何处管理自己仓库。如下图所示,可以快速预览到有多少星标了你的仓库、拉取了多少次镜像,以及该仓库是私有还是对公众开放的信息:
图3.3 – Docker仓库列表
可以看到,这里一个创建仓库的按钮。因为我们还会在创建自动化构建一节中进一步讲解,这里先进入下一节。
开发组织
组织既可以是自己创建的,也可以是你加入的。组织让我们可以对多人协作的项目进行分层控制。组织可以有自己的设置,如是否将仓库默认作为公有或私有存储,或者是修改方案来允许不同数量的私有仓库并与你本人或他人拥有的仓库进行整体分离:
图3.4 – 浏览账户下的组织列表
也可以在仪表盘页面Docker的 logo 下面访问或切换账户或组织,在登录的情况下通常会在该处看到你自己的用户名:
图3.5 – 切换组织
在对不同项目或应用进行容器镜像分发时组织就非常有用了。
获取帮助
这一下拉菜单可跳转至不同的由Docker维护的帮助及支持网站。我们来快速看一下它们分别指向哪些链接:
- Documentation: 链往Docker Hub的官方文档。
- Docker Hub: 直接进入Docker社区论坛的Docker Hub分类页。
- What’s New: 前往标签为Docker Hub的Docker博客文章列表页。
- Support: 这是一个Docker Hub的常见问题页面,还可联系客服。
个人中心和设置
顶部菜单的最后一个选项是管理个人主页、内容和账号设置:
图3.6 – 查看个人主页
账号设置页面中可设置对外的资料,包含如下选项:
- 通用:可以对账号添加email地址、修改密码以及在个人主页中可见的信息,如姓名、公司地点及链接。
- 关联账号:可以在这里关联GitHub或Bitbucket账户(更多内容会在创建自动化构建一节中讲述)。
- 安全:这里可以管理私人访问令牌以及近期引入的双因素认证。
- 默认隐私:让新创建的仓库默认保持对外还是私人访问?可在这里进行选择。
- 通知:可以在此处订阅构建和账户动态的通知。可在此处提供一个email地址或连接Slack。
- 转换账号:可在此将账号转换为组织账号。最好不要这么做,在进一步使用这一选项前阅读该页的警告。
- 取消账号:就是字面意思。同样请注意在进行这一操作前阅读该页的警告,操作不可撤销。
- 我的主页:这一菜单会通往对外的主页;作者的页面为https://hub.docker.com/u/russmckendrick/。
- 我的内容:这一链接通往在Docker Hub中订阅的容器列表。
创建一个自动化构建
在这一部分中,我们将学习自动化构建。自动化构建是指你可以关联自己的GitHub或Bitbucket账户,当代码仓库里的代码更新时,你可以让镜像在Docker Hub上自动构建。我们会来讲解所需的各个部分,最终,读者能够设置自己的自动化构建。
设置代码
创建自动化构建的第一步是配置你的GitHub或Bitbucket账户。代码存储有两种选项。在我们的示例中,我会使用GitHub,但对于GitHub和Bitbucket的设置实际上是一样的。
事实上,我们会使用与本书配套的仓库。因为这个仓库是对公众开放的,你可以fork它并在自己的GitHub账户中进行后续的操作,参照如下的截图:
图3.7 – Fork本书配套GitHub仓库
在第二章 创建容器镜像中,我使用了几个不同的Dockerfile。我们将使用这些来进行自动化构建。你如果还记得的话,我们安装了Nginx并添加了含有Hello world! 信息的简单页面。这由Docker来处理,并且我们还使用了多阶段构建。
明确了所使用的Dockerfile,下面我们在Docker Hub配置仓库。
设置Docker Hub
在Docker Hub中,我们使用仓库下的创建仓库按钮。在点击之后,会需要对构建提供一些信息。也需要选择数据源:
图3.8 – 在Docker Hub中创建仓库
从如上的截图中可以看出,我们已经将GitHub账户与Docker Hub账户相关联。关联这两个工具的过程非常简单,只需按照屏幕指示授权Docker Hub来访问我们的GitHub账户。
在将Docker Hub连接到GitHub时有两个选项:
- Public:这限制Docker Hub仅能访问对外开放的仓库和组织。如果你在关联账号时使用了这一选项,Docker Hub将不能配置自动化构建时所需的Webhook。那么你就需要从这两个地方搜索并选择进行自动化构建所要的仓库。这会创建一个Webhook来告知在所选的代码仓库完成commit时,在Docker Hub上创建一个新的构建。
- Private:这是推荐的选项。Docker Hub将可以访问所有你的公有和私有仓库,以及组织。Docker Hub还可以配置在设置自动化构建时所需的Webhook。
译者注:新版免费版未发现可针对仓库级别的关联,以下文字仅保留原文,与截图不相关
在以上截图中,我选择了Mastering-Docker-Third-Edition并访问了设置页面来进行自动化构建。在这里,我们可以选择镜像所关联的Docker Hub账户、对镜像命名、将其从公有镜像修改为私有镜像、描述这个构建并通过点击Click here to customize来进行自定义。我们可以通过如下方式让Docker Hub知道我们的Dockerfile的位置:
译者注:在创建仓库页面仅有 Dockerfile location,如需从 GitHub 中Dockerfile目录下拷贝文件,测试构建会报错,而在创建完成后进入相应仓库的 Builds 页面的 Configure Automated Builds重新配置则可以,本例中Build Context我们设置为/Chapter02/dockerfile-example/,参见下图:
如果要照着操作的话,我输入了如下信息:
- Repository Namespace & Name: dockerfile-example
- Visibility: public
- Short Description: Testing an automated build
- Push Type: Branch
- Name: master Dockerfile
- Dockerfile Location: /chapter02/dockerfile-example/
- Docker Tag: latest
通过点击Create,你会进入类似如下截图的页面:
我们已经定义了自己的构建,还可以通过Builds 进行其它的配置。因为我们使用的是官方的Alpine Linux镜像,我们可以将其我们的构建相关联。要这么做,在Repository Links部分中点击Add Repository Link(译者注:新版本似不允许自动输入,而是读取 Dockerfile中的 FROM)。这样在每次官方Alpine Linux镜像发布时可以进行无人值守的构建。
那么现在只要我们更新GitHub仓库或者官方发布镜像我们的镜像就会自动地重建和发布。由于这两者都不会马上发生,点击Trigger按钮(译者注:新版应为 Save and Build)来手动开始构建。你会注意到按钮过一会儿会变成绿色,这表明构建在后台中进行了计划执行(新版中使用了 Pending 等状态的柱状图)。
一旦我们触发了构建,点击Build Details(新版为 Builds)会显示所有构建镜像的列表,不管是构建成功还是失败。我们应该可以看到构建在进行中,点击它就会看到构建的日志:
一旦完成了构建,你就可以通过运行如下命令来将其迁移到本地的Docker中安装,如果你一直照着操作请使用你自己的镜像:
1 2 |
$ docker image pull alanhou7/dockerfile-example $ docker image ls |
命令的执行如下图所示:
你可以使用如下的命令来运行Docker Hub所创建的镜像,同样如果你有自己镜像请使用你自己的。
1 |
$ docker container run -d -p8080:80 --name example alanhou7/dockerfile-example |
我还以完全相同的方式添加了多阶段构建。Docker Hub处理这种构建毫无障碍,从以下的日志中可以看出,开始处会显示Docker构建环境的部分信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Building in Docker Cloud's infrastructure... Cloning into '.'... Warning: Permanently added the RSA host key for IP address '192.30.253.112' to the list of known hosts. Reset branch 'master' Your branch is up-to-date with 'origin/master'. KernelVersion: 4.4.0-1060-aws Components: [{u'Version': u'18.03.1-ee-3', u'Name': u'Engine', u'Details': {u'KernelVersion': u'4.4.0-1060-aws', u'Os': u'linux', u'BuildTime': u'2018-08-30T18:42:30.000000000+00:00', u'ApiVersion': u'1.37', u'MinAPIVersion': u'1.12', u'GitCommit': u'b9a5c95', u'Arch': u'amd64', u'Experimental': u'false', u'GoVersion': u'go1.10.2'}}] Arch: amd64 BuildTime: 2018-08-30T18:42:30.000000000+00:00 ApiVersion: 1.37 Platform: {u'Name': u''} Version: 18.03.1-ee-3 MinAPIVersion: 1.12 GitCommit: b9a5c95 Os: linux GoVersion: go1.10.2 |
构建紧接着会编译我们的代码,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Starting build of index.docker.io/alanhou7/multi-stage:latest... Step 1/8 : FROM golang:latest as builder ---> c7942203692b Step 2/8 : WORKDIR /go-http-hello-world/ Removing intermediate container fe203bea964d ---> 6af57c2a58d8 Step 3/8 : RUN go get -d -v golang.org/x/net/html ---> Running in fe018fcfa4b4 Fetching https://golang.org/x/net/html?go-get=1 Parsing meta tags from https://golang.org/x/net/html?go-get=1 (status code 200) get "golang.org/x/net/html": found meta tag get.metaImport{Prefix:"golang.org/x/net", VCS:"git", RepoRoot:"https://go.googlesource.com/net"} at https://golang.org/x/net/html?go-get=1 get "golang.org/x/net/html": verifying non-authoritative meta tag Fetching https://golang.org/x/net?go-get=1 Parsing meta tags from https://golang.org/x/net?go-get=1 (status code 200) golang.org/x/net (download) Removing intermediate container fe018fcfa4b4 ---> 03dffb75d33f Step 4/8 : ADD https://raw.githubusercontent.com/geetarista/go-http-hello-world/master/hello_world/hello_world.go ./hello_world.go ---> c66d430da880 Step 5/8 : RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . ---> Running in 5a67a9112b97 Removing intermediate container 5a67a9112b97 ---> 949d7192578d |
此时已经编译了我们的代码,接着会拷贝应用二进制到最终的镜像中:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Step 6/8 : FROM scratch ---> Step 7/8 : COPY --from=builder /go-http-hello-world/app . ---> c44f17998250 Step 8/8 : CMD ["./app"] ---> Running in 8659ff378cae Removing intermediate container 8659ff378cae ---> c4be21ae7095 Successfully built c4be21ae7095 Successfully tagged alanhou7/multi-stage:latest Pushing index.docker.io/alanhou7/multi-stage:latest... Done! Build finished |
你可以通过如下命令来使用该镜像拉取并启动一个容器:
1 2 3 4 |
$ docker image pull alanhou7/multi-stage $ docker image ls $ docker container run -d -p 8000:80 --name go-hello-world alanhou7/multi-stage $ curl http://localhost:8000/ |
从下图中可以看出,镜像的执行和在本地时的操作完全一致:
你可以通过如下命令来删除自己启动的容器:
1 2 3 4 |
$ docker container stop example $ docker container rm example $ docker container stop go-hello-world $ docker container rm go-hello-world |
我们已经学习了自动化构建,下面可以讨论将镜像推送到Docker Hub.上了。
推送自己的镜像
在第二章 创建容器镜像中,我们讨论了不使用Dockerfile即可创建镜像。但这不是一个好的方法,并且仅在确实需要时才这样使用,你可以将自己的镜像推送到Docker Hub上。
小贴士:在以这种方式向Docker Hub推送镜像时,确保不要包含你不希望向公众开放的代码、文件或环境变量。
要实现这点,首先我们需要使用如下命令将本地Docker客户端与Docker Hub进行关联:
1 |
$ docker login |
接下来就会提示你输入Docker ID和密码:
同时,如果你是在Mac或Windows上使用Docker,那么现在你在应用中也已登录,应该可以从菜单中访问Docker Hub了:
既然我们的客户端已经获取与Docker Hub交互的授权,我们需要一个来构建的镜像。让我们来推送第二章 创建容器镜像中从零开始的镜像。首先,我们需要构建该镜像。要执行这一操作,我们使用如下命令:
1 |
$ docker build --tag masteringdocker3/scratch-example:latest . |
如果读者在照着操作的话,应将masteringdocker3修改为自己的用户名或组织名:
一旦构建了镜像,我们就可以通过运行如下命令来将其推送到Docker Hub:
1 |
$ docker image push masteringdocker3/scratch-example:latest |
输出如下图所示:
可以看出,因为我们在构建镜像时定义了masteringdocker3/scratch-example:latest,Docker自动地将镜像上传到该位置,并将新加的镜像放到了masteringdocker3这一组织中:
你会看到在Docker Hub中对这一构建可做的操作有限。这是因为该镜像不是由Docker Hub所构建的,因此,它并不太知道构建镜像所经过的操作。
Docker商店
你可能还记得在第一章 Docker概览中,我们从Docker商店下载了macOS和Windows的 Docker。不仅可以下载在不同平台上的Docker CE和Docker EE,它还是下载Docker镜像和插件的推荐地址。
译者注:2018年12月Docker 团队宣布Docker Store和Docker Cloud都已作为Docker Hub的一部分了
虽然你仅能在Docker商店中查找官方和认证镜像,但还可使用Docker商店的界面来从Docker Hub中搜索。同时,你可以下载Docker Hub中所不存在的镜像,如Citrix NetScaler CPX Express镜像:
你可能注意到,该镜像附带有一个价格(Express版的价格为$0.00),这表示你可以通过Docker商店来购买商业软件,因为它有内置付款和证书。如果你是软件发布商,你就可以通过Docker商家来签署和发布你自己的软件。
我们在本章稍后中讲解Docker插件时来看Docker商店中更多的操作。
Docker仓库
这一部分中,我们将会来看Docker仓库。Docker仓库是一个开源应用,可用于存储镜像并在你希望的任何地方运行。我们将会来看Docker仓库和Docker Hub之间的不同,以及如何进行两者的选择。在本部分的最后,我们会学习如何运行我们自己的Docker仓库并了解它是否适合你自己。
Docker仓库概览
前面已经提到,Docker仓库是一个你可以选择平台并用于存储镜像的开源应用。这样你可以保持100%的私密或与其他人进行分享。
如何你不想为Docker Hub上的私有特性进行支付又希望部署自己的仓库,那么Docker仓库就非常有用了。下面我们对比下Docker Hub和Docker仓库,来帮助你臻选在哪个平台上存储自己的镜像。
Docker仓库有如下特征:
- 托管并管理你自己的仓库,通过它可以让所有的仓库私有、公有或是兼而有之
- 根据需要为仓库扩容,基于你托管了多少个镜像以及对外要处理多少个拉取请求
- 所有操作都是基于命令行的
使用 Docker Hub,你可以:
- 获取基于GUI的界面来管理你的镜像
- 在云端拥有一处已配置好的仓库来处理公有和/或私有镜像
- 无需担忧对托管所有镜像服务器的管理工作
部署自己的仓库
你可能也猜到了,Docker仓库作为Docker Hub的一个镜像进行发布,这样仅需运行如下命令即可部署仓库:
1 2 |
$ docker image pull registry:2 $ docker container run -d -p 5000:5000 --name registry registry:2 |
以上命令将会进行Docker仓库的基础安装。我们来快速看一下如何对其推送和拉取镜像。首先我们需要一个镜像,让我们再次使用Alpine镜像吧:
1 |
$ docker image pull alpine |
现在我们已经有了一个Alpine Linux镜像的拷贝,我们需要将其推送到可通过localhost:5000访问的本地Docker仓库中。要实现这一操作,我们需要使用本地Docker仓库的URL来对Alpine Linux镜像打标签,并使用一个不同的镜像名:
1 |
$ docker image tag alpine localhost:5000/localalpine |
我们已经对镜像打了标签,接着就可以通过运行如下命令来将其推送到本地的Docker仓库上了:
1 |
$ docker image push localhost:5000/localalpine |
下图显示了以上命令的输出:
尝试运行如下命令:
1 |
$ docker image ls |
输出中会显示有两个镜像的IMAGE ID完全相同:
在从本地Docker仓库中重新拉取该镜像之前,我们应删除该镜像的两个本地拷贝。我们需要使用REPOSITORY名称而非IMAGE ID来进行这一操作,因为我们在两处有相同的 ID,这样Docker会抛出错误的:
1 |
$ docker image rm alpine localhost:5000/localalpine |
现在我们已删除了原始镜像和重打标签的镜像,可以通过运行如下命令来从本地Docker仓库拉取镜像:
1 2 |
$ docker image pull localhost:5000/localalpine $ docker image ls |
可以看出,我们已经从运行在localhost:5000上的Docker仓库拉取了我们镜像的一个拷贝:
你可以运行如下命令来停止和删除Docker仓库:
1 2 |
$ docker container stop registry $ docker container rm -v registry |
那么在启动自己的Docker仓库时有很多选项和考量。你可以想象得到,最重要的是有关存储。
因为仓库的唯一目的是存储和发布镜像,使用某种级别的持久化OS存储就非常重要了。Docker仓库目前支持如下存储选项:
- 文件系统:如其字面意思,所有的镜像将存储在你所指定的文件系统中。默认位置为/var/lib/registry。
- Azure:使用微软Azure Blob存储
- GCS:使用Google云存储
- S3:使用亚马逊简单存储服务(Amazon S3)
- Swift:使用OpenStack Swift
可以看出,除文件系统外,所支持的所有存储引擎都是高可用、分布式的对象级别存储。我们会在后面的章节来讲解这些云服务。
Docker认证仓库
分发商业版Docker EE的一个组件是Docker认证仓库(DTR)。可将其看作可以在自己的基础设施上托管的一个Docker Hub版本。DTR在Docker Hub和Docker仓库之上添加了如下特性:
- 集成入你的认证服务,如Active Directory或LDAP
- 在你的防火墙后部署在你自己的设备(或云)上
- 镜像签名来确保镜像是可信的
- 内置安全扫描
- Docker直接提供的高优化级支持服务
第三方仓库
不只有Docker提供镜像仓库服务,其它公司如Red Hat也提供它们自己的仓库,在上面可以查看到 Red Hat容器目录,托管着Red Hat 产品的所有容器化版本,以及支持其OpenShift的容器。
JFrog的Artifactory一类的服务提供私有Docker仓库来作为其构建服务的一部分。还有其它的仓库即服务(RaaS)产品,如CoreOS的Quay,现在已由Red Hat掌管,以及 AWS 和微软Azure所提供的服务。我在讲解云端的Docker时会来看这些服务。
Microbadger
Microbadger是针对分发容器或镜像的一个强大工具。它会深入到具体Docker镜像的每一层中所发生的操作,并输出每一层在实际大小或所占用磁盘量的权重。
在访问Microbadger官网https://microbadger.com/时将会显示如下页面:
你可以搜索Docker Hub中的镜像来让Microbadger将该镜像的信息展示给你,或者如果你要提供一些示例镜像或更多复杂的设置时你可以载入一个示例镜像集。
本例中,我们将搜索在本章前面推送的masteringdockerthirdedition/dockerfiles-example镜像,并选择latest标签。可以在下图中看出,在输入的内容会实时返回自动从Docker Hub中搜索的结果。
译者注:尚无法搜索到本文中上传的镜像,此处将使用原作者的镜像
默认情况下,它会载入latest标签,但你也可以从Versions下拉菜单中选择所需标签来进行修改。比如你有一个分阶标签并想要将这一新镜像推送给latest标签,却想要先看看其对于镜像大小的影响时,这就非常有用了。
从下图中可以看出,Microbadger显示了该镜像包含了多少层的信息:
通过显示各层的大小以及在镜像构建时所执行的Dockerfile命令,你可以看到在哪个阶段的镜像构建的大小扩充的大小,这在想要减小镜像的大小的非常有用。
Microbadger的另一个重要特性让你可以将基础统计数据内嵌到你的Git仓库或Docker Hub中,例如,下图显示了一个作者镜像的Docker Hub页面:
可以看出,Microbadger显示了镜像的整体大小,本例中为5.9MB,同时显示该镜像总共由几层组成,这里为7层。Microbadger服务还处于beta阶段,新功能还在持续加入。我建议你保持时刻关注。
总结
本章中,我们使用了Docker Hub手动及自动构建容器镜像的几种方式。我们讨论了除Docker Hub外可以使用的几种仓库,如Docker商店及Red Hat的容器目录。
我们还学习了部署自己的本地Docker仓库,并涉及到了部署时需要考虑到的存储问题。最后,我们一起来看了Microbadger,该服务让我们可以显示远程托管的容器镜像的信息。
下一章中,我们将一起来学习如何通过命令行管理我们的容器。
课后问题
- 是非题:Docker Hub是你能下载官方Docker镜像的唯一来源。
- 讲述为什么你会想将自动化构建与一个官方Docker Hub镜像相关联。
- Docker Hub是否支持多阶段构建?
- 是非题:在命令行中登录Docker的同时桌面应用也会登入?
- 你要如何删除IMAGE ID相同的两个镜像?
- 默认Docker仓库运行在哪个端口?
扩展阅读
有关Docker商店、认证仓库和仓库的更多信息,参见:
- Docker商家发布者注册:https://store.docker.com/publisher/signup/
- Docker认证仓库(DTR):https://docs.docker.com/ee/dtr/
- Docker仓库文档:https://docs.docker.com/registry/
在如下链接中你可以找到针对Docker仓库的不同类型的云存储更多信息:
- Azure Blob存储: https://azure.microsoft.com/en-gb/services/storage/blobs/
- Google云存储: https://cloud.google.com/storage/
- Amazon简单存储服务(Amazon S3): https://aws.amazon.com/s3/
- Swift: 使用OpenStack Swift: https://wiki.openstack.org/wiki/Swift
部分第三方仓库服务如下:
- Red Hat容器目录: https://access.redhat.com/containers/
- OpenShift: https://www.openshift.com/
- Artifactory by JFrog: https://www.jfrog.com/artifactory/
- Quay: https://quay.io/
最后,作者Apache Bench的Docker Hub和Microbadger的链接如下:
- Apache Bench镜像(Docker Hub): https://hub.docker.com/r/russmckendrick/ab/
- Apache Bench镜像(Microbadger): https://microbadger.com/images/russmckendrick/ab