mysqldockercontainers

Error with ibdata1 write when starting customised Docker MySQL container as non-root user


I need to start a MySQL container based on a MySQL image having an existing database as part of the image and set as the default database. It needs to run with non-root user of mysql since running as root is not permitted on our private Kubernetes cluster. Referencing another solution from SO for starting MySQL with a pre-existing database, created below Dockerfile. It started up a container successfully locally on Docker desktop UNTIL I made changes to try and make container runnable as user mysql.

The database schema was output from existing database on a VM using mysqdump and out to eddie_backup2.sql.

Dockerfile:

FROM containerregistry-na.foocompany/container-external/mysql:5.7.29 as builder

# That file does the DB initialization but also runs mysql daemon, by removing the last line it will only init
RUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]
ENV MYSQL_ALLOW_EMPTY_PASSWORD="y" 
ENV MYSQL_USER="eddie" MYSQL_PASSWORD="eddie_pwd" MYSQL_DATABASE="eddie"

ADD eddie_backup2.sql /tmp/eddie_backup2.sql
COPY setup.sql docker-entrypoint-initdb.d/

# Need to change the datadir to something else that /var/lib/mysql because the parent docker file defines it as a volume.
# https://docs.docker.com/engine/reference/builder/#volume :
#       Changing the volume from within the Dockerfile: If any build steps change the data within the volume after
#       it has been declared, those changes will be discarded.

RUN ["/usr/local/bin/docker-entrypoint.sh", "mysqld", "--datadir", "/initialized-db" ]
# added below line to change ownership
RUN    ["/bin/bash", "-c", "chown -R mysql:mysql /initialized-db/"]

# starting with mysql image again and using the generated datadirectory from above interim image
FROM containerregistry.foocompany.net/container-external/mysql:5.7.29 as actual_base
COPY --from=builder /initialized-db /var/lib/mysql

# change owner to mysql and list immediately to verify it was done
RUN ["/bin/bash", "-c", "chown -R mysql:mysql ./var/lib/mysql/ -v && ls -lrt /var/lib/mysql"]
USER mysql

CMD mysqld --datadir=/var/lib/mysql --user=mysql

MySQL script setup.sql run at initialisation, as it is located in special directory where the process looks:

use eddie;
source /tmp/eddie_backup2.sql ;

However, the logs indicated an issue with permissions to write to Innodb* folders. I think these are or should be present under /var/lib/mysql . That is as far as I got.

docker build --no-cache -t eddie-mysql:0.3 .

Logs:

changed ownership of './var/lib/mysql/performance_schema/file_summary_by_event_n
ame.frm' from root:root to mysql:mysql
changed ownership of './var/lib/mysql/performance_schema/events_transactions_sum
mary_by_thread_by_event_name.frm' from root:root to mysql:mysql
changed ownership of './var/lib/mysql/performance_schema/hosts.frm' from root:ro
ot to mysql:mysql
changed ownership of './var/lib/mysql/performance_schema' from root:root to mysq
l:mysql
changed ownership of './var/lib/mysql/ib_buffer_pool' from root:root to mysql:my
sql
changed ownership of './var/lib/mysql/ca.pem' from root:root to mysql:mysql
changed ownership of './var/lib/mysql/private_key.pem' from root:root to mysql:m
ysql
changed ownership of './var/lib/mysql/ibdata1' from root:root to mysql:mysql
changed ownership of './var/lib/mysql/auto.cnf' from root:root to mysql:mysql
changed ownership of './var/lib/mysql/client-key.pem' from root:root to mysql:my
sql
ownership of './var/lib/mysql/' retained as mysql:mysql
total 176196
-rw------- 1 mysql mysql     1680 Oct  2 15:07 server-key.pem
-rw-r--r-- 1 mysql mysql     1112 Oct  2 15:07 server-cert.pem
-rw-r----- 1 mysql mysql 50331648 Oct  2 15:07 ib_logfile1
-rw-r--r-- 1 mysql mysql     1112 Oct  2 15:07 ca.pem
-rw------- 1 mysql mysql     1676 Oct  2 15:07 ca-key.pem
-rw-r----- 1 mysql mysql       56 Oct  2 15:07 auto.cnf
-rw------- 1 mysql mysql     1680 Oct  2 15:07 client-key.pem
-rw-r--r-- 1 mysql mysql     1112 Oct  2 15:07 client-cert.pem
-rw-r--r-- 1 mysql mysql      452 Oct  2 15:07 public_key.pem
-rw------- 1 mysql mysql     1680 Oct  2 15:07 private_key.pem
-rw-r----- 1 mysql mysql 79691776 Oct  2 15:07 ibdata1
-rw-r----- 1 mysql mysql 50331648 Oct  2 15:07 ib_logfile0
-rw-r----- 1 mysql mysql     1452 Oct  2 15:07 ib_buffer_pool
drwxr-x--- 2 mysql mysql    12288 Oct  2 15:07 sys
drwxr-x--- 2 mysql mysql     4096 Oct  2 15:07 performance_schema
drwxr-x--- 2 mysql mysql     4096 Oct  2 15:07 mysql
drwxr-x--- 2 mysql mysql     4096 Oct  2 15:07 eddie
Removing intermediate container 29e35ac511ea
 ---> ce46892514e4
