在项目中构建镜像时,构建目录令人头大,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构建镜像目录问题
关注公众号 "字节航海家" 及时获取最新内容