【发布时间】:2021-04-16 00:18:28
【问题描述】:
问题(2):
执行docker-compose --build 或docker-compose up --build 会导致所有容器的构建时间都很长。此外,docker 似乎正在 /tmp 中创建一个非常大的 tmp 文件,我相信这是写入该文件的当前目录。
疑难解答:
- 尝试将 docker 升级到 20.10.6
- 执行
watch df -H显示主分区已填满,然后系统什么也不做(docker-compose --build 进程挂起,没有任何反应)。 - 我执行了
docker system prune -a,删除了大约 50GB。 - 主机为 / 设置了 200GB 分区,这是所有 docker 卷所在的位置。我将此分区扩展到 500GB,并尝试再次构建,此时第一个容器映像最终构建(耗时 20 分钟)。之后下一个镜像开始,构建也需要 20 分钟,以此类推,其他容器需要大约 2 小时来构建所有内容。
- 我找到了空间耗尽的根源。在 /tmp 中有一个名为“tmpsx30lncc”的文件(我假设最后是随机字符),它的大小正在增长,并且与构建过程中消耗的大小相匹配。运行
file tmpsx30lncc会显示其 POSIX tar 存档。我在网上读到这个文件是我当前运行docker-compose build的目录的存档。传输速率似乎有所不同。根据文件增加的情况,它是每秒 50-250MB 的任何地方。 - 在某些时候(我相信当所有内容都归档到 /tmp 中的 tmp 归档文件时,
df -H显示返回的大小缓慢,而每个容器都进入了它的构建步骤。 - 我做了一个
du --block-size=M -a / | sort -n -r | head -n 20,大文件的罪魁祸首是 /tmp 文件(运行 docker-compose 的目录的完整大小),我的 docker-registry 文件夹(~70GB),最后是 gitea(4GB),其他容器也有其他文件夹加起来。 docker-compose 复制所有文件的主目录约为 76GB。
系统
- 操作系统:Ubuntu 18.04
- Docker 版本:19.03.3
- 尝试在 docker-compose 中构建的容器:gitea、postgres、drone、drone-runner、docker-registry
- volumes:都位于我的/分区的不同位置。 Gitea 将在某个时候构建,但下一个映像将表现出相同的行为,并且需要同样长的时间并填满硬盘驱动器。
码头信息:
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
scan: Docker Scan (Docker Inc., v0.7.0)
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 19.03.3
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
runc version: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
init version: fec3683
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.15.0-141-generic
Operating System: Ubuntu 18.04.5 LTS
OSType: linux
Architecture: x86_64
CPUs: 10
Total Memory: 15.64GiB
Name: taxmd01-gitjenkins-v
ID: ZZYO:KANZ:3AH3:UO4U:HFHC:G6OW:4UFQ:S7Q5:QNVC:O5QH:33P7:MRMN
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
如何重现
- 使用与上述相同的系统和版本
- 这是我的 docker-compose.yaml(我已调整 IP、域、密码和机密),要使其正常工作,您需要调整 IP 的端口、证书和目录结构。
- 在 ubuntu 中使用 netplan 在一个接口上配置所有 IP 地址
- 部署recreate目录结构,并在与下面的docker-compose.yaml文件相同的目录下运行
docker-compose build。我担心如果您确实正确设置了所有内容,您可能不会遇到与我相同的问题,因为随着时间的推移,我的图像/体积会很大。
version: "3.7"
services:
gitea:
build:
context: ./
dockerfile: services/gitea/gitea.Dockerfile
volumes:
- ./services/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- 10.10.10.31:22:22
- 10.10.10.31:80:3080
- 10.10.10.31:443:3443
environment:
- USER_UID=1000
- USER_GID=1000
- DB_TYPE=postgres
- DB_HOST=postgres:5432
- DB_NAME=myDBname
- DB_USER=myUser
- DB_PASSWD=myPassword
postgres:
image: postgres:latest
volumes:
- ./services/postgres/data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=myUser
- POSTGRES_PASSWORD=myPassword
- POSTGRES_DB=myDBname
drone:
build:
context: ./
dockerfile: services/drone/drone.Dockerfile
ports:
- 10.10.10.28:80:80
- 10.10.10.28:443:443
volumes:
- ./services/drone/data:/data
environment:
DRONE_GITEA_SERVER: "https://gitea2.example.internal"
DRONE_GITEA_CLIENT_ID: 023f302d-ffff-22b3-83fc-898d9b68fbe1
DRONE_GITEA_CLIENT_SECRET: MySecretab897a797c979d79779e79f
DRONE_USER_CREATE: username:drone-admin,machine:false,admin:true,token:MyToken3892183902183902183012
DRONE_SERVER_PROTO: https
DRONE_SERVER_HOST: "drone2.example.internal"
DRONE_RPC_SECRET: MyRPCSecretab897a797c979d79779e79f
DRONE_TLS_CERT: /cert/drone.crt
DRONE_TLS_KEY: /cert/drone.key
DRONE_LOGS_DEBUG: "false"
DRONE_LOGS_TRACE: "false"
drone-runner:
build:
context: ./
dockerfile: services/drone-runner/drone-runner.Dockerfile
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
DRONE_RPC_PROTO: https
DRONE_RPC_HOST: drone
DRONE_RPC_SECRET: MyRPCSecretab897a797c979d79779e79f
DRONE_RUNNER_CAPACITY: 4
DRONE_RUNNER_NAME: drone-runner
DRONE_RPC_DUMP_HTTP: "false"
DRONE_RPC_DUMP_HTTP_BODY: "false"
docker-registry:
build:
context: ./
dockerfile: services/docker-registry/docker-registry.Dockerfile
ports:
- 10.10.10.27:443:443
volumes:
- ./services/docker-registry/data:/var/lib/registry
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:443
REGISTRY_HTTP_TLS_CERTIFICATE: /cert/docker-registry.crt
REGISTRY_HTTP_TLS_KEY: /cert/docker-registry.key
这里是每个 docker 文件:
srv/ci/services# cat gitea/gitea.Dockerfile
from gitea/gitea:latest
copy ./ca/* /usr/local/share/ca-certificates/
run update-ca-certificates
copy ./services/gitea/cert /cert
run chmod 700 /cert && chown -R myUser:myUser /cert
/srv/ci/services# cat drone/drone.Dockerfile
from drone/drone:1
run apk update && apk add --no-cache ca-certificates
copy ./ca/ca.crt /usr/local/share/ca-certificates/
run update-ca-certificates
copy ./services/drone/cert /cert
run chmod 700 /cert
/srv/ci/services# cat drone-runner/drone-runner.Dockerfile
from drone/drone-runner-docker:1
run apk update && apk add --no-cache ca-certificates
copy ./ca/ca.crt /usr/local/share/ca-certificates/
run update-ca-certificates
/srv/ci/services# cat docker-registry/docker-registry.Dockerfile
from registry
run apk update && apk add --no-cache ca-certificates
copy ./ca/ca.crt /usr/local/share/ca-certificates/
run update-ca-certificates
copy ./services/docker-registry/cert /cert/
run chmod 700 /cert
这是目录结构
所以请原谅我,我不是 docker 方面的专家,而且我最初并没有构建这个系统,它是用于我们的开发团队的。该系统已经存在 2 年了,并且在空间利用率方面已经增长了很多。我只能假设问题是容器的数据库被填满了,或者 docker-registry 有许多图像占用了太多空间。
问题:
- 为什么我的每个容器都需要 20 分钟来构建? (我假设是因为它需要复制位于 docker-compose 文件中的所有文件。)
- 为什么我的 /tmp 目录中有这么大的 tmp 文件,为什么我的系统传输到这个文件的速度这么慢?有没有办法阻止 docker 创建这个文件?
- 关于如何减少这些可笑的长构建时间的任何建议?
【问题讨论】:
-
你能提供一个minimal reproducible example吗?当你运行
docker build时,你在哪个目录下?这大致听起来像是将构建上下文传输到 Docker 守护程序的过程,因此,如果您正在运行使用/作为构建上下文的映像构建,或者您的主机构建创建了非常大的工件,而.dockerignore文件没有忽视,它可能会导致这种症状。 -
@DavidMaze 感谢您的回复。我更新了我的帖子(我希望)对于一个最小的可重复示例来说已经足够了。回复:“当你运行 docker build 时,你在哪个目录?”我不运行
docker build,我运行docker-compose build,我在与docker-compose.yaml 文件相同的文件夹中执行此操作。此文件位于 /srv/ci。 /srv/ci 专用于我们的 ci 的所有容器,这些容器用于 docker 构建,仅此而已。您可以在我刚刚发布的屏幕截图中看到目录结构,我从 /srv/ci 运行树。 -
@DavidMaze 回复:回复:使用 .dockerignore,我今天不使用这个文件。如果我要使用它,我应该尝试忽略哪些文件?在我的无知中,我认为 docker-compose 需要所有文件来创建构建,这不是真的吗?如果您需要任何其他数据或信息,请告诉我。
-
例如,如果
docker-registry/data是 70 GB,它将作为映像构建的一部分发送到 Docker 守护进程,这将需要很长时间并且需要大量的根分区空间。也许将*/data添加到*目录中的.dockerignorefile 会有所帮助? -
@DavidMaze,这解释了漫长的构建时间。这是 docker-registry,超过 70GB 的数据。我为 ./services/docker-registry/* 创建了一个 .dockerignore 并将其从 docker-compose 文件中删除以进行测试。现在临时文件只增长到 7GB。不幸的是,似乎为每个容器构建了 tmp 文件。第一个容器构建它,创建 tmp,一旦构建,它就会被删除。下一个容器正在构建,tmp 创建,一旦完全创建,tmp 已删除,等等。因此,它没有那么慢,但仍然很慢。有没有办法让 docker 不会为每个容器构建重新构建这个 tmp 文件?
标签: docker docker-compose build docker-registry