dockershelldockerfilepermission-denied

Permission Issue Running a Shell Script Inside Docker Entrypoint


As I understand it, I should be able to run a shell script upon creating a container by copying it to the /docker-entrypoint-initdb.d directory through my Dockerfile.

The issue I have is after running docker compose up, I receive the following error -

mysql_container-1  | 2024-12-16 21:14:21+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/shell.sh                                                     
mysql_container-1  | touch: cannot touch '/mysql_server/test': Permission denied

I had expected the shell script to run and create a file named test. Confusingly, I have been able to remove this script from my Dockerfile and exec into the container and touch a file without issue. I had also tried to add RUN ["chmod", "u+x", "/docker-entrypoint-initdb.d/shell.sh"] to my Dockerfile to no avail. Please see my docker-compose.yml, Dockerfile and shell.sh files below.

TIA for any help or guidance on this.

Dockerfile:

FROM mysql:lts
WORKDIR /mysql_server

COPY shell.sh /docker-entrypoint-initdb.d
RUN ["chmod", "u+x", "/docker-entrypoint-initdb.d/shell.sh"]

docker-compose.yml:

services:
  mysql_container:
    image: mysql_image:Dockerfile
    build: 
      context: .
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
      - MYSQL_DATABASE=docker_db

shell.sh:

#!/bin/sh
touch /mysql_server/test

Solution

  • The mysql image's entrypoint script contains this fragment:

    # If container is started as root user, restart as dedicated mysql user
    if [ "$(id -u)" = "0" ]; then
        mysql_note "Switching to dedicated user 'mysql'"
        exec gosu mysql "$BASH_SOURCE" "$@"
    fi
    

    So when it runs the scripts in /docker-entrypoint-initdb.d, it's as the mysql user, if the user hasn't started the container as some other user.

    You can in principle work around this by changing the directory's owner ship to match

    # In the Dockerfile
    RUN chown mysql /mysql_server
    

    However, the important thing about the /docker-entrypoint-initdb.d directory is that it only runs the very first time the container runs on a given MySQL data volume. If the volume is already initialized then the entrypoint setup scripts won't run. If you run the container twice, your file won't be there the second time

    docker volume create mysql_data
    docker run -v mysql_data:/var/lib/mysql mysql_image:Dockerfile ls -l
    docker run -v mysql_data:/var/lib/mysql mysql_image:Dockerfile ls -l
    

    Also remember that a container only runs a single process, and it's hard to access a container's filesystem from elsewhere. Whatever files this script creates, you may have trouble actually accessing or using them.