Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failing to read file in 4.21.1 #6912

Closed
SethThomasEmcee opened this issue Jul 12, 2023 · 5 comments
Closed

Failing to read file in 4.21.1 #6912

SethThomasEmcee opened this issue Jul 12, 2023 · 5 comments

Comments

@SethThomasEmcee
Copy link

Description

We are running a multi-container application, and after updating to Docker desktop for silicon Mac I was getting the following error trying to build and run many of our service containers:

docker compose up --build merchant_service
[+] Building 0.0s (2/2) FINISHED
=> [merchant_service internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 2B 0.0s
=> [merchant_service internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
failed to solve: failed to read dockerfile: open /var/lib/docker/tmp/buildkit-mount2085790808/Dockerfile: no such file or directory

Reproduce

Create a multi - container application with this structure

full-stack
|- - docker-compose.yaml
| - - serviceA
| - - - - docker-compose.yaml
| - - - - Dockerfile
| - - serviceB
etc.

And try to run docker compose up --build serviceA from the full-stack directory. The following error will be encountered:

docker compose up --build serviceA
[+] Building 0.0s (2/2) FINISHED
=> [serviceA internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 2B 0.0s
=> [serviceA internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
failed to solve: failed to read dockerfile: open /var/lib/docker/tmp/buildkit-mount2085790808/Dockerfile: no such file or directory

Expected behavior

The container should build and run

docker version

Please note this is my current version and not the version that was affected. I rolled back to 4.20.1 because the issue is not present there. The problematic version is the latest release (4.21.1)

Client:
 Version:    24.0.2
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.10.5
    Path:     /Users/seththomas/.docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.18.1
    Path:     /Users/seththomas/.docker/cli-plugins/docker-compose
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-dev
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.19
    Path:     /Users/seththomas/.docker/cli-plugins/docker-extension
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v0.1.0-beta.4
    Path:     /Users/seththomas/.docker/cli-plugins/docker-init
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc.)
    Version:  0.6.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-sbom
  scan: Docker Scan (Docker Inc.)
    Version:  v0.26.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-scan
  scout: Command line tool for Docker Scout (Docker Inc.)
    Version:  v0.12.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-scout

Server:
 Containers: 4
  Running: 4
  Paused: 0
  Stopped: 0
 Images: 4
 Server Version: 24.0.2
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 2
 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 io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 3dce8eb055cbb6872793272b4f20ed16117344f8
 runc version: v1.1.7-0-g860f061
 init version: de40ad0
 Security Options:
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 5.15.49-linuxkit-pr
 Operating System: Docker Desktop
 OSType: linux
 Architecture: aarch64
 CPUs: 5
 Total Memory: 7.667GiB
 Name: docker-desktop
 ID: 9ad08d15-220e-4d75-a2ca-2eecc2f84213
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
 Live Restore Enabled: false

seththomas@Seths-MBP emcee-stack % docker version
Client:
 Cloud integration: v1.0.33
 Version:           24.0.2
 API version:       1.43
 Go version:        go1.20.4
 Git commit:        cb74dfc
 Built:             Thu May 25 21:51:16 2023
 OS/Arch:           darwin/arm64
 Context:           desktop-linux

Server: Docker Desktop 4.20.1 (110738)
 Engine:
  Version:          24.0.2
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.4
  Git commit:       659604f
  Built:            Thu May 25 21:50:59 2023
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.6.21
  GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8
 runc:
  Version:          1.1.7
  GitCommit:        v1.1.7-0-g860f061
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

docker info

Client:
 Version:    24.0.2
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.10.5
    Path:     /Users/seththomas/.docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.18.1
    Path:     /Users/seththomas/.docker/cli-plugins/docker-compose
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-dev
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.19
    Path:     /Users/seththomas/.docker/cli-plugins/docker-extension
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v0.1.0-beta.4
    Path:     /Users/seththomas/.docker/cli-plugins/docker-init
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc.)
    Version:  0.6.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-sbom
  scan: Docker Scan (Docker Inc.)
    Version:  v0.26.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-scan
  scout: Command line tool for Docker Scout (Docker Inc.)
    Version:  v0.12.0
    Path:     /Users/seththomas/.docker/cli-plugins/docker-scout

Server:
 Containers: 4
  Running: 4
  Paused: 0
  Stopped: 0
 Images: 4
 Server Version: 24.0.2
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 2
 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 io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 3dce8eb055cbb6872793272b4f20ed16117344f8
 runc version: v1.1.7-0-g860f061
 init version: de40ad0
 Security Options:
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 5.15.49-linuxkit-pr
 Operating System: Docker Desktop
 OSType: linux
 Architecture: aarch64
 CPUs: 5
 Total Memory: 7.667GiB
 Name: docker-desktop
 ID: 9ad08d15-220e-4d75-a2ca-2eecc2f84213
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
 Live Restore Enabled: false

Diagnostics ID

Can't regenerate without going to broken version again

Additional Info

Rolling back to 4.20.1 fixed the issue. I can't replicate the error in 4.20.1, so I am unable to provide some of the information requested above. 4.21.1 is the version that has the issue.

@milas
Copy link

milas commented Jul 12, 2023

Can you provide a slightly more complete repro example?

.
├── compose.yaml
├── serviceA
│   └── Dockerfile
└── serviceB
    └── Dockerfile

compose.yaml:

services:
  service-a:
    build:
      context: serviceA
  service-b:
    build:
      context: .
      dockerfile: ./serviceB/Dockerfile

Dockerfile (same for service-a and service-b):

FROM nginx
❯ docker compose up --wait --build
[+] Building 0.1s (8/8) FINISHED
 => [service-a internal] load build definition from Dockerfile                                                                                        0.0s
 => => transferring dockerfile: 85B                                                                                                                   0.0s
 => [service-a internal] load .dockerignore                                                                                                           0.0s
 => => transferring context: 2B                                                                                                                       0.0s
 => [service-b internal] load metadata for docker.io/library/nginx:latest                                                                             0.0s
 => CACHED [service-b 1/1] FROM docker.io/library/nginx                                                                                               0.0s
 => [service-a] exporting to image                                                                                                                    0.0s
 => => exporting layers                                                                                                                               0.0s
 => => writing image sha256:b3e55f3faec3c2f56d1fde218969e0696bddb20c44cb3d9a883a430f1f4755af                                                          0.0s
 => => naming to docker.io/library/formac6912-service-a                                                                                               0.0s
 => [service-b internal] load build definition from Dockerfile                                                                                        0.0s
 => => transferring dockerfile: 85B                                                                                                                   0.0s
 => [service-b internal] load .dockerignore                                                                                                           0.0s
 => => transferring context: 2B                                                                                                                       0.0s
 => [service-b] exporting to image                                                                                                                    0.0s
 => => exporting layers                                                                                                                               0.0s
 => => writing image sha256:5af17e2fbbdbaff3565107c3b1e0545f243ac9233d5501fecd324115ebe291e5                                                          0.0s
 => => naming to docker.io/library/formac6912-service-b                                                                                               0.0s
[+] Running 3/3
 ✔ Network formac6912_default        Created                                                                                                          0.0s
 ✔ Container formac6912-service-a-1  Healthy                                                                                                          0.9s
 ✔ Container formac6912-service-b-1  Healthy                                                                                                          0.9s

@SethThomasEmcee
Copy link
Author

SethThomasEmcee commented Jul 12, 2023

Sure, let me know if this helps.

full-stack/docker-compose.yaml:

  serviceA:
    extends:
      file: ./serviceA/docker-compose.yaml
      service: api
    environment:
      PORT: 3005
      KAFKA_URL: ${KAFKA_HOST}
      DATABASE_URL: ${DATABASE_BASE_URL}/merchant
      DD_AGENT_HOST: datadog_agent
    ports:
      - "3005:3005"
      - "30005:9229"
    depends_on:
      - db


  serviceB:
    extends:
      file: ./serviceB/docker-compose.yaml
      service: api
    environment:
      PORT: 3005
      KAFKA_URL: ${KAFKA_HOST}
      DATABASE_URL: ${DATABASE_BASE_URL}/merchant
      DD_AGENT_HOST: datadog_agent
    ports:
      - "3005:3005"
      - "30005:9229"
    depends_on:
      - db
...

  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: <redacted>
      POSTGRES_PASSWORD: <redacted>
    ports:
      - "5432:5432"
    volumes:
      - dbData:/var/lib/postgresql/data

full-stack/serviceA/docker-compose.yaml:

services:
  api:
    image: serviceA:llatest
    build:
      target: development
    volumes:
      - .:/usr/src/app
      - serviceA_nodeModules:/usr/src/app/node_modules
    command: pnpm run start:debug
    env_file:
      .env
volumes:
  serviceA_nodeModules:

full-stack/serviceA/Dockerfile:

FROM node:18-alpine As development

ENV NODE_ENV development

RUN npm i -g pnpm nest

# Create app directory
WORKDIR /usr/src/app

COPY --chown=node:node package.json pnpm-lock.yaml ./

# Install app dependencies
RUN pnpm install --ignore-scripts


FROM node:18-alpine As build

RUN npm i -g pnpm

WORKDIR /usr/src/app

COPY --chown=node:node package.json pnpm-lock.yaml ./

# In order to run `pnpm run build` we need access to the Nest CLI.
# The Nest CLI is a dev dependency,
# In the previous development stage we ran `npm ci` which installed all dependencies.
# So we can copy over the node_modules directory from the development image into this build image.
COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules

COPY --chown=node:node . .

# Run the build command which creates the production bundle
RUN pnpm run build

# Set NODE_ENV environment variable
ENV NODE_ENV production

# Install production dependencies only.
# This ensures that the node_modules directory is as optimized as possible.
RUN pnpm install --frozen-lockfile --prod --ignore-scripts

USER node


FROM node:18-alpine As production

WORKDIR /usr/src/app

# Set NODE_ENV environment variable
ENV NODE_ENV production

# Copy the bundled code from the build stage to the production image
COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist

# Start the server using the production build
CMD [ "node", "dist/src/main.js" ]

Service B is defined similarly

@milas
Copy link

milas commented Jul 12, 2023

Thank you, I pinpointed the issue and we will get a fix into Compose.

The key here is around the lack of build.context field, as a temporary workaround, you can explicitly set that to ., e.g.

services:
     image: serviceA:latest
     build:
       target: development
+      context: .
     volumes:
       - .:/usr/src/app
       - serviceA_nodeModules:/usr/src/app/node_modules

That will properly resolve the build context to full-stack/serviceA when run from full-stack/compose.yaml.

@SethThomasEmcee
Copy link
Author

@milas thanks for the workaround! I will try it out tomorrow and let you know if that resolves the issue.

milas added a commit to milas/compose-go that referenced this issue Jul 13, 2023
When using `extends.file` to load a service from another Compose
file, if the `build.context` field wasn't explicitly set, it would
get ignored by the path resolution.

As a result, the build context would end up as the working directory
of the _root_ Compose file instead of the working directory of the
_loaded_ Compose file.

This was because the relative path resolution logic ignored empty
`build.context` values. Unfortunately, removing that restriction
is itself not sufficient, as it then attempted to verify that the
local path existed in an attempt to avoid unintentionally joining
the working directory with a remote context value (e.g.
`/foo/https://github.com/my/repo.git`).

This is problematic because the working directory itself might be
relative (rooted to an unknown location that is != `.`), so it
will be resolved relative to the current process working directory,
and thus fail the existence check.

In practice, this happens when using `extends.file`, where we do
resolve paths but intentionally pass a potentially relative value
for the working dir, thus making it unsafe to be doing real
filesystem operations here.

In fact, even if a context was specified, it was possible to break
this by running Compose from a different directory than the _root_
Compose file while specifying the path to it.

As there's no formal specification for determining local path vs.
remote build contexts (see discussion in compose-spec#385), I'm simply
eliminating the existence check. This COULD mean that Compose
begins to erroneously consider remote context values as local paths
if builders add new unsupported syntaxes, but I think it's fair for
us to be more restrictive.

Additionally, I've ensured that when path resolution is happening,
it _always_ resolves the `build.context` to an absolute path for
consistency. In particular, this should help make it easier to
use the output of `docker compose config` from arbitrary working
directories.

There's a new test that covers the `extends.file` + `build.context`
behavior, and everal existing test adjustments to account for the
fact that Compose was emitting relative `build.context` paths from
`docker compose config` despite everything else being absolute
(such as volumes).

Fixes docker/for-mac#6912.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
@ndeloof
Copy link

ndeloof commented Feb 2, 2024

This specific scenario is not well covered (actually, not covered at all) by the specs and documentation. We could debate context defaults to . before or after yaml merge occurred. Actually with the redesign of the compose parser the former was preferred as there's also some usage scenario where it makes better sense: we allow the extend source to not be a fully valid compose file, so from this point of view there's no reason we force a default value when unspecified (while required by the model)

so, basically, to support this use-case, you better should use an explicit context: . entry
(see compose-spec/compose-go#558)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants