Skip to content
This repository has been archived by the owner on Nov 8, 2019. It is now read-only.

Redesign mysql image to work in OpenShift as well #219

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
60 changes: 48 additions & 12 deletions mysql/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
FROM fedora
MAINTAINER http://fedoraproject.org/wiki/Cloud
FROM fedora:23

RUN dnf -y update && dnf clean all
RUN dnf -y install community-mysql-server community-mysql pwgen supervisor bash-completion psmisc net-tools && dnf clean all
# 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

ADD ./start.sh /start.sh
ADD ./config_mysql.sh /config_mysql.sh
ADD ./supervisord.conf /etc/supervisord.conf
MAINTAINER http://fedoraproject.org/wiki/Cloud

# RUN echo %sudo ALL=NOPASSWD: ALL >> /etc/sudoers
ENV MYSQL_VERSION=5.6 \
HOME=/var/lib/mysql

RUN chmod 755 /start.sh
RUN chmod 755 /config_mysql.sh
RUN /config_mysql.sh
LABEL io.k8s.description="MySQL is a multi-user, multi-threaded SQL database server" \
io.k8s.display-name="MySQL 5.6" \
io.openshift.expose-services="3306:mysql" \
io.openshift.tags="database,mysql,mysql56"

EXPOSE 3306

CMD ["/bin/bash", "/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.
# https://git.fedorahosted.org/cgit/setup.git/tree/uidgid
# policycoreutils installed for restorecon called in container-setup script
RUN INSTALL_PKGS="tar rsync gettext hostname bind-utils policycoreutils community-mysql-server community-mysql community-mysql-libs" && \
dnf -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \
rpm -V $INSTALL_PKGS && \
dnf clean all && \
mkdir -p /var/lib/mysql/data && chown -R mysql.0 /var/lib/mysql && \
rpm -q --qf '%{version}' community-mysql-server | grep -e '5\.6\.' && \
test "$(id mysql)" = "uid=27(mysql) gid=27(mysql) groups=27(mysql)"

# Get prefix path and path to scripts rather than hard-code them in scripts
ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/mysql \
MYSQL_PREFIX=/usr

ADD root /

# this is needed due to issues with squash
# when this directory gets rm'd by the container-setup
# script.
RUN rm -rf /etc/my.cnf.d/*
RUN /usr/libexec/container-setup

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

USER 27

ENTRYPOINT ["container-entrypoint"]
CMD ["run-mysqld"]
168 changes: 130 additions & 38 deletions mysql/README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,133 @@
dockerfiles-fedora-MySQL
========================

This repo contains a recipe for making Docker container for SSH and MySQL on Fedora.

Check your Docker version

# docker version

Perform the build

# docker build --rm -t <yourname>/mysql .

Check the image out.

# docker images

Run it:

# docker run -d -p 3306:3306 <yourname>/mysql

Get container ID:

# docker ps

Keep in mind the password set for MySQL is: mysqlPassword

Get the IP address for the container:

# docker inspect <container_id> | grep -i ipaddr

For MySQL:
# mysql -h 172.17.0.x -utestdb -pmysqlPassword


Create a table:
MySQL Docker image
==================

This repository contains a Dockerfile for MySQL image, which is working
on standard Linux machine and also for OpenShift.


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

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

| 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) |

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

| 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_MAX_ALLOWED_PACKET` | The maximum size of one packet or any generated/intermediate string | 200M
| `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
| `MYSQL_TABLE_OPEN_CACHE` | The number of open tables for all threads | 400
| `MYSQL_KEY_BUFFER_SIZE` | The size of the buffer used for index blocks | 32M (or 10% of available memory)
| `MYSQL_SORT_BUFFER_SIZE` | The size of the buffer used for sorting | 256K
| `MYSQL_READ_BUFFER_SIZE` | The size of the buffer used for a sequential scan | 8M (or 5% of available memory)
| `MYSQL_INNODB_BUFFER_POOL_SIZE`| The size of the buffer pool where InnoDB caches table and index data | 32M (or 50% of available memory)
| `MYSQL_INNODB_LOG_FILE_SIZE` | The size of each log file in a log group | 8M (or 15% of available available)
| `MYSQL_INNODB_LOG_BUFFER_SIZE` | The size of the buffer that InnoDB uses to write to the log files on disk | 8M (or 15% of available memory)
| `MYSQL_DEFAULTS_FILE` | Point to an alternative configuration file | /etc/my.cnf
| `MYSQL_BINLOG_FORMAT` | Set sets the binlog format, supported values are `row` and `statement` | statement

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

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

**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 which is running inside the container.**

Usage
---------------------------------

For this, we will assume that you are using the `fedora/mysql` image.
If you want to set only the mandatory environment variables and not store
the database in a host directory, execute the following command:

```
\> CREATE TABLE test (name VARCHAR(10), owner VARCHAR(10),
-> species VARCHAR(10), birth DATE, death DATE);
$ docker run -d --name mysql_database -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -e MYSQL_DATABASE=db -p 3306:3306 fedora/mysql
```

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.

If the database directory is not initialized, the entrypoint script will first
run [`mysql_install_db`](https://dev.mysql.com/doc/refman/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`.


MySQL auto-tuning
-----------------

When the MySQL image is run with the `--memory` parameter set and you didn't
specify value for some parameters, their values will be automatically
calculated based on the available memory.

| Variable name | Configuration parameter | Relative value
| :-------------------------------| ------------------------- | --------------
| `MYSQL_KEY_BUFFER_SIZE` | `key_buffer_size` | 10%
| `MYSQL_READ_BUFFER_SIZE` | `read_buffer_size` | 5%
| `MYSQL_INNODB_BUFFER_POOL_SIZE` | `innodb_buffer_pool_size` | 50%
| `MYSQL_INNODB_LOG_FILE_SIZE` | `innodb_log_file_size` | 15%
| `MYSQL_INNODB_LOG_BUFFER_SIZE` | `innodb_log_buffer_size` | 15%


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.

To disable remote root access, simply unset `MYSQL_ROOT_PASSWORD` and restart
the container.


Changing passwords
------------------

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.

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.

Default my.cnf file
-------------------
With environment variables we are able to customize a lot of different parameters
or configurations for the mysql bootstrap configurations. If you'd prefer to use
your own configuration file, you can override the `MYSQL_DEFAULTS_FILE` env
variable with the full path of the file you wish to use. For example, the default
location is `/etc/my.cnf` but you can change it to `/etc/mysql/my.cnf` by setting
`MYSQL_DEFAULTS_FILE=/etc/mysql/my.cnf`

Changing the replication binlog_format
--------------------------------------
Some applications may wish to use `row` binlog_formats (for example, those built
with change-data-capture in mind). The default replication/binlog format is
`statement` but to change it you can set the `MYSQL_BINLOG_FORMAT` environment
variable. For example `MYSQL_BINLOG_FORMAT=row`. Now when you run the database
with `master` replication turned on (ie, set the Docker/container `cmd` to be
`run-mysqld-master`) the binlog will emit the actual data for the rows that change
as opposed to the statements (ie, DML like insert...) that caused the change.
29 changes: 0 additions & 29 deletions mysql/config_mysql.sh

This file was deleted.

10 changes: 10 additions & 0 deletions mysql/root/etc/my.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[mysqld]

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links = 0

# http://www.percona.com/blog/2008/05/31/dns-achilles-heel-mysql-installation/
skip_name_resolve

!includedir /etc/my.cnf.d

92 changes: 92 additions & 0 deletions mysql/root/usr/bin/cgroup-limits
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/python3

"""
Script for parsing cgroup information

This script will read some limits from the cgroup system and parse
them, printing out "VARIABLE=VALUE" on each line for every limit that is
successfully read. Output of this script can be directly fed into
bash's export command. Recommended usage from a bash script:

set -o errexit
export_vars=$(cgroup-limits) ; export $export_vars

Variables currently supported:
MAX_MEMORY_LIMIT_IN_BYTES
Maximum possible limit MEMORY_LIMIT_IN_BYTES can have. This is
currently constant value of 9223372036854775807.
MEMORY_LIMIT_IN_BYTES
Maximum amount of user memory in bytes. If this value is set
to the same value as MAX_MEMORY_LIMIT_IN_BYTES, it means that
there is no limit set. The value is taken from
/sys/fs/cgroup/memory/memory.limit_in_bytes
NUMBER_OF_CORES
Number of detected CPU cores that can be used. This value is
calculated from /sys/fs/cgroup/cpuset/cpuset.cpus
NO_MEMORY_LIMIT
Set to "true" if MEMORY_LIMIT_IN_BYTES is so high that the caller
can act as if no memory limit was set. Undefined otherwise.
"""

from __future__ import print_function
import sys


def _read_file(path):
try:
with open(path, 'r') as f:
return f.read().strip()
except IOError:
return None


def get_memory_limit():
"""
Read memory limit, in bytes.
"""

limit = _read_file('/sys/fs/cgroup/memory/memory.limit_in_bytes')
if limit is None or not limit.isdigit():
print("Warning: Can't detect memory limit from cgroups",
file=sys.stderr)
return None
return int(limit)


def get_number_of_cores():
"""
Read number of CPU cores.
"""

core_count = 0

line = _read_file('/sys/fs/cgroup/cpuset/cpuset.cpus')
if line is None:
print("Warning: Can't detect number of CPU cores from cgroups",
file=sys.stderr)
return None

for group in line.split(','):
core_ids = list(map(int, group.split('-')))
if len(core_ids) == 2:
core_count += core_ids[1] - core_ids[0] + 1
else:
core_count += 1

return core_count


if __name__ == "__main__":
env_vars = {
"MAX_MEMORY_LIMIT_IN_BYTES": 9223372036854775807,
"MEMORY_LIMIT_IN_BYTES": get_memory_limit(),
"NUMBER_OF_CORES": get_number_of_cores()
}

env_vars = {k: v for k, v in env_vars.items() if v is not None}

if env_vars.get("MEMORY_LIMIT_IN_BYTES", 0) >= 92233720368547:
env_vars["NO_MEMORY_LIMIT"] = "true"

for key, value in env_vars.items():
print("{0}={1}".format(key, value))
2 changes: 2 additions & 0 deletions mysql/root/usr/bin/container-entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
exec "$@"
1 change: 1 addition & 0 deletions mysql/root/usr/bin/mysqld-master
1 change: 1 addition & 0 deletions mysql/root/usr/bin/mysqld-slave
Loading