Docker容器作为部署和管理云原生分布式系统的最佳实践正在兴起。 容器是Docker映像的实例。 事实证明,关于图像有很多知识。
在这个分为两部分的教程中,我将深入介绍Docker映像。 在第一部分中,我讨论了基本原理,设计注意事项和图像内部检查。 在这一部分中,我将介绍构建自己的映像,进行故障排除以及使用映像存储库。
另一方面,您将对Docker镜像到底是什么以及如何在自己的应用程序和系统中有效利用它们有了深刻的了解。
建筑图片
有两种生成映像的方法。 您可以修改现有容器,然后将其提交为新映像,或者可以编写Dockerfile并将其构建为映像。 我们将仔细研究两者,并说明其优缺点。
手动构建
通过手动构建,您可以像对待普通计算机一样对待容器。 安装软件包,编写文件,完成所有工作后,提交并最终得到一个新映像,该映像用作模板来创建更多相同的容器甚至基于其他映像。
让我们从alpine映像开始,它是基于Alpine Linux的非常小的斯巴达式映像。 我们可以以交互方式运行它以进入外壳。 我们的目标是添加一个名为“ yeah”的文件,其中包含文本“ it works!”。 到根目录,然后从中创建一个名为“ yeah-alpine”的新映像。
开始了。 好的,我们已经在根目录下了。 让我们看看那里有什么。
- > docker run -it alpine /bin/sh
- / # ls
- bin dev etc home lib linuxrc media mnt proc root run sbin srv sys tmp usr var
有什么可用的编辑器? 没有vim,没有纳米?
- / # vim
- /bin/sh: vim: not found
- / # nano
- /bin/sh: nano: not found
那好吧。 我们只想创建一个文件:
- / # echo "it works!" > yeah
- / # cat yeah
- it works!
我从交互式外壳退出,可以看到带有docker docker ps --all
名为“ vibrant_spenc”的容器。 --all
标志很重要,因为容器不再运行。
- > docker ps --all
- CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
- c8faeb05de5f alpine "/bin/sh" 6 minutes ago Exited vibrant_spence
在这里,我从“ vibrate_spence”容器创建一个新图像。 我添加了提交消息“地雷,地雷,地雷”。
- > docker commit -m "mine, mine, mine" vibrant_spence yeah-alpine
- sha256:e3c98cd21f4d85a1428...e220da99995fd8bf6b49aa
让我们来看看。 是的,有一个新图像,在它的历史中,您可以看到带有“地雷,地雷,地雷”注释的新图层。
- > docker images
- REPOSITORY TAG IMAGE ID SIZE
- yeah-alpine latest e3c98cd21f4d 4.8 MB
- python latest 775dae9b960e 687 MB
- d4w/nsenter latest 9e4f13a0901e 83.8 kB
- ubuntu-with-ssh latest 87391dca396d 221 MB
- ubuntu latest bd3d4369aebc 127 MB
- hello-world latest c54a2cc56cbb 1.85 kB
- alpine latest 4e38e38c8ce0 4.8 MB
- nsqio/nsq latest 2a82c70fe5e3 70.7 MB
-
- > docker history yeah-alpine
- IMAGE CREATED SIZE COMMENT
- e3c98cd21f4d 40 seconds ago 66 B mine, mine, mine
- 4e38e38c8ce0 7 months ago 4.8 MB
现在进行真正的测试。 让我们删除该容器,然后根据图像创建一个新容器。 预期结果是“ yeah”文件将出现在新容器中。
- > docker rm vibrant_spence
- vibrant_spence
-
- > docker run -it yeah-alpine /bin/sh
- / # cat yeah
- it works!
- / #
我能说什么 是的,它有效!
使用Dockerfile
用修改后的容器创建图像很酷,但是没有责任。 很难跟踪更改并知道具体的修改是什么。 创建映像的严格方法是使用Dockerfile生成映像。
Dockerfile是类似于Shell脚本的文本文件,但它支持多个命令。 每个修改文件系统的命令都会创建一个新层。 在第一部分中,我们讨论了将图像正确分成几层的重要性。 Dockerfile本身就是一个大话题。
在这里,我将演示几个命令,以基于Dockerfile创建另一个映像“ oh-yeah-alpine”。 除了创建臭名昭著的“ yeah”文件,我们还要安装vim。 高山Linux发行版使用称为“ apk”的软件包管理系统。 这是Dockerfile:
- FROM alpine
-
- # Copy the "yeah" file from the host
- COPY yeah /yeah
-
- # Update and install vim using apk
- RUN apk update && apk add vim
-
- CMD cat /yeah
基本图像是高山的。 它从Dockerfile所在的主机目录(构建上下文路径)中复制“ yeah”文件。 然后,它运行apk update
并安装vim。 最后,它设置在容器运行时执行的命令。 在这种情况下,它将在屏幕上打印“是”文件的内容。
好。 现在我们知道了要进入的内容,让我们来构建这个东西。 “ -t”选项设置存储库。 我没有指定标签,因此它将是默认的“最新”标签。
- > docker build -t oh-yeah-alpine .
- Sending build context to Docker daemon 3.072 kB
- Step 1/4 : FROM alpine
- ---> 4e38e38c8ce0
- Step 2/4 : COPY yeah /yeah
- ---> 1b2a228cc2a5
- Removing intermediate container a6221f725845
- Step 3/4 : RUN apk update && apk add vim
- ---> Running in e2c0524bd792
- fetch http://dl-cdn.alpinelinux.org/.../APKINDEX.tar.gz
- fetch http://dl-cdn.alpinelinux.org.../x86_64/APKINDEX.tar.gz
- v3.4.6-60-gc61f5bf [http://dl-cdn.alpinelinux.org/alpine/v3.4/main]
- v3.4.6-33-g38ef2d2 [http://dl-cdn.alpinelinux.org/.../v3.4/community]
- OK: 5977 distinct packages available
- (1/5) Installing lua5.2-libs (5.2.4-r2)
- (2/5) Installing ncurses-terminfo-base (6.0-r7)
- (3/5) Installing ncurses-terminfo (6.0-r7)
- (4/5) Installing ncurses-libs (6.0-r7)
- (5/5) Installing vim (7.4.1831-r2)
- Executing busybox-1.24.2-r9.trigger
- OK: 37 MiB in 16 packages
- ---> 7fa4cba6d14f
- Removing intermediate container e2c0524bd792
- Step 4/4 : CMD cat /yeah
- ---> Running in 351b4f1c1eb1
- ---> e124405f28f4
- Removing intermediate container 351b4f1c1eb1
- Successfully built e124405f28f4
看起来挺好的。 让我们确认图像已创建:
- > docker images | grep oh-yeah
-
- oh-yeah-alpine latest e124405f28f4 About a minute ago 30.5 MB
请注意,安装vim及其依赖项如何使容器的大小从基本高山映像的4.8MB膨胀到庞大的30.5MB!
一切都很好。 但这有效吗?
- > docker run oh-yeah-alpine
- it works!
哦,是的,它有效!
如果您仍然怀疑,让我们进入容器,并使用我们新安装的vim检查“是”文件。
- > docker run -it oh-yeah-alpine /bin/sh
- / # vim yeah
-
- it works!
- ~
- ~
- .
- .
- .
- ~
- "yeah" 1L, 10C
构建上下文和.dockerignore文件
我没有告诉你,但最初当我尝试构建“哦,是高山”图像时,它只是挂了几分钟。 问题是我只是将Dockerfile放在我的主目录中。 Docker构建映像时,它首先打包Dockerfile所在的整个目录(包括子目录),并使其可用于Dockerfile中的COPY命令。
Docker并不想变得聪明,并分析您的COPY命令。 它只是包装了整个东西。 请注意,构建内容不会以映像结尾,但是如果构建上下文不必要地大,则会减慢构建命令的速度。
在这种情况下,我只需将Dockerfile和“ yeah”复制到一个子目录中,然后在该子目录中运行docker build命令。 但是有时您有一个复杂的目录树,您想从中复制特定的子目录和文件而忽略其他目录和文件。 输入.dockerignore文件。
该文件使您可以精确控制构建上下文中包含的内容。 我最喜欢的技巧是首先排除所有内容,然后开始包含我需要的点点滴滴。 例如,在这种情况下,我可以创建以下.dockerignore文件,并将Docker文件和“ yeah”保留在主目录中:
- # Exclude EVERYTHING first
- *
-
- # Now selectively include stuff
- !yeah
无需在构建上下文中包含“ Dockerfile”本身或“ .dockerignore”文件。
复制与安装
有时需要将文件复制到映像中,但是在其他情况下,您可能希望容器更加动态并可以在主机上使用文件。 这是卷和挂载发挥作用的地方。
挂载主机目录是另一回事。 数据归主机所有,不归容器所有。 容器停止时可以修改数据。 可以在安装了不同主机目录的情况下启动同一容器。
标记图像
如果您开发基于微服务的系统并且生成许多有时必须彼此关联的图像,则标记图像非常重要。 您可以向图像添加任意数量的标签。
您已经看到了默认的“最新”标签。 有时,添加其他标签是有意义的,例如“ tested”,“ release-1.4”或与映像相对应的git commit。
您可以在构建期间或之后标记图像。 这是将标签添加到现有图像的方法。 请注意,虽然它被称为标签,但您也可以分配一个新的存储库。
- > docker tag oh-yeah-alpine oh-yeah-alpine:cool-tag
- > docker tag oh-yeah-alpine oh-yeah-alpine-2
-
- > docker images | grep oh-yeah
- oh-yeah-alpine-2 latest e124405f28f4 30.5 MB
- oh-yeah-alpine cool-tag e124405f28f4 30.5 MB
- oh-yeah-alpine latest e124405f28f4 30.5 MB
您也可以通过按标签名称删除图像来取消标签。 这有点吓人,因为如果您不小心删除了最后一个标签,则会丢失图像。 但是,如果您从Dockerfile生成映像,则只需重建映像即可。
- > docker rmi oh-yeah-alpine-2
- Untagged: oh-yeah-alpine-2:latest
-
- > docker rmi oh-yeah-alpine:cool-tag
- Untagged: oh-yeah-alpine:cool-tag
如果我尝试删除最后剩余的标记图像,则会收到错误消息,因为该图像已被容器使用。
- > docker rmi oh-yeah-alpine
-
- Error response from daemon: conflict: unable to remove repository
- reference "oh-yeah-alpine" (must force) -
- container a1443a7ca9d2 is using its referenced image e124405f28f4
但是如果我取出容器...
- > docker rmi oh-yeah-alpine
- Untagged: oh-yeah-alpine:latest
- Deleted: sha256:e124405f28f48e...441d774d9413139e22386c4820df
- Deleted: sha256:7fa4cba6d14fdf...d8940e6c50d30a157483de06fc59
- Deleted: sha256:283d461dadfa6c...dbff864c6557af23bc5aff9d66de
- Deleted: sha256:1b2a228cc2a5b4...23c80a41a41da4ff92fcac95101e
- Deleted: sha256:fe5fe2290c63a0...8af394bb4bf15841661f71c71e9a
-
- > docker images | grep oh-yeah
是的 没了。 但是不用担心。 我们可以重建它:
- > docker build -t oh-yeah-alpine .
-
- > docker images | grep oh-yeah
- oh-yeah-alpine latest 1e831ce8afe1 1 minutes ago 30.5 MB
是的,回来了。 Dockerfile的胜利!
使用图像注册中心
图像在某些方面与git存储库非常相似。 它们也是根据一组有序的提交构建的。 您可以想到两个使用相同基础映像作为分支的映像(尽管在Docker中没有合并或变基)。 图像注册表相当于GitHub等中央git托管服务。 猜猜官方Docker镜像注册表的名称是什么? 没错, Docker Hub 。
拉图像
当您运行映像时,如果该映像不存在,则Docker将尝试从您配置的映像注册表之一中提取它。 默认情况下,它进入Docker Hub,但是您可以在“〜/ .docker / config.json”文件中对其进行控制。 如果使用其他注册表,则可以按照他们的指示进行操作,这通常涉及使用其凭据进行登录。
让我们删除“ hello-world”图像,然后使用docker pull
命令再次将其docker pull
。
- > dockere images | grep hello-world
- hello-world latest c54a2cc56cbb 7 months ago 1.85 kB
-
- > docker rmi hello-world
- hello-world
没了。 现在就拉。
- > docker pull hello-world
- Using default tag: latest
- latest: Pulling from library/hello-world
- 78445dd45222: Pull complete
- Digest: sha256:c5515758d4c5e1e...07e6f927b07d05f6d12a1ac8d7
- Status: Downloaded newer image for hello-world:latest
-
- > dockere images | grep hello-world
- hello-world latest 48b5124b2768 2 weeks ago 1.84 kB
最新的hello-world已被更新的版本取代。
推送图像
推送图像会更加复杂。 首先,您需要在Docker Hub(或其他注册表)上创建一个帐户。 接下来,您登录。然后,您需要根据您的帐户名(在我的情况下为“ g1g1”)标记要推送的图像。
- > docker login -u g1g1 -p <password>
- Login Succeeded
-
- > docker tag hello-world g1g1/hello-world
-
- > docker images | grep hello
-
- g1g1/hello-world latest 48b5124b2768 2 weeks ago 1.84 kB
- hello-world latest 48b5124b2768 2 weeks ago 1.84 kB
现在,我可以推送g1g1 / hello-world标记的图像。
- > docker push g1g1/hello-world
- The push refers to a repository [docker.io/g1g1/hello-world]
- 98c944e98de8: Mounted from library/hello-world
- latest: digest: sha256:c5515758d4c5e...f6d12a1ac8d7 size: 524
结论
Docker映像是容器的模板。 通过使用分层文件系统存储驱动程序,它们被设计为高效并提供最大的重用性。
Docker提供了很多用于列出,检查,构建和标记图像的工具。 您可以将映像拉入和推送到Docker Hub之类的映像注册表中,以轻松管理和共享映像。
翻译自: https://code.tutsplus.com/tutorials/docker-from-the-ground-up-building-images--cms-28166