Dockerfile语法、自定义镜像构建详解

简单的说Dockerfile就是一个文本文件。

Docker使用它就可以帮助我们构建镜像。

大部分镜像都可以在DockerHub上找到。

但是以后自己写的微服务,想要发布到Docker上运行,就需要自己来构建镜像了。

一、镜像的结构

镜像是一个分层结构,每一层称为一个Layer.

可以大致把这些层分为三部分:

1.1 基础镜像层(BaseImage)

应用依赖的函数库、环境变量、配置、文件系统等。

最底层的Layer

1.2 中间层(Layer)

BaseImage的基础上,添加安装包、依赖、配置等。

中间层并不是只单独的一层,而是基础镜像层和入口层之间的所有Layer

1.3 入口层(Entrypoint)

指镜像的运行入口,可以是程序的启动脚本。

是最顶层的Layer

1.4 镜像分层的好处

最直接的好处就是节省磁盘空间和共享资源。

比如有多个镜像都是从相同的BaseImage构建来的。

那么Docker只需要在磁盘上保持一份BaseImage,并且内存也只需加载一份BaseImage

这样就实现了BaseImage的复用。

1.5 注意点

Docker镜像一旦制作完成,层级就不能够再去更改,这也是从安全性和可维护可拓展性考虑。

如果想要修改镜像,比如拓展镜像的功能,只能够在原来的层级上加一层,再统一打包成镜像。

如果不了解这个过程,自己制作镜像时,也可以从头开始打包。

1.6 镜像的概念

镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合。

然后编写好启动脚本和上面的文件组合统统打包在一起形成的文件。

要自定义构建镜像,就是实现上述打包的过程。

二、Dockerfile及其相关命令

自己构建自定义的镜像时,并不需要把所有文件一个个拷贝,打包。

只要告诉Docker,镜像的组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、以及启动脚本。

Docker会帮助我们构建镜像。

而描述上述信息的文件就是Dockerfile文件,它相当于就是构建镜像的说明书。

因此,Dockerfile就是一个文本文件,它提供了一种可以通过描述文件来构建镜像的一种方式

用指令来说明Docker要执行什么操作去构建镜像。

每一个指令都会形成一层Layer

2.1 Dockerfile常用命令

指令名称说明示例
FROM指定基础镜像是什么FROM centos:7
ENV设置环境变量,可在后面指令使用ENV key value
COPY拷贝本地文件到镜像的指定目录COPY <源路径> <目标路径>
ADD将文件、目录或远程 URL 从源目录复制到镜像中的目标目录ADD <源路径> <目标路径>
RUN执行Linux的shell命令,一般是当前应用安装过程的命令RUN yum install gcc
EXPOSE指定容器运行时监听的端口EXPOSE 80
ENTRYPOINT镜像中应用的启动命令,容器运行时调用ENTRYPOINT java -jar xx.jar

2)关于 ADDCOPY

ADDCOPY 都是用于将文件从主机复制到 Docker 镜像中的命令,但它们之间有一些区别。

ADD 命令的功能比 COPY 更强大。除了复制文件, ADD 命令还支持以下功能:

  • 如果源路径是一个 URL,它可以自动下载并将文件复制到镜像中。
  • 如果源文件是一个归档文件(如 tar 文件),它会自动解压缩并将文件复制到镜像中。
  • 如果目标路径不存在, ADD 命令会自动创建目标路径。

COPY 命令相对简单,只能用于将本地文件或目录复制到镜像中,不支持自动解压缩和下载功能。

但是,由于 COPY 命令的行为更明确和可预测,所以在大多数情况下,建议使用 COPY 命令而不是 ADD 命令。

总结ADD 命令在功能上更丰富,而 COPY 命令更直观和可控。根据具体需求,选择适合的命令来复制文件到 Docker 镜像中。

2)关于EXPOSE

EXPOSE 监听的端口,一般也是在docker run 运行镜像生成容器时,需要把容器和宿主机相关联的端口。

如果上面的命令满足不了构建镜像的需要时。

可以查阅官方文档 :

https://docs.docker.com/engine/reference/builder/

文档里什么命令都有,但是有相当一部分是不常用的

三、使用Dockerfile一个JavaWeb程序构建为镜像

