- resolve CVE-2021-3711, CVE-2021-3712
|1 month ago|
|.idea/.idea.ab-mariadb-alpine.dir/.idea||1 month ago|
|.gitattributes||1 month ago|
|.gitignore||1 month ago|
|Dockerfile||1 month ago|
|README.md||1 month ago|
|entrypoint.sh||5 months ago|
MariaDB on Alpine Linux (dockerized)
Fully functional dockerized installation of MariaDB server and client running on Alpine Linux. This container is roughly half the size of the official MariaDB container which runs on Ubuntu but still aims to mimic all its features while adding a few extra ;-) Note that this container is built against the Alpine EDGE repository for newer versions of mariaDB.
- Quick Start
- Connecting as a client
- Shell Access
- Checking Logs
- Environment Variables
- Root Account
- Data Persistence
- Data instantiation/import
- Custom Scripts
- Custom Configuration
- Database dumps
- Final Thoughts
Pull the image
The latest images are on my private docker registry. I also try to keep the ones on Dockerhub updated within a few days.
# pull from my private repo docker pull docker.asifbacchus.dev/mariadb/ab-mariadb-alpine:latest # pull from dockerhub docker pull asifbacchus/ab-mariadb-alpine:latest
The examples in this document will refer to dockerhub, but know that anywhere you
asifbacchus/ab-mariadb-alpine:tag you can use
docker.asifbacchus.app/mariadb/ab-mariadb-alpine:tag to use my
I have abandoned using Docker's signing mechanisms in favour of CodeNotary. Not only are they free, they offer several big advantages including avoiding Docker's weird and over-complicated key management system. The only drawback is that verifying images requires you downloading their client software which is free to use and does not require an account for verifying images or anything else. On Linux, you can simply rename the downloaded file
vcn and place it somewhere in your path like
/usr/local/bin, make it executable and then you can verify this image. Here's an example, obviously you need to modify it for your environment:
# run commands as root sudo -s # download vcn to proper location wget https://github.com/vchain-us/vcn/releases/download/v0.9.9/vcn-v0.9.9-linux-amd64 -O /usr/local/bin/vcn chmod +x /usr/local/bin/vcn # make sure it works vcn --version # verify container image vcn authenticate docker://asifbacchus/ab-mariadb-alpine:latest
If you want to confirm the image is authentic before each run, you can do:
vcn verify docker://asifbacchus/ab-mariadb-alpine:latest && docker run ... docker://asifbacchus/ab-mariadb-alpine:latest
Since you are making verification a prerequisite to running the docker command (i.e. using
&&), you can be sure that you are working with a verified and signed image.
You can get more information on installing the client software for different platforms here.
Run the image
The image has sensible defaults and can be run without setting many environment variables. In the example below, we will start MariaDB server and create an empty database called 'CompanyX', set a root password and create a user account for Jane Doe which has full privileges for the CompanyX database. Data will be stored in the named volume 'companyDB'.
docker run -d \ -v companyDB:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD='SuPeR$ecurEP@$$w0rd' \ -e MYSQL_DATABASE='CompanyX' \ -e MYSQL_USER='JaneDoe' \ -e MYSQL_PASSWORD='JanesPa$$w0rd' \ asifbacchus/ab-mariadb-alpine
Let's take a quick overview of the options used above:
Create a database
Assuming an existing database does not exist in the container's data directory already, it will create an empty database for you. The name of this database is controlled by the environment variable
MYSQL_DATABASE. This defaults to 'myData'. If you would like to create a database called 'CompanyX', for example, you would set the environment variable as follows:
docker run -d -e MYSQL_DATABASE='CompanyX' asifbacchus/ab-mariadb-alpine
If you do not set a root password for mySQL, the container will generate one for you and will display that password in the logs right before MariaDB starts up. To see the password, you will have to access the logs:
docker logs <container name>. Then scroll up until you see the password.
In normal usage, you will want to set the root password instead of having it generated for you. This is accomplished by setting the environment variable
MYSQL_ROOT_PASSWORD. The command would look something like:
docker run -d -e MYSQL_ROOT_PASSWORD='SuPeR$ecurEP@$$w0rd' asifbacchus/ab-mariadb-alpine
If you would like a user account created for you with FULL privileges to the database created by the container, you must set two environment variables:
MYSQL_PASSWORD. You can do that as follows:
docker run -d -e MYSQL_USER='JaneDoe' -e MYSQL_PASSWORD='JanesPa$$w0rd' asifbacchus/ab-mariadb-alpine
Connecting as a client
You can connect directly to the container, depending on how you have set your permissions. By default, the container allows integrated root access via the root account. You can connect this way from your host machine:
docker exec -it container_name mysql
This will log you into the container using the root account and connect you to MariaDB using that root account without a password. Naturally, you will have to weigh whether or not retaining this ability is appropriate for your environment, but it is very helpful when testing/developing or learning about MariaDB/mySQL since you actively have to try to lock yourself out.
N.B. Connecting this way is distinct from logging in using the root account with a password. Here, we are using the account 'root'@'localhost' whereas using the one with a password (even the one created by this container) is 'root'@'%'.
You can launch another instance of the container and use that as a client to connect to your server container or any other remote MariaDB/mySQL instance. In this case, we don't want to pass any environment variables, but we want to pass a separate CMD parameter as follows:
docker run -it --rm asifbacchus/ab-mariadb-alpine mysql -hmysql.host.tld -uusername -ppassword
*N.B. I used the
--rm Docker parameter to automatically remove the container on exit. This is optional.
There are times where you will want to connect to your container and access the shell. Most often this is for troubleshooting or verifying settings. Logs are better accessed as outlined in the next section. To access the container's shell, run the following command:
docker exec -it container_name /bin/sh
Please note this is an Alpine Linux container so it uses the ASH shell. This is a POSIX-compliant shell that does not have the bells and whistles you may be used to in shells like BASH, etc. Also, Alpine uses BusyBox for most of its commands so some familiar Linux commands may not work as you are used to or may be entirely missing. Notably, however, ping is installed and functional in this container.
The container logs everything to the console, so the best way to check logs is via the
docker logs command:
# get default look-back period of logs docker logs container_name # get last 50 lines (n can be whatever you like) docker logs -n50 container_name # follow log (see realtime updates -- CTRL-C to exit) docker logs -f container_name # display the last 5 lines and follow in realtime after that docker logs -n5 -f container_name
Most container configuration is accomplished via environment variables. We've already encountered some in the Quick Start but I'll reiterate them here for completeness:
|MYSQL_UID||8100||User ID (UID) for the mysql user account. Useful when coordinating between your host and the container.|
|MYSQL_GID||8100||Group ID (GID) for the mysql user account. Useful when coordinating between your host and the container.|
|TZ||Etc/UTC||Timezone used by the container and, by extension, MariaDB.|
|MYSQL_SKIP_NAME_RESOLVE||TRUE||This will tell MariaDB NOT to run reverse DNS lookups on connecting hosts. As a result, user accounts should be defined by IP address versus hostname. This is the default setting for Docker containers since hostnames are generally random and accounts are specified as 'user'@'%'. If you need to use hostnames, set this to 'FALSE' so you can use hostnames in account definitions.|
|MYSQL_CHARSET||utf8mb4||Character Set for the newly created database. Will NOT affect existing or imported databases.|
|MYSQL_COLLATION||utf8mb4_general_ci||Collation rules for the newly created database. Will NOT affect existing or imported databases.|
|MYSQL_ROOT_PASSWORD||auto-generated||Sets the root password for your MariaDB server. If you leave this blank (default) the container will generate a password for you and display it in the logs. In practice, you should really define this yourself. This will be ignored if you are mounting a volume/directory with an existing database. Please refer to the Root Account section for some interesting notes.|
|MYSQL_DATABASE||myData||Name of the new database you would like created. If you do not specify anything, a new database called 'myData' will be created. If you mount a volume/directory with an existing database, this value will be ignored.|
|MYSQL_USER||none||Username of the account to be created and granted full privileges on MYSQL_DATABASE. If you do not specify this value, no user account will be created. This only applies to the MYSQL_DATABASE|
|MYSQL_PASSWORD||none||Password for the account specified by MYSQL_USER. If you do not specify this value, MYSQL_USER will not be created. This only applies to the MYSQL_DATABASE|
There are actually two (2) root accounts for this container and you should carefully review whether your need both or just one.
The default setup of the container allows 'root'@'localhost' to connect without a password using Linux-integrated authentication. In other words, if you are logged into the container as root, you also have root access to the database without a password. You can delete this by changing/removing the root@localhost account in the mysql.user container using the regular GRANT command.
The container creates a user 'root'@'%' account using the password as set or auto-generated by MYSQL_ROOT_PASSWORD. This account can connect by remote assuming the correct password is used. You may want to change the '%' (any) host to a specific address/hostname, but that is a decision for you as the DB-admin!
By default, the container will create a volume to store your mySQL database so you don't accidentally lose any important information. In this case, the name is auto-generated by docker and is not very user-friendly. If, instead, you would like to use an existing volume, control the name of the created volume or use a bind-mount, you can do so by specifying a mapping to /var/lib/mysql in the container. For example:
# create a volume or use an existing named-volume docker run -d -v mydatabase:/var/lib/mysql asifbacchus/ab-mariadb-alpine # use a bind-mount location docker run -d -v /my/local/dir:/var/lib/mysql asifbacchus/ab-mariadb-alpine
Existing DB (mysql directory)
The entrypoint script of the container simply checks to see if the /var/lib/mysql directory is empty and, if so, creates a new database for you. Thus, if you want to import an existing database, you simply have to mount a valid mysql subdirectory:
docker run -d -v /existing/mysql:/var/lib/mysql asifbacchus/ab-mariadb-alpine
If you want to 'instantiate' your newly created database (add tables, some default data, set privileges, etc.) then you can import SQL files with commands preloaded. Any .sql or .sql.gz files mounted in the container's /docker-entrypoint-initdb.d folder will be imported after the new database is created.
docker run -d -v /sql/import/scripts:/docker-entrypoint-initdb.d asifbacchus/ab-mariadb-alpine
You should review the logs when doing this to see if MariaDB throws any errors due to syntax errors or other mistakes in your SQL files. An easy way to do this is:
docker run -d --name db -v /sql/import/scripts:/docker-entrypoint-initdb.d asifbacchus/ab-mariadb-alpine && docker logs -f db
You can, of course, name your container anything you like. Just change 'db' in both places to whatever you choose.
You can run custom scripts for whatever reason before and after MariaDB initialization by importing them into your container in the appropriate location.
To run scripts before MariaDB is initialized (i.e. before a database is created), simply mount your scripts in /docker-entrypoint-preinit.d.
To run scripts after MariaDB is initialized (i.e. after a database is created and SQL files are imported) but right before mysqld is started, simply mount your scripts in /docker-entrypoint-postinit.d.
docker run -d \ -v /my/pre-init/scripts:/docker-entrypoint-preinit.d \ -v /my/post-init/scripts:/docker-entrypoint-postinit.d \ asifbacchus/ab-mariadb-alpine
Entrypoint Task Order
For reference, the sequence of events in the entrypoint script is:
- Verify environment variables
- Change mysql UID/GID
- Update mysql configuration file
- Execute pre-init scripts
- Create runtime PID file
- Create database if one does not exist
- Create system tables
- Create database
- Add root account and set permissions
- Add user account if necessary
- Drop default 'test' table
- Import SQL files if they exist
- Execute post-init scripts
- Start mysqld
You can pass MariaDB command-line parameters to your container just as your would with a regular mysqld instance. For example:
docker run -d asifbacchus/ab-mariadb-alpine --innodb-ft-min-token-size=2
The container will concatenate any parameters your supply with the default ones of --console --user=mysql. Note that command-line parameters override environment variable parameters supplied to the container.
If you would like to use a completely custom MariaDB configuration you will need to mount your configuration files in the proper locations. In most cases, it's easiest to just load a single /etc/my.cnf file. If you want to use a multi-directory/multi-file format, I would still suggest creating a /etc/my.cnf file and pointing to the other locations within that file. If you only want to change a few server-related parameters, you can add files to the /etc/my.cnf.d/ directory.
# custom my.cnf docker run -d \ -v /mysql/configuration/my.cnf:/etc/my.cnf \ asifbacchus/ab-mariadb-alpine # custom server-related files docker run -d \ -v /mysql/server-config:/etc/my.cnf.d \ asifbacchus/ab-mariadb-alpine # complex configuration using custom my.cnf # this completely depends on how you specify things in my.cnf docker run -d \ -v /mysql/config/my.cnf:/etc/my.cnf \ -v /mysql/other-config:/etc/mysql/some-directory \ -v /mysql/more-configs:/etc/mysql/cnf/another-dir \ asifbacchus/ab-mariadb-alpine
You should be aware that the container passes '--console --user=mysql' command-line parameters to mysqld by default and that will override parameters specified in my.cnf or any other configuration file. If you need to override these defaults, you will have to pass the mysqld command manually:
docker run -d \ -v /mysql/configuration/my.cnf:/etc/my.cnf \ asifbacchus/ab-mariadb-alpine \ mysqld --user=anotheruser
The above command would run the process forked into the background (why you would do this, I'm not sure) and would run as 'anotheruser'. This is a contrived example for illustration purposes only.
This is exactly the same as the official container. I will repeat their instructions here for completeness and add a few more examples to make things clearer.
Creating dumps can be done using
docker exec and will be written to the host machine. It is easiest to take advantage of root-integrated access for operations like this.
# dump all databases -- root-integrated access docker exec container_name /bin/sh -c 'exec mysqldump --all-databases' > /local/path/mySQLdumps/all_databases.sql # dump selected databases -- remote-root access docker exec container_name /bin/sh -c 'exec mysqldump -uroot -p"SuPeR$ecurEP@$$w0rd" --databases myData otherDB' > /local/path/mySQLdumps/multiple.sql # dump 'myData' database -- user access (assuming permissions are correct) docker exec container_name /bin/sh -c 'exec mysqldump -uusername -p"password" --database myData' > /local/path/mySQLdumps/myData.sql
Restoring dumps can also be done using
docker exec. Again, this is easiest using root-integrated authentication.
# restore using root-integrated authentication docker exec -it container_name /bin/sh -c 'exec mysql' < /local/path/mySQLdumps/filename.sql # restore using username and password (e.g. root) docker exec -it container_name /bin/sh -c 'exec mysql -uroot -p"SuPeR$ecurEP@$$w0rd"' < /local/path/mySQLdumps/filename.sql
Starting with internal version 2.0-10.6.4-r0, I've added a very basic healthcheck to the container. It simply checks that the mysqld daemon is running in the container and accepting connections. It does NOT check anything to do with the actual database. As such, you may want to override this with a more specific healthcheck for your particular use-case. If you just need to know MariaDB is actually running though, this healthcheck will work just fine.
If anyone has suggestions for a better healthcheck, PLEASE let me know!
The source for this container build (Dockerfile, entrypoint.sh) are available on my private git repo or on GitHub. Note that the newest versions will be on my repo and GitHub will be updated at most a few days later. Also, I'd prefer issues be filed on my repo, but I understand if GitHub is easier/more familiar for you.
I hope this container is useful to you and helps you run a database where memory may be at a premium. I do my best to make sure everything runs properly and as much like the official container as possible. If you find any bugs, implementation issues or have any suggestions, please file an issue and let me know! I am NOT affiliated with MariaDB in any way and this container is strictly my implementation of their software. Please do not bother them with any issues you have with this container, let me know instead! Happy dockerizing :-)