《精通Docker第三版》完整目录:
第一章 Docker概览
第二章 创建容器镜像
第三章 存储和发布镜像
第四章 管理容器
第五章 Docker Compose
第六章 Windows容器
第七章 Docker Machine
第八章 Docker Swarm
第九章 Docker和Kubernetes
第十章 在公有云上运行Docker
第十一章 Portainer – 一个Docker的GUI
第十二章 Docker安全
第十三章 Docker工作流
第十四章 Docker进阶
本章中,我们会讲解几个服务,如Docker Hub,可以让我们存储镜像,还有Docker私有仓库,我们可以使用它来运行本地存储的Docker容器。我们还将回顾这些服务间的不同以及在何时、怎样使用这些服务。
本章还将涵盖如何使用Webhooks来设置自动化构建,以及进行这一设置的各个组成部分。我们来快速看下本章将要学习的主要内容:
- Docker Hub
- Docker商店
- Docker私有仓库
- 第三方仓库
- Microbadger
技术准备
本章中,我们将使用我们的Docker安装来构建镜像。和之前一样,虽然本章中的截图来自我个人偏爱的操作系统macOS,我们所运行的命令在前述的三个操作系统中都可以生效。本章中的完整代码可参见:https://github.com/alanhou/mastering-docker。
访问如下视频来查看实现代码的运行:http://t.cn/Ai9rSNbd
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的仪表盘:
译者注:在翻译本书时,Docker Hub 的界面发生了较大的变化,文中截图均使用新版本界面
从这里,你可以进入Docker Hub的所有其它子页面。但是,在查看其它部分之前,我们先来说说仪表盘。在这里,你可以查看自己所有的镜像,包括公有的和私有的。它们的排序首先是star数,然后是拉取的数量,这一排序无法修改。
在接下来的小节中,我们将一起来了解仪表盘上所能看到的所有内容,先从顶部的深蓝色(已更改为蓝色)菜单开始。
发现
Explore发现选项会列出官方的Docker镜像,像仪表盘一样,它们以star数和拉取数进行排序(排序规则已调整)。你可以从如下截图中看出,每个官方镜像有上千万次拉取:
这并不是推荐的下载官方镜像的Docker商店的方法。Docker现在推荐你使用Docker商店,但因本章稍后会深入了解这里,我们暂不会详细讨论。
开发组织
组织既可以是你创建的,也可以是你加入的。组织让我们可以对多人协作的项目进行分层控制。组织可以有自己的设置,如是否将仓库默认作为仅有或私有存储,或者是修改方案来允许不同数量的私有仓库并与你本人或他人拥有的仓库进行整体分离。
你也可以在仪表盘页面Docker的 logo 下面访问或切换账户或组织,在登录的情况下通常会看到你自己的用户名:
创建
我们将在稍后的部分中深入学习创建仓库以及进行自动化构建,所以这里不会详细讨论,仅仅会说明创建菜单提供了三个选项:
- 创建仓库
- 创建自动化构建
- 创建组织
这些选项可以在下图中看到:
译者注:官网已进行大改版,省略截图
个人中心和设置
顶部菜单的最后一个选项是管理个人中心和账号设置:
账号设置页面允许我们设置对外的资料,包含如下选项:
- 修改密码
- 查看所属组织
- 查看对 email 更新的订阅
- 设置你想要接收的具体通知
- 设置哪些授权服务可以访问你的信息
- 查看关联账号(如你的GitHub或Bitbucket账户)
- 查看你的企业证书、付款信息和全局设置
目前唯一需选择的全局设置是确定创建仓库时默认为公有还是私有。默认的是创建为公有仓库:
My Profile 菜单项可进入到你的对外资料页,我们的页面为https://hub.docker.com/u/russmckendrick/
其它菜单选项
在仪表盘页深蓝色的菜单栏下方还有两个没讲到的区域。第一个是Stars页面,让我们可以查看自己加星的仓库:
译者注:已调整至My Profile 页面
这在你遇到想要使用的仓库时非常有用,你可以访问它们来查看最近是否有更新,或是这些仓库有没有进行过其它修改。
第二个是一个新设置Contributed。点击它会打开个区域,显示你做过提交的非自有仓库的其它仓库列表。
创建一个自动化构建
在这一部分中,我们将来看自动化构建。自动化构建是指你可以关联自己的GitHub或Bitbucket账户,当代码仓库里的代码更新时,你可以让镜像在Docker Hub上自动构建。我们会来讲解所需的各个部分,最终,你们能够自动化自己所有的构建。
设置代码
创建自动化构建的第一步是配置你的GitHub或Bitbucket账户。选择在何处存储你的代码有两种选项。在我们的示例是,我会使用GitHub,但对于GitHub和Bitbucket的设置是一样的。
事实上,我们会使用与本书配套的仓库。因为这个仓库是对公众开放的,你可以fork它并在自己的GitHub账户中进行后续的操作,参照如下的截图:
在第二章 创建容器镜像中,我使用了几个不同的Dockerfile。我们将使用这些来进行自动化构建。你如果还记得的话,我们安装了Nginx并添加了含有Hello world! 信息的简单页面。这由Docker来处理,并且我们还多阶段构建。
设置Docker Hub
在Docker Hub中,我们将使用创建下拉菜单并选择创建自动化构建。在选择之后,会进入到一个显示你关联了GitHub或Bitbucket账户的页面。
译者注:目前创建自动化构建已经迁移到创建仓库页面
从如上的截图中可以看出,我们已经将GitHub账户与Docker Hub账户相关联。关联这两个工具的过程非常简单,我们只需按照屏幕指示授权Docker Hub来访问我的GitHub账户。
在将Docker Hub连接到GitHub是有两个选项:
- Public and Private:这是推荐的选项。Docker Hub将可以访问所有你的公有和私有仓库,以及组织。Docker Hub还可以配置在设置自动化构建时所需的Webhook。
- Limited Access:这限制Docker Hub仅能访问对外开放的仓库和组织。如果你在关联账号时使用了这一选项,Docker Hub将不能配置自动化构建时所需的Webhook。那么你就需要从这两个地方搜索并选择进行自动化构建所要的仓库。这会创建一个Webhook来告知在所选的代码仓库完成commit时,在Docker Hub上创建一个新的构建。
译者注:新版免费版未发现可针对仓库级别的关联,以下文字仅保留原文,与截图不相关
在以上截图中,我选择了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