Search K
Appearance
Appearance
Dockerfile
Dockerfile 是一个文本文件,其中包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令都会对镜像进行修改。Dockerfile 包含了构建镜像所需的所有指令,可以通过 Dockerfile 构建出一个完整的镜像。
要想自己构建镜像,必须先了解镜像的结构。
之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。
举个例子,我们要从 0 部署一个 Java 应用,大概流程是这样:
那因此,我们打包镜像也是分成这么几步:
上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合。
但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一 id,称为Layer(层)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。
例如,第一步中需要的 Linux 运行环境,通用性就很强,所以 Docker 官方就制作了这样的只包含 Linux 运行环境的镜像。我们在制作 java 镜像时,就无需重复制作,直接使用 Docker 官方提供的 CentOS 或 Ubuntu 镜像作为基础镜像。然后再搭建其它层即可,这样逐层搭建,最终整个 Java 项目的镜像结构如图所示:

Layers
The order of Dockerfile instructions matters. A Docker build consists of a series of ordered build instructions. Each instruction in a Dockerfile roughly translates to an image layer. The following diagram illustrates how a Dockerfile translates into a stack of layers in a container image. Dockerfile 指令的顺序很重要。Docker 构建由一系列有序的构建指令组成。Dockerfile 中的每条指令大致相当于一个映像层。下图说明了 Dockerfile 如何转化为容器映像中的层堆栈。

