Automate privilege preparation for Docker volume mountpoints

Satisfy container preconditions with `depends_on` in Docker Compose

Geschrieben von Timo Rieber am 24. März 2024

When I added Elasticsearch to the Cloudapps Docker Compose stack, the container refused to start. Elasticsearch runs as a non-root user - UID 1000, GID 0 - and the data directory, mounted as a Docker volume, was owned by root.

Years ago Elasticsearch still had a system property es.insecure.allow.root to bypass this, but they removed it - rightfully so, even if the discussion was controversial. Security over convenience. But it means the deployment needs to prepare volume ownership before the container starts.

Manually fixing permissions on the host works once, but breaks the next time someone provisions the server from scratch.

Preparing volumes with depends_on

A throwaway init container can fix ownership before the actual service starts. Docker Compose's depends_on with condition: service_completed_successfully makes this declarative:

volumes:
  elasticsearch-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /srv/data/elasticsearch

services:
  elasticsearch-volume-init:
    image: alpine
    volumes:
      - elasticsearch-data:/tmp/change-ownership
    command: chown --recursive 1000:0 /tmp/change-ownership

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.2
    depends_on:
      elasticsearch-volume-init:
        condition: service_completed_successfully
    volumes:
      - elasticsearch-data:/usr/share/elasticsearch/data
    # ... Elasticsearch config (memory, security, etc.)
Yaml

The elasticsearch-volume-init service runs chown on the mounted volume and exits. The elasticsearch service only starts after the init container succeeds. If permissions are already correct, the chown is a no-op - it runs on every docker compose up and needs no external provisioning scripts.

The pattern works for any non-root container that writes to a mounted volume. Match the UID and GID to whatever user the target container runs as.

Credit to Pratik Chowdhury for the original idea.