Fixing World-writable MySql error in Docker

14,510

Solution 1

It seems solution for having files with not full permissions when using Windows host is sharing files with "intermediate directory" and then copy those files into desired directory in Docker container.

In above case (MySQL container) it could be done like this (you can use this method also in other cases)

Dockerfile:

# Base image
FROM mysql:5.7

# Copy starting scripts file
COPY start.sh /root/start.sh

# Run necessary services
CMD ["/bin/bash", "/root/start.sh"]

docker-compose.yml (showed only db container)

db:
  build: ../builds/mysql-5.7
  environment:
     - MYSQL_ROOT_PASSWORD=pass
     - MYSQL_DATABASE=
     - MYSQL_USER=
     - MYSQL_PASSWORD=
  expose:
     - 3306
  volumes:
    - /c/Users/marcin/dock-test/composers/l1.app/mysql/data/:/var/lib/mysql/
    - /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/source
    - /c/Users/marcin/dock-test/composers/l1.app/mysql/log/:/var/log/mysql/

Plese notice that above we mount conf.d directory to /etc/mysql/conf.d/source directory and not to /etc/mysql/conf.d/ directory (so MySql won't load this file for now).

start.sh

#!/bin/sh

cp /etc/mysql/conf.d/source/* /etc/mysql/conf.d/

/entrypoint.sh mysqld

Above we copy now all files from conf.d/source directly into conf.d - those files are not shared with Windows host so they will be created with Linux permissions (in my case leaving defaults - without using chmod is fine).

To verify whether custom mysql configuration values are loaded now I run:

mysql -u root -p

and type my password.

When I type SHOW VARIABLES; I will see some settings from my.cnf that previously (without putting this file had different values), so it's working as expected.

Of course drawback of this solution is that those files won't be really shared so in case those files would be changed in Docker machine, they won't be updated in Windows host, but in above case when we want to use custom config files it doesn't make any difference and solve the issue.

Solution 2

I just encountered this issue and the fix for me is just to set my.cnf file to read-only in Windows.

Solution 3

This works for me

      mysql:
        networks:
          - main
        image: library/mysql:5.7
        container_name: 'mysql'
        command: >
          bash -c "
          chmod 644 /etc/mysql/conf.d/*.cnf
          && /entrypoint.sh mysqld
          "
        ports:
          - "3308:3308"
        volumes:
          - ./my_local_dir/var/lib/mysql:/var/lib/mysql
          - ./my_local_dir/etc/mysql/conf.d/:/etc/mysql/conf.d/
        restart: always
        environment:
          MYSQL_ROOT_PASSWORD: 'root'
          MYSQL_DATABASE: 'some'

Solution 4

I have an alternative answer for those that just need to set a few configuration options.

In the docker compose file you can do something like this.

db:
  image: mysql
  command: >
            bash -c "mysqld --user=root --group_concat_max_len=1844674407370954752"
  environment:
     - MYSQL_ROOT_PASSWORD=pass
     - MYSQL_DATABASE=
     - MYSQL_USER=
     - MYSQL_PASSWORD=
  expose:
     - 3306

Notice I run mysqld and then set the options --group_concat_max_len as an example. If you need more options just add more -- within the "" with the name of the option. This is an elegant solution that does not require making a new image from the default mysql one.

What command does in a docker compose file is overwrites the default CMD command in the image. The images default command simply runs mysqld (you can look it up on their github page), so I simply just run it as well but give it some parameters to pass in. Refer to the very last line of this file to see the CMD command. (refer to this: https://github.com/docker-library/mysql/blob/master/5.5/Dockerfile)

Using this method you do not even need to worry about voluming in a mysql configuration file, which for me was a big issue since it had to be 777 to work when doing docker-compose up but would then proceed to fail due to the world writable problem.

Solution 5

Thanks to @marcin-nabiałek for the inspiration, I got this solution working without having to write a custom script to run commands as I was still ending up with permissions issues. The script contents could've been completed with the Dockerfile commands (see mariadb/Dockerfile contents below).

I run docker-compose -p my_project up --build -d in the project-root directory.

File structure is as follows. project-root:

drwxr-xr-x 1 cmeza 197121    0 Aug 22 16:19 .git/
-rw-r--r-- 1 cmeza 197121   40 Aug 22 15:41 .gitignore
-rw-r--r-- 1 cmeza 197121 1056 Aug 22 13:24 Dockerfile
-rw-r--r-- 1 cmeza 197121  291 Aug 22 13:24 PROJECT.md
-rw-r--r-- 1 cmeza 197121 3642 Aug 22 13:24 README.md
drwxr-xr-x 1 cmeza 197121    0 Aug 22 13:24 bin/
-rw-r--r-- 1 cmeza 197121  944 Aug 22 15:42 docker-compose.yml
drwxr-xr-x 1 cmeza 197121    0 Aug 22 15:41 mariadb/

project-root/mariadb:

-rw-r--r-- 1 cmeza 197121  193 Aug 22 15:46 Dockerfile 
drwxrwxrwx 1 cmeza 197121    0 Aug 22 13:57 conf/      
-rwxrwxrwx 1 cmeza 197121 5013 Aug 22 13:57 conf/my_custom.cnf
drwxrwxrwx 1 cmeza 197121    0 Aug 22 16:07 data/
-rwxrwxrwx 1 cmeza 197121    0 Aug 22 16:07 data/.gitignore     
drwxrwxrwx 1 cmeza 197121    0 Aug 22 16:06 entrypoint/
-rwxrwxrwx 1 cmeza 197121 1163 Aug 22 16:06 entrypoint/default.sql
drwxrwxrwx 1 cmeza 197121    0 Aug 22 15:52 log/
-rwxrwxrwx 1 cmeza 197121    0 Aug 22 15:52 log/.gitignore 

docker-compose.yml (note the relative paths for the volumes):

(other services here)

db:
  environment:
      - MYSQL_ROOT_PASSWORD=my_super_secret_password
      - MYSQL_DATABASE=my_db
  ports:
      - "3306:3306" 
  volumes:
      - ./mariadb/entrypoint:/docker-entrypoint-initdb.d
      - ./mariadb/conf:/etc/mysql/conf.d/my_conf_files
      - ./mariadb/data:/var/lib/mysql
      - ./mariadb/log:/var/log/mysql
  build: ./mariadb
  entrypoint:
      - docker-entrypoint.sh
      - mysqld

(some other services here)

mariadb/Dockerfile:

# Base image
FROM mariadb:5.5

# Copy custom conf file(s)
# .\conf being your relative host path from this Dockerfile
# \etc\mysql\conf.d\ being the VM path
COPY .\conf\* \etc\mysql\conf.d\

# Make the conf files not writeable so mysql will read them
RUN chmod a-w \etc\mysql\conf.d\*

This got me everything I needed & I still have some hair left on my head. Let me know if this helps anyone else.

Share:
14,510
Marcin Nabiałek
Author by

Marcin Nabiałek

I'm a Cerified Laravel Developer & Zend Certified PHP Engineer experienced in making code reviews. If you need remote Laravel PHP developer or you are looking for someone to help you to keep high code quality, feel free to contact. Learn more about me at Marcin Nabiałek - Laravel PHP developer

Updated on June 03, 2022

Comments

  • Marcin Nabiałek
    Marcin Nabiałek almost 2 years

    I'm using docker-compose, for db I have such container defined:

    db:
      build: ../builds/mysql-5.7
      environment:
         - MYSQL_ROOT_PASSWORD=pass
         - MYSQL_DATABASE=
         - MYSQL_USER=
         - MYSQL_PASSWORD=
      expose:
         - 3306
      volumes:
        - /c/Users/marcin/dock-test/composers/l1.app/mysql/data/:/var/lib/mysql/
        - /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/
        - /c/Users/marcin/dock-test/composers/l1.app/mysql/log/:/var/log/mysql/
    

    My Dockerfile for this image is:

    # Base image
    FROM mysql:5.7
    
    # Set valid file permissions - otherwise MySql won't read those files
    
    #COPY mysql-perm-fix.sh /etc/init.d/mysql-perm-fix.sh
    #RUN chmod +x /etc/init.d/mysql-perm-fix.sh
    #RUN update-rc.d mysql-perm-fix.sh defaults 100
    
    #RUN mkdir /etc/mysql/conf.d/source
    #RUN cp /etc/mysql/conf.d/source/my.cnf /etc/mysql/conf.d/my.cnf
    #RUN chmod -R 644 /etc/mysql/conf.d
    

    At the moment everything is commented except base MySql image.

    The problem is, when I start my containers, my MySql cnf file won't be used by MySql because of this warning:

    mysqld: [Warning] World-writable config file '/etc/mysql/conf.d/my.cnf' is ignored.

    I'm using Windows as my host system. The problem is that Docker mounts diretory with full permissions and they couldn't be changed.

    The question - how could it be solved? As you see in my Dockerfile I've tried a few solutions, but none of them works for me (but maybe I'm doing something wrong).

    At the moment I think the most reasonable solution would be mounting MySql conf files not directly into /etc/mysql/conf.d/ but into some other directory and copy those files to /etc/mysql/conf.d/ directory before MySql starts and set them not 777 permissions. I've tried it, but in Dockerfile those files are not present yet so they cannot be copied.

    Is there any easy solution to fix it? Or maybe some MySql settings could be changed to don't care about conf file permissions?

    I also cannot simple use COPY inside Dockerfile to copy Mysql config files (instead of using volumes) because I want to use those images by multiple sites and each of them might have different configuration.

  • Marcin Nabiałek
    Marcin Nabiałek about 8 years
    The problem is that I don't want to share those volumes between containers at all. I just want to include into container cnf files i have in my host system (Windows) into MySql container.
  • Ken Cochrane
    Ken Cochrane about 8 years
    Ok, I included another option in the answer for not sharing between containers, but that wouldn't pull from the host. I'll see if I can think of something else.
  • Marcin Nabiałek
    Marcin Nabiałek about 8 years
    Thank you for your effort. It seems I've managed to solve this (see my answer)
  • Tarmo
    Tarmo over 5 years
    This should be the accepted answer really now. 1 checkbox instead of building a new image
  • Aldo Inácio da Silva
    Aldo Inácio da Silva about 3 years
    I just give less permission to the file my.cnf chmod 0444 my.cnf and it worked. If I give all permissions chmod 777 my.cnf it doesn't work.
  • hpca01
    hpca01 almost 3 years
    YOU sir are the REAL MVP.
  • izogfif
    izogfif about 2 years
    The issue is that there is no way to mark the file as read-only in git commit :(