乐趣区

关于docker:docker-学习笔记第六集dockerfile-定制镜像

应用 Dockerfile 定制镜像

什么是 Dockerfile 呢?

Dockerfile 是一个文本文档,其中蕴含用户能够在命令行上调用以组装映像的所有命令。Docker 能够通过浏览该文件中的指令来主动构建映像。(相似于 Linux 上的 bash 脚本,Docker 通过该脚本构建镜像)

应用 dockerfile 制作一个 nginx 镜像

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile   // 首字母必须大写 

Dockerfile 文件内容如下

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

这个 Dockerfile 很简略,一共就两行。波及到了两条指令,FROM 和 RUN。

FROM

性能:指定根底镜像

所谓定制镜像,那肯定是以一个镜像为根底,在其上进行定制。就像咱们之前运行了一个 nginx 镜像的容器,再进行批改一样,根底镜像是必须指定的。而 FROM 就是指定 根底镜像,因而一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。

个别应用中咱们通过 Docker Hub 来查找相干镜像。如下图所示,红标中标识的为官网镜像

除了抉择现有镜像为根底镜像外,Docker 还存在一个非凡的镜像,名为 scratch(该镜像不能通过 docker pull 命令间接拉取)。这个镜像是虚构的概念,并不理论存在,它示意一个空白的镜像。

因为自己只对 PHP 较为相熟,没有应用过 go,这个也不是很理解,就先跳过了

RUN

性能:执行命令

用来执行命令行命令的

理论应用下有两种格局

  1. shell 格局:RUN < 命令 >
  2. exec 格局:RUN ["可执行文件", "参数 1", "参数 2"]

Dockerfile 中每一个指令都会建设一层,RUN 也不例外。每一个 RUN 执行完结后,都会 commit 这一层的批改,形成新的镜像。所以在应用中尽力缩小指令。

FROM debian:stretch

RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

下面的这种写法,创立了 7 层镜像。这是齐全没有意义的,而且很多运行时不须要的货色,都被装进了镜像里,比方编译环境、更新的软件包等等。后果就是产生十分臃肿、十分多层的镜像,不仅仅减少了构建部署的工夫,也很容易出错。咱们在当前的应用应该防止。正确的写法如下所示:

FROM debian:stretch

RUN buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

在上一个 Dockerfile 中所有的命令只有一个目标,就是编译、装置 redis 可执行文件。因而没有必要建设很多层,这只是一层的事件。因而,这里咱们仅仅应用一个 RUN 指令,并应用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。

在撰写 Dockerfile 的时候,要常常揭示本人,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。

构建

命里格局:docker build [选项] < 上下文门路 /URL/->

$ docker build -t mynginx:v1 .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 08393e824c32
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 1d7edd724b5f
Removing intermediate container 1d7edd724b5f
 ---> e29ba82c8e43
Successfully built e29ba82c8e43
Successfully tagged mynginx:v1

// 查看刚刚创立的镜像
$ docker image ls
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
mynginx                 v1                  e29ba82c8e43        3 minutes ago       132MB
  1. -t 示意指定镜像的名称和标签,格局为 name:tag
  2. 最初有个点,示意构建的上下文门路为当前目录

其余构建形式

  1. 通过 Git repo 进行构建
  2. 应用 tar 包进行构建

罕用指令介绍

COPY 复制文件

格局:

  • COPY [--chown=<user>:<group>] < 源门路 > < 指标门路 > (罕用)
  • COPY [--chown=<user>:<group>] ["< 源门路 1 >", "< 指标门路 >"]

构建上下文目录中 < 源门路 > 的文件 / 目录复制到新的一层的镜像内的 < 指标门路 > 地位。

COPY package.json /usr/src/app/

加上 –chown=<user>:<group> 选项来扭转文件的所属用户及所属组

COPY --chown=55:mygroup files* /mydir/
COPY --chown=bin files* /mydir/
COPY --chown=1 files* /mydir/
COPY --chown=10:11 files* /mydir/

ADD 更高级的复制

和 COPY 的格局和性质基本一致。然而在 COPY 根底上减少了一些性能。

  • < 源门路 > 能够是一个 URL。Docker 引擎会试图去下载这个链接的文件放到 < 指标门路 > 去。下载后的文件权限主动设置为 600
  • < 源门路 > 为一个 tar 压缩文件的话,压缩格局为 gzip, bzip2 以及 xz 的状况下,ADD 指令将会主动解压缩这个压缩文件到 < 指标门路 > 去。

在 Docker 官网的 Dockerfile 最佳实际文档 中要求,尽可能的应用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则蕴含了更简单的性能,其行为也不肯定很清晰。最适宜应用 ADD 的场合,就是所提及的须要主动解压缩的场合。

CMD 容器启动命令

Docker 不是虚拟机,容器就是过程。既然是过程,那么在启动容器的时候,须要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主过程的启动命令的。

格局:

  • shell 格局:CMD < 命令 >
  • exec 格局:CMD [“ 可执行文件 ”, “ 参数 1 ”, “ 参数 2 ″…](举荐,肯定要应用双引号)

ENV 设置环境变量

用于设置环境变量,无论是前面的其它指令,如 RUN,还是运行时的利用,都能够间接应用这里定义的环境变量。

格局:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

ARG 构建参数

格局:

  • ARG < 参数名 >[=< 默认值 >]

与 ENV 指令一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在未来容器运行时是不会存在这些环境变量的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值能够在构建命令 docker build 中用 --build-arg < 参数名 >=< 值 > 来笼罩。

VOLUME 定义匿名卷

格局:

  • VOLUME ["< 门路 1 >", "< 门路 2 >"...]
  • VOLUME < 门路 >

示例:

容器中的 /data 目录主动挂载到匿名卷中

VOLUME /data

该指令能够在运行时被笼罩

docker run -d -v mydata:/data xxxx

EXPOSE 裸露端口

格局:

  • EXPOSE < 端口 1 > [< 端口 2 >...]

申明运行时容器提供服务端口,这只是一个申明,在运行时并不会因为这个申明就会开启这个端口的服务。

写入这样的申明有两个益处,一个是帮忙镜像使用者了解这个镜像服务的守护端口,以不便配置映射;另一个用途则是在运行时应用随机端口映射时,也就是 docker run -P 时,会主动随机映射 EXPOSE 的端口。

WORKDIR 指定工作目录

格局:

  • WORKDIR < 工作目录门路 >。

应用 WORKDIR 指令能够来指定工作目录(或者称为当前目录),当前各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建设目录。

RUN cd /app
RUN echo "hello" > world.txt

应用下面的内容构建镜像后会发现基本找不到 /app/world.txt 文件。起因其实很简略,在 Shell 中,间断两行是同一个过程执行环境,因而前一个命令批改的内存状态,会间接影响后一个命令;而在 Dockerfile 中,这两行 RUN 命令的执行环境基本不同,是两个齐全不同的容器。这就是对 Dockerfile 构建分层存储的概念不理解所导致的谬误。

因而如果须要扭转当前各层的工作目录的地位,那么应该应用 WORKDIR 指令。

USER 指定以后用户

格局:

  • USER < 用户名 >[:< 用户组 >]

USER 指令和 WORKDIR 类似,都是扭转环境状态并影响当前的层。WORKDIR 是扭转工作目录,USER 则是扭转之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。当然,和 WORKDIR 一样,USER 只是帮忙你切换到指定用户而已,这个用户必须是当时建设好的,否则无奈切换。

其余指令参考官网文档

退出移动版