Docker镜像构建

一、简介

  在构建容器化应用时,相当重要的步骤莫过于镜像制作,本文将介绍镜像制作方法以及镜像制作的建议。通常镜像的制作有两种方式:
  • 使用现有的容器使用docker commit 生成镜像
  • 使用Dockerfile进行镜像构建
    采用docker commit 生成的镜像实际上是容器内的文件系统进行修改在进行提交,而运行的容器实际上是在镜像的文件系统顶层添加了一层读写层,所都的修改都是基于这一层,当生成镜像时会将这一层数据保存,所以每次使用commit提交镜像时候都会比原来多一层,这样会使得镜像越来越大并且不易维护。同时,对于镜像使用者来说完全不透明,使用者不清楚该镜像怎么样构建的,是否安全等,这种方式及其不推荐。
    而使用Dockerfile构建镜像,对于使用者来说完全透明,构建镜像的每一个步骤都在Dockerfile文件中描述的清清楚楚,同时当需要对镜像修改时候,只需修改Dockerfile文件中的指令,维护镜像只需要维护一个Dockerfile,这也是镜像构建的最佳方式。当然,要使用Dockerfile就必须明白Dockerfile的语法和各个指令,以下将作详细介绍。
 

二、Dockerfile介绍

 
Dockerfile实际上就是一个文本文件,只不过这里的文件内容被Docker Deamon识别从而进行镜像构建。
使用Dockerfile步骤:
  1.编写Dockerfile文件,用于描述镜像生成的步骤
  2.使用docker build -t name:tag 命令构建镜像
 

语法规则

1.#号代表注解。
2.Dockerfile每一行都是以某个指令(约定大写字母)开始,后面可加参数构成完整指令,用于描述镜像构建步骤。
3.指令从上倒下依次执行
4.Dockerfile的第一个指令一定是FROM指令,用于指定基础镜像
5.Dockerfile还可以使用.dockerignore文件来忽略在制作镜像时候需要忽略的文件或者目录,列如使用COPY指令时候忽略某些文件或者目录。
6.所有指令参数为数组时,最好使用双引号
 

环境变量引用

1.若要在Dockerfile中引环境变量则使用$variable_name或${variable_name}
2.当变量为空或者变量值未设置可以使用${variable_name:-value}来指定变量的默认值
 

docker build命令

docker build 命令用于基于Dockerfile构建镜像,使用语法:
docker build [OPTIONS] PATH | URL | -
其中PATH代表含有Dockfile的目录,当然也可以是URL中含有Dockerfile
常用选项:
  • -t,--tag list  指定生成镜像标签,格式为name:tag
  • -f,--file string  单独指定Dockerfile文件位置
  • --build-arg list  设置构建时的变量
  • --no-cache  构建镜像时候不使用缓存
 

快速开始

