Docker 快速入门之 Dockerfile
本文从一个具体的例子出发，讲述了如何利用 Dockerfile 构建镜像，然后解释了 Dockerfile 文件中的指令的语法，有关更多内容可访问官方文档。
容器 Docker
本文从一个具体的例子出发，讲述了如何利用 Dockerfile 构建镜像，然后解释了 Dockerfile 文件中的指令的语法，有关更多内容可访问官方文档。
![docker](/data/attachment/album/201710/20/222828ouudmzdmouzrfmyd.jpg)


在[之前的文章](/article-8932-1.html)中我们提到可以通过容器创建一个我们自定义过的镜像，那么我们是否可以直接通过基础的镜像直接自定义镜像呢？答案当然是可以的，在 Docker 中我们可以从名为 `Dockerfile` 的文件中读取指令并且自动构建镜像。在本文中，将介绍 Dockerfile 的基本语法以及基本知识。


### 1、Dockerfile 是什么？


Dockerfile 其实是一份文本文档，里面包含了用户可以用来操作镜像的一些指令。通过顺序执行这些指令，最后得到一个自定义的镜像，这有点类似于我们的 shell 脚本。



### 2、Dockerfile 示例


接下来先看一个 Dockerfile 示例：



```
FROM centos
LABEL maintainer="Locez <locez@locez.com>"
ENV TEST="This is a test env"
COPY nginx.repo /etc/yum.repos.d/nginx.repo
RUN yum update -y && \
        yum install -y nginx
COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /usr/share/nginx/html/index.html
COPY index_files/ /usr/share/nginx/html/index_files/
EXPOSE 80
CMD ["/usr/sbin/nginx","-g","daemon off;"]


```

在上面我们可以看到 Dockerfile 中的一些指令，通过名称我们也可以猜到这些指令大概是干嘛的，其中有一些对文件的操作，因此我们先来看看用于存放 Dockerfile 的这个目录的目录结构:



```
# tree .
.
├── Dockerfile
├── index_files
│   ├── 145049z4og8xyjhx4xy8go.jpg
│   ├── 222746e5vh38d7ey3leyps.jpg
│   ├── 88x31.png
│   ├── archlinux-splash.png
│   ├── bdshare.css
│   ├── Best-Linux-Markdown-Editors.png
│   ├── core.js
│   ├── docker-icon.jpg
│   ├── hadoop-pic1.png
│   ├── jquery_002.js
│   ├── jquery.css
│   ├── jquery.js
│   ├── MathJax.js
│   ├── pic.gif
│   ├── raspberrypiraspberry-pi-logo.jpg
│   ├── script.js
│   ├── scrollup.png
│   ├── share.js
│   ├── style.css
│   └── z_stat.js
├── index.html
├── nginx.conf
└── nginx.repo

1 directory, 24 files

```

### 构建镜像


在当前目录下执行以下命令构建镜像:



```
# docker build -t locez/nginx .
Sending build context to Docker daemon 1.851 MB
Step 1/10 : FROM centos
 ---> 196e0ce0c9fb
Step 2/10 : LABEL maintainer "Locez <locez@locez.com>"
 ---> Using cache
 ---> 9bba3042bcdb
Step 3/10 : ENV TEST "This is a test env"
 ---> Using cache
 ---> c0ffe95ea0c5
Step 4/10 : COPY nginx.repo /etc/yum.repos.d/nginx.repo
 ---> Using cache
 ---> bb6ee4c30d56
Step 5/10 : RUN yum update -y &&        yum install -y nginx
 ---> Using cache
 ---> 6d46b41099c3
Step 6/10 : COPY nginx.conf /etc/nginx/nginx.conf
 ---> Using cache
 ---> cfe908390aae
Step 7/10 : COPY index.html /usr/share/nginx/html/index.html
 ---> Using cache
 ---> 21729476079d
Step 8/10 : COPY index_files/ /usr/share/nginx/html/index_files/
 ---> Using cache
 ---> 662f06ec7b46
Step 9/10 : EXPOSE 80
 ---> Using cache
 ---> 30db5a889d0a
Step 10/10 : CMD /usr/sbin/nginx -g daemon off;
 ---> Using cache
 ---> d29b9d4036d2
Successfully built d29b9d4036d2

```

然后用该镜像启动容器：



```
# docker run -d -it --rm --name test-nginx -p 8080:80 locez/nginx
e06fd991ca1b202e08cf1578f8046355fcbba10dd9a90e11d43282f3a1e36d29

```

用浏览器访问 `http://localhost:8080/` 即可看到部署的内容。


### 3 Dockerfile 指令解释