| 指令 | 说明 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 | FROM ubuntu:18.04 |
| MAINTAINER | 指定镜像维护者信息 | MAINTAINER Ryanjie |
| RUN | 在镜像中执行 shell 命令,每执行一次就会在镜像上新建一层 | RUN apt-get update |
| CMD | 指定容器启动时要运行的命令 | CMD ["nginx", "-g"] |
| EXPOSE | 指定容器对外暴露的端口,是给镜像使用者看的 | EXPOSE 80 |
| ENV | 设置环境变量 | ENV JAVA_HOME /usr |
| ADD | 将文件或目录复制到镜像中 | ADD ./test.txt / |
| COPY | 将文件或目录复制到镜像中 | COPY ./test.txt / |
| ENTRYPOINT | 指定容器启动时要运行的命令 | ENTRYPOINT ["nginx"] |
| VOLUME | 指定容器中的数据卷 | VOLUME /data |
基于 Ubuntu 镜像来构建一个 Java 应用,其 Dockerfile 内容如下:
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK 的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝 jdk 和 java 项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装 JDK
RUN cd $JAVA_DIR \
&& tar -xf ./jdk8.tar.gz \
&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 指定项目监听的端口
EXPOSE 8080
# 入口,java 项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]将 Linux 系统环境、JDK 环境这两层合并成一个基础镜像 openjdk:11.0-jre-buster,以后制作 java 镜像只需要配置 jar 包就行。
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝 jar 包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]实验资料
demo 项目 (demo.jar) 及对应的 Dockerfile 文件在课程资料中。目录:资料 → demo。
当 Dockerfile 文件写好以后,就可以利用命令来构建镜像了。
将课前资料提供的 docker-demo.jar 包以及 Dockerfile 拷贝到虚拟机的 /root/demo 目录。
❯ tree
.
├── docker-demo.jar
└── Dockerfile
0 directories, 2 files然后执行 docker build -t demo:1.0 . 命令构建镜像。
docker build:构建镜像的命令-t demo:1.0:指定镜像的名称(repository)和版本(tag),名称为 demo,版本号为 1.0,不指定 tag 时,默认为 latest.:指定 Dockerfile 文件所在的目录,这里是当前目录。 Dockerfile,则需要使用 -f 参数指定文件名。docker build -t demo:1.0 -f Dockerfile.dev .docker build -t demo:1.0 /root/demo执行命令后,Docker 会按照 Dockerfile 文件中的指令逐层构建镜像,最终生成一个镜像文件。
❯ docker build -t demo:1.0 .
[+] Building 7.6s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 299B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 1.2s
=> [1/3] FROM docker.io/library/openjdk:11.0-jre-buster@sha256:569ba9252ddd693a29d39e81b3123481f308eb6d 5.4s
=> => resolve docker.io/library/openjdk:11.0-jre-buster@sha256:569ba9252ddd693a29d39e81b3123481f308eb6d 0.0s
=> => sha256:fa46ae940938ca17b5634fac0d58da875f0d7c53688cb7a8a4d6ac47f658d4d3 1.58kB / 1.58kB 0.0s
=> => sha256:0b489110c503fc781fea676ea3550679969b5de8bd237c21eb5dca7077ef2869 7.52kB / 7.52kB 0.0s
=> => sha256:cc915d298757b72963f0d061cc16ca4925e9f4481446b87a5297b4043ffc8033 10.00MB / 10.00MB 0.6s
=> => sha256:569ba9252ddd693a29d39e81b3123481f308eb6d529827a40c93710444e421b0 549B / 549B 0.0s
=> => sha256:7e6a53d1988fa8e19db6bcfc96ee6783afb079c38dbe047528e691815d19a9fa 50.44MB / 50.44MB 1.0s
=> => sha256:4fe4e1c58b4af82939a918665dd1e7b5b636dd73c710b4bccb530edbb15470d2 7.86MB / 7.86MB 0.6s
=> => sha256:6cd61a4b7a06678967e883d8b11485979d28989d5306ba06bf2c6b483c05b516 211B / 211B 0.9s
=> => sha256:0f795594794cd5bee4c556ac9e51dde9dface10e4512f611fd067ad2a357d0bd 5.53MB / 5.53MB 0.9s
=> => sha256:62acc5f6f7aae46e03d13e9f65af350b1bca82d942b72a1c7ff81c012bd384ed 45.77MB / 45.77MB 1.6s
=> => extracting sha256:7e6a53d1988fa8e19db6bcfc96ee6783afb079c38dbe047528e691815d19a9fa 2.1s
=> => extracting sha256:4fe4e1c58b4af82939a918665dd1e7b5b636dd73c710b4bccb530edbb15470d2 0.2s
=> => extracting sha256:cc915d298757b72963f0d061cc16ca4925e9f4481446b87a5297b4043ffc8033 0.2s
=> => extracting sha256:0f795594794cd5bee4c556ac9e51dde9dface10e4512f611fd067ad2a357d0bd 0.2s
=> => extracting sha256:6cd61a4b7a06678967e883d8b11485979d28989d5306ba06bf2c6b483c05b516 0.0s
=> => extracting sha256:62acc5f6f7aae46e03d13e9f65af350b1bca82d942b72a1c7ff81c012bd384ed 0.9s
=> [internal] load build context 0.2s
=> => transferring context: 17.70MB 0.1s
=> [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/time 0.6s
=> [3/3] COPY docker-demo.jar /app.jar 0.2s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:bcdc2a0828279af824cfe27308b3dfa596d26580bbfb5b30741f7832f71c84e4 0.0s
=> => naming to docker.io/library/demo:1.0 0.0s查看镜像列表。从镜像列表中可以看到,刚刚构建的镜像已经存在了。
❯ dkIls # docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
demo 1.0 bcdc2a082827 About a minute ago 315MB
nginx latest c20060033e06 8 days ago 187MB
mysql latest a3b6608898d6 2 weeks ago 596MB
hello-world latest 9c7a54a9a43c 6 months ago 13.3kB运行镜像。运行镜像的命令是 docker run,-d 参数表示以后台方式运行,-p 参数表示将容器内的端口映射到宿主机的端口上,demo:1.0 是镜像的名称和版本号。
❯ docker run -d --name dockerfile-demo -p 80:8080 demo:1.0
dd02e6e65d395a710674c479b900b7b516492c64497e11c73cabf0074f2bfa85查看容器列表。从容器列表中可以看到,刚刚运行的容器已经存在了。
❯ dkps # docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd02e6e65d39 demo:1.0 "java -jar /app.jar" 46 seconds ago Up 45 seconds 0.0.0.0:80->8080/tcp, :::80->8080/tcp dockerfile-demo访问应用。
❯ curl localhost:80/hello/count
<h5>欢迎访问黑马商城,这是您第 1 次访问<h5>%
❯ curl localhost:80/hello/count
<h5>欢迎访问黑马商城,这是您第 2 次访问<h5>%
❯ curl localhost:80/hello/count
<h5>欢迎访问黑马商城,这是您第 3 次访问<h5>%
❯
~/demo ❯总结
docker build -t 镜像名:标签名 Dockerfile所在目录