Docker-Dockerfile

简介

学习完 Docker 后你一定有这样的以为,那这些镜像从何而来?比如说以前的 redis 它是怎么变成一个镜像供大家使用的? 我们能不能把自己的 SpringBoot 项目也变成一个镜像?如何制作自定义镜像就是本文要探讨的了。

Dockerfile 是一个文本文件,里面包含了一条条的指令(instruction),这些指令告诉 Docker 如何一步一步地构建一个镜像。你可以把它想象成一个制作菜谱,Dockerfile 就是这个菜谱,里面详细说明了每一步的操作,最终输出的就是一道美味的菜肴——一个定制化的 Docker 镜像。

Dockerfile 的作用:

  • 自动化构建镜像: 通过 Dockerfile,我们可以将镜像构建过程自动化,避免手动执行繁琐的命令。
  • 复用性: 一个 Dockerfile 可以用来构建多个相同的镜像,提高了效率。
  • 可读性: Dockerfile 使用简单的指令,易于阅读和理解。
  • 可维护性: 可以方便地修改 Dockerfile 来更新镜像。

Dockerfile 仅仅是一个文件,依据文件的配置来制作镜像,它是 Docker 引擎自带的功能,所以不需要另外安装任何东西。

官方文档:https://docs.docker.com/reference/dockerfile/

原理

Dockerfile 的基本指令并不多,不用一次记住,用到的时候,慢慢理解就行。

  • FROM: 指定基础镜像。
  • MAINTAINER: 指定镜像维护者。
  • RUN: 在镜像中执行命令。
  • COPY: 将本地文件复制到镜像中。
  • ADD: 和 COPY 类似,但可以从 URL 下载文件。
  • EXPOSE: 声明容器暴露的端口。
  • ENV: 设置环境变量。
  • WORKDIR: 设置工作目录。
  • VOLUME: 创建挂载点。
  • CMD: 指定容器启动时默认执行的命令。
  • ENTRYPOINT: 指定容器启动时执行的命令,与 CMD 类似,但优先级更高。

Docker 镜像并不是一个简单的一体化文件,而是由多层叠加而成的。每一层就代表着 Dockerfile 中的一条指令,这些层按照顺序叠加起来,最终形成一个完整的镜像。所以过多无意义的层,会造成镜像膨胀过大,构建的速度就慢。

形象地说,Docker 镜像就像是一座大楼,每一层代表着大楼中的一层楼。每一层楼都有自己的功能和作用,这些楼层一层一层叠加起来,最终形成了整座大楼。

镜像层的特点是

  • 只读: 每一层都是只读的,也就是说,一旦创建了一个层,就不能对其进行修改。
  • 复用: 如果后续的镜像构建过程中,某一步操作与之前已经创建的层完全一致,那么 Docker 会直接复用该层,而不需要重新构建。
  • 缓存: Docker 会缓存每一层,这样在后续的构建过程中,如果底层的镜像没有发生变化,就可以直接使用缓存中的层,从而加快构建速度。

镜像的工作原理

  • 基础层: 每一层都基于前一层构建,最底层通常是一个基础镜像,比如 Ubuntu、Alpine 等。
  • 指令层: Dockerfile 中的每一条指令都会创建一个新的层。例如,RUN apt-get update && apt-get install -y python3 这条指令会创建一个新的层,在这个层中安装了 Python3。
  • 层叠加: 这些层按照顺序叠加起来,形成一个完整的镜像。当运行容器时,Docker 会将这些层联合起来,形成一个可读写的容器层。

我们从最基础的镜像来说起吧。创建一个 Dockerfile 文件,这个文件是没有后缀名的

FROM python:3.9-slim-buster

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app.py"]

最后在 Dockerfile 所在目录执行docker build -t my_python:v3 . 命令构建镜像。

这个 Dockerfile 会创建一个包含以下层的镜像:

  1. 基础层: Python 3.9-slim-buster 镜像。
  2. 工作目录层: 设置工作目录为 /app
  3. 复制 requirements.txt 层:requirements.txt 文件复制到 /app 目录。
  4. 安装依赖层: 安装 requirements.txt 中列出的依赖。
  5. 复制代码层: 将项目代码复制到 /app 目录。
  6. 运行容器后执行 app.py 脚本。