Dockerfile 支持 `FROM`、 `RUN`、 `CMD`、 `LABEL`、 `EXPOSE`、 `ENV`、 `ADD`、 `COPY`、 `ENTRYPOINT`、 `VOLUME`、 `USER`、 `WORKDIR`、 `ARG`、 `ONBUILD`、 `SHELL` 等指令，这里只选择常用的几个进行讲解，可结合上面的示例进行理解。其它的请自行查阅官方文档。


#### 3.1 FROM


`FROM` 指令用于指定要操作的基础镜像，因为在我们构建我们自己的镜像的时候需要一个基础镜像。 语法：



```
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]

```

其中 `[AS <name>]` 为指定一个名称，在一个 Dockerfile 中多次使用 `FROM` 时如有需要，可用 `COPY --from=<name|index>` 语法进行复制。


#### 3.2 RUN


`RUN` 指令用于执行命令，并且是在新的一层上执行，并把执行后的结果提交，也就是生成新的一层。基于这个问题，我们在使用 `RUN` 指令时应该尽可能的把要执行的命令一次写完，以减少最后生成的镜像的层数。 语法：



```
RUN <command>
RUN ["executable", "param1", "param2"]

```

#### 3.3 CMD


`CMD` 指令用于给容器启动时指定一个用于执行的命令，例如上例中的 nginx 启动命令。 语法：



```
CMD ["executable","param1","param2"]
CMD ["param1","param2"] ### 用于给 ENTRYPOINT 指令提供默认参数
CMD command param1 param2

```

#### 3.4 LABEL


`LABEL` 指令用于为镜像指定标签，可用 `docker inspect` 命令查看。可用来代替被舍弃的 `MAINTAINER` 命令。 语法：



```
LABEL <key>=<value> <key>=<value> <key>=<value> ...

```

#### 3.5 EXPOSE


`EXPOSE` 指令用于告诉 Docker 容器监听的特殊端口，但是此时端口还没有暴露给 host ，只有当在运行一个容器显式用参数 `-p` 或者 `-P` 的时候才会暴露端口。 语法：



```
EXPOSE <port> [<port>/<protocol>...]

```

#### 3.6 ENV


`ENV` 指令用于设定环境变量。 语法：



```
ENV <key> <value>
ENV <key>=<value> ...

```

#### 3.7 ADD


`ADD` 指令用于复制新文件，目录，远程文件到容器中。其中 `<src>` 可以为文件，目录，URL，若为可解压文件，在复制后会解压。 语法：



```
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]

```

#### 3.8 COPY


`COPY` 指令与 `ADD` 指令非常相似，但 `COPY` 比较直观且简单，它只支持本地的文件以及目录的复制，不像 `ADD` 指令可以远程获取文件并解压。 语法：



```
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

```

#### 3.9 ENTRYPOINT


`ENTRYPOINT` 指令也跟 `CMD` 指令相似，用于指定容器启动时执行的命令。当使用 `ENTRYPOINT` 指令时，可用 `CMD` 命令配合，这样在启动容器时，可以对 `CMD` 指令写入的参数进行覆盖。 语法：



```
ENTRYPOINT ["executable", "param1", "param2"]

```

例子：



```
ENTRYPOINT ["top","-b"]
CMD ["-c"]

```

上面的 `-c` 参数可以在启动时覆盖 `docker run -it --rm --name test top -H`。 如果要覆盖 `ENTRYPOINT` 指令则用 `--entrypoint` 参数启动容器。


#### 3.10 VOLUME


`VOLUME` 指令用于为容器创建一个挂载点，这个挂载点可以用来挂载 `本地文件/文件夹` 也可以用来挂载 `数据卷`。其中若在启动一个新容器时没有指定挂载目录，则会自动创建一个数据卷，当容器被销毁时，数据卷如果没有被其它容器引用则会被删除。 语法：



```
VOLUME ["/data1","/data2"]

```

#### 3.11 USER


`USER` 指令用于设置执行 `RUN`, `CMD`, `ENTRYPOINT` 等指令的用户以及用户组。默认为 `root` 用户。 语法：



```
USER <user>[:<group>]

```

#### 3.12 WORKDIR


`WORKDIR` 指令用于设置 `RUN`, `CMD`, `ENTRYPOINT`, `COPY`, `ADD` 等指令的工作目录。 语法：



```
WORKDIR /path/to/workdir

```

### 4 总结




---


本文从一个具体的例子出发，讲述了如何利用 Dockerfile 构建镜像，然后解释了 Dockerfile 文件中的指令的语法，有关更多内容可访问官方文档。


### 5 参考资料




---


* [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)
