02 . DockerFile构建镜像和Docker仓库
Posted lonelyxmas
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02 . DockerFile构建镜像和Docker仓库相关的知识,希望对你有一定的参考价值。
原文:02 . DockerFile构建镜像和Docker仓库
1|0为什么用DockerFile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
说dockerfile之前我们先说一下dockercommit
1|1利用commit理解镜像构成
注意: docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现 场等。但是,不要使用 docker commit 定制镜像,定制镜像应该使用 Dockerfile 来完成
镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础。
我们之前所使用的镜像都是docker hub等网站上的,直接使用这些镜像可以满足一定的需求,而当这些镜像无法直接满足需求时候,我们需要定制这些镜像.之前有说过,镜像是多层存储,每一层是在前一层的基础上进行的修改,而容器也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层.
1|2定制一个Web服务器
现在我们定制好了变化,我们希望将其保存下来形成镜像.
要知道,当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被 记录于容器存储层里。而 Docker 提供了一个 docker commit 命令,可以将容器的存储层保 存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新 的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化(类似于虚拟机的快照)。
1|3慎用docker commit
使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境 中并不会这样使用。
首先,如果仔细观察之前的 docker diff webserver 的结果,你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的执行,还有很多文件被改动或添加 了。这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添 加进来,如果不小心清理,将会导致镜像极为臃肿。
此外,使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑 箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根 本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体在操作的。虽 然 docker diff 或许可以告诉得到一些线索,但是远远不到可以确保生成一致镜像的地步。 这种黑箱镜像的维护工作是非常痛苦的。
而且,回顾之前提及的镜像所使用的分层存储的概念,除当前层外,之前的每一层都是不会 发生改变的,换句话说,任何修改的结果仅仅是在当前层进行标记、添加、修改,而不会改 动上一层。如果使用 docker commit 制作镜像,以及后期修改的话,每一次修改都会让镜像 更加臃肿一次,所删除的上一层的东西并不会丢失,会一直如影随形的跟着这个镜像,即使 根本无法访问到。这会让镜像更加臃肿.
2|0使用Dockerfile定制镜像
从刚才的 docker commit 的学习中,我们可以了解到,镜像的定制实际上就是定制每一层所 添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚 本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问 题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层, 因此每一条指令的内容,就是描述该层应当如何构建。
还以之前定制 nginx 镜像为例,这次我们使用 Dockerfile 来定制。
在一个空白目录中,建立一个文本文件,并命名为 Dockerfile :
2|1FROM指定基础镜像
FROM为指定基础镜像,我们定制镜像,肯定要以一个镜像为基础,在其上做定制,而FROM就是指定基础镜像,因此一个Dockerfile中FROM是必备的命令,并且必须是第一条指令.
在Docker Store上有非常多高质量的官方镜像,有可以直接拿来使用的服务类镜像,如nginx,redis,mysql,mongo,tomcat等,也有方便开发、构建、运行各种语言的镜像,如node,openjdk,python,ruby,golang等,可以在其中寻找一个最符合我们的镜像为基础镜像进行定制.
如果还没有找到对应服务的镜像,官方镜像中提供了一些更为基础的操作系统镜像,如ubuntu,debian,centos,fedora,alpine等,这些操作系统的软件库为我们提供了更广阔的扩展空间.
除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch 。这个镜像 是虚拟的概念,并不实际存在,它表示一个空白的镜像。
如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作 为镜像第一层开始存在。 不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 swarm 、 coreos/etcd 。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时 支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小 巧。使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
2|2RUN 执行命令
RUN 指令是用来执行命令行命令的。由于命令行的强大能力, RUN 指令在定制镜像时是最 常用的指令之一。其格式有两种:
shell 格式: RUN <命令> ,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中 的 RUN 指令就是这种格式。
exec 格式: RUN ["可执行文件", "参数1", "参数2"] ,这更像是函数调用中的格式。 既然 RUN 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个 命令对应一个 RUN 呢?比如这样:
之前说过,Dockerfile 中每一个指令都会建立一层, RUN 也不例外。每一个 RUN 的行为, 就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束 后, commit 这一层的修改,构成新的镜像。
而上面的这种写法,创建了 7 层镜像。这是完全没有意义的,而且很多运行时不需要的东 西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常 多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常 犯的一个错误。
Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。因此上面Dockerfile可以这样写:
首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立 很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是 仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每 一层该如何构建。
并且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 的命令换行方 式,以及行首 # 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障 更为容易,这是一个比较好的习惯。
此外,还可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的 软件,清理了所有下载、展开的文件,并且还清理了 apt 缓存文件。这是很重要的一步,我 们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。 因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清 理掉。
很多人初学 Docker 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要 清理掉无关文件。
2|3构建镜像
在之前Dockerfile文件所在目录执行
从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 Step 2 中,如同我们之前 所说的那样, RUN 指令启动了一个容器231d40e811cd,执行了所要求的命令,并最后提交 了这一层 3a439666c4da ,随后删除了所用到的这个容器78990dc4a6a6。
docker build [选项] <上下文路径/URL/->
构建成功后我们可以跟nginx:v2那样运行这个镜像,结果一样.
这只是默认行为,实际上 Dockerfile 的文件名并不要求必须为 Dockerfile ,而且并不要求 必须位于上下文目录中,比如可以用 -f ../Dockerfile.php 参数指定某个文件作为 Dockerfile
2|4上下文路径
是指在docker构建镜像,有时候想要使用本机的文件(比如复制),docker build命令知道这个路径后,会将这个路径下所有内容打包.
由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
2|5Docker build的用法
直接用git repo 进行构建
这行命令指定了构建所需的Git repo,并且指定默认的master分支,构建目录为/8.14/,然后Docker就会自己去git clone这个项目,切换到指定分支,并进入到指定目录后开始构建.
用给定的tar压缩包构建
从标准输入中读取Dockerfile进行构建
如果标准输入传入的是文本文件,则将其视为 Dockerfile ,并开始构建。这种形式由于直接 从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本 地文件 COPY 进镜像之类的事情。
从标准输入中读取上下文压缩包进行构建
3|0Dockerfile指令详解
3|1FROM 和 RUN 指令的作用
FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
RUN:用于执行后面跟着的命令行命令。有以下俩种格式
shell格式
exec格式
注意: Dockerfile的指令是每执行一次都会在docker上新建一层,所以过多无意义的层,会造成镜像膨胀过大,上面提到过,可以用&&符号链接命令,这样执行后,只会创建一层镜像
3|2COPY复制文件
3|3ADD
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
3|4CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
格式:
3|5ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
格式:
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
不传参运行
传参运行
3|6ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
3|7ARG
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:
3|8VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
格式
3|9EXPOSE
仅仅只是声明端口。
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:
3|10WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
格式:
3|11USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:
3|12HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:
3|13ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
格式
4|0Docker仓库
5|0访问仓库
仓库(Repository)是集中存放镜像的地方
一个容易混淆的概念是注册服务器( Registry )。实际上注册服务器是管理仓库的具体服务 器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以 被认为是一个具体的项目或目录。例如对于仓库地址 dl.dockerpool.com/ubuntu 来 说, dl.dockerpool.com 是注册服务器地址, Ubuntu 是仓库名。
大部分时候,并不需要这两者的概念.
6|0Docker Hub
目前Docker官方维护了一个公共仓库Docker Hub,其中包括了数量超过15000的镜像,大部分需求都可以通过在Docker Hub中直接下载镜像来实现.
注册,可以直接在https://cloud.docker.com免费注册一个Docker Hub账号.
登陆
可以通过执行docker login 命令交互式的输入用户名及密码来完成命令行界面登陆Docker Hub。docker logout退出登陆.
6|1拉取镜像
可以通过docker search命令来查找官方仓库中的镜像,并利用docker pull命令将他下载到本地.
可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、收藏数(表示该镜像的受关注程度),是否官方创建、是否自动创建.
根据是否是官方提供,可将镜像资源分为两类.
一种是类似centos这样的镜像,被称为基础镜像或根镜像,这些基础镜像由Docker公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字.
还有一种类型,比如tianon/centos镜像,他是由Docker的用户创建并维护的,往往带有用户名称前缀,可以通过前缀username/来指定某个用户提供的镜像,比如tianon用户.
另外,在查找的时候可以通过--filter=stars=N参数可以显示收藏数量为N以上的镜像.
6|2推送镜像
用户可以在登陆后通过docker push命令将自己的镜像推送到Docker Hub。
以下命令的flyingdreams请替换为你的Docker账号用户名.
6|3自动创建
自动创建(Automated Builds)功能对于需要经常升级镜像内程序来说,十分方便.
有时候,用户创建了镜像,安装了某个软件,如果程序发布新版本则需要手动更新镜像.
而自动创建允许用户Docker Hub指定跟踪一个目标网站(目前支持GitHub或BitBucket)上的项目,一旦项目发生新的提交或者创建新的标签(tag),Docker Hub会自动构建镜像并推送到Docker Hub中.
要配置自动创建,包括如下的步骤:
7|0私有仓库docker-registry
有时候使用Docker Hub这样的公共仓库可能不安全,用户可以创建一个本地仓库供私人使用.
通过官方提供的私有仓库镜像
registry
来搭建私有仓库。通过 humpback 快速搭建轻量级的Docker容器云管理平台此外还有像Harbor,rancher等私有仓库。
7|1安装运行docker-registry
8|0安装运行harbor(http方式)
Harbor 可帮助用户迅速搭建企业级的 Registry 服务, 它提供了管理图形界面, 基于角色的访问控制 ( Role Based Access Control), 镜像远程复制 (同步), AD/LDAP 集成, 以及审计日志等企业用户需求的功能, 同时还原生支持中文, 深受中国用户的喜爱;
8|1安装harbor
是
VMware
公司开源了企业级Registry
项目, 其的目标是帮助用户迅速搭建一个企业级的Docker registry
服务。由于 Harbor 是基于 Docker Registry V2 版本,所以 docker 版本必须
>=1.10.0
docker-compose>=1.6.0
下载最新版 Docker Compose
curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
下载最新版Docker Harbor
wget https://github.com/goharbor/harbor/releases/download/v1.10.0-rc1/harbor-offline-installer-v1.10.0-rc1.tgz
接下来我们可以直接浏览器访问配置文件定义的IP或者域名加端口
8|2修改harbor端口
8|3使用harbor
为了体现出效果,建议使用非harbor的另一台机器
9|0安装harbor(https方式)
9|1DNS服务器安装dnsmasq
生成harbor证书
官方建议不要在Harbor上启用https,而是将Harbor放置到一个SLB的后边,配置SLB的端口转发进行访问,或者再装一个Nginx,进行Nginx的端口转发.
如果想做一个HA方案的话,可以按照如下方式构建一个(主从模式个人感觉很不靠谱
负载均衡同时还要承担检查的任务,而Redis用于数据的缓存和消息队列的实现,Mysql存储用户信息和仓库信息,云存储用来存储Docker镜像.
__EOF__
本文链接:https://www.cnblogs.com/you-men/p/13121835.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
以上是关于02 . DockerFile构建镜像和Docker仓库的主要内容,如果未能解决你的问题,请参考以下文章