Skip to content
This repository was archived by the owner on Nov 8, 2019. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions mariadb/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
FROM fedora

# MySQL image for OpenShift.
#
# Volumes:
# * /var/lib/mysql/data - Datastore for MySQL
# Environment:
# * $MYSQL_USER - Database user name
# * $MYSQL_PASSWORD - User's password
# * $MYSQL_DATABASE - Name of the database to create
# * $MYSQL_ROOT_PASSWORD (Optional) - Password for the 'root' MySQL account

MAINTAINER http://fedoraproject.org/wiki/Cloud
RUN dnf -y update && dnf clean all
RUN dnf -y install mariadb-server pwgen psmisc net-tools hostname && \
dnf clean all

ADD scripts /scripts
RUN chmod 755 /scripts/*
ENV MARIADB_VERSION=10.0 \
HOME=/var/lib/mysql

LABEL io.k8s.description="MariaDB is a multi-user, multi-threaded SQL database server" \
io.k8s.display-name="MariaDB 10.0" \
io.openshift.expose-services="3306:mysql" \
io.openshift.tags="database,mysql,mariadb,mariadb100"

VOLUME ["/var/lib/mysql", "/var/log/mysql"]
EXPOSE 3306

CMD ["/bin/bash", "/scripts/start.sh"]
# This image must forever use UID 27 for mysql user so our volumes are
# safe in the future. This should *never* change, the last test is there
# to make sure of that.
RUN dnf -y --setopt=tsflags=nodocs install gettext hostname bind-utils mariadb-server mariadb && \
dnf clean all && \
mkdir -p /var/lib/mysql/data && chown -R mysql.0 /var/lib/mysql && \
test "$(id mysql)" = "uid=27(mysql) gid=27(mysql) groups=27(mysql)"

COPY run-*.sh /usr/local/bin/
COPY contrib /var/lib/mysql/

# Loosen permission bits for group to avoid problems running container with
# arbitrary UID
# When only specifying user, group is 0, that's why /var/lib/mysql must have
# owner mysql.0; that allows to avoid a+rwx for this dir
RUN chmod -R g+rwx /var/lib/mysql

VOLUME ["/var/lib/mysql/data"]

USER 27

ENTRYPOINT ["run-mysqld.sh"]
CMD ["mysqld"]
130 changes: 65 additions & 65 deletions mariadb/README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,88 @@
dockerfiles-fedora-mariadb
==========================
MariaDB for general usage and OpenShift - Docker image
======================================================

Based on scollier's mysql dockerfile.
This repository contains Dockerfiles for MariaDB images for general usage and for OpenShift.

This repo contains a recipe for making a Docker container for mariadb
on Fedora.

Setup
-----
Environment variables and volumes
----------------------------------

Check your Docker version
The image recognizes the following environment variables that you can set during
initialization by passing `-e VAR=VALUE` to the Docker run command.

# docker version
| Variable name | Description |
| :--------------------- | ----------------------------------------- |
| `MYSQL_USER` | User name for MySQL account to be created |
| `MYSQL_PASSWORD` | Password for the user account |
| `MYSQL_DATABASE` | Database name |
| `MYSQL_ROOT_PASSWORD` | Password for the root user (optional) |

Perform the build
The following environment variables influence the MySQL configuration file. They are all optional.

# docker build --rm -t <yourname>/mariadb .
| Variable name | Description | Default
| :------------------------------ | ----------------------------------------------------------------- | -------------------------------
| `MYSQL_LOWER_CASE_TABLE_NAMES` | Sets how the table names are stored and compared | 0
| `MYSQL_MAX_CONNECTIONS` | The maximum permitted number of simultaneous client connections | 151
| `MYSQL_FT_MIN_WORD_LEN` | The minimum length of the word to be included in a FULLTEXT index | 4
| `MYSQL_FT_MAX_WORD_LEN` | The maximum length of the word to be included in a FULLTEXT index | 20
| `MYSQL_AIO` | Controls the `innodb_use_native_aio` setting value in case the native AIO is broken. See http://help.directadmin.com/item.php?id=529 | 1

Check the image out.
You can also set the following mount points by passing the `-v /host:/container` flag to Docker.

# docker images
| Volume mount point | Description |
| :----------------------- | -------------------- |
| `/var/lib/mysql/data` | MySQL data directory |

Launching MariaDB
-----------------
**Notice: When mouting a directory from the host into the container, ensure that the mounted
directory has the appropriate permissions and that the owner and group of the directory
matches the user UID or name which is running inside the container.**

### Stand-alone database: ###
Usage
---------------------------------

# docker run --name=mariadb -d -p 3306:3306 <yourname>/mariadb
For this, we will assume that you are using the `openshift/mysql-55-centos7` image.
If you want to set only the mandatory environment variables and not store
the database in a host directory, execute the following command:

This will create the system tables and a database named 'db', with user 'dbuser' and a generated password. To find out what the password is, check the logs:
```
$ docker run -d --name mysql_database -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -e MYSQL_DATABASE=db -p 3306:3306 fedora/mariadb
```

# docker logs mariadb | grep -E '^USER|^PASS'
This will create a container named `mysql_database` running MySQL with database
`db` and user with credentials `user:pass`. Port 3306 will be exposed and mapped
to the host. If you want your database to be persistent across container executions,
also add a `-v /host/db/path:/var/lib/mysql/data` argument. This will be the MySQL
data directory.

### Adjustable configuration ###
If the database directory is not initialized, the entrypoint script will first
run [`mysql_install_db`](https://dev.mysql.com/doc/refman/5.6/en/mysql-install-db.html)
and setup necessary database users and passwords. After the database is initialized,
or if it was already present, `mysqld` is executed and will run as PID 1. You can
stop the detached container by running `docker stop mysql_database`.

Create a data volume container:

# docker run --name=mariadb-data -v /var/lib/mysql \
--entrypoint /bin/echo <yourname>/mariadb "MariaDB data volume"
MySQL root user
---------------------------------
The root user has no password set by default, only allowing local connections.
You can set it by setting the `MYSQL_ROOT_PASSWORD` environment variable. This
will allow you to login to the root account remotely. Local connections will
still not require a password.

Now create the persistent container, using the data volume container for storage:
To disable remote root access, simply unset `MYSQL_ROOT_PASSWORD` and restart
the container.

# docker run --name=mariadb --volumes-from=mariadb-data \
-p 3306:3306 -d <yourname>/mariadb

The container will not re-initialise an already-initialised data volume.
Changing passwords
------------------

Using your MariaDB container
----------------------------
Since passwords are part of the image configuration, the only supported method
to change passwords for the database user (`MYSQL_USER`) and root user is by
changing the environment variables `MYSQL_PASSWORD` and `MYSQL_ROOT_PASSWORD`,
respectively.

Connecting to mariadb:
Changing database passwords through SQL statements or any way other than through
the environment variables aforementioned will cause a mismatch between the
values stored in the variables and the actual passwords. Whenever a database
container starts it will reset the passwords to the values stored in the
environment variables.

# mysql --protocol=tcp db -udbuser -p

Use the password indicated in the 'docker logs' output.

Create a sample table:

\> CREATE TABLE test (name VARCHAR(10), owner VARCHAR(10),
-> species VARCHAR(10), birth DATE, death DATE);

Linking with another container
------------------------------

To arrange for linking with another container, set the USER, PASS, and NAME environment variables when creating the mariadb container. You don't need to expose any ports, as they are available to other containers automatically:

# docker run --name=mariadb --volumes-from=mariadb-data \
-e USER=user -e PASS=mypassword -e NAME=mydb \
-d <yourname>/mariadb

This will create a database named 'mydb', and a user 'user' with the specified password. To link another container to this one, use the --link option to 'docker run':

# docker run --link=mariadb:db -d <yourname>/mydbapp

As we've set the alias for the linked mariadb container to 'db', the 'mydbapp' container will have environment variables set to give it the information it needs:

- DB_PORT will specify the protocol, host, and port
- DB_ENV_NAME will be 'mydb'
- DB_ENV_USER will be 'user'
- DB_ENV_PASS will be 'mypassword'

Using mariadb as a client to an existing mariadb container
----------------------------------------------------------

To run a query against an existing container, using the client from this container image, create a new container linked to the existing one:

# docker run --rm --link=mariadb:db -i -t <yourname>/mariadb sh -c 'mysql -h $DB_PORT_3306_TCP_ADDR -P $DB_PORT_3306_TCP_PORT -u$DB_ENV_USER -p$DB_ENV_PASS'
165 changes: 165 additions & 0 deletions mariadb/contrib/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/bin/bash

# Data directory where MySQL database files live. The data subdirectory is here
# because .bashrc and my.cnf both live in /var/lib/mysql/ and we don't want a
# volume to override it.
export MYSQL_DATADIR=/var/lib/mysql/data

# Configuration settings.
export MYSQL_DEFAULTS_FILE=$HOME/my.cnf
export MYSQL_LOWER_CASE_TABLE_NAMES=${MYSQL_LOWER_CASE_TABLE_NAMES:-0}
export MYSQL_MAX_CONNECTIONS=${MYSQL_MAX_CONNECTIONS:-151}
export MYSQL_FT_MIN_WORD_LEN=${MYSQL_FT_MIN_WORD_LEN:-4}
export MYSQL_FT_MAX_WORD_LEN=${MYSQL_FT_MAX_WORD_LEN:-20}
export MYSQL_AIO=${MYSQL_AIO:-1}

# Be paranoid and stricter than we should be.
# https://dev.mysql.com/doc/refman/5.6/en/identifiers.html
mysql_identifier_regex='^[a-zA-Z0-9_]+$'
mysql_password_regex='^[a-zA-Z0-9_~!@#$%^&*()-=<>,.?;:|]+$'

function usage() {
[ $# == 2 ] && echo "error: $1"
echo "You must either specify the following environment variables:"
echo " MYSQL_USER (regex: '$mysql_identifier_regex')"
echo " MYSQL_PASSWORD (regex: '$mysql_password_regex')"
echo " MYSQL_DATABASE (regex: '$mysql_identifier_regex')"
echo "Or the following environment variable:"
echo " MYSQL_ROOT_PASSWORD (regex: '$mysql_password_regex')"
echo "Or both."
echo "Optional Settings:"
echo " MYSQL_LOWER_CASE_TABLE_NAMES (default: 0)"
echo " MYSQL_MAX_CONNECTIONS (default: 151)"
echo " MYSQL_FT_MIN_WORD_LEN (default: 4)"
echo " MYSQL_FT_MAX_WORD_LEN (default: 20)"
echo " MYSQL_AIO (default: 1)"
exit 1
}

function validate_variables() {
# Check basic sanity of specified variables
if [[ -v MYSQL_USER && -v MYSQL_PASSWORD && -v MYSQL_DATABASE ]]; then
[[ "$MYSQL_USER" =~ $mysql_identifier_regex ]] || usage "Invalid MySQL username"
[ ${#MYSQL_USER} -le 16 ] || usage "MySQL username too long (maximum 16 characters)"
[[ "$MYSQL_PASSWORD" =~ $mysql_password_regex ]] || usage "Invalid password"
[[ "$MYSQL_DATABASE" =~ $mysql_identifier_regex ]] || usage "Invalid database name"
[ ${#MYSQL_DATABASE} -le 64 ] || usage "Database name too long (maximum 64 characters)"
user_specified=1
fi

if [ -v MYSQL_ROOT_PASSWORD ]; then
[[ "$MYSQL_ROOT_PASSWORD" =~ $mysql_password_regex ]] || usage "Invalid root password"
root_specified=1
fi

# Either combination of user/pass/db or root password is ok
if [[ "${user_specified:-0}" == "0" && "${root_specified:-0}" == "0" ]]; then
usage
fi

# Specifically check of incomplete specification
if [[ -v MYSQL_USER || -v MYSQL_PASSWORD || -v MYSQL_DATABASE ]] && \
[[ "${user_specified:-0}" == "0" ]]; then
usage
fi
}

# Make sure env variables don't propagate to mysqld process.
function unset_env_vars() {
unset MYSQL_USER MYSQL_PASSWORD MYSQL_DATABASE MYSQL_ROOT_PASSWORD
}

# Poll until MySQL responds to our ping.
function wait_for_mysql() {
pid=$1 ; shift

while [ true ]; do
if [ -d "/proc/$pid" ]; then
mysqladmin --socket=/tmp/mysql.sock ping &>/dev/null && return 0
else
return 1
fi
echo "Waiting for MySQL to start ..."
sleep 1
done
}

function start_local_mysql() {
# Now start mysqld and add appropriate users.
echo 'Starting local mysqld server ...'
/usr/libexec/mysqld \
--defaults-file=$MYSQL_DEFAULTS_FILE \
--skip-networking --socket=/tmp/mysql.sock "$@" &
mysql_pid=$!
wait_for_mysql $mysql_pid
}

# Initialize the MySQL database (create user accounts and the initial database)
function initialize_database() {
echo 'Running mysql_install_db ...'
# Using --rpm since we need mysql_install_db behaves as in RPM
mysql_install_db --rpm --datadir=$MYSQL_DATADIR
start_local_mysql "$@"

[ -v MYSQL_RUNNING_AS_SLAVE ] && return

# Do not care what option is compulsory here, just create what is specified
if [ -v MYSQL_USER ]; then
mysql $mysql_flags <<EOSQL
CREATE USER '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';
EOSQL
fi

if [ -v MYSQL_DATABASE ]; then
mysqladmin $admin_flags create "${MYSQL_DATABASE}"

if [ -v MYSQL_USER ]; then
mysql $mysql_flags <<EOSQL
GRANT ALL ON \`${MYSQL_DATABASE}\`.* TO '${MYSQL_USER}'@'%' ;
FLUSH PRIVILEGES ;
EOSQL
fi
fi

if [ -v MYSQL_ROOT_PASSWORD ]; then
mysql $mysql_flags <<EOSQL
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
EOSQL
fi
}

# The 'server_id' number for slave needs to be within 1-4294967295 range.
# This function will take the 'hostname' if the container, hash it and turn it
# into the number.
# See: https://dev.mysql.com/doc/refman/5.6/en/replication-options.html#option_mysqld_server-id
function server_id() {
checksum=$(sha256sum <<< $(hostname -i))
checksum=${checksum:0:14}
echo -n $((0x${checksum}%4294967295))
}

function wait_for_mysql_master() {
while true; do
echo "Waiting for MySQL master (${MYSQL_MASTER_SERVICE_NAME}) to accept connections ..."
mysqladmin --host=${MYSQL_MASTER_SERVICE_NAME} --user="${MYSQL_MASTER_USER}" \
--password="${MYSQL_MASTER_PASSWORD}" ping &>/dev/null && return 0
sleep 1
done
}

function validate_replication_variables() {
if ! [[ -v MYSQL_DATABASE && -v MYSQL_MASTER_USER && -v MYSQL_MASTER_PASSWORD && \
( "${MYSQL_RUNNING_AS_SLAVE:-0}" != "1" || -v MYSQL_MASTER_SERVICE_NAME ) ]]; then
echo
echo "For master/slave replication, you have to specify following environment variables:"
echo " MYSQL_MASTER_SERVICE_NAME (slave only)"
echo " MYSQL_DATABASE"
echo " MYSQL_MASTER_USER"
echo " MYSQL_MASTER_PASSWORD"
echo
fi
[[ "$MYSQL_DATABASE" =~ $mysql_identifier_regex ]] || usage "Invalid database name"
[[ "$MYSQL_MASTER_USER" =~ $mysql_identifier_regex ]] || usage "Invalid MySQL master username"
[ ${#MYSQL_MASTER_USER} -le 16 ] || usage "MySQL master username too long (maximum 16 characters)"
[[ "$MYSQL_MASTER_PASSWORD" =~ $mysql_password_regex ]] || usage "Invalid MySQL master password"
}
10 changes: 10 additions & 0 deletions mariadb/contrib/my-master.cnf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[mysqld]

server-id = ${MYSQL_SERVER_ID}
log_bin = ${MYSQL_DATADIR}/mysql-bin.log
binlog_do_db = mysql
binlog_do_db = ${MYSQL_DATABASE}
log-slave-updates = ON

# Include the common MySQL settings
!include ${HOME}/my-common.cnf
11 changes: 11 additions & 0 deletions mariadb/contrib/my-slave.cnf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[mysqld]

server-id = ${MYSQL_SERVER_ID}
log_bin = ${MYSQL_DATADIR}/mysql-bin.log
relay-log = ${MYSQL_DATADIR}/mysql-relay-bin.log
binlog_do_db = mysql
binlog_do_db = ${MYSQL_DATABASE}
log-slave-updates = ON

# Include the common MySQL settings
!include ${HOME}/my-common.cnf
Loading