Dockerfile 是一个文本格式的配置文件, 我们可以使用 Dockerfile 来快速创建自定义的镜像。
1 基本结构
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。
一般而言,Dockerfile分为四部分:
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时执行指令
#第一行必须指定基于的基础镜像
FROM ubuntu:xeniel
#维护者信息
MAINTAINER docker_user docker_user@email.com
#镜像的操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe ">> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
#容器启动时执行指令
CMD /usr/bin/nginx
每运行一条RUN指令,镜像添加新的一层,并提交。最后CMD指令,来指定运行容器时的操作命令。
1.1 nginx的Dockerfile
在debian:jessie
基础镜像基础上安装Nginx环境, 从而创建一个新的nginx镜像
FROM debian:jessie
LABEL maintainer docker_user<docker_user@email.com>
ENV NGINX VERSION 1.10.1-1-jessie
RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3DBFBC641079A6ABABF5BDB27BD9BF62 \
&& echo "deb http://nginx.org/packages/debian/ jessie nsuginx" >> /etc/apt/sources.list \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
ca-certificates \
nginx=${NGINX_VERSION} \
nginx-module-xslt \
nginx-module-geoip \
nginx-module-image-filter \
nginx-module-perl \
nginx-module-njs \
gettext-base \
&& rm -rf /var/lib/apt/lists/*
# forward request and error logs to docker log callector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
1.2 Go的Dockerfile
基于buildpack-deps:jessie-scm
基础镜像,安装Golang相关环境, 制作一个Go语言的运行环境镜像。
FROM buildpack-deps:jessie-scm
# gee for ego
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
gcc \
libe6-dev \
make \
&& rm -rf /var/lib/apt/lists/*
ENV GOLANG VERSION 1. 6. 3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG DOWNLOAD SHA256 cdde5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
&& echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c -\
&&tar -c /usr/local -xzf golang.tar.gz \
&& rm golang.tar.gz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin/
2 指令说明
指令的一般格式为INSTRUCTION arguments
,指令包括"配置指令(配置镜像信息)“和"操作指令(具体执行操作)”。
分类 | 指令 | 说明 |
---|---|---|
配置指令 | ARG | 定义创建镜像过程中使用的变量 |
配置指令 | FROM | 指定所创建镜像的基础镜像 |
配置指令 | LABEL | 为生成的镜像添加元数据标签信息 |
配置指令 | EXPOSE | 声明镜像内服务监听的端口 |
配置指令 | ENV | 指定环境变量 |
配置指令 | ENTRYPOINT | 指定镜像的默认入口命令 |
配置指令 | VOLUME | 创建一个数据卷挂载点 |
配置指令 | USER | 指定运行容器时的用户名或UID |
配置指令 | WORKDIR | 配置工作目录 |
配置指令 | ONBUILD | 创建子镜像时指定自动执行的操作指令 |
配置指令 | STOPSIGNAL | 指定退出的信号值 |
配置指令 | HEALTHCHECK | 配置所启动容器如何进行健康检查 |
配置指令 | SHELL | 指定默认shell类型 |
操作指令 | RUN | 运行指定命令 |
操作指令 | CMD | 启动容器时指定默认执行的命令 |
操作指令 | ADD | 添加内容到镜像 |
操作指令 | COPY | 复制内容到镜像 |
2.1 配置指令
2.1.1 ARG
定义创建镜像过程中使用的变量。格式为
ARG <name>[=<default value>]
在执行docker build
时, 可以通过-build-arg[=]
来为变量赋值。
ARG
和ENV
的效果一样,都是设置环境变量。所不同的是,ARG
所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用ARG
保存密码之类的信息,因为docker history
还是可以看到所有值的。
灵活的使用ARG
指令,能够在不修改Dockerfile的情况下,构建出不同的镜像。
ARG
指令有生效范围,如果在FROM
指令之前指定,那么只能用于FROM
指令中。
ARG DOCKER_USERNAME=library
FROM ${DOCKER_USERNAME}/alpine
RUN set -x ; echo ${DOCKER_USERNAME}
使用上述Dockerfile会发现无法输${DOCKER_USERNAME}
变量的值,要想正常输出,你必须在FROM
之后再次指定ARG
# 只在 FROM 中生效
ARG DOCKER_USERNAME=library
FROM ${DOCKER_USERNAME}/alpine
# 要想在 FROM 之后使用,必须再次指定
ARG DOCKER_USERNAME=library
RUN set -x ; echo ${DOCKER_USERNAME}
对于多阶段构建,尤其要注意这个问题
# 这个变量在每个 FROM 中都生效
ARG DOCKER_USERNAME=library
FROM ${DOCKER_USERNAME}/alpine
RUN set -x ; echo 1
FROM ${DOCKER_USERNAME}/alpine
RUN set -x ; echo 2
对于上述Dockerfile两个FROM
指令都可以使用${DOCKER_USERNAME}
,对于在各个阶段中使用的变量都必须在每个阶段分别指定:
ARG DOCKER_USERNAME=library
FROM ${DOCKER_USERNAME}/alpine
# 在FROM 之后使用变量,必须在每个阶段分别指定
ARG DOCKER_USERNAME=library
RUN set -x ; echo ${DOCKER_USERNAME}
FROM ${DOCKER_USERNAME}/alpine
# 在FROM 之后使用变量,必须在每个阶段分别指定
ARG DOCKER_USERNAME=library
RUN set -x ; echo ${DOCKER_USERNAME}
Docker内置了一些镜像创建变量,用户可以直接使用而无须声明,包括(不区分大小写)HTTP_PROXY
、HTTPS_PROXY
、FTP_PROXY
、NO_PROXY
。
2.1.2 FROM
指定所创建镜像的基础镜像。格式为:
FROM <image> [AS <name>]
或
FROM <image>:<tag> [AS <name>]
或
FROM <image>@<digest> [AS <name>] 。
任何Dockerfile中第一条指令必须为FROM
指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM
指令(每个镜像一次)。
为了保证镜像精简,可以选用体积较小的镜像如Alpine或Debian作为基础镜像。 例如:
ARG VERSION=9.3
FROM debian:${VERSION}
在Docker Hub上有非常多的高质量的官方镜像:
- 有可以直接拿来使用的服务类的镜像,如
nginx
、redis
、mongo
、mysql
、httpd
、php
、tomcat
等; - 也有一些方便开发、构建、运行各种语言应用的镜像,如
node
、openjdk
、python
、ruby
、golang
等。
可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。
如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如ubuntu
、debian
、centos
、fedora
、alpine
等,这些操作系统的软件库为我们提供了更广阔的扩展空间。
除了选择现有镜像为基础镜像外,Docker还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
FROM scratch
...
如果你以scratch
为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,对于Linux下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch
会让镜像体积更加小巧。使用Go语言开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为Go是特别适合容器微服务架构的语言的原因之一。
2.1.3 LABEL
LABEL指令可以为生成的镜像添加元数据标签信息。 这些信息可以用来辅助过滤出特定镜像。格式为:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
例如:
LABEL version="l.0.0-rc3"
LABEL author="yeasy@github" date="2020-01-01"
LABEL description="This text illustrates \
that label-values can span multiple lines."
具体可以参考https://github.com/opencontainers/image-spec/blob/master/annotations.md
2.1.4 EXPOSE
声明镜像内服务监听的端口。格式为:
EXPOSE <port> [<port>/<protocol>... ]
例如:
EXPOSE 22 80 8443
注意该指令只是起到声明作用,并不会自动完成端口映射。如果要映射端口出来,在启动容器时可以使用-P
参数(Docker主机会自动分配一个宿主机的临时端口)或-p HOST_PORT:CONTAINER_PORT
参数(具体指定所映射的本地端口)。
2.1.5 ENV
指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。格式为:
ENV <key> <value>
或
ENV <key1>=<value1> <key2>=<value2>...
例如:
ENV APP VERSION=1.0.0
ENV APP_HOME=/usr/local/app
ENV PATH $PATH:/usr/local/bin
指令指定的环境变量在运行时可以被覆盖掉, 如
docker run --env <key>=<value> built_image
注意当一条ENV指令中同时为多个环境变量赋值并且值也是从环境变量读取时,会为变量都赋值后再更新。如下面的指令,最终结果为keyl=valuel key2=value2
:
ENV k