构建一个简单的nginx镜像:
1.创建一个目录用于存放DockerFile
mkdir /opt/demo -/opt/demo/
2.编辑Dockerfile文件,如果文件名称不是Dockerfile需要用-f指定名称。
FROM centos:latest LABEL Author=“wd” RUN yum install -y yum epel-release && yum install -y nginx && echo > /usr/share/nginx/html/index.html CMD [ ,,,,
3.构建镜像
[root@app51 demo] Sending build context to Docker daemon 21/4--->2/4 : LABEL Author= --->--->3/4 : RUN yum install -y yum epel-release && yum install -y nginx && echo > /usr/share/nginx/html/--->--->4/4 : CMD [ ,---> Running --->
4.利用制作的镜像启动容器,并查看是否运行成功.
[root@app51 demo] 60e5de135132-nginx server [root@app51 demo]
以上的Dockerfile中的每一行是一个指令,用于描述镜像生成的步骤,以下将介绍这些指令用法。
 

三、指令详解 

FROM

  FROM指令是最重要且必须为Dockerfile中的第一个非注视指令,用于为构建的镜像指定基础镜像。后续指令运行环境基于该基础镜像,构建镜像时候默认会先从主机上寻找镜像,若不存在时则从Docker HUB上拉取镜像。
语法 :
FROM [:@

解释:
repository:镜像仓库
tag:镜像标签,省略就是latest
digest:镜像哈希码
示例: 
FROM centos:latest

LABEL

  LABEL用于为镜像提供元数据信息,其数据格式为key=value。
语法 :
LABEL = = = ...

示例:

LABEL = LABEL maintainer=

MAINTAINER (deprecated)

  用于提供镜像提供者的信息,可以在Docker任何位置。该语法可能废弃,推荐使用LABEL
语法:
MAINTAINER

解释:
message:可以是任意文本信息
示例: 
MAINTAINER "wd "

COPY

  用于主机中的文件或者复制到镜像中

语法:

COPY [--chown=:] ... --chown=:] [,... ]

解释:
src:源文件或者目录,支持通配符。如果src是目录,src目录自己不会被复制,复制的是目录中的文件
dest:容器中文件系统目录,如果目录不存在自动创建创建。
user:复制到容器中的文件所属用户
group:复制到容器中的文件所属用户组
注意事项:
  1. 如果复制的src或dest中存在空格字符需使用第二种加双引号方式
  2. src必须是 build的上下文目录(Dockerfile同级目录或子目录),不能是父目录或者绝对路径
  3. 如果指定来多个src或者src中使用了通配符,则dest必须是一个目录,且必须以/结尾
示例: 
COPY hom* /mydir/ COPY hom?.txt /mydir/

ADD

  ADD指令类似于COPY,但是ADD比COPY更强大,支持TAR文件和URL路径

语法:

ADD [--chown=:] ... --chown=:] [,... ]

解释
src:源文件或者目录,支持通配符。如果src是目录,src目录自己不会被复制,复制的是目录中的文件
dest:容器中文件系统目录,如果目录不存在自动创建创建。
user:复制到容器中的文件所属用户
group:复制到容器中的文件所属用户组
注意事项:
  1. 当src是URL时,如果dest不以/结尾,则src指定的文件将被下载并且被创建为dest,如果dest以/结尾,则src指定下载的文件会保存在dest目录下。
  2. 当src是一个本地目录的一个tar压缩格式文件,其在容器中会被展开为目录,类型与tar -x命令,通过URL下载的tar文件则不会被解压。
  3. 如果指定来多个src或者src中使用了通配符,则dest必须是一个目录,且必须以/结尾,多个文件一同被复制在dest目录下
示例:
ADD hom* /mydir//mydir/

WORKDIR

  用于为Dockerfile中的各个指定设置工作目录,可以使用多次,当使用相对路径时目录是基于前一个WORKDIR指令。
语法 :
WORKDIR dirpath

示例:

WORKDIR /usr/local

ENV

  用于为镜像定义所需的环境变量,并可被Dockfile中位于其以后的指令所调用,如ADD、COPY、RUN等调用格式为$variable_name或者${variable_name},此外在启动容器时候这些变量也是存在的。

语法:

ENV = ...

注意:
  1. 第一种格式中key之后的所有值会被作为value,因此一次只能设置一个变量
  2. 第二种格式可一次性设置多个变量,每个变量为一个key=value的键值对,如果value种包含空格,可以用反斜线(\)转义,也可以通过对value加引号进行标识,此外反斜线也可用于续行,多个变量时候建议使用。 

示例:

ENV myName= ENV myCat fluffy

RUN

  用于在build过程中运行的程序,可以是任何指令,可以指定多个RUN

语法:

RUN RUN [,,

示例:

RUN yum install -,]

EXPOSE

  用于为容器暴露端口到外部,用于实现通讯,类似于docker run的-p选项

语法:

EXPOSE [/...]

解释:
port:端口
protocol:协议,可以是udp或tcp,默认tcp
示例: 
EXPOSE 80808080/udp 8088/tcp

VOLUME

  用于在image中创建一个挂载目录,以挂载宿主机上的目录

语法:

VOLUME ]