docker build -t my_python:v3 . 命令的解释:

  • docker build: 这是 Docker 的构建命令,用于根据 Dockerfile 创建一个新的镜像。
  • -t my_python:v3: 这个选项用来给新构建的镜像打上标签。my_python 是镜像的名称,v3 是镜像的版本号。
  • . (点号): 这个点表示构建上下文,也就是 Dockerfile 所在的目录。Docker 会从这个目录中读取 Dockerfile 并开始构建。

重点

一个基础的 Dockerfile 学会后,我们再回头去理解下镜像层和缓存,这非常非常重要,一定要理解清楚。

  1. 既然每个指令都是一层,那么为了避免层数膨胀,我们应该尽量减少层数,以加快镜像制作。

    RUN apt-get update
    RUN apt-get install -y package1

    将上述两层合并成一层

    RUN apt-get update && apt-get install -y package1
  2. Docker 会将 Dockerfile 所在目录下的所有文件都包含在镜像中,一些不必要的文件我们可以通过.dockerignore 文件来排除,以减轻镜像的体积。

  3. 每个指令的变更,位置移动,都会改变层,使其后的层缓存失效。

  4. 将经常更改的层放到后面,充分利用镜像层的缓存,加快构建。

  5. 缓存有时候也不是个好东西, 比如某个镜像依赖一个包,这个包更新了,下次构建镜像的时候用了缓存层,导致构建出的镜像还用的以前的包。这个坑可是我踩过的!但是想半天没想通为什么新包没其效果。我提供三种方式来强制不适用缓存构建镜像。

    • 构建镜像时通过参数--no-cache 禁用缓存,比如: docker build --no-cache -t my_python:v3
    • 在构建前通过docker system prune -a --force 命令删除全部缓存。
    • 在 Dockerfile 中添加一个自定义参数,每次构建的时候,传递一个新值改变这个自定义参数,使得其后的层都不使用缓存。
      比如设置一个自定义参数 CACHEBUST
      # ... 可以使用缓存的其他指令 ...
      ARG CACHEBUST=1
      # ... 不希望它使用缓存的其他指令 ...

      在构建时传递不同的值,强制其后的层不使用缓存。docker build --build-arg CACHEBUST=2 -t my_image .

Dockerfile 构建 java 项目镜像

目标是将传统的 Springboot 项目制作成镜像,并根据这个镜像启动项目容器。
首先是要在项目中写一个Dockerfile 文件,然后根据该文件制作镜像,最后启动容器。java 项目就通过容器跑起来了。

  1. 在 Springboot 项目根目录下创建 Dockerfile 文件,文件内容如下:

    FROM openjdk:11.0.2-jdk
    LABEL maintainer=systemcaller
    COPY target/*.jar /app.jar
    ENTRYPOINT ["java","-jar", "/app.jar"]

    配置文件解析:

    • FROM openjdk:11.0.2-jdk 是以jdk为基础运行环境。
    • LABEL maintainer=systemcaller 是标镜像制作者是systemcaller 。
    • COPY target/*.jar /app.jar 表示从target目录下*.jar 文件复制到容器内的 /app.jap 文件,注意 target 和 Dockerfile 都在项目根目录下。
    • ENTRYPOINT ["java","-jar", "/app.jar"]表示运行容器的命令是java -jar /app.jar
  2. 将 target 目录和 Dockerfile 文件上传到服务器上,构建镜像并启动容器。

    
    [root@VM-4-14-centos java]# pwd
    /root/java
    [root@VM-4-14-centos java]# ls
    Dockerfile  target
    [root@VM-4-14-centos java]# docker build -t javademo:v1.0 .
    [root@VM-4-14-centos java]# docker images
    REPOSITORY     TAG                 IMAGE ID       CREATED          SIZE
    javademo       v1.0                f4c1b5ccbde5   38 seconds ago   849MB
    [root@VM-4-14-centos java]# docker run -d --name myjava -p 8080:8080 javademo:v1.0
SystemCaller
SystemCaller

https://gravatar.com/noisily745e35dad0

文章: 47

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注