├── container-files ├── etc │ ├── my.cnf.d │ │ ├── security.cnf │ │ ├── engine.cnf │ │ ├── charsets.cnf │ │ ├── logging.cnf │ │ ├── slowlog.cnf │ │ ├── networking.cnf │ │ └── tuning.cnf │ └── mysql │ │ └── my.cnf ├── run.sh └── mariadb-functions.sh ├── Dockerfile ├── circle.yml └── README.md /container-files/etc/my.cnf.d/security.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | skip_show_database 3 | -------------------------------------------------------------------------------- /container-files/etc/my.cnf.d/engine.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | default-storage-engine = InnoDB 3 | innodb = FORCE 4 | -------------------------------------------------------------------------------- /container-files/etc/my.cnf.d/charsets.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | character_set_server = utf8 3 | collation_server = utf8_unicode_ci 4 | skip-character-set-client-handshake 5 | 6 | [client] 7 | default_character_set = utf8 8 | -------------------------------------------------------------------------------- /container-files/etc/my.cnf.d/logging.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | pid_file = /var/lib/mysql/mysql.pid 3 | log_error = /var/lib/mysql/error.log 4 | log_warnings = 2 5 | 6 | # General logging has huge performance penalty therefore is disabled by default 7 | general_log = off 8 | general_log_file = /var/lib/mysql/error.log 9 | -------------------------------------------------------------------------------- /container-files/etc/my.cnf.d/slowlog.cnf: -------------------------------------------------------------------------------- 1 | # 2 | # Pre-configure slow logging. 3 | # Disabled it by default, but it can be switched on during runtime 4 | # and the log entries simply appear in the error.log 5 | # 6 | [mysqld] 7 | slow_query_log = off 8 | slow_query_log_file = /var/lib/mysql/error.log 9 | long_query_time = 3 10 | log_queries_not_using_indexes = on 11 | -------------------------------------------------------------------------------- /container-files/etc/my.cnf.d/networking.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | bind_address = 0.0.0.0 3 | 4 | # When a client connects, the server will perform hostname resolution, 5 | # and when DNS is slow, establishing the connection will become slow as well. 6 | # It is therefore recommended to start the server with skip-name-resolve to 7 | # disable all DNS lookups. The only limitation is that the GRANT statements 8 | # must then use IP addresses only. 9 | skip_name_resolve 10 | 11 | [client] 12 | protocol = tcp 13 | -------------------------------------------------------------------------------- /container-files/etc/mysql/my.cnf: -------------------------------------------------------------------------------- 1 | # 2 | # This group is read both both by the client and the server 3 | # use it for options that affect everything 4 | # 5 | [client-server] 6 | 7 | # 8 | # include all files from the config directory 9 | # 10 | !include /etc/my.cnf.d/charset.cnf 11 | !include /etc/my.cnf.d/engine.cnf 12 | !include /etc/my.cnf.d/logging.cnf 13 | !include /etc/my.cnf.d/networking.cnf 14 | !include /etc/my.cnf.d/security.cnf 15 | !include /etc/my.cnf.d/slowlog.cnf 16 | !include /etc/my.cnf.d/tuning.cnf 17 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | # Set TERM env to avoid mysql client error message "TERM environment variable not set" when running from inside the container 4 | ENV TERM=xterm \ 5 | MARIADB_VERSION=10.1 6 | 7 | RUN \ 8 | apk --no-cache add mariadb~${MARIADB_VERSION} mariadb-client net-tools pwgen curl bash; \ 9 | rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/*; \ 10 | rm -rf /var/lib/mysql/* /etc/mysql/; \ 11 | curl -sSL http://mysqltuner.pl/ -o mysqltuner.pl 12 | 13 | # Copy only files required for the following RUN commands (leverage Docker caching) 14 | COPY container-files / 15 | 16 | EXPOSE 3306 17 | 18 | CMD ["/run.sh"] 19 | -------------------------------------------------------------------------------- /container-files/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | source ./mariadb-functions.sh 6 | 7 | # User-provided env variables 8 | MARIADB_USER=${MARIADB_USER:="admin"} 9 | MARIADB_PASS=${MARIADB_PASS:-$(pwgen -s 12 1)} 10 | 11 | # Other variables 12 | VOLUME_HOME="/var/lib/mysql" 13 | ERROR_LOG="$VOLUME_HOME/error.log" 14 | MYSQLD_PID_FILE="$VOLUME_HOME/mysql.pid" 15 | 16 | # Trap INT and TERM signals to do clean DB shutdown 17 | trap terminate_db SIGINT SIGTERM 18 | 19 | install_db 20 | tail -F $ERROR_LOG & # tail all db logs to stdout 21 | 22 | /usr/bin/mysqld_safe & # Launch DB server in the background 23 | MYSQLD_SAFE_PID=$! 24 | 25 | wait_for_db 26 | secure_and_tidy_db 27 | show_db_status 28 | create_admin_user 29 | 30 | # Do not exit this script untill mysqld_safe exits gracefully 31 | wait $MYSQLD_SAFE_PID 32 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | services: 3 | - docker 4 | 5 | dependencies: 6 | override: 7 | - RELEASE=$(grep "MARIADB_VERSION=" Dockerfile | sed 's|^.*=||g' |awk '{print $1}'); docker build -t million12/mariadb:$RELEASE . 8 | - docker build -t million12/mariadb:latest . 9 | 10 | test: 11 | override: 12 | - docker run -d -p 13306:3306 -e MARIADB_PASS="mypass" --name db million12/mariadb:$RELEASE 13 | - docker logs -f db > ${CIRCLE_ARTIFACTS}/docker-db.log: 14 | background: true 15 | # Wait till DB is fully bootstrapped 16 | - while true; do if grep "ready for connections" ${CIRCLE_ARTIFACTS}/docker-db.log; then break; else sleep 1; fi done 17 | - mysqladmin -uadmin -pmypass -h127.0.0.1 -P13306 ping 18 | - mysql -uadmin -pmypass -h127.0.0.1 -P13306 -e "show databases" 19 | 20 | deployment: 21 | production: 22 | branch: master 23 | commands: 24 | - docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS 25 | - RELEASE=$(grep "MARIADB_VERSION=" Dockerfile | sed 's|^.*=||g' |awk '{print $1}'); docker push million12/mariadb:$RELEASE 26 | - docker push million12/mariadb:latest -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MariaDB 10 Docker Image (Alpine ~100Mb) 2 | [![CircleCI Build Status](https://img.shields.io/circleci/project/million12/docker-mariadb/master.svg)](https://circleci.com/gh/million12/docker-mariadb/tree/master) 3 | [![GitHub Open Issues](https://img.shields.io/github/issues/million12/docker-mariadb.svg)](https://github.com/million12/docker-mariadb/issues) 4 | [![Stars](https://img.shields.io/github/stars/million12/docker-mariadb.svg?style=social&label=Stars)]() 5 | [![Fork](https://img.shields.io/github/forks/million12/docker-mariadb.svg?style=social&label=Fork)]() 6 | [![](https://img.shields.io/github/release/million12/docker-mariadb.svg)](http://microbadger.com/images/million12/mariadb) 7 | [![Docker build](http://dockeri.co/image/million12/mariadb)](https://hub.docker.com/r/million12/mariadb/) 8 | 9 | Felling like supporting me in my projects use donate button. Thank You! 10 | [![](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.me/POzgo) 11 | 12 | 13 | This is a MariaDB 10 in a Docker [million12/mariadb](https://registry.hub.docker.com/u/million12/mariadb/). 14 | 15 | **IMPORTANT: Migarted to Alpine Linux which shrinked the image from 1024M to ~120Mb** 16 | 17 | Note: be aware that, by default in this container, MariaDB is configured to use ~1GB memory (innodb_buffer_pool_size in [tuning.cnf](container-files/etc/my.cnf.d/tuning.cnf)). If you try to run it on node with less memory, it will fail. 18 | 19 | Please use tags on Docker Hub for different versions. 20 | 21 | ## Usage 22 | 23 | Run the image as daemon and bind it to port 3306: 24 | 25 | ```bash 26 | docker run -d \ 27 | -p 3306:3306 \ 28 | million12/mariadb 29 | ``` 30 | 31 | Run the image as daemon and specify MariaDB version 10.2: 32 | 33 | ```bash 34 | docker run -d \ 35 | million12/mariadb:10.1 36 | ``` 37 | 38 | The first time that you run your container, a new user admin with all privileges will be created in MariaDB with a random password. To get the password, check the logs of the container by running: 39 | `docker logs ` 40 | 41 | You will see an output like the following: 42 | 43 | ```bash 44 | ======================================================================== 45 | You can now connect to this MariaDB Server using: 46 | 47 | mysql -uadmin -pCoFlnc3ZBS58 -h 48 | 49 | Please remember to change the above password as soon as possible! 50 | MariaDB user 'root' has no password but only allows local connections 51 | ======================================================================== 52 | ``` 53 | In this case, `CoFlnc3ZBS58` is the password assigned to the `admin` user. 54 | 55 | ### Custom Password for user admin 56 | If you want to use a preset password instead of a random generated one, you can set the environment variable MARIADB_PASS to your specific password when running the container: 57 | 58 | ```bash 59 | docker run -d \ 60 | -p 3306:3306 \ 61 | -e MARIADB_PASS="mypass" \ 62 | million12/mariadb 63 | ``` 64 | 65 | ### Data volumes 66 | 67 | MariaDB stores data in `/var/lib/mysql` location. Mount a volume 68 | to that location - below is an example with `docker-compose` how to do that: 69 | 70 | ```yaml 71 | version: '2' 72 | 73 | volumes: 74 | dbdata: 75 | 76 | services: 77 | db: 78 | image: million12/mariadb:latest 79 | volumes: 80 | - dbdata:/var/lib/mysql 81 | ``` 82 | 83 | --- 84 | 85 | ## Authors 86 | 87 | Author: Marcin Ryzycki () 88 | Author: Przemyslaw Ozgo () 89 | -------------------------------------------------------------------------------- /container-files/etc/my.cnf.d/tuning.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | max_allowed_packet = 16M 3 | 4 | # Sort buffer is used to perform sorts for some ORDER BY and GROUP BY 5 | # queries. If sorted data does not fit into the sort buffer, a disk 6 | # based merge sort is used instead - See the "Sort_merge_passes" 7 | # status variable. Allocated per thread if sort is needed. 8 | # Comment out for now, the default in MariaDB 10.2 is 2M 9 | #sort_buffer_size = 1M 10 | 11 | # Size of the buffer used for doing full table scans. 12 | # Allocated per thread, if a full scan is needed. 13 | read_buffer_size = 1M 14 | 15 | # When reading rows in sorted order after a sort, the rows are read 16 | # through this buffer to avoid disk seeks. You can improve ORDER BY 17 | # performance a lot, if set this to a high value. 18 | # Allocated per thread, when needed. 19 | read_rnd_buffer_size = 8M 20 | 21 | join_buffer_size = 8M # should be equal to read_rnd_buffer_size? 22 | 23 | # Maximum allowed size for a single HEAP (in memory) table. This option 24 | # is a protection against the accidential creation of a very large HEAP 25 | # table which could otherwise use up all memory resources. 26 | max_heap_table_size = 64M 27 | tmp_table_size = 64M # Should be equal to max_heap_table_size 28 | 29 | ## Generally, it is unwise to set the query cache to be larger than 64-128M 30 | ## as the costs associated with maintaining the cache outweigh the performance 31 | ## gains. 32 | ## The query cache is a well known bottleneck that can be seen even when 33 | ## concurrency is moderate. The best option is to disable it from day 1 34 | ## by setting query_cache_size = 0 (now the default on MySQL 5.6) 35 | ## and to use other ways to speed up read queries: good indexing, adding 36 | ## replicas to spread the read load or using an external cache. 37 | query_cache_type = on 38 | query_cache_size = 32M 39 | query_cache_strip_comments = on 40 | query_cache_min_res_unit = 2K 41 | # query_cache_limit = 256K # Default is 1M now 42 | 43 | thread_cache_size = 16 44 | table_open_cache = 4096 45 | table_definition_cache = 1024 46 | 47 | # 48 | # InnoDB 49 | # 50 | # The buffer pool is where data and indexes are cached: having it as large as possible 51 | # will ensure you use memory and not disks for most read operations. 52 | # Typical values are 50..75% of available RAM. 53 | innodb_buffer_pool_size = 768M # 75% of 1GB RAM 54 | innodb_log_file_size = 192M # 25% of innodb_buffer_pool_size 55 | innodb_flush_method = O_DIRECT 56 | 57 | # This setting should be set to 0 (disabled) on SSDs which do not have 58 | # any performance gains with sequential IO. 59 | innodb_flush_neighbors = 0 60 | 61 | # The default setting of 1 means that InnoDB is fully ACID compliant. 62 | # It is the best value when your primary concern is data safety, for instance on a master. 63 | # However it can have a significant overhead on systems with slow disks because of the 64 | # extra fsyncs that are needed to flush each change to the redo logs. 65 | # Setting it to 2 is a bit less reliable because committed transactions will be 66 | # flushed to the redo logs only once a second, but that can be acceptable on some situations 67 | # for a master and that is definitely a good value for a replica. 0 is even faster 68 | # but you are more likely to lose some data in case of a crash: it is only a good value for a replica. 69 | innodb_flush_log_at_trx_commit = 0 70 | 71 | # Conquer an InnoDB crash with `InnoDB: A long semaphore wait` error 72 | # See http://stackoverflow.com/questions/24860111/warning-a-long-semaphore-wait 73 | # See http://www.markleith.co.uk/2009/05/13/innodb_stats_on_metadata-innodb_adaptive_hash_index/ 74 | innodb_adaptive_hash_index = off 75 | 76 | # Kill iddle connections after 10min 77 | wait_timeout = 600 78 | 79 | [mysqldump] 80 | max-allowed-packet = 16M 81 | -------------------------------------------------------------------------------- /container-files/mariadb-functions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ######################################################### 4 | # Check in the loop (every 1s) if the database backend 5 | # service is already available for connections. 6 | ######################################################### 7 | function wait_for_db() { 8 | set +e 9 | 10 | echo "Waiting for DB service..." 11 | while true; do 12 | if grep "ready for connections" $ERROR_LOG; then 13 | break; 14 | else 15 | echo "Still waiting for DB service..." && sleep 1 16 | fi 17 | done 18 | 19 | set -e 20 | } 21 | 22 | ######################################################### 23 | # Check in the loop (every 1s) if the database backend 24 | # service is already available for connections. 25 | ######################################################### 26 | function terminate_db() { 27 | local pid=$(cat $VOLUME_HOME/mysql.pid) 28 | echo "Caught SIGTERM signal, shutting down DB..." 29 | kill -TERM $pid 30 | 31 | while true; do 32 | if tail $ERROR_LOG | grep -s -E "mysqld .+? ended" $ERROR_LOG; then break; else sleep 0.5; fi 33 | done 34 | } 35 | 36 | ######################################################### 37 | # Cals `mysql_install_db` if empty volume is detected. 38 | # Globals: 39 | # $VOLUME_HOME 40 | # $ERROR_LOG 41 | ######################################################### 42 | function install_db() { 43 | if [ ! -d $VOLUME_HOME/mysql ]; then 44 | echo "=> An empty/uninitialized MariaDB volume is detected in $VOLUME_HOME" 45 | echo "=> Installing MariaDB..." 46 | mysql_install_db --user=mysql > /dev/null 2>&1 47 | echo "=> Installing MariaDB... Done!" 48 | else 49 | echo "=> Using an existing volume of MariaDB." 50 | fi 51 | 52 | # Move previous error log (which might be there from previously running container 53 | # to different location. We do that to have error log from the currently running 54 | # container only. 55 | if [ -f $ERROR_LOG ]; then 56 | echo "----------------- Previous error log -----------------" 57 | tail -n 20 $ERROR_LOG 58 | echo "----------------- Previous error log ends -----------------" && echo 59 | mv -f $ERROR_LOG "${ERROR_LOG}.old"; 60 | fi 61 | 62 | touch $ERROR_LOG && chown mysql $ERROR_LOG 63 | } 64 | 65 | ######################################################### 66 | # Check in the loop (every 1s) if the database backend 67 | # service is already available for connections. 68 | # Globals: 69 | # $MARIADB_USER 70 | # $MARIADB_PASS 71 | ######################################################### 72 | function create_admin_user() { 73 | echo "Creating DB admin user..." && echo 74 | local users=$(mysql -s -e "SELECT count(User) FROM mysql.user WHERE User='$MARIADB_USER'") 75 | if [[ $users == 0 ]]; then 76 | echo "=> Creating MariaDB user '$MARIADB_USER' with '$MARIADB_PASS' password." 77 | mysql -uroot -e "CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASS'" 78 | else 79 | echo "=> User '$MARIADB_USER' exists, updating its password to '$MARIADB_PASS'" 80 | mysql -uroot -e "SET PASSWORD FOR '$MARIADB_USER'@'%' = PASSWORD('$MARIADB_PASS')" 81 | fi; 82 | 83 | mysql -uroot -e "GRANT ALL PRIVILEGES ON *.* TO '$MARIADB_USER'@'%' WITH GRANT OPTION" 84 | 85 | echo "========================================================================" 86 | echo " You can now connect to this MariaDB Server using: " 87 | echo " mysql -u$MARIADB_USER -p$MARIADB_PASS -h " 88 | echo " " 89 | echo " For security reasons, you might want to change the above password. " 90 | echo " The 'root' user has no password but only allows local connections " 91 | echo "========================================================================" 92 | } 93 | 94 | function show_db_status() { 95 | echo "Showing DB status..." && echo 96 | mysql -uroot -e "status" 97 | } 98 | 99 | function secure_and_tidy_db() { 100 | echo "Securing and tidying DB..." 101 | mysql -uroot -e "DROP DATABASE IF EXISTS test" 102 | mysql -uroot -e "DELETE FROM mysql.user where User = ''" 103 | 104 | # Remove warning about users with hostnames (as DB is configured with skip_name_resolve) 105 | mysql -uroot -e "DELETE FROM mysql.user where User = 'root' AND Host NOT IN ('127.0.0.1','::1')" 106 | mysql -uroot -e "DELETE FROM mysql.proxies_priv where User = 'root' AND Host NOT IN ('127.0.0.1','::1')" 107 | echo "Securing and tidying DB... Done!" 108 | } 109 | --------------------------------------------------------------------------------