3.1 文件准备

在这里插入图片描述

  • docker-demo.jar:需要制作成镜像的SpringBoot项目。
  • Dockerfile:包含了镜像构建的全部步骤。
  • jdk-8u171-linux-x64.tar.gz:jdk安装包。

先解压jdk-8u171-linux-x64.tar.gz,是因为我想知道解压出来的目录叫什么名字,在Dockerfile中有用。

3.2 编写Dockerfile文件

# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local

# 拷贝jdk和java项目的包
COPY ./jdk-8u171-linux-x64.tar.gz $JAVA_DIR/	# 把jdk压缩包复制到/usr/local目录下
COPY ./docker-demo.jar /soft/app.jar			# 把java程序移动到/soft目录下并重命令为app.jar

# 使用RUN命令执行Linux的shell命令
RUN cd $JAVA_DIR \								# 跳转到 到/usr/local目录下
 && tar -xf ./jdk-8u171-linux-x64.tar.gz \		# 解压缩jdk的安装包
 && mv ./jdk1.8.0_171 ./java8					# 把jdk解压出来的目录重命名为java8
										# 其实重命名操作都是非必须的,只是用更短的名字更好操作一些
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8			# 把jdk的安装目录配置成环境变量JAVA_HOME
ENV PATH=$PATH:$JAVA_HOME/bin			# 最后再配置PATH变量为jdk的安装目录

# 暴露需要被监听端口,就是让被完全隔离的容器暴露出一个可以被外界访问的端口
# 一般就是application.yml中配置的端口号
EXPOSE 8999
# 程序运行入口,就是java项目的启动命令
# 这句话也是容器成功运行后,第一个执行的命令
ENTRYPOINT java -jar /soft/app.jar

3.3 构建镜像

运行构建镜像命令

# 写法一:默认文件名称必须叫Dockerfile
# -t	代表以' Name:tag'格式命名和可选的标记 (相当于就是-tag)
# . 	代表构建镜像所需的文件都在Dockerfile文件所在的目录下
docker build -t javaapp:1.0 .	

# 写法二:自己执行Dockerfile文件是谁
# -f 手动指定Dockerfile的文件名称
docker build -f mydockerfile -t javaapp:1.0 


注意:

1)构建的镜像名称必须全部小写

2)没有特殊情况文件名称就用Dockerfile就行,容易记忆,更加直观,也符合习惯

在这里插入图片描述

可以看到Docker在一步步执行Dockerfile文件中的步骤。一共是9步。

最终构建成功!

构建成功后查看镜像:

docker images

确认镜像存在后运行镜像:

# --name myApp  定义容器名称为myApp
# -p 把主机的8999端口和容器的8999相关联
# -d 后台运行
# javaapp:1.0 需要运行的镜像名称
docker run --name myApp -p 8999:8999 -d javaapp:1.0

成功运行后查看正在运行的容器:

docker ps

确认java程序在容器中正常运行后,就可以在浏览器中访问了。

四、使用java:8-alpine镜像去优化Dockerfile文件的编写

在微服务项目中,肯定不止一个镜像需要我们去构建。

如果每个微服务都是使用java编写的话。

那么Dockerfile文件中,选择基础镜像、安装jdk、配置环境变量的操作都是一致的。

我们没必要对每个微服务的镜像构建都做一次上面的操作。java:8-alpine这个镜像就已经做了上面的操作。

所以我们只要选择java:8-alpine,作为我们的基础镜像,就可以避免上面的重复操作了。

这也是Docker镜像分层的体现。

如果对Docker镜像分层机制不了解,可以查看我Docker专栏下的Docker的概念、架构、安装详解这篇博文。

了解了java:8-alpine镜像的作用之后,就可以这么优化Dockerfile文件了:

# 指定java:8-alpine作为基础镜像,它包含了java程序部署的基本环境依赖
FROM java:8-alpine
# 暴露需要被监听端口(一般就是application.yml中配置的端口号)
EXPOSE 8999
# 程序运行入口,就是java项目的启动命令
ENTRYPOINT java -jar /soft/app.jar

这样以后构建别的微服务的Dockerfile文件就方便多了。

并且使用它构建镜像时,步骤也从9步变成了4步。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