项目中docker-compose构建镜像目录问题

在项目中构建镜像时,构建目录令人头大,docker-compose里的目录和DockerFile的目录是什么关系,docker-compose存放目录不同,这些目录也不一样,本文从底层原理来带你了解他们之间的关系。

案例介绍

我们以上图的案例为例,backend为我们的python后端,我们通过docker-compose把它构建为一个镜像,我们把docker相关的文件都放在docker目录下,

docker构建容器原理

要弄清楚这些目录之间的关系,我们需要先清楚docker 构建镜像的原理。

Docker 构建上下文(Build Context)是指构建镜像时,Docker CLI 发送给 Docker Daemon 的一组文件和目录。这个上下文中包含了 Dockerfile 和上下文目录的内容。构建过程中,Docker Daemon 使用这个上下文来执行 Dockerfile 中的指令。

1. Dockerfile 和上下文目录:

Dockerfile: Dockerfile 是构建镜像的指令脚本,定义了从基础镜像开始如何构建新镜像的步骤。

上下文目录: 上下文目录是 Dockerfile 所在的目录及其子目录的内容。Docker CLI 在构建时将整个上下文目录发送给 Docker Daemon。

2. 传输到 Docker Daemon:

Docker CLI 在构建命令中指定了 Dockerfile 的位置和上下文目录。例如:

docker build -f path/to/Dockerfile context_directory

这个命令中,-f 参数指定 Dockerfile 的位置,context_directory 指定上下文目录。

3. 缓存和构建效率:

由于构建上下文包含 Dockerfile 和上下文目录的内容,Docker 使用这个上下文来执行指令。在构建时,Docker Daemon 会检查每个指令的依赖项是否发生变化。如果 Dockerfile 中的某个指令及其依赖项未发生变化,Docker 将使用缓存而不重新执行这个指令,从而提高构建效率。

4. 文件过滤和.dockerignore:

在传输上下文到 Docker Daemon 之前,Docker CLI 会应用文件过滤。这是通过 .dockerignore 文件实现的,类似于 .gitignore。.dockerignore 中列出的文件和目录将被排除在构建上下文之外,以减小传输的大小。

5. 理解构建上下文的重要性:

构建上下文包含了构建所需的全部信息,因此要保持足够小,以减少构建时间和网络传输的开销。

需要谨慎处理构建上下文,确保只包含必要的文件,而不包含大量不相关或不需要的文件。

理解和优化 Docker 构建上下文有助于提高构建效率、减小镜像大小,并且在使用 .dockerignore 等方式时能够更好地控制构建的内容。

案例解释

1. 首先我们要确定docker-compose中context目录,我们把这个目录指定为最外层,在构建时docker会把整个目录拷贝到一个临时目录,为了减少构建时间,及镜像大小,我们需要在context目录下创建一个 .dockerignore 文件,过滤掉我们不需要的文件

version: "3"

services:
  backend:
    container_name: ${PRE_FIX}_${BACKEND_NAME}
    build:
      context: ../
      dockerfile: ./docker/backend/Dockerfile
      args:
        BACKEND_DIR: ${BACKEND_DIR}

.dockerignore 文件 只保留我们需要的文件, 同时目录结构还是存在的

*
!backend/requirements.txt
!docker/backend/Dockerfile

2. Dockerfile文件, 在此文件中, 目录都是相对我们上一步中的临时目录, 目录结构跟保存一致, 这里的WORKDIR变量是上一步通过args传过来的, 如果在忽略文件中忽略.env那么Dockerfile是不是可以直接使用呢, 大家可以试一下

FROM python:3.9
ARG BACKEND_DIR

WORKDIR ${BACKEND_DIR}
COPY ./backend/requirements.txt ./
RUN python -m pip install --upgrade pip & pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

3. 其它文件

.env文件

# DOCKER START

# GLOBAL
SUBNET=172.10.0.0/24
GATEWAY=172.10.0.1
PRE_FIX=blog
BACKEND_DIR=/opt/blog

# BACKEND
BACKEND_NAME=backend
BACKEND_PORT=38080
BACKEND_IP_ADDR=172.10.0.3

# DOCKER END

docker-compose 文件

version: "3"

services:
  backend:
    container_name: ${PRE_FIX}_${BACKEND_NAME}
    build:
      context: ../
      dockerfile: ./docker/backend/Dockerfile
      args:
        BACKEND_DIR: ${BACKEND_DIR}
    ports:
      - "${BACKEND_PORT}:5000"
    working_dir: ${BACKEND_DIR}
    volumes:
      - ../backend:${BACKEND_DIR}
      - /etc/localtime:/etc/localtime:ro
    command: ["python", "manage.py", "admin"]
    networks:
      blog:
        ipv4_address: ${BACKEND_IP_ADDR}
    logging:
      driver: "json-file"
      options:
        max-size: "30m"
        max-file: "10"
    privileged: true
    restart: always

networks:
  blog:
    driver: bridge
    ipam:
      config:
        - subnet: ${SUBNET}
          gateway: ${GATEWAY}

练习

如果把docker-compose直接放在最外层, 你知道怎么改了吗

查看原文:项目中docker-compose构建镜像目录问题

关注公众号 "字节航海家" 及时获取最新内容