> For the complete documentation index, see [llms.txt](https://pshizhsysu.gitbook.io/docker/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pshizhsysu.gitbook.io/docker/dockerfile.md).

# Dockerfile

## FROM

如果可能，尽可能使用官方镜像作为基础镜像。推荐使用 [Alpine](https://hub.docker.com/_/alpine/) 镜像。

## RUN

尽可能地把多条命令放在一个RUN语句中，每个命令占用一行，用反斜杠分隔。比如：

```
RUN wget www.xxx.com/a.tgz \
    &&  tar xzvf a.tgz
```

## COPY

一般情况下，尽量使用COPY而不是ADD。COPY没有副作用，它只把本地文件拷贝到容器内。

当同时拷贝多个文件时，使用如下命令

```
COPY file1 file2 /containerPath/
```

如果拷贝目录的命令如下（注意在拷贝目录时，不会在容器内新建dir目录，所以需要显示地在容器内新建dir目录）：

```
COPY dir /containerPath/dir/
```

## ADD

ADD会有副作用，除了拷贝到容器内外，还会进行解压。所以ADD适用的场景是：当需要拷贝tar或war到容器内并且需要解压时，建议使用ADD。其他场景请使用COPY

```
ADD app1.war /usr/local/tomcat/webapps
```

同时ADD多个压缩包

```
ADD app1.war app2.war /usr/local/tomcat/webapps
```

## ENTRYPOINT

ENTRYPOINT + CMD 加起来组成了容器起动时的指令。当我们想把目标镜像作为一个一次性运行的程序时，则在ENTRYPOINT中设置可执行命令，在CMD中设置参数。

比如有一个二进制的可执行文件square，需要一个参数，对其求平方值。那么我们可以打一个平方工具的镜像：

```
FROM baseImage
ADD square /usr/bin/
RUN chmod +x /usr/bin/square
ENTRYPOINT ["/usr/bin/square"]
CMD ["2"]
```

那么，打出来镜像后（假设镜像名为squareImage:1.0），我们就可以这样使用镜像，这个命令会直接输出结果4，然后容器退出。

```
docker run squareImage:1.0
```

当然，我们还可以在docker run的时候覆盖CMD，如下命令会直接输出结果9，然后容器退出。

```
docker run squareImage:1.0 3
```

### executable vs shell

ENTRYPOINT有两种形式，executable与shell，如下：

* `ENTRYPOINT ["executable"]` : executable form
* `ENTRYPOINT executable` : shell form

executable形式下ENTRYPOINT与CMD组成的完整命令就是

```
executable CMD
```

shell形式下ENTRYPOINT与CMD组成的完整命令就是

```
sh -c "executable" CMD
```

## CMD

CMD指令也有两种使用方式：

* `CMD ["command", "param1"]` ：exec Form，推荐方式
* `CMD command param1` ： shell Form

它们与ENTRYPOINT组成的完整命令为（假设ENTRYPOINT是executable形式）：

```
ENTRYPOINT command param1
```

第二种形式与ENTRYPOINT组成的完整命令为（假设ENTRYPOINT为executable形式），所以拼接完后，该命令可能执行不了，除非ENTRYPOINT为空：

```
ENTRYPOINT sh -c "command param1"
```