解释:
path:代表容器中的目录,与docker run 不同,Dockerfile中不能指定宿主机目录,默认使用docker管理的挂载点
示例: 
VOLUME [ VOLUME /myvol

CMD

  用于为在镜像启动为容时候提供的默认命令,该指定可以有多个,但是只有最后一个生效。
语法 :
CMD command param1 param2 CMD [, CMD [,

注意:

  1. 在第一种格式中command 通常是一个shell命令,且默认以/bin/sh -c来运行它,这意味着此进程在容器的的PID不为1,不能接受unix信号,因此使用docker stop 命令停止容器时,此进程接受不到SIGTERM信号。
  2. 第二种格式是可执行程序运行方式,不会以"/bin/sh -c”来发起,无shell环境,所有shell变量不能引用,但是可以用"/bin/bash -c”作为启动命令达到第一种格式效果
  3. 第三种格式需要结合ENTRYPOINT使用,作用是为其提供默认参数 

ENTRYPOINT

  类似于CMD功能,用于为启动容器指定默认启动命令,与CMD不同的是ENTRYPOINT命令不会随着docker run 后使用的命令覆盖而会把命令作为参数,除非docker run 参数中指定了—entrypoint
语法 :
ENTRYPOINT ,,]

注意事项:
  • 与CMD类似,第一种方式默认会以/bin/sh -c 启动,而第二种则不会,也就意味着没有shell环境
  • 通常ENTRPOINT用于使用ENTRPOINT脚本启动
  • 当CMD与ENTRYPOINT同时存在时,CMD的参数为ENTRYPOINT提供 

示例:

[“nginx”,]

USER

  用于指定构建镜像时RUN、CMD、ENTRYPOINT等指令使用的用户或UID,默认情况容器运行身份为ROOT
语法 :
USER [:[:]

注意事项:
  1. 指定的USER或者GROUP必须在容器中存在,否则指令会运行失败
示例: 
USER nginx

STOPSIGNAL

  该指令用于设置容器停止时向容器内进程发送的信号,列如 9 、SIGKILL、SIGTERM。

语法:

STOPSIGNAL signal

示例:

STOPSIGNAL SIGKILL

注意事项:
  1. 向容器发送信号只能被PID=1的进程所接收,当PID=1进程不是应用进程时候,应用进程收不到终止信号。 

HEALTHCHECK

  该指令在1.12版本中添加,用于对容器中的应用进行健康检查,不做检查使用NONE。当对容器做了健康检查时候,检查值为0表示成功,非0表示不健康。 
语法:
HEALTHCHECK [OPTIONS] CMD command

其中OPTIONS有如下选项:

  • --interval=DURATION 检查间隔(默认: 30s)
  • --timeout=DURATION 超时时间(默认t: 30s)
  • --start-period=DURATION 等待检查的时间,默认0s代表一启动就检查 (默认: 0s)
  • --retries=N (default: 3)  重试次数 

示例:

HEALTHCHECK --interval=5m --timeout=-f http://localhost/ || exit 1

SHELL

  将可执行程序运行为shell环境,默认以/bin/sh -c运行

语法:

SHELL [,]

示例:

SHELL [,“hello

ARG

  该指令用于在build过程中提供参数,而在命令行使用--build-arg =来传递参数值,这样可以使用参数进行构建镜像。 
语法:
ARG [=]

示例:
Dockerfile
==

构建镜像:

[root@app51 ~] Sending build context to Docker daemon 2251/4--->2/4 : ARG CONF= --->--->3/4 : LABEL Author=--->--->4/4 : RUN touch ---> Running --->2

运行容器查看:

[root@app51 ~] -rw-r--r-- 1 root root 0 Feb 27 11:18 /etc/test.conf

ONBULD

  用于在Dockerfile中定义一个触发器,当制作出来的镜像被别人用于基础镜像时候自动触发。

语法:

ONBUILD [INSTRUCTION]

解释:
INSTRUCTION:指令可以是RUN 、COPY等
注意事项:
  1. ONBUILD不会触发FROM指令。
  2. 在镜像标签中应明确指出onbuild关键字,以标记使用其基础镜像会触发其他指令 

示例:

ONBUILD ADD . /app//usr/local/bin/python-build --dir /app/src

四、使用multi-stage

  在构建镜像过程中,我们可能只需要某些镜像的产物,比如在运行一个go程序需要先go程序包编译后才运行,如果在一个镜像里面完成,先要经过安装编译环境,程序编译完再安装运行环境,最后运行程序,这样的镜像体积往往比较大,不利于我们使用。而真正我们需要的镜像是只有程序包和运行环境,编译环境的构建在运行容器时候是不需要的,所以Docker提供了一种解决方案就是multi-stage(多阶段构建)。
    Docker允许多个镜像的构建可以使用同一个Dockerfile,每个镜像构建过程可以称之为一个stage,简单理解就是一个FROM指令到下一个FROM指令,而每个stage可使用上一个stage过程的产物或环境(其实还支持其他镜像的),这样一来,最终所得镜像体积相对较小。不仅如此多阶段构建同样可以很方便地将多个彼此依赖的项目通过一个Dockerfile就可轻松构建出期望的容器镜像,而不用担心镜像太大、项目环境依赖等问题。
    通过上述介绍,我们可以在第一个stage将go程序编译得到编译后程序包,然后在第二个stage中直接拷贝编译好的go程序包到运行环境中,最后的镜像中就只有程序包和运行环境。以下作为示例: 
FROM golang:1.7.3/go/src/github.com/alexellis/href-counter/-d -v golang.org/x/net/=0 GOOS=linux go build -a -installsuffix cgo -FROM alpine:latest
RUN apk
--no-cache add ca-<span style="color: #000000;">certificates
WORKDIR
/root/<span style="color: #000000;">
COPY
--<span style="color: #0000ff;">from
=0 /go/src/github.com/alexellis/href-counter/<span style="color: #000000;">app .
CMD [<span style="color: #800000;">"<span style="color: #800000;">./app<span style="color: #800000;">"]

在以上Dockerfile中存在两个FROM指令,也就是两个stage,第一个stage用于构建产物,而在第二个stage中使用COPY --from=0 意思将第一个stage中的/go/src/github.com/alexellis/href-counter/app拷贝到.目录,第二个stage仅仅相当于执行copy就有了构建产物,不用在安装编译环境,镜像会很缩小。 
 

命名stage

  默认情况下,stage未命名,可以通过整数来引用它们,第一个stage表示0,第二个表1以此类推。 但是,当有多个stage时候,这样会显得麻烦,Docker提供AS 语法可以为stage命名:

FROM golang:1.7.3 as builder

然后在另一个stage中使用:

COPY --=builder /go/src/github.com/alexellis/href-counter/app .

使用本地stage

  除了可以使用Dockerfile中的stage外,构建镜像时候还可以直接使用本地已存在的环境和产物,例如:

COPY --=nginx:latest /etc/nginx/nginx.conf /nginx.conf

构建镜像建议

  1. 基础镜像尽量选择比体积较小的镜像,如每个官方发行的alpine镜像。虽然这版本镜像比较小,但是与之带来的是利用该类镜像运行的容器中排错的命令很少;
  2. 使用RUN指令时候,尽量把多个RUN指令合并为一个,通常做法是使用&&符号;
  3. 通过multi-stage方法减少一些不必要使用的环境来减小镜像;
  4. 安装完成软件同时删除一些不需要的文件或目录; 

ref:
 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


最近一直在开发Apworks框架的案例代码,同时也在一起修复Apworks框架中的Bug和一些设计上的不足。遇到的一个普遍问题是,代码的调试过程需要依赖很多外部系统,比如MongoDB、PostgreSQL、RabbitMQ等。当然可以在本机逐一安装这些服务,然后对服务进行配置,使其满足自己开发调试
最近每天都在空闲时间努力编写Apworks框架的案例代码WeText。在文本发布和处理微服务中,我打算使用微软的SQL Server for Linux来做演示,于是也就在自己的docker-compose中加入了MS SQL Server的服务。其实在Docker中运行SQL Server是非常容
在《Kubernetes中分布式存储Rook-Ceph部署快速演练》文章中,我快速介绍了Kubernetes中分布式存储Rook-Ceph的部署过程,这里介绍如何在部署于Kubernetes的ASP.NET Core MVC的应用程序中使用Rook-Ceph所创建的存储对象。 构建ASP.NET C
最近在项目中有涉及到Kubernetes的分布式存储部分的内容,也抽空多了解了一些。项目主要基于Rook-Ceph运行,考虑到Rook-Ceph部署也不那么简单,官方文档的步骤起点也不算低,因此,在整合官方文档的某些步骤的基础上,写篇文章简单总结一下。 Rook-Ceph是Kubernetes中分布
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.netcore(二) 之 Dockerfile CentOS下Docker与.netcore(三)之 三剑客之一Docker-Compose CentOS下Docker与.netcore(四)之 三剑客之一D
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.netcore(二) 之 Dockerfile CentOS下Docker与.netcore(三)之 三剑客之一Docker-Compose CentOS下Docker与.netcore(四)之 三剑客之一D
构建镜像最具挑战性的一点是使镜像大小尽可能的小。Dockerfile中的每条指令都为图像添加了一个图层,您需要记住在移动到下一层之前清理任何不需要的工件。对于多阶段构建,您可以在Dockerfile中使用多个FROM语句。每个FROM指令可以使用不同的基础,并且每个指令都开始一个新的构建。您可以选择
本文介绍compose配置文件参数的使用,熟练编写compose文件 [root@docker lnmp]# cat lnmp.yaml version: &#39;3&#39; services: nginx: build: /root/docker_demo/nginx/ ports: - &q
环境 docker-machine主机:192.168.1.9 docker主机:192.168.1.10 步骤: 安装docker-machine 创建ssh密钥对,实现两主机无密登录 创建docker主机,命名host1 变更docker环境变量 运行容器查看两端是否同步 镜像容器同步测试成功
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.netcore(二) 之 Dockerfile CentOS下Docker与.netcore(三)之 三剑客之一Docker-Compose CentOS下Docker与.netcore(四)之 三剑客之一D
https://blog.csdn.net/wanglei_storage/article/details/77508620 实践中会发现,生产环境中使用单个 Docker 节点是远远不够的,搭建 Docker 集群势在必行。然而,面对 Kubernetes, Mesos 以及 Swarm 等众多容
1.引言 紧接上篇.NET Core容器化@Docker,这一节我们先来介绍如何使用Nginx来完成.NET Core应用的反向代理,然后再介绍多容器应用的部署问题。 2. Why Need Nginx .NET Core中默认的Web Server为Kestrel。 Kestrel is grea
docker rm `docker ps -a | grep Exited | awk &#39;{print $1}&#39;` 删除异常停止的docker容器 docker rmi -f `docker images | grep &#39;&lt;none&gt;&#39; | awk &#3
什么是Docker Compose 在微服务盛行的今天,我们通常是这么定义Compose的:对容器的统一启动和关闭的编排工具。 但是我以前还是有个疑惑,谁会用Compose在一台服务器上部署多个服务呢?干脆直接用单体服务就行了!直到我遇到了以下的一个需求,让我明白了在一台服务器上不得不用多个服务的时
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.netcore(二) 之 Dockerfile CentOS下Docker与.netcore(三)之 三剑客之一Docker-Compose CentOS下Docker与.netcore(四)之 三剑客之一D
很多时候,我们在本地开发过程中程序运行很正常,但是发布到线上之后由于环境的原因,可能会有一些异常。通常我们会通过日志来分析问题,除了日志还有一种常用的调试手段就是:附加进程。 VS中的附加进程非常强大,目前提供了9种常用的附加方式。 在当前.Net Core支持跨平台的大背景下,其中Linux环境和
https://www.cnblogs.com/bigberg/p/8867326.html 一、简介 Docker有个编排工具docker-compose,可以将组成某个应该的多个docker容器编排在一起,同时管理。同样在Swarm集群中,可以使用docker stack 将一组相关联的服务进行
.Net6中想实现对某个网址截屏,可通过Selenium模拟访问网址并实现截图。 实现 安装Nuget包 &lt;PackageReference Include=&quot;Selenium.Chrome.WebDriver&quot; Version=&quot;85.0.0&quot; /&g
原文&#160;https://www.cnblogs.com/gispathfinder/p/5871043.html 我们在使用docker run创建Docker容器时,可以用--net选项指定容器的网络模式,Docker有以下4种网络模式: host模式,使用--net=host指定。 co