笔记簿
ᴄᴏᴅɪɴɢ ɪs ᴀʀᴛ
首页
关于
搜索
登录
注册
Dockerfile解析 - Dockerfile
#### Dockerfile介绍 ##### 1、基本结构 Dockerfile 由一行行命令语句组成,并且支持以 `#` 开头的注释行。一般的,Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。 ```dockerfile FROM openjdk:7-jre-slim MAINTAINER xuxueli ENV PARAMS="" ENV TZ=PRC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ADD target/xxl-job-admin-*.jar /app.jar ENTRYPOINT ["sh","-c","java -jar /app.jar $PARAMS"] ``` 其中,一开始必须指明所基于的镜像名称,接下来推荐说明维护者信息。 后面则是镜像操作指令,例如 `RUN` 指令,`RUN` 指令将对镜像执行跟随的命令。每运行一条 `RUN` 指令,镜像添加新的一层,并提交。 最后是 `CMD` 指令,来指定运行容器时的操作命令。 ##### 2、指令 指令的一般格式为 `INSTRUCTION arguments`,指令包括 `FROM`、`MAINTAINER`、`RUN` 等。 ###### 2.1 FROM 格式为 `FROM
`或`FROM
:
`。 第一条指令必须为 `FROM` 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 `FROM` 指令(每个镜像一次)。 ###### 2.2 MAINTAINER 格式为 `MAINTAINER
`,指定维护者信息。 ###### 2.3 RUN 格式为 `RUN
` 或 `RUN ["executable", "param1", "param2"]`。 前者将在 shell 终端中运行命令,即 `/bin/sh -c`;后者则使用 `exec` 执行。指定使用其它终端可以通过第二种方式实现,例如 `RUN ["/bin/bash", "-c", "echo hello"]`。 每条 `RUN` 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 `\` 来换行。 ###### 2.4 CMD 支持三种格式 - `CMD ["executable","param1","param2"]` 使用 `exec` 执行,推荐方式; - `CMD command param1 param2` 在 `/bin/sh` 中执行,提供给需要交互的应用; - `CMD ["param1","param2"]` 提供给 `ENTRYPOINT` 的默认参数; 指定启动容器时执行的命令,***每个 Dockerfile 只能有一条 `CMD` 命令***。***如果指定了多条命令,只有最后一条会被执行***。 如果用户启动容器时候指定了运行的命令,则会覆盖掉 `CMD` 指定的命令。 ###### 2.5 EXPOSE 格式为 `EXPOSE
[
...]`。 告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。 ###### 2.6 ENV 格式为 `ENV
`。 指定一个环境变量,会被后续 `RUN` 指令使用,并在容器运行时保持。 ###### 2.7 ADD 格式为 `ADD
`。 该命令将复制指定的 `
` 到容器中的 `
`。 其中 `
` 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。 ###### 2.8 COPY 格式为 `COPY
`。 复制本地主机的 `
`(为 Dockerfile 所在目录的相对路径)到容器中的 `
`。 当使用本地目录为源目录时,推荐使用 `COPY`。 ###### 2.9 ENTRYPOINT 两种格式: - `ENTRYPOINT ["executable", "param1", "param2"]` - `ENTRYPOINT command param1 param2`(shell中执行)。 配置容器启动后执行的命令,并且不可被 `docker run` 提供的参数覆盖。 每个 Dockerfile 中只能有一个 `ENTRYPOINT`,当指定多个时,只有最后一个起效。 ###### 2.10 VOLUME 格式为 `VOLUME ["/data"]`。 创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。 ###### 2.11 USER 格式为 `USER daemon`。 指定运行容器时的用户名或 UID,后续的 `RUN` 也会使用指定用户。 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户, 例如:`RUN groupadd -r postgres && useradd -r -g postgres postgres`。 要临时获取管理员权限可以使用 [`gosu`](https://github.com/tianon/gosu),而不推荐 `sudo`。 ###### 2.12 WORKDIR 格式为 `WORKDIR /path/to/workdir`。 为后续的 `RUN`、`CMD`、`ENTRYPOINT` 指令配置工作目录。 可以使用多个 `WORKDIR` 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。 ###### 2.13 ONBUILD 格式为 `ONBUILD [INSTRUCTION]`。 配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。 ```dockerfile # Dockerfile for apollo-configservice # 1. Copy apollo-configservice-${VERSION}-github.zip to current directory # 2. Build with: docker build -t apollo-configservice . # 3. Run with: docker run -p 8080:8080 -d -v /tmp/logs:/opt/logs --name apollo-configservice apollo-configservice FROM openjdk:8-jre-alpine MAINTAINER ameizi
ENV VERSION 1.5.0-SNAPSHOT ENV SERVER_PORT 8080 # DataSource Info ENV DS_URL "" ENV DS_USERNAME "" ENV DS_PASSWORD "" RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \ && echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \ && apk update upgrade \ && apk add --no-cache procps unzip curl bash tzdata \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone ADD apollo-configservice-${VERSION}-github.zip /apollo-configservice/apollo-configservice-${VERSION}-github.zip RUN unzip /apollo-configservice/apollo-configservice-${VERSION}-github.zip -d /apollo-configservice \ && rm -rf /apollo-configservice/apollo-configservice-${VERSION}-github.zip \ && sed -i '$d' /apollo-configservice/scripts/startup.sh \ && chmod +x /apollo-configservice/scripts/startup.sh \ && echo "tail -f /dev/null" >> /apollo-configservice/scripts/startup.sh EXPOSE $SERVER_PORT CMD ["/apollo-configservice/scripts/startup.sh"] ``` ##### 3、创建镜像 编写完成 Dockerfile 之后,可以通过 `docker build` 命令来创建镜像。 基本的格式为 `docker build [选项] 路径`,该命令将读取指定路径下(包括子目录)的 Dockerfile,并将该路径下所有内容发送给 Docker 服务端,由服务端来创建镜像。因此一般建议放置 Dockerfile 的目录为空目录。也可以通过 `.dockerignore` 文件(每一行添加一条匹配模式)来让 Docker 忽略路径下的目录和文件。 ```dockerfile # Dockerfile for apollo-configservice # 1. Copy apollo-configservice-${VERSION}-github.zip to current directory # 2. Build with: docker build -t apollo-configservice . # 3. Run with: docker run -p 8080:8080 -d -v /tmp/logs:/opt/logs --name apollo-configservice apollo-configservice ``` ##### 4、Docker执行Dockerfile的大致流程 - docker从基础镜像运行一个容器 - 执行一条指令并对容器作出修改 - 执行类似docker commit的操作提交一个新的镜像层 - docker再基于刚提交的镜像运行一个新容器 - 执行dockerfile中的下一条指令直到所有指令都执行完成 ##### 5、总结  从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段, - Dockerfile是软件的原材料 - Docker镜像是软件的交付品 - Docker容器则可以认为是软件的运行态。 Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。 1. Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等; 2. Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务; 3. Docker容器,容器是直接提供服务的。