Step 13/14 : USER mysql
 ---> Running in fd1831317581
Removing intermediate container fd1831317581
 ---> ae9d3e300cbf
Step 14/14 : CMD mysqld --datadir=/var/lib/mysql --user=mysql
 ---> Running in 17143095e06f
Removing intermediate container 17143095e06f
 ---> 9712fc738c4c
Successfully built 9712fc738c4c
Successfully tagged eddie-mysql:0.3

It can be seen above ibdata1 ownership changed to mysql. This is relevant later . .

docker run -d  --name abc  eddie-mysql:0.3

docker logs 746a210065840

Below log indicates ibdata is not writeable by user mysql even though according to image build log it is owned by mysql !

2020-10-02T15:13:08.264040Z 0 [Note] InnoDB: Completed initialization of buffer
pool
2020-10-02T15:13:08.265201Z 0 [Note] InnoDB: If the mysqld execution user is aut
horized, page cleaner thread priority can be changed. See the man page of setpri
ority().
2020-10-02T15:13:08.275162Z 0 [ERROR] InnoDB: The innodb_system data file 'ibdat
a1' must be writable
2020-10-02T15:13:08.275231Z 0 [ERROR] InnoDB: The innodb_system data file 'ibdat
a1' must be writable
2020-10-02T15:13:08.275263Z 0 [ERROR] InnoDB: Plugin initialization aborted with
 error Generic error
2020-10-02T15:13:08.876474Z 0 [ERROR] Plugin 'InnoDB' init function returned err
or.
2020-10-02T15:13:08.876491Z 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE
ENGINE failed.
2020-10-02T15:13:08.876494Z 0 [ERROR] Failed to initialize builtin plugins.
2020-10-02T15:13:08.876496Z 0 [ERROR] Aborting

2020-10-02T15:13:08.876500Z 0 [Note] Binlog end
2020-10-02T15:13:08.876723Z 0 [Note] Shutting down plugin 'CSV'
2020-10-02T15:13:08.877008Z 0 [Note] mysqld: Shutdown complete

Solution

  • This may not be the most elegant solution but as mentioned earlier I could see that user mysql owns the file as a result of the chown added to my dockerfile. However discovered, it did not have write permission to it (confimred that after temporarily adding RUN ls -lrt /var/lib/mysql -v to list folder perms for debugging purposes ) which makes sense given the error message. Seems there is no publicly available image that takes care of this use case of starting a mySQL container as non root user.

    So amended my Dockerfile to give most priveleged permissions to file ibdata1 (as well as the containing folder for good measure) right after mysqld initialisation with no-default data directory:

    RUN ["/usr/local/bin/docker-entrypoint.sh", "mysqld", "--datadir", "/initialized-db" ] 
    
    RUN    ["/bin/bash", "-c", "chown -R mysql:mysql /initialized-db/"]
    RUN    ["/bin/bash", "-c", "chmod ugo=rwx -R /initialized-db/"]
    RUN chmod -R ugo+rwx /initialized-db/ibdata1
    

    Here is the pertinent part of the build log:

    Step 9/13 : RUN    ["/bin/bash", "-c", "chown -R mysql:mysql /initialized-db/"]
     ---> Running in 973c96b0f535
    Removing intermediate container 973c96b0f535
     ---> f190deb49406
    Step 10/13 : RUN    ["/bin/bash", "-c", "chmod ugo=rwx -R /initialized-db/"]
     ---> Running in 2e4612d7674c
    Removing intermediate container 2e4612d7674c
     ---> efa6715342e2
    Step 11/13 : RUN chmod -R ugo+rwx /initialized-db/ibdata1
     ---> Running in 3c2e288c19b7
    Removing intermediate container 3c2e288c19b7
     ---> 1c0e7a32b2a4
    Step 12/13 : FROM some-private-registry.net/container-external/mysql:5.7
    .29 as actual_base
     ---> 5d9483f9a7b2
    Step 13/13 : COPY --from=builder /initialized-db /var/lib/mysql
     ---> 19f51e56ae40
    

    I could then run the image as user mysql:

    docker container run -d --user mysql --name foo_name --user mysql foo-mysql:1.0