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

[BUG] extends with YAML merge anchors will ignore !override and !reset #11706

Open
ShadowLNC opened this issue Apr 10, 2024 · 1 comment
Open

Comments

@ShadowLNC
Copy link

ShadowLNC commented Apr 10, 2024

Description

I think this might be two separate issues - please let me know and feel free to split it up.

End goal: 10+ containers use the configs entry with dummy data, so I need that to be inherited. However a small number (about 3) need a volume mount of real information, so I want those to override (but inherit from each other using YAML anchors/aliases) - these are represented by x and y in my example below..

When a volume is in the same location as a config, there is no error and it is undefined behaviour or a race condition as to which one is applied first. In my case, the config is actually a sub-path of the volume, and the volume is read only, so if the volume wins, Compose reports an error when trying to deal with the config, otherwise it just works.

Secondly, I have a complex inheritance system where extends is used in a YAML anchor. When declaring the configs element with a !reset or !override directive, the new configs declaration is lost/ignored when the alias is later referenced.

Because I was unaware of the second issue, I was unknowingly running into the first issue (though I had explicitly tried to avoid it). Had Compose had a clearer error message, the second issue would have been easier to identify.

Steps To Reproduce

Files:

stuff/file1 and stuff/file2 -> some random text

docker-compose.template.yml
services:
    base:
        configs:
            - source: credentials
              target: /credentials/file1
docker-compose.yml
services:
    x: &x
        extends:
            file: ./docker-compose.template.yml
            service: base
        image: alpine
        command: echo "hi"
        # configs: !reset []
        configs: !override
            - source: credentials
              target: /literally-anywhere-else
        volumes:
            - type: bind
              source: ./stuff/
              target: /credentials/
              read_only: true
              bind:
                  create_host_path: false

    y:
        <<: *x
        command: echo "y"

configs:
    credentials:
        content: |
            dummy value

Try docker compose up -d.

When the volume is mounted first (for container y), the race condition causes this error:

Error response from daemon: unlinkat /credentials/file1: read-only file system

Sometimes it will just work if the configs are applied first.

Compose Version

docker compose version
Docker Compose version v2.26.1-desktop.1

Docker Environment

Output of docker info
Client:
 Version:    26.0.0
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.13.1-desktop.1
    Path:     /Users/scott/.docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.26.1-desktop.1
    Path:     /Users/scott/.docker/cli-plugins/docker-compose
  debug: Get a shell into any image or container. (Docker Inc.)
    Version:  0.0.27
    Path:     /Users/scott/.docker/cli-plugins/docker-debug
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.2
    Path:     /Users/scott/.docker/cli-plugins/docker-dev
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.23
    Path:     /Users/scott/.docker/cli-plugins/docker-extension
  feedback: Provide feedback, right in your terminal! (Docker Inc.)
    Version:  v1.0.4
    Path:     /Users/scott/.docker/cli-plugins/docker-feedback
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v1.1.0
    Path:     /Users/scott/.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/scott/.docker/cli-plugins/docker-sbom
  scout: Docker Scout (Docker Inc.)
    Version:  v1.6.3
    Path:     /Users/scott/.docker/cli-plugins/docker-scout
WARNING: Plugin "/Users/scott/.docker/cli-plugins/docker-scan" is not valid: failed to fetch metadata: fork/exec /Users/scott/.docker/cli-plugins/docker-scan: no such file or directory

Server:
 Containers: 22
  Running: 1
  Paused: 0
  Stopped: 21
 Images: 37
 Server Version: 26.0.0
 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 splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc version: v1.1.12-0-g51d5e94
 init version: de40ad0
 Security Options:
  seccomp
   Profile: unconfined
  cgroupns
 Kernel Version: 6.6.22-linuxkit
 Operating System: Docker Desktop
 OSType: linux
 Architecture: aarch64
 CPUs: 8
 Total Memory: 7.755GiB
 Name: docker-desktop
 ID: 85b60fc6-eedd-4b8c-996a-89f62a45ab85
 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
 Labels:
  com.docker.desktop.address=unix:///Users/scott/Library/Containers/com.docker.docker/Data/docker-cli.sock
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: daemon is not using the default seccomp profile

Anything else?

docker compose config output
docker compose config
name: testing
services:
  x:
    command:
      - echo
      - hi
    configs:
      - source: credentials
        target: /literally-anywhere-else
    image: alpine
    networks:
      default: null
    volumes:
      - type: bind
        source: /Users/scott/Documents/infra/docker-dev-environment/testing/stuff
        target: /credentials/
        read_only: true
        bind: {}
  "y":
    command:
      - echo
      - "y"
    configs:
      - source: credentials
        target: /credentials/file1
      - source: credentials
        target: /literally-anywhere-else
    image: alpine
    networks:
      default: null
    volumes:
      - type: bind
        source: /Users/scott/Documents/infra/docker-dev-environment/testing/stuff
        target: /credentials/
        read_only: true
        bind: {}
networks:
  default:
    name: testing_default
configs:
  credentials:
    name: testing_credentials
    content: |
      dummy value

You can see that for service y, the configs directive is a merge of both base and x while ignoring the !override directive. A reset directive behaves the same way (it just inherits from base as x is empty).

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

2 participants