skip to Main Content

I am trying to compose Apache Guacamole environment with docker-compose file for containers definition and a Dockerfile to initialize the database.

I followed this tutorial, it generally worked without the automated database setup (Dockerfile), but when I try to put the instructions in the Dockerfile, docker throws an error.

docker-compose file:

version: '3'

services:
  guacd:
    restart: always
    image: guacamole/guacd

  guacamole-server:
    restart: always
    image: guacamole/guacamole
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - GUACD_HOSTNAME=guacd
      - POSTGRESQL_HOSTNAME=database
      - POSTGRESQL_DATABASE=${GUACAMOLE_DATABASE}
      - POSTGRESQL_USER=${GUACAMOLE_USER}
      - POSTGRESQL_PASSWORD=${GUACAMOLE_PASSWORD}
    depends_on:
      - guacd
      - database
    volumes:
      - ./initdb.sql:/initdb.sql:ro

  database:
    restart: always
    image: postgres
    environment:
      - POSTGRES_USER=${GUACAMOLE_USER}
      - POSTGRES_DB=${GUACAMOLE_DATABASE}
      - POSTGRES_PASSWORD=${GUACAMOLE_PASSWORD}
    volumes:
      - ./db:/var/lib/postgresql/data:rw
      - ./initdb.sql:/initdb.sql:ro
    command: >
      sh -c "psql -U ${GUACAMOLE_USER} ${GUACAMOLE_DATABASE} -f /initdb.sql && 
             tail -f /dev/null"
volumes:
  db:

Dockerfile:

# Dockerfile for guacamole/guacamole container
FROM guacamole/guacamole:latest

USER root
# Generate the initdb.sql file for PostgreSQL
RUN /opt/guacamole/bin/initdb.sh --postgresql > initdb.sql

USER guacamole

When i run docker-compose up --build -d it builds succesfully, only after the build the error below is thrown and the databse (PostgreSQL) container goes into restarting state.

Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/scripts/Cherry-VM-Manager/docker/apache-guacamole/initdb.sql" to rootfs at "/initdb.sql": mount /scripts/Cherry-VM-Manager/docker/apache-guacamole/initdb.sql:/initdb.sql (via /proc/self/fd/6), flags: 0x5001: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

Directory with docker-compose file:

total 16
drwxr-xr-x 1 root root  112 Aug  3 18:18 .
drwxr-xr-x 1 root root   74 Jul 25 12:58 ..
-rw-r--r-- 1 root root   82 Aug  3 18:18 .env
-rw-r--r-- 1 root root  217 Aug  3 18:18 Dockerfile
drwxr-xr-x 1 root root    0 Aug  3 17:17 db
-rw-r--r-- 1 root root 1048 Aug  3 18:18 docker-compose.yml
-rw-r--r-- 1 root root  852 Aug  3 18:18 docker-compose.yml.bak

2

Answers


  1. The tutorial includes an initial step to create the initdb.sql file. It appears that this step was skipped or was unsuccessful:

    docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgresql > initdb.sql
    

    That step would have created the file in your current directory.

    Login or Signup to reply.
  2. You can’t really share files from one container to another. It looks like in your setup you’re trying to generate the initialization script in one image, then use it in a separate container, and that doesn’t really work.

    The Docker Hub guacamole/guacamole image page suggests you need to generate the init.sql script and execute it outside of Docker. To reiterate its advice, and actually load in the file, I might run (manually, once)

    docker-compose run guacamole-server 
      /opt/guacamole/bin/initdb.sh --postgres > initdb.sql
    docker-compose run -e PGHOST=database 
      database 
      psql < initdb.sql
    

    (The second line may need to set $PGUSER, $PGPASSWORD, and $PGDATABASE as well.)


    If you wanted this to run automatically on container startup, you’d need to arrange for this to happen within the guacamole-server container, on startup. I usually use an entrypoint wrapper script for this, which would run the initialization steps and then run exec "$@" to run the main container command. So that script could look like

    #!/bin/sh
    
    # Load the initial data
    PGHOST="$POSTGRESQL_HOSTNAME" 
    PGDATABASE="$POSTGRESQL_DATABASE" 
    PGUSER="$POSTGRESQL_USER" 
    PGPASSWORD="$POSTGRESQL_PASSWORD" 
    PGHOST="$psql < initdb.sql
    
    # Run the main container command
    exec "$@"
    

    You’d need to find the original Dockerfile (it seems to be this: when your image changes its ENTRYPOINT it needs to repeat the CMD from the original Dockerfile.

    FROM guacamole/guacamole:latest
    
    USER root
    RUN /opt/guacamole/bin/initdb.sh --postgresql > initdb.sql
    USER guacamole
    
    COPY entrypoint.sh ./
    ENTRYPOINT ["./entrypoint.sh"]
    CMD ["/opt/guacamole/bin/entrypoint.sh"] # from original image
    

    What’s wrong with the original setup? When the Compose file says

    volumes:
      - ./initdb.sql:/initdb.sql:ro
    

    This always takes what’s in ./initdb.sql on the host system, and replaces what was in the original image with that. So in this setup, the initdb.sql file you create in the Dockerfile is lost.

    I’m guessing the file never existed on the host system, but if you look now, ls -ld initdb.sql will show you an empty directory on the host. This is a long-standing Docker behavior to create an empty directory as the source for a bind mount if it doesn’t already exist. When Docker tries to mount that directory over the plain file that’s in the error, that results in the specific error you get.

    You will also have problems because a container command: runs instead of the normal thing the container does. So in this setup you’re trying to run psql to load the data, instead of running a database server, and the psql command will fail.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search