├── .architectures-lib ├── .travis.yml ├── 10.1 ├── Dockerfile ├── docker-entrypoint.sh ├── version └── whitelist.yml ├── 10.2 ├── Dockerfile ├── docker-entrypoint.sh ├── version └── whitelist.yml ├── 10.3 ├── Dockerfile ├── docker-entrypoint.sh ├── version └── whitelist.yml ├── 10.4 ├── Dockerfile ├── docker-entrypoint.sh ├── version └── whitelist.yml ├── Dockerfile.template ├── LICENSE ├── README.md ├── docker-entrypoint.sh ├── generate-stackbrew-library.sh ├── tx_sandbox ├── Dockerfile ├── docker-compose.yml ├── labs.md ├── readme.md └── whitelist.yml └── update.sh /.architectures-lib: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | hasBashbrewArch() { 4 | local version="$1"; shift 5 | local bashbrewArch="$1"; shift 6 | local arches="$(grep 'bashbrew-architectures:' "$version/Dockerfile" | cut -d':' -f2)" 7 | [[ " $arches " == *" $bashbrewArch "* ]] 8 | } 9 | 10 | _generateParentRepoToArches() { 11 | local repo="$1"; shift 12 | local officialImagesUrl='https://github.com/docker-library/official-images/raw/master/library/' 13 | 14 | eval "declare -g -A parentRepoToArches=( $( 15 | find -name 'Dockerfile' -exec awk ' 16 | toupper($1) == "FROM" && $2 !~ /^('"$repo"'|scratch|microsoft\/[^:]+)(:|$)/ { 17 | print "'"$officialImagesUrl"'" $2 18 | } 19 | ' '{}' + \ 20 | | sort -u \ 21 | | xargs bashbrew cat --format '[{{ .RepoName }}:{{ .TagName }}]="{{ join " " .TagEntry.Architectures }}"' 22 | ) )" 23 | } 24 | _generateParentRepoToArches 'mariadb' 25 | 26 | parentArches() { 27 | local version="$1"; shift # "1.8", etc 28 | 29 | local parent="$(awk 'toupper($1) == "FROM" { print $2 }' "$version/Dockerfile")" 30 | echo "${parentRepoToArches[$parent]:-}" 31 | } 32 | versionArches() { 33 | local version="$1"; shift # "1.8", etc 34 | 35 | local parentArches="$(parentArches "$version")" 36 | 37 | local variantArches=() 38 | for arch in $parentArches; do 39 | if hasBashbrewArch "$version" "$arch"; then 40 | variantArches+=( "$arch" ) 41 | fi 42 | done 43 | echo "${variantArches[*]}" 44 | } 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: bash 4 | services: docker 5 | env: 6 | - VERSION=10.3 7 | - VERSION=10.2 8 | - VERSION=10.1 9 | - VERSION=10.4 10 | 11 | install: 12 | - git clone https://github.com/mariadb-corporation/mariadb-docker-images ~/mariadb-docker-images 13 | 14 | before_script: 15 | - env | sort 16 | - wget -qO- 'https://github.com/tianon/pgp-happy-eyeballs/raw/master/hack-my-builds.sh' | bash 17 | - cd "$VERSION" 18 | - image="mariadb-server-docker:$VERSION" 19 | 20 | script: 21 | - | 22 | ( 23 | set -Eeuo pipefail 24 | set -x 25 | echo "image is $image" 26 | docker build -t "$image" . 27 | ~/mariadb-docker-images/test/run.sh "$image" 28 | docker run -p 5432:5432 -d --name db arminc/clair-db:latest 29 | docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1 30 | docker run -v /var/run/docker.sock:/var/run/docker.sock -d --name clair-scanner mariadb/clair-scanner:latest tail -f /dev/null 31 | clair_ip=`docker exec -it clair hostname -i | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'` 32 | scanner_ip=`docker exec -it clair-scanner hostname -i | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'` 33 | echo "clair_ip = $clair_ip" 34 | echo "scanner_ip = $scanner_ip" 35 | docker cp whitelist.yml clair-scanner:/whitelist.yml 36 | docker exec -it clair-scanner clair-scanner --ip ${scanner_ip} --clair=http://${clair_ip}:6060 -t High -w /whitelist.yml $image 37 | ) 38 | 39 | after_script: 40 | - docker images 41 | 42 | notifications: 43 | email: 44 | recipients: 45 | - cpe@mariadb.com 46 | on_success: never # default: change 47 | on_failure: always # default: always -------------------------------------------------------------------------------- /10.1/Dockerfile: -------------------------------------------------------------------------------- 1 | # vim:set ft=dockerfile: 2 | FROM ubuntu:bionic 3 | 4 | # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added 5 | RUN groupadd -r mysql && useradd -r -g mysql mysql 6 | 7 | # https://bugs.debian.org/830696 (apt uses gpgv by default in newer releases, rather than gpg) 8 | RUN set -ex; \ 9 | apt-get update; \ 10 | if ! which gpg; then \ 11 | apt-get install -y --no-install-recommends gnupg; \ 12 | fi; \ 13 | # Ubuntu includes "gnupg" (not "gnupg2", but still 2.x), but not dirmngr, and gnupg 2.x requires dirmngr 14 | # so, if we're not running gnupg 1.x, explicitly install dirmngr too 15 | if ! gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \ 16 | apt-get install -y --no-install-recommends dirmngr; \ 17 | fi; \ 18 | rm -rf /var/lib/apt/lists/* 19 | 20 | # add gosu for easy step-down from root 21 | ENV GOSU_VERSION 1.10 22 | RUN set -ex; \ 23 | \ 24 | fetchDeps=' \ 25 | ca-certificates \ 26 | wget \ 27 | '; \ 28 | apt-get update; \ 29 | apt-get install -y --no-install-recommends $fetchDeps; \ 30 | rm -rf /var/lib/apt/lists/*; \ 31 | \ 32 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 33 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 34 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 35 | \ 36 | # verify the signature 37 | export GNUPGHOME="$(mktemp -d)"; \ 38 | gpg --keyserver keyserver.ubuntu.com --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 39 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 40 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 41 | rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 42 | \ 43 | chmod +x /usr/local/bin/gosu; \ 44 | # verify that the binary works 45 | gosu nobody true; \ 46 | \ 47 | apt-get purge -y --auto-remove $fetchDeps 48 | 49 | RUN mkdir /docker-entrypoint-initdb.d 50 | 51 | # install "pwgen" for randomizing passwords 52 | # install "tzdata" for /usr/share/zoneinfo/ 53 | RUN apt-get update && apt-get install -y --no-install-recommends \ 54 | apt-transport-https ca-certificates \ 55 | pwgen \ 56 | tzdata \ 57 | && rm -rf /var/lib/apt/lists/* 58 | 59 | ENV GPG_KEYS \ 60 | # Key fingerprint = 1993 69E5 404B D5FC 7D2F E43B CBCB 082A 1BB9 43DB 61 | # MariaDB Package Signing Key 62 | # for MariaDB 5.5 63 | 199369E5404BD5FC7D2FE43BCBCB082A1BB943DB \ 64 | # pub rsa4096 2016-03-30 [SC] 65 | # 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 66 | # uid [ unknown] MariaDB Signing Key 67 | # sub rsa4096 2016-03-30 [E] 68 | # for MariaDB 10+ 69 | 177F4010FE56CA3336300305F1656F24C74CD1D8 70 | 71 | RUN set -ex; \ 72 | export GNUPGHOME="$(mktemp -d)"; \ 73 | for key in $GPG_KEYS; do \ 74 | gpg --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ 75 | done; \ 76 | gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; \ 77 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 78 | rm -r "$GNUPGHOME"; \ 79 | apt-key list 80 | 81 | # bashbrew-architectures: amd64 arm64v8 ppc64le 82 | ENV MARIADB_MAJOR 10.1 83 | #ENV MARIADB_VERSION 1:10.1.36+maria-1~bionic 84 | 85 | RUN set -e;\ 86 | echo "deb http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_MAJOR/repo/ubuntu bionic main" > /etc/apt/sources.list.d/mariadb.list; \ 87 | { \ 88 | echo 'Package: *'; \ 89 | echo 'Pin: release o=MariaDB'; \ 90 | echo 'Pin-Priority: 999'; \ 91 | } > /etc/apt/preferences.d/mariadb 92 | # add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies 93 | # libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.61+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed 94 | 95 | # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) 96 | # also, we set debconf keys to make APT a little quieter 97 | RUN set -ex; \ 98 | { \ 99 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password password 'unused'; \ 100 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password_again password 'unused'; \ 101 | } | debconf-set-selections; \ 102 | backupPackage='mariadb-backup-10.1'; \ 103 | apt-get update; \ 104 | apt-get install -y \ 105 | "mariadb-server" \ 106 | $backupPackage \ 107 | socat \ 108 | ; \ 109 | rm -rf /var/lib/apt/lists/*; \ 110 | # comment out any "user" entires in the MySQL config ("docker-entrypoint.sh" or "--user" will handle user switching) 111 | sed -ri 's/^user\s/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/*; \ 112 | # purge and re-create /var/lib/mysql with appropriate ownership 113 | rm -rf /var/lib/mysql; \ 114 | mkdir -p /var/lib/mysql /var/run/mysqld; \ 115 | chown -R mysql:mysql /var/lib/mysql /var/run/mysqld; \ 116 | # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime 117 | chmod 777 /var/run/mysqld; \ 118 | # comment out a few problematic configuration values 119 | find /etc/mysql/ -name '*.cnf' -print0 \ 120 | | xargs -0 grep -lZE '^(bind-address|log)' \ 121 | | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/'; \ 122 | # don't reverse lookup hostnames, they are usually another container 123 | echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf 124 | 125 | VOLUME /var/lib/mysql 126 | 127 | COPY docker-entrypoint.sh /usr/local/bin/ 128 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat 129 | ENTRYPOINT ["docker-entrypoint.sh"] 130 | 131 | EXPOSE 3306 132 | CMD ["mysqld"] 133 | -------------------------------------------------------------------------------- /10.1/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | shopt -s nullglob 4 | 5 | # if command starts with an option, prepend mysqld 6 | if [ "${1:0:1}" = '-' ]; then 7 | set -- mysqld "$@" 8 | fi 9 | 10 | # skip setup if they want an option that stops mysqld 11 | wantHelp= 12 | for arg; do 13 | case "$arg" in 14 | -'?'|--help|--print-defaults|-V|--version) 15 | wantHelp=1 16 | break 17 | ;; 18 | esac 19 | done 20 | 21 | # usage: file_env VAR [DEFAULT] 22 | # ie: file_env 'XYZ_DB_PASSWORD' 'example' 23 | # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of 24 | # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) 25 | file_env() { 26 | local var="$1" 27 | local fileVar="${var}_FILE" 28 | local def="${2:-}" 29 | if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then 30 | echo >&2 "error: both $var and $fileVar are set (but are exclusive)" 31 | exit 1 32 | fi 33 | local val="$def" 34 | if [ "${!var:-}" ]; then 35 | val="${!var}" 36 | elif [ "${!fileVar:-}" ]; then 37 | val="$(< "${!fileVar}")" 38 | fi 39 | export "$var"="$val" 40 | unset "$fileVar" 41 | } 42 | 43 | _check_config() { 44 | toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" ) 45 | if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then 46 | cat >&2 <<-EOM 47 | 48 | ERROR: mysqld failed while attempting to check config 49 | command was: "${toRun[*]}" 50 | 51 | $errors 52 | EOM 53 | exit 1 54 | fi 55 | } 56 | 57 | # Fetch value from server config 58 | # We use mysqld --verbose --help instead of my_print_defaults because the 59 | # latter only show values present in config files, and not server defaults 60 | _get_config() { 61 | local conf="$1"; shift 62 | "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }' 63 | } 64 | 65 | # allow the container to be started with `--user` 66 | if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then 67 | _check_config "$@" 68 | DATADIR="$(_get_config 'datadir' "$@")" 69 | mkdir -p "$DATADIR" 70 | chown -R mysql:mysql "$DATADIR" 71 | exec gosu mysql "$BASH_SOURCE" "$@" 72 | fi 73 | 74 | if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then 75 | # still need to check config, container may have started with --user 76 | _check_config "$@" 77 | # Get config 78 | DATADIR="$(_get_config 'datadir' "$@")" 79 | 80 | if [ ! -d "$DATADIR/mysql" ]; then 81 | # for backward compability support both MYSQL_ and MARIADB_ env vars 82 | file_env 'MYSQL_ROOT_PASSWORD' 83 | file_env 'MARIADB_ROOT_PASSWORD' 84 | MARIADB_ROOT_PASSWORD="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}" 85 | MARIADB_ALLOW_EMPTY_PASSWORD="${MARIADB_ALLOW_EMPTY_PASSWORD:-$MYSQL_ALLOW_EMPTY_PASSWORD}" 86 | MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-$MYSQL_RANDOM_ROOT_PASSWORD}" 87 | if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 88 | echo >&2 'error: database is uninitialized and password option is not specified ' 89 | echo >&2 ' You need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' 90 | exit 1 91 | fi 92 | 93 | mkdir -p "$DATADIR" 94 | 95 | echo 'Initializing database' 96 | # "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here) 97 | mysql_install_db --datadir="$DATADIR" --rpm "${@:2}" 98 | echo 'Database initialized' 99 | 100 | SOCKET="$(_get_config 'socket' "$@")" 101 | "$@" --skip-networking --socket="${SOCKET}" & 102 | pid="$!" 103 | 104 | mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" ) 105 | 106 | for i in {30..0}; do 107 | if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then 108 | break 109 | fi 110 | echo 'MySQL init process in progress...' 111 | sleep 1 112 | done 113 | if [ "$i" = 0 ]; then 114 | echo >&2 'MySQL init process failed.' 115 | exit 1 116 | fi 117 | 118 | if [ -z "${MARIADB_INITDB_SKIP_TZINFO:-$MYSQL_INITDB_SKIP_TZINFO}" ]; then 119 | # sed is for https://bugs.mysql.com/bug.php?id=20545 120 | mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql 121 | fi 122 | 123 | if [ ! -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 124 | # we have to filter characters like ' and \ that will terminate the sql query or don't count 125 | # as special characters to keep the enterprise server password policy in mind. 126 | MARIADB_ROOT_PASSWORD="'" 127 | while [[ $MARIADB_ROOT_PASSWORD == *"'"* ]] || [[ $MARIADB_ROOT_PASSWORD == *"\\"* ]]; do 128 | export MARIADB_ROOT_PASSWORD="$(pwgen -1 32 -y)" 129 | done 130 | fi 131 | 132 | 133 | rootCreate= 134 | # default root to listen for connections from anywhere 135 | file_env 'MYSQL_ROOT_HOST' 136 | file_env 'MARIADB_ROOT_HOST' '%' 137 | MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-$MYSQL_ROOT_HOST}" 138 | if [ ! -z "$MARIADB_ROOT_HOST" -a "$MARIADB_ROOT_HOST" != 'localhost' ]; then 139 | # no, we don't care if read finds a terminating character in this heredoc 140 | # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 141 | read -r -d '' rootCreate <<-EOSQL || true 142 | CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ; 143 | GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; 144 | EOSQL 145 | fi 146 | 147 | "${mysql[@]}" <<-EOSQL 148 | -- What's done in this file shouldn't be replicated 149 | -- or products like mysql-fabric won't work 150 | SET @@SESSION.SQL_LOG_BIN=0; 151 | 152 | DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ; 153 | SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ; 154 | GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; 155 | ${rootCreate} 156 | DROP DATABASE IF EXISTS test ; 157 | FLUSH PRIVILEGES ; 158 | EOSQL 159 | 160 | if [ ! -z "$MARIADB_ROOT_PASSWORD" ]; then 161 | mysql+=( -p"${MARIADB_ROOT_PASSWORD}" ) 162 | fi 163 | 164 | file_env 'MYSQL_DATABASE' 165 | file_env 'MARIADB_DATABASE' 166 | MARIADB_DATABASE="${MARIADB_DATABASE:-$MYSQL_DATABASE}" 167 | if [ "$MARIADB_DATABASE" ]; then 168 | echo "CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\` ;" | "${mysql[@]}" 169 | mysql+=( "$MARIADB_DATABASE" ) 170 | fi 171 | 172 | file_env 'MYSQL_USER' 173 | file_env 'MARIADB_USER' 174 | MARIADB_USER="${MARIADB_USER:-$MYSQL_USER}" 175 | file_env 'MYSQL_PASSWORD' 176 | file_env 'MARIADB_PASSWORD' 177 | MARIADB_PASSWORD="${MARIADB_PASSWORD:-$MYSQL_PASSWORD}" 178 | if [ "$MARIADB_USER" -a "$MARIADB_PASSWORD" ]; then 179 | echo "CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;" | "${mysql[@]}" 180 | 181 | if [ "$MARIADB_DATABASE" ]; then 182 | echo "GRANT ALL ON \`$MARIADB_DATABASE\`.* TO '$MARIADB_USER'@'%' ;" | "${mysql[@]}" 183 | fi 184 | fi 185 | 186 | echo 187 | for f in /docker-entrypoint-initdb.d/*; do 188 | case "$f" in 189 | *.sh) echo "$0: running $f"; . "$f" ;; 190 | *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; 191 | *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; 192 | *) echo "$0: ignoring $f" ;; 193 | esac 194 | echo 195 | done 196 | 197 | if ! kill -s TERM "$pid" || ! wait "$pid"; then 198 | echo >&2 'MySQL init process failed.' 199 | exit 1 200 | fi 201 | 202 | echo 203 | echo 'MySQL init process done. Ready for start up.' 204 | echo 205 | fi 206 | fi 207 | 208 | exec "$@" 209 | -------------------------------------------------------------------------------- /10.1/version: -------------------------------------------------------------------------------- 1 | 10.1.43 2 | -------------------------------------------------------------------------------- /10.1/whitelist.yml: -------------------------------------------------------------------------------- 1 | generalwhitelist: #Approve CVE for any image 2 | CVE-2017-6055: XML 3 | CVE-2017-5586: OpenText 4 | images: 5 | ubuntu: #Apprive CVE only for ubuntu image, regardles of the version 6 | CVE-2017-5230: Java 7 | CVE-2017-5230: XSX 8 | alpine: 9 | CVE-2017-3261: SE 10 | CVE-2016-9840: zlib 11 | CVE-2016-9841: zlib 12 | CVE-2016-9842: zlib 13 | CVE-2016-9843: zlib -------------------------------------------------------------------------------- /10.2/Dockerfile: -------------------------------------------------------------------------------- 1 | # vim:set ft=dockerfile: 2 | FROM ubuntu:bionic 3 | 4 | # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added 5 | RUN groupadd -r mysql && useradd -r -g mysql mysql 6 | 7 | # https://bugs.debian.org/830696 (apt uses gpgv by default in newer releases, rather than gpg) 8 | RUN set -ex; \ 9 | apt-get update; \ 10 | if ! which gpg; then \ 11 | apt-get install -y --no-install-recommends gnupg; \ 12 | fi; \ 13 | # Ubuntu includes "gnupg" (not "gnupg2", but still 2.x), but not dirmngr, and gnupg 2.x requires dirmngr 14 | # so, if we're not running gnupg 1.x, explicitly install dirmngr too 15 | if ! gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \ 16 | apt-get install -y --no-install-recommends dirmngr; \ 17 | fi; \ 18 | rm -rf /var/lib/apt/lists/* 19 | 20 | # add gosu for easy step-down from root 21 | ENV GOSU_VERSION 1.10 22 | RUN set -ex; \ 23 | \ 24 | fetchDeps=' \ 25 | ca-certificates \ 26 | wget \ 27 | '; \ 28 | apt-get update; \ 29 | apt-get install -y --no-install-recommends $fetchDeps; \ 30 | rm -rf /var/lib/apt/lists/*; \ 31 | \ 32 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 33 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 34 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 35 | \ 36 | # verify the signature 37 | export GNUPGHOME="$(mktemp -d)"; \ 38 | gpg --keyserver keyserver.ubuntu.com --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 39 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 40 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 41 | rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 42 | \ 43 | chmod +x /usr/local/bin/gosu; \ 44 | # verify that the binary works 45 | gosu nobody true; \ 46 | \ 47 | apt-get purge -y --auto-remove $fetchDeps 48 | 49 | RUN mkdir /docker-entrypoint-initdb.d 50 | 51 | # install "pwgen" for randomizing passwords 52 | # install "tzdata" for /usr/share/zoneinfo/ 53 | RUN apt-get update && apt-get install -y --no-install-recommends \ 54 | apt-transport-https ca-certificates \ 55 | pwgen \ 56 | tzdata \ 57 | && rm -rf /var/lib/apt/lists/* 58 | 59 | ENV GPG_KEYS \ 60 | # Key fingerprint = 1993 69E5 404B D5FC 7D2F E43B CBCB 082A 1BB9 43DB 61 | # MariaDB Package Signing Key 62 | # for MariaDB 5.5 63 | 199369E5404BD5FC7D2FE43BCBCB082A1BB943DB \ 64 | # pub rsa4096 2016-03-30 [SC] 65 | # 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 66 | # uid [ unknown] MariaDB Signing Key 67 | # sub rsa4096 2016-03-30 [E] 68 | # for MariaDB 10+ 69 | 177F4010FE56CA3336300305F1656F24C74CD1D8 70 | 71 | RUN set -ex; \ 72 | export GNUPGHOME="$(mktemp -d)"; \ 73 | for key in $GPG_KEYS; do \ 74 | gpg --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ 75 | done; \ 76 | gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; \ 77 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 78 | rm -r "$GNUPGHOME"; \ 79 | apt-key list 80 | 81 | # bashbrew-architectures: amd64 arm64v8 ppc64le 82 | ENV MARIADB_MAJOR 10.2 83 | #ENV MARIADB_VERSION 1:10.2.18+maria~bionic 84 | 85 | RUN set -e;\ 86 | echo "deb http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_MAJOR/repo/ubuntu bionic main" > /etc/apt/sources.list.d/mariadb.list; \ 87 | { \ 88 | echo 'Package: *'; \ 89 | echo 'Pin: release o=MariaDB'; \ 90 | echo 'Pin-Priority: 999'; \ 91 | } > /etc/apt/preferences.d/mariadb 92 | # add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies 93 | # libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.61+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed 94 | 95 | # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) 96 | # also, we set debconf keys to make APT a little quieter 97 | RUN set -ex; \ 98 | { \ 99 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password password 'unused'; \ 100 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password_again password 'unused'; \ 101 | } | debconf-set-selections; \ 102 | backupPackage='mariadb-backup-10.2'; \ 103 | apt-get update; \ 104 | apt-get install -y \ 105 | "mariadb-server" \ 106 | $backupPackage \ 107 | socat \ 108 | ; \ 109 | rm -rf /var/lib/apt/lists/*; \ 110 | # comment out any "user" entires in the MySQL config ("docker-entrypoint.sh" or "--user" will handle user switching) 111 | sed -ri 's/^user\s/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/*; \ 112 | # purge and re-create /var/lib/mysql with appropriate ownership 113 | rm -rf /var/lib/mysql; \ 114 | mkdir -p /var/lib/mysql /var/run/mysqld; \ 115 | chown -R mysql:mysql /var/lib/mysql /var/run/mysqld; \ 116 | # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime 117 | chmod 777 /var/run/mysqld; \ 118 | # comment out a few problematic configuration values 119 | find /etc/mysql/ -name '*.cnf' -print0 \ 120 | | xargs -0 grep -lZE '^(bind-address|log)' \ 121 | | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/'; \ 122 | # don't reverse lookup hostnames, they are usually another container 123 | echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf 124 | 125 | VOLUME /var/lib/mysql 126 | 127 | COPY docker-entrypoint.sh /usr/local/bin/ 128 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat 129 | ENTRYPOINT ["docker-entrypoint.sh"] 130 | 131 | EXPOSE 3306 132 | CMD ["mysqld"] 133 | -------------------------------------------------------------------------------- /10.2/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | shopt -s nullglob 4 | 5 | # if command starts with an option, prepend mysqld 6 | if [ "${1:0:1}" = '-' ]; then 7 | set -- mysqld "$@" 8 | fi 9 | 10 | # skip setup if they want an option that stops mysqld 11 | wantHelp= 12 | for arg; do 13 | case "$arg" in 14 | -'?'|--help|--print-defaults|-V|--version) 15 | wantHelp=1 16 | break 17 | ;; 18 | esac 19 | done 20 | 21 | # usage: file_env VAR [DEFAULT] 22 | # ie: file_env 'XYZ_DB_PASSWORD' 'example' 23 | # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of 24 | # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) 25 | file_env() { 26 | local var="$1" 27 | local fileVar="${var}_FILE" 28 | local def="${2:-}" 29 | if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then 30 | echo >&2 "error: both $var and $fileVar are set (but are exclusive)" 31 | exit 1 32 | fi 33 | local val="$def" 34 | if [ "${!var:-}" ]; then 35 | val="${!var}" 36 | elif [ "${!fileVar:-}" ]; then 37 | val="$(< "${!fileVar}")" 38 | fi 39 | export "$var"="$val" 40 | unset "$fileVar" 41 | } 42 | 43 | _check_config() { 44 | toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" ) 45 | if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then 46 | cat >&2 <<-EOM 47 | 48 | ERROR: mysqld failed while attempting to check config 49 | command was: "${toRun[*]}" 50 | 51 | $errors 52 | EOM 53 | exit 1 54 | fi 55 | } 56 | 57 | # Fetch value from server config 58 | # We use mysqld --verbose --help instead of my_print_defaults because the 59 | # latter only show values present in config files, and not server defaults 60 | _get_config() { 61 | local conf="$1"; shift 62 | "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }' 63 | } 64 | 65 | # allow the container to be started with `--user` 66 | if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then 67 | _check_config "$@" 68 | DATADIR="$(_get_config 'datadir' "$@")" 69 | mkdir -p "$DATADIR" 70 | chown -R mysql:mysql "$DATADIR" 71 | exec gosu mysql "$BASH_SOURCE" "$@" 72 | fi 73 | 74 | if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then 75 | # still need to check config, container may have started with --user 76 | _check_config "$@" 77 | # Get config 78 | DATADIR="$(_get_config 'datadir' "$@")" 79 | 80 | if [ ! -d "$DATADIR/mysql" ]; then 81 | # for backward compability support both MYSQL_ and MARIADB_ env vars 82 | file_env 'MYSQL_ROOT_PASSWORD' 83 | file_env 'MARIADB_ROOT_PASSWORD' 84 | MARIADB_ROOT_PASSWORD="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}" 85 | MARIADB_ALLOW_EMPTY_PASSWORD="${MARIADB_ALLOW_EMPTY_PASSWORD:-$MYSQL_ALLOW_EMPTY_PASSWORD}" 86 | MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-$MYSQL_RANDOM_ROOT_PASSWORD}" 87 | if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 88 | echo >&2 'error: database is uninitialized and password option is not specified ' 89 | echo >&2 ' You need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' 90 | exit 1 91 | fi 92 | 93 | mkdir -p "$DATADIR" 94 | 95 | echo 'Initializing database' 96 | # "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here) 97 | mysql_install_db --datadir="$DATADIR" --rpm "${@:2}" 98 | echo 'Database initialized' 99 | 100 | SOCKET="$(_get_config 'socket' "$@")" 101 | "$@" --skip-networking --socket="${SOCKET}" & 102 | pid="$!" 103 | 104 | mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" ) 105 | 106 | for i in {30..0}; do 107 | if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then 108 | break 109 | fi 110 | echo 'MySQL init process in progress...' 111 | sleep 1 112 | done 113 | if [ "$i" = 0 ]; then 114 | echo >&2 'MySQL init process failed.' 115 | exit 1 116 | fi 117 | 118 | if [ -z "${MARIADB_INITDB_SKIP_TZINFO:-$MYSQL_INITDB_SKIP_TZINFO}" ]; then 119 | # sed is for https://bugs.mysql.com/bug.php?id=20545 120 | mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql 121 | fi 122 | 123 | if [ ! -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 124 | # we have to filter characters like ' and \ that will terminate the sql query or don't count 125 | # as special characters to keep the enterprise server password policy in mind. 126 | MARIADB_ROOT_PASSWORD="'" 127 | while [[ $MARIADB_ROOT_PASSWORD == *"'"* ]] || [[ $MARIADB_ROOT_PASSWORD == *"\\"* ]]; do 128 | export MARIADB_ROOT_PASSWORD="$(pwgen -1 32 -y)" 129 | done 130 | fi 131 | 132 | 133 | rootCreate= 134 | # default root to listen for connections from anywhere 135 | file_env 'MYSQL_ROOT_HOST' 136 | file_env 'MARIADB_ROOT_HOST' '%' 137 | MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-$MYSQL_ROOT_HOST}" 138 | if [ ! -z "$MARIADB_ROOT_HOST" -a "$MARIADB_ROOT_HOST" != 'localhost' ]; then 139 | # no, we don't care if read finds a terminating character in this heredoc 140 | # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 141 | read -r -d '' rootCreate <<-EOSQL || true 142 | CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ; 143 | GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; 144 | EOSQL 145 | fi 146 | 147 | "${mysql[@]}" <<-EOSQL 148 | -- What's done in this file shouldn't be replicated 149 | -- or products like mysql-fabric won't work 150 | SET @@SESSION.SQL_LOG_BIN=0; 151 | 152 | DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ; 153 | SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ; 154 | GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; 155 | ${rootCreate} 156 | DROP DATABASE IF EXISTS test ; 157 | FLUSH PRIVILEGES ; 158 | EOSQL 159 | 160 | if [ ! -z "$MARIADB_ROOT_PASSWORD" ]; then 161 | mysql+=( -p"${MARIADB_ROOT_PASSWORD}" ) 162 | fi 163 | 164 | file_env 'MYSQL_DATABASE' 165 | file_env 'MARIADB_DATABASE' 166 | MARIADB_DATABASE="${MARIADB_DATABASE:-$MYSQL_DATABASE}" 167 | if [ "$MARIADB_DATABASE" ]; then 168 | echo "CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\` ;" | "${mysql[@]}" 169 | mysql+=( "$MARIADB_DATABASE" ) 170 | fi 171 | 172 | file_env 'MYSQL_USER' 173 | file_env 'MARIADB_USER' 174 | MARIADB_USER="${MARIADB_USER:-$MYSQL_USER}" 175 | file_env 'MYSQL_PASSWORD' 176 | file_env 'MARIADB_PASSWORD' 177 | MARIADB_PASSWORD="${MARIADB_PASSWORD:-$MYSQL_PASSWORD}" 178 | if [ "$MARIADB_USER" -a "$MARIADB_PASSWORD" ]; then 179 | echo "CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;" | "${mysql[@]}" 180 | 181 | if [ "$MARIADB_DATABASE" ]; then 182 | echo "GRANT ALL ON \`$MARIADB_DATABASE\`.* TO '$MARIADB_USER'@'%' ;" | "${mysql[@]}" 183 | fi 184 | fi 185 | 186 | echo 187 | for f in /docker-entrypoint-initdb.d/*; do 188 | case "$f" in 189 | *.sh) echo "$0: running $f"; . "$f" ;; 190 | *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; 191 | *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; 192 | *) echo "$0: ignoring $f" ;; 193 | esac 194 | echo 195 | done 196 | 197 | if ! kill -s TERM "$pid" || ! wait "$pid"; then 198 | echo >&2 'MySQL init process failed.' 199 | exit 1 200 | fi 201 | 202 | echo 203 | echo 'MySQL init process done. Ready for start up.' 204 | echo 205 | fi 206 | fi 207 | 208 | exec "$@" 209 | -------------------------------------------------------------------------------- /10.2/version: -------------------------------------------------------------------------------- 1 | 10.2.29 2 | -------------------------------------------------------------------------------- /10.2/whitelist.yml: -------------------------------------------------------------------------------- 1 | generalwhitelist: #Approve CVE for any image 2 | CVE-2017-6055: XML 3 | CVE-2017-5586: OpenText 4 | images: 5 | ubuntu: #Apprive CVE only for ubuntu image, regardles of the version 6 | CVE-2017-5230: Java 7 | CVE-2017-5230: XSX 8 | alpine: 9 | CVE-2017-3261: SE 10 | CVE-2016-9840: zlib 11 | CVE-2016-9841: zlib 12 | CVE-2016-9842: zlib 13 | CVE-2016-9843: zlib -------------------------------------------------------------------------------- /10.3/Dockerfile: -------------------------------------------------------------------------------- 1 | # vim:set ft=dockerfile: 2 | FROM ubuntu:bionic 3 | 4 | # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added 5 | RUN groupadd -r mysql && useradd -r -g mysql mysql 6 | 7 | # https://bugs.debian.org/830696 (apt uses gpgv by default in newer releases, rather than gpg) 8 | RUN set -ex; \ 9 | apt-get update; \ 10 | if ! which gpg; then \ 11 | apt-get install -y --no-install-recommends gnupg; \ 12 | fi; \ 13 | # Ubuntu includes "gnupg" (not "gnupg2", but still 2.x), but not dirmngr, and gnupg 2.x requires dirmngr 14 | # so, if we're not running gnupg 1.x, explicitly install dirmngr too 15 | if ! gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \ 16 | apt-get install -y --no-install-recommends dirmngr; \ 17 | fi; \ 18 | rm -rf /var/lib/apt/lists/* 19 | 20 | # add gosu for easy step-down from root 21 | ENV GOSU_VERSION 1.10 22 | RUN set -ex; \ 23 | \ 24 | fetchDeps=' \ 25 | ca-certificates \ 26 | wget \ 27 | '; \ 28 | apt-get update; \ 29 | apt-get install -y --no-install-recommends $fetchDeps; \ 30 | rm -rf /var/lib/apt/lists/*; \ 31 | \ 32 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 33 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 34 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 35 | \ 36 | # verify the signature 37 | export GNUPGHOME="$(mktemp -d)"; \ 38 | gpg --keyserver keyserver.ubuntu.com --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 39 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 40 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 41 | rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 42 | \ 43 | chmod +x /usr/local/bin/gosu; \ 44 | # verify that the binary works 45 | gosu nobody true; \ 46 | \ 47 | apt-get purge -y --auto-remove $fetchDeps 48 | 49 | RUN mkdir /docker-entrypoint-initdb.d 50 | 51 | # install "pwgen" for randomizing passwords 52 | # install "tzdata" for /usr/share/zoneinfo/ 53 | RUN apt-get update && apt-get install -y --no-install-recommends \ 54 | apt-transport-https ca-certificates \ 55 | pwgen \ 56 | tzdata \ 57 | && rm -rf /var/lib/apt/lists/* 58 | 59 | ENV GPG_KEYS \ 60 | # Key fingerprint = 1993 69E5 404B D5FC 7D2F E43B CBCB 082A 1BB9 43DB 61 | # MariaDB Package Signing Key 62 | # for MariaDB 5.5 63 | 199369E5404BD5FC7D2FE43BCBCB082A1BB943DB \ 64 | # pub rsa4096 2016-03-30 [SC] 65 | # 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 66 | # uid [ unknown] MariaDB Signing Key 67 | # sub rsa4096 2016-03-30 [E] 68 | # for MariaDB 10+ 69 | 177F4010FE56CA3336300305F1656F24C74CD1D8 70 | 71 | RUN set -ex; \ 72 | export GNUPGHOME="$(mktemp -d)"; \ 73 | for key in $GPG_KEYS; do \ 74 | gpg --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ 75 | done; \ 76 | gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; \ 77 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 78 | rm -r "$GNUPGHOME"; \ 79 | apt-key list 80 | 81 | # bashbrew-architectures: amd64 arm64v8 ppc64le 82 | ENV MARIADB_MAJOR 10.3 83 | #ENV MARIADB_VERSION 1:10.3.10+maria~bionic 84 | 85 | RUN set -e;\ 86 | echo "deb http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_MAJOR/repo/ubuntu bionic main" > /etc/apt/sources.list.d/mariadb.list; \ 87 | { \ 88 | echo 'Package: *'; \ 89 | echo 'Pin: release o=MariaDB'; \ 90 | echo 'Pin-Priority: 999'; \ 91 | } > /etc/apt/preferences.d/mariadb 92 | # add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies 93 | # libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.61+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed 94 | 95 | # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) 96 | # also, we set debconf keys to make APT a little quieter 97 | RUN set -ex; \ 98 | { \ 99 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password password 'unused'; \ 100 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password_again password 'unused'; \ 101 | } | debconf-set-selections; \ 102 | backupPackage='mariadb-backup'; \ 103 | apt-get update; \ 104 | apt-get install -y \ 105 | "mariadb-server" \ 106 | $backupPackage \ 107 | socat \ 108 | ; \ 109 | rm -rf /var/lib/apt/lists/*; \ 110 | # comment out any "user" entires in the MySQL config ("docker-entrypoint.sh" or "--user" will handle user switching) 111 | sed -ri 's/^user\s/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/*; \ 112 | # purge and re-create /var/lib/mysql with appropriate ownership 113 | rm -rf /var/lib/mysql; \ 114 | mkdir -p /var/lib/mysql /var/run/mysqld; \ 115 | chown -R mysql:mysql /var/lib/mysql /var/run/mysqld; \ 116 | # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime 117 | chmod 777 /var/run/mysqld; \ 118 | # comment out a few problematic configuration values 119 | find /etc/mysql/ -name '*.cnf' -print0 \ 120 | | xargs -0 grep -lZE '^(bind-address|log)' \ 121 | | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/'; \ 122 | # don't reverse lookup hostnames, they are usually another container 123 | echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf 124 | 125 | VOLUME /var/lib/mysql 126 | 127 | COPY docker-entrypoint.sh /usr/local/bin/ 128 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat 129 | ENTRYPOINT ["docker-entrypoint.sh"] 130 | 131 | EXPOSE 3306 132 | CMD ["mysqld"] 133 | -------------------------------------------------------------------------------- /10.3/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | shopt -s nullglob 4 | 5 | # if command starts with an option, prepend mysqld 6 | if [ "${1:0:1}" = '-' ]; then 7 | set -- mysqld "$@" 8 | fi 9 | 10 | # skip setup if they want an option that stops mysqld 11 | wantHelp= 12 | for arg; do 13 | case "$arg" in 14 | -'?'|--help|--print-defaults|-V|--version) 15 | wantHelp=1 16 | break 17 | ;; 18 | esac 19 | done 20 | 21 | # usage: file_env VAR [DEFAULT] 22 | # ie: file_env 'XYZ_DB_PASSWORD' 'example' 23 | # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of 24 | # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) 25 | file_env() { 26 | local var="$1" 27 | local fileVar="${var}_FILE" 28 | local def="${2:-}" 29 | if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then 30 | echo >&2 "error: both $var and $fileVar are set (but are exclusive)" 31 | exit 1 32 | fi 33 | local val="$def" 34 | if [ "${!var:-}" ]; then 35 | val="${!var}" 36 | elif [ "${!fileVar:-}" ]; then 37 | val="$(< "${!fileVar}")" 38 | fi 39 | export "$var"="$val" 40 | unset "$fileVar" 41 | } 42 | 43 | _check_config() { 44 | toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" ) 45 | if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then 46 | cat >&2 <<-EOM 47 | 48 | ERROR: mysqld failed while attempting to check config 49 | command was: "${toRun[*]}" 50 | 51 | $errors 52 | EOM 53 | exit 1 54 | fi 55 | } 56 | 57 | # Fetch value from server config 58 | # We use mysqld --verbose --help instead of my_print_defaults because the 59 | # latter only show values present in config files, and not server defaults 60 | _get_config() { 61 | local conf="$1"; shift 62 | "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }' 63 | } 64 | 65 | # allow the container to be started with `--user` 66 | if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then 67 | _check_config "$@" 68 | DATADIR="$(_get_config 'datadir' "$@")" 69 | mkdir -p "$DATADIR" 70 | chown -R mysql:mysql "$DATADIR" 71 | exec gosu mysql "$BASH_SOURCE" "$@" 72 | fi 73 | 74 | if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then 75 | # still need to check config, container may have started with --user 76 | _check_config "$@" 77 | # Get config 78 | DATADIR="$(_get_config 'datadir' "$@")" 79 | 80 | if [ ! -d "$DATADIR/mysql" ]; then 81 | # for backward compability support both MYSQL_ and MARIADB_ env vars 82 | file_env 'MYSQL_ROOT_PASSWORD' 83 | file_env 'MARIADB_ROOT_PASSWORD' 84 | MARIADB_ROOT_PASSWORD="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}" 85 | MARIADB_ALLOW_EMPTY_PASSWORD="${MARIADB_ALLOW_EMPTY_PASSWORD:-$MYSQL_ALLOW_EMPTY_PASSWORD}" 86 | MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-$MYSQL_RANDOM_ROOT_PASSWORD}" 87 | if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 88 | echo >&2 'error: database is uninitialized and password option is not specified ' 89 | echo >&2 ' You need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' 90 | exit 1 91 | fi 92 | 93 | mkdir -p "$DATADIR" 94 | 95 | echo 'Initializing database' 96 | # "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here) 97 | mysql_install_db --datadir="$DATADIR" --rpm "${@:2}" 98 | echo 'Database initialized' 99 | 100 | SOCKET="$(_get_config 'socket' "$@")" 101 | "$@" --skip-networking --socket="${SOCKET}" & 102 | pid="$!" 103 | 104 | mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" ) 105 | 106 | for i in {30..0}; do 107 | if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then 108 | break 109 | fi 110 | echo 'MySQL init process in progress...' 111 | sleep 1 112 | done 113 | if [ "$i" = 0 ]; then 114 | echo >&2 'MySQL init process failed.' 115 | exit 1 116 | fi 117 | 118 | if [ -z "${MARIADB_INITDB_SKIP_TZINFO:-$MYSQL_INITDB_SKIP_TZINFO}" ]; then 119 | # sed is for https://bugs.mysql.com/bug.php?id=20545 120 | mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql 121 | fi 122 | 123 | if [ ! -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 124 | # we have to filter characters like ' and \ that will terminate the sql query or don't count 125 | # as special characters to keep the enterprise server password policy in mind. 126 | MARIADB_ROOT_PASSWORD="'" 127 | while [[ $MARIADB_ROOT_PASSWORD == *"'"* ]] || [[ $MARIADB_ROOT_PASSWORD == *"\\"* ]]; do 128 | export MARIADB_ROOT_PASSWORD="$(pwgen -1 32 -y)" 129 | done 130 | fi 131 | 132 | 133 | rootCreate= 134 | # default root to listen for connections from anywhere 135 | file_env 'MYSQL_ROOT_HOST' 136 | file_env 'MARIADB_ROOT_HOST' '%' 137 | MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-$MYSQL_ROOT_HOST}" 138 | if [ ! -z "$MARIADB_ROOT_HOST" -a "$MARIADB_ROOT_HOST" != 'localhost' ]; then 139 | # no, we don't care if read finds a terminating character in this heredoc 140 | # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 141 | read -r -d '' rootCreate <<-EOSQL || true 142 | CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ; 143 | GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; 144 | EOSQL 145 | fi 146 | 147 | "${mysql[@]}" <<-EOSQL 148 | -- What's done in this file shouldn't be replicated 149 | -- or products like mysql-fabric won't work 150 | SET @@SESSION.SQL_LOG_BIN=0; 151 | 152 | DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ; 153 | SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ; 154 | GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; 155 | ${rootCreate} 156 | DROP DATABASE IF EXISTS test ; 157 | FLUSH PRIVILEGES ; 158 | EOSQL 159 | 160 | if [ ! -z "$MARIADB_ROOT_PASSWORD" ]; then 161 | mysql+=( -p"${MARIADB_ROOT_PASSWORD}" ) 162 | fi 163 | 164 | file_env 'MYSQL_DATABASE' 165 | file_env 'MARIADB_DATABASE' 166 | MARIADB_DATABASE="${MARIADB_DATABASE:-$MYSQL_DATABASE}" 167 | if [ "$MARIADB_DATABASE" ]; then 168 | echo "CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\` ;" | "${mysql[@]}" 169 | mysql+=( "$MARIADB_DATABASE" ) 170 | fi 171 | 172 | file_env 'MYSQL_USER' 173 | file_env 'MARIADB_USER' 174 | MARIADB_USER="${MARIADB_USER:-$MYSQL_USER}" 175 | file_env 'MYSQL_PASSWORD' 176 | file_env 'MARIADB_PASSWORD' 177 | MARIADB_PASSWORD="${MARIADB_PASSWORD:-$MYSQL_PASSWORD}" 178 | if [ "$MARIADB_USER" -a "$MARIADB_PASSWORD" ]; then 179 | echo "CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;" | "${mysql[@]}" 180 | 181 | if [ "$MARIADB_DATABASE" ]; then 182 | echo "GRANT ALL ON \`$MARIADB_DATABASE\`.* TO '$MARIADB_USER'@'%' ;" | "${mysql[@]}" 183 | fi 184 | fi 185 | 186 | echo 187 | for f in /docker-entrypoint-initdb.d/*; do 188 | case "$f" in 189 | *.sh) echo "$0: running $f"; . "$f" ;; 190 | *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; 191 | *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; 192 | *) echo "$0: ignoring $f" ;; 193 | esac 194 | echo 195 | done 196 | 197 | if ! kill -s TERM "$pid" || ! wait "$pid"; then 198 | echo >&2 'MySQL init process failed.' 199 | exit 1 200 | fi 201 | 202 | echo 203 | echo 'MySQL init process done. Ready for start up.' 204 | echo 205 | fi 206 | fi 207 | 208 | exec "$@" 209 | -------------------------------------------------------------------------------- /10.3/version: -------------------------------------------------------------------------------- 1 | 10.3.20 2 | -------------------------------------------------------------------------------- /10.3/whitelist.yml: -------------------------------------------------------------------------------- 1 | generalwhitelist: #Approve CVE for any image 2 | CVE-2017-6055: XML 3 | CVE-2017-5586: OpenText 4 | images: 5 | ubuntu: #Apprive CVE only for ubuntu image, regardles of the version 6 | CVE-2017-5230: Java 7 | CVE-2017-5230: XSX 8 | alpine: 9 | CVE-2017-3261: SE 10 | CVE-2016-9840: zlib 11 | CVE-2016-9841: zlib 12 | CVE-2016-9842: zlib 13 | CVE-2016-9843: zlib -------------------------------------------------------------------------------- /10.4/Dockerfile: -------------------------------------------------------------------------------- 1 | # vim:set ft=dockerfile: 2 | FROM ubuntu:bionic 3 | 4 | # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added 5 | RUN groupadd -r mysql && useradd -r -g mysql mysql 6 | 7 | # https://bugs.debian.org/830696 (apt uses gpgv by default in newer releases, rather than gpg) 8 | RUN set -ex; \ 9 | apt-get update; \ 10 | if ! which gpg; then \ 11 | apt-get install -y --no-install-recommends gnupg; \ 12 | fi; \ 13 | # Ubuntu includes "gnupg" (not "gnupg2", but still 2.x), but not dirmngr, and gnupg 2.x requires dirmngr 14 | # so, if we're not running gnupg 1.x, explicitly install dirmngr too 15 | if ! gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \ 16 | apt-get install -y --no-install-recommends dirmngr; \ 17 | fi; \ 18 | rm -rf /var/lib/apt/lists/* 19 | 20 | # add gosu for easy step-down from root 21 | ENV GOSU_VERSION 1.10 22 | RUN set -ex; \ 23 | \ 24 | fetchDeps=' \ 25 | ca-certificates \ 26 | wget \ 27 | '; \ 28 | apt-get update; \ 29 | apt-get install -y --no-install-recommends $fetchDeps; \ 30 | rm -rf /var/lib/apt/lists/*; \ 31 | \ 32 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 33 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 34 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 35 | \ 36 | # verify the signature 37 | export GNUPGHOME="$(mktemp -d)"; \ 38 | gpg --keyserver keyserver.ubuntu.com --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 39 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 40 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 41 | rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 42 | \ 43 | chmod +x /usr/local/bin/gosu; \ 44 | # verify that the binary works 45 | gosu nobody true; \ 46 | \ 47 | apt-get purge -y --auto-remove $fetchDeps 48 | 49 | RUN mkdir /docker-entrypoint-initdb.d 50 | 51 | # install "pwgen" for randomizing passwords 52 | # install "tzdata" for /usr/share/zoneinfo/ 53 | RUN apt-get update && apt-get install -y --no-install-recommends \ 54 | apt-transport-https ca-certificates \ 55 | pwgen \ 56 | tzdata \ 57 | && rm -rf /var/lib/apt/lists/* 58 | 59 | ENV GPG_KEYS \ 60 | # Key fingerprint = 1993 69E5 404B D5FC 7D2F E43B CBCB 082A 1BB9 43DB 61 | # MariaDB Package Signing Key 62 | # for MariaDB 5.5 63 | 199369E5404BD5FC7D2FE43BCBCB082A1BB943DB \ 64 | # pub rsa4096 2016-03-30 [SC] 65 | # 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 66 | # uid [ unknown] MariaDB Signing Key 67 | # sub rsa4096 2016-03-30 [E] 68 | # for MariaDB 10+ 69 | 177F4010FE56CA3336300305F1656F24C74CD1D8 70 | 71 | RUN set -ex; \ 72 | export GNUPGHOME="$(mktemp -d)"; \ 73 | for key in $GPG_KEYS; do \ 74 | gpg --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ 75 | done; \ 76 | gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; \ 77 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 78 | rm -r "$GNUPGHOME"; \ 79 | apt-key list 80 | 81 | # bashbrew-architectures: amd64 arm64v8 ppc64le 82 | ENV MARIADB_MAJOR 10.4 83 | 84 | RUN set -e;\ 85 | echo "deb http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_MAJOR/repo/ubuntu bionic main" > /etc/apt/sources.list.d/mariadb.list; \ 86 | { \ 87 | echo 'Package: *'; \ 88 | echo 'Pin: release o=MariaDB'; \ 89 | echo 'Pin-Priority: 999'; \ 90 | } > /etc/apt/preferences.d/mariadb 91 | # add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies 92 | # libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.61+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed 93 | 94 | # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) 95 | # also, we set debconf keys to make APT a little quieter 96 | RUN set -ex; \ 97 | { \ 98 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password password 'unused'; \ 99 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password_again password 'unused'; \ 100 | } | debconf-set-selections; \ 101 | backupPackage='mariadb-backup'; \ 102 | apt-get update; \ 103 | apt-get install -y \ 104 | "mariadb-server" \ 105 | $backupPackage \ 106 | socat \ 107 | ; \ 108 | rm -rf /var/lib/apt/lists/*; \ 109 | # comment out any "user" entires in the MySQL config ("docker-entrypoint.sh" or "--user" will handle user switching) 110 | sed -ri 's/^user\s/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/*; \ 111 | # purge and re-create /var/lib/mysql with appropriate ownership 112 | rm -rf /var/lib/mysql; \ 113 | mkdir -p /var/lib/mysql /var/run/mysqld; \ 114 | chown -R mysql:mysql /var/lib/mysql /var/run/mysqld; \ 115 | # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime 116 | chmod 777 /var/run/mysqld; \ 117 | # comment out a few problematic configuration values 118 | find /etc/mysql/ -name '*.cnf' -print0 \ 119 | | xargs -0 grep -lZE '^(bind-address|log)' \ 120 | | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/'; \ 121 | # don't reverse lookup hostnames, they are usually another container 122 | echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf 123 | 124 | VOLUME /var/lib/mysql 125 | 126 | COPY docker-entrypoint.sh /usr/local/bin/ 127 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat 128 | ENTRYPOINT ["docker-entrypoint.sh"] 129 | 130 | EXPOSE 3306 131 | CMD ["mysqld"] 132 | -------------------------------------------------------------------------------- /10.4/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | shopt -s nullglob 4 | 5 | # if command starts with an option, prepend mysqld 6 | if [ "${1:0:1}" = '-' ]; then 7 | set -- mysqld "$@" 8 | fi 9 | 10 | # skip setup if they want an option that stops mysqld 11 | wantHelp= 12 | for arg; do 13 | case "$arg" in 14 | -'?'|--help|--print-defaults|-V|--version) 15 | wantHelp=1 16 | break 17 | ;; 18 | esac 19 | done 20 | 21 | # usage: file_env VAR [DEFAULT] 22 | # ie: file_env 'XYZ_DB_PASSWORD' 'example' 23 | # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of 24 | # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) 25 | file_env() { 26 | local var="$1" 27 | local fileVar="${var}_FILE" 28 | local def="${2:-}" 29 | if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then 30 | echo >&2 "error: both $var and $fileVar are set (but are exclusive)" 31 | exit 1 32 | fi 33 | local val="$def" 34 | if [ "${!var:-}" ]; then 35 | val="${!var}" 36 | elif [ "${!fileVar:-}" ]; then 37 | val="$(< "${!fileVar}")" 38 | fi 39 | export "$var"="$val" 40 | unset "$fileVar" 41 | } 42 | 43 | _check_config() { 44 | toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" ) 45 | if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then 46 | cat >&2 <<-EOM 47 | 48 | ERROR: mysqld failed while attempting to check config 49 | command was: "${toRun[*]}" 50 | 51 | $errors 52 | EOM 53 | exit 1 54 | fi 55 | } 56 | 57 | # Fetch value from server config 58 | # We use mysqld --verbose --help instead of my_print_defaults because the 59 | # latter only show values present in config files, and not server defaults 60 | _get_config() { 61 | local conf="$1"; shift 62 | "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | grep "^$conf " | awk '{ print $2 }' 63 | } 64 | 65 | # allow the container to be started with `--user` 66 | if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then 67 | _check_config "$@" 68 | DATADIR="$(_get_config 'datadir' "$@")" 69 | mkdir -p "$DATADIR" 70 | chown -R mysql:mysql "$DATADIR" 71 | exec gosu mysql "$BASH_SOURCE" "$@" 72 | fi 73 | 74 | if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then 75 | # still need to check config, container may have started with --user 76 | _check_config "$@" 77 | # Get config 78 | DATADIR="$(_get_config 'datadir' "$@")" 79 | 80 | if [ ! -d "$DATADIR/mysql" ]; then 81 | # for backward compability support both MYSQL_ and MARIADB_ env vars 82 | file_env 'MYSQL_ROOT_PASSWORD' 83 | file_env 'MARIADB_ROOT_PASSWORD' 84 | MARIADB_ROOT_PASSWORD="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}" 85 | MARIADB_ALLOW_EMPTY_PASSWORD="${MARIADB_ALLOW_EMPTY_PASSWORD:-$MYSQL_ALLOW_EMPTY_PASSWORD}" 86 | MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-$MYSQL_RANDOM_ROOT_PASSWORD}" 87 | if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 88 | echo >&2 'error: database is uninitialized and password option is not specified ' 89 | echo >&2 ' You need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' 90 | exit 1 91 | fi 92 | 93 | mkdir -p "$DATADIR" 94 | 95 | echo 'Initializing database' 96 | # "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here) 97 | mysql_install_db --auth-root-socket-user=mysql --datadir="$DATADIR" --rpm "${@:2}" 98 | echo 'Database initialized' 99 | 100 | SOCKET="$(_get_config 'socket' "$@")" 101 | "$@" --skip-networking --socket="${SOCKET}" & 102 | pid="$!" 103 | 104 | mysql=( mysql --protocol=socket -umysql -hlocalhost --socket="${SOCKET}" ) 105 | 106 | for i in {30..0}; do 107 | if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then 108 | break 109 | fi 110 | echo 'MySQL init process in progress...' 111 | sleep 1 112 | done 113 | if [ "$i" = 0 ]; then 114 | echo >&2 'MySQL init process failed.' 115 | exit 1 116 | fi 117 | 118 | if [ -z "${MARIADB_INITDB_SKIP_TZINFO:-$MYSQL_INITDB_SKIP_TZINFO}" ]; then 119 | # sed is for https://bugs.mysql.com/bug.php?id=20545 120 | mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql 121 | fi 122 | 123 | if [ ! -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 124 | # we have to filter characters like ' and \ that will terminate the sql query or don't count 125 | # as special characters to keep the enterprise server password policy in mind. 126 | MARIADB_ROOT_PASSWORD="'" 127 | while [[ $MARIADB_ROOT_PASSWORD == *"'"* ]] || [[ $MARIADB_ROOT_PASSWORD == *"\\"* ]]; do 128 | export MARIADB_ROOT_PASSWORD="$(pwgen -1 32 -y)" 129 | done 130 | echo "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" 131 | fi 132 | 133 | 134 | rootCreate= 135 | # default root to listen for connections from anywhere 136 | file_env 'MYSQL_ROOT_HOST' 137 | file_env 'MARIADB_ROOT_HOST' '%' 138 | MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-$MYSQL_ROOT_HOST}" 139 | if [ ! -z "$MARIADB_ROOT_HOST" -a "$MARIADB_ROOT_HOST" != 'localhost' ]; then 140 | # no, we don't care if read finds a terminating character in this heredoc 141 | # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 142 | read -r -d '' rootCreate <<-EOSQL || true 143 | CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ; 144 | GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; 145 | EOSQL 146 | fi 147 | 148 | "${mysql[@]}" <<-EOSQL 149 | -- What's done in this file shouldn't be replicated 150 | -- or products like mysql-fabric won't work 151 | SET @@SESSION.SQL_LOG_BIN=0; 152 | 153 | DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root', 'mysql') OR host NOT IN ('localhost') ; 154 | SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ; 155 | GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; 156 | ${rootCreate} 157 | DROP DATABASE IF EXISTS test ; 158 | FLUSH PRIVILEGES ; 159 | EOSQL 160 | 161 | if [ ! -z "$MARIADB_ROOT_PASSWORD" ]; then 162 | mysql+=( -p"${MARIADB_ROOT_PASSWORD}" ) 163 | fi 164 | 165 | file_env 'MYSQL_DATABASE' 166 | file_env 'MARIADB_DATABASE' 167 | MARIADB_DATABASE="${MARIADB_DATABASE:-$MYSQL_DATABASE}" 168 | if [ "$MARIADB_DATABASE" ]; then 169 | echo "CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\` ;" | "${mysql[@]}" 170 | mysql+=( "$MARIADB_DATABASE" ) 171 | fi 172 | 173 | file_env 'MYSQL_USER' 174 | file_env 'MARIADB_USER' 175 | MARIADB_USER="${MARIADB_USER:-$MYSQL_USER}" 176 | file_env 'MYSQL_PASSWORD' 177 | file_env 'MARIADB_PASSWORD' 178 | MARIADB_PASSWORD="${MARIADB_PASSWORD:-$MYSQL_PASSWORD}" 179 | if [ "$MARIADB_USER" -a "$MARIADB_PASSWORD" ]; then 180 | echo "CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;" | "${mysql[@]}" 181 | 182 | if [ "$MARIADB_DATABASE" ]; then 183 | echo "GRANT ALL ON \`$MARIADB_DATABASE\`.* TO '$MARIADB_USER'@'%' ;" | "${mysql[@]}" 184 | fi 185 | fi 186 | 187 | echo 188 | for f in /docker-entrypoint-initdb.d/*; do 189 | case "$f" in 190 | *.sh) echo "$0: running $f"; . "$f" ;; 191 | *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; 192 | *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; 193 | *) echo "$0: ignoring $f" ;; 194 | esac 195 | echo 196 | done 197 | 198 | if ! kill -s TERM "$pid" || ! wait "$pid"; then 199 | echo >&2 'MySQL init process failed.' 200 | exit 1 201 | fi 202 | 203 | echo 204 | echo 'MySQL init process done. Ready for start up.' 205 | echo 206 | fi 207 | fi 208 | 209 | exec "$@" 210 | -------------------------------------------------------------------------------- /10.4/version: -------------------------------------------------------------------------------- 1 | 10.4.10 2 | -------------------------------------------------------------------------------- /10.4/whitelist.yml: -------------------------------------------------------------------------------- 1 | generalwhitelist: #Approve CVE for any image 2 | CVE-2017-6055: XML 3 | CVE-2017-5586: OpenText 4 | images: 5 | ubuntu: #Apprive CVE only for ubuntu image, regardles of the version 6 | CVE-2017-5230: Java 7 | CVE-2017-5230: XSX 8 | alpine: 9 | CVE-2017-3261: SE 10 | CVE-2016-9840: zlib 11 | CVE-2016-9841: zlib 12 | CVE-2016-9842: zlib 13 | CVE-2016-9843: zlib -------------------------------------------------------------------------------- /Dockerfile.template: -------------------------------------------------------------------------------- 1 | # vim:set ft=dockerfile: 2 | FROM ubuntu:%%SUITE%% 3 | 4 | # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added 5 | RUN groupadd -r mysql && useradd -r -g mysql mysql 6 | 7 | # https://bugs.debian.org/830696 (apt uses gpgv by default in newer releases, rather than gpg) 8 | RUN set -ex; \ 9 | apt-get update; \ 10 | if ! which gpg; then \ 11 | apt-get install -y --no-install-recommends gnupg; \ 12 | fi; \ 13 | # Ubuntu includes "gnupg" (not "gnupg2", but still 2.x), but not dirmngr, and gnupg 2.x requires dirmngr 14 | # so, if we're not running gnupg 1.x, explicitly install dirmngr too 15 | if ! gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \ 16 | apt-get install -y --no-install-recommends dirmngr; \ 17 | fi; \ 18 | rm -rf /var/lib/apt/lists/* 19 | 20 | # add gosu for easy step-down from root 21 | ENV GOSU_VERSION 1.10 22 | RUN set -ex; \ 23 | \ 24 | fetchDeps=' \ 25 | ca-certificates \ 26 | wget \ 27 | '; \ 28 | apt-get update; \ 29 | apt-get install -y --no-install-recommends $fetchDeps; \ 30 | rm -rf /var/lib/apt/lists/*; \ 31 | \ 32 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 33 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 34 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 35 | \ 36 | # verify the signature 37 | export GNUPGHOME="$(mktemp -d)"; \ 38 | gpg --keyserver keyserver.ubuntu.com --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 39 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 40 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 41 | rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 42 | \ 43 | chmod +x /usr/local/bin/gosu; \ 44 | # verify that the binary works 45 | gosu nobody true; \ 46 | \ 47 | apt-get purge -y --auto-remove $fetchDeps 48 | 49 | RUN mkdir /docker-entrypoint-initdb.d 50 | 51 | # install "pwgen" for randomizing passwords 52 | # install "tzdata" for /usr/share/zoneinfo/ 53 | RUN apt-get update && apt-get install -y --no-install-recommends \ 54 | apt-transport-https ca-certificates \ 55 | pwgen \ 56 | tzdata \ 57 | && rm -rf /var/lib/apt/lists/* 58 | 59 | ENV GPG_KEYS \ 60 | # Key fingerprint = 1993 69E5 404B D5FC 7D2F E43B CBCB 082A 1BB9 43DB 61 | # MariaDB Package Signing Key 62 | # for MariaDB 5.5 63 | 199369E5404BD5FC7D2FE43BCBCB082A1BB943DB \ 64 | # pub rsa4096 2016-03-30 [SC] 65 | # 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 66 | # uid [ unknown] MariaDB Signing Key 67 | # sub rsa4096 2016-03-30 [E] 68 | # for MariaDB 10+ 69 | 177F4010FE56CA3336300305F1656F24C74CD1D8 70 | 71 | RUN set -ex; \ 72 | export GNUPGHOME="$(mktemp -d)"; \ 73 | for key in $GPG_KEYS; do \ 74 | gpg --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ 75 | done; \ 76 | gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; \ 77 | command -v gpgconf > /dev/null && gpgconf --kill all || :; \ 78 | rm -r "$GNUPGHOME"; \ 79 | apt-key list 80 | 81 | # bashbrew-architectures:%%ARCHES%% 82 | ENV MARIADB_MAJOR %%MARIADB_MAJOR%% 83 | ENV MARIADB_VERSION %%MARIADB_VERSION%% 84 | 85 | RUN set -e;\ 86 | echo "deb http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_MAJOR/repo/ubuntu %%SUITE%% main" > /etc/apt/sources.list.d/mariadb.list; \ 87 | { \ 88 | echo 'Package: *'; \ 89 | echo 'Pin: release o=MariaDB'; \ 90 | echo 'Pin-Priority: 999'; \ 91 | } > /etc/apt/preferences.d/mariadb 92 | # add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies 93 | # libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed 94 | 95 | # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) 96 | # also, we set debconf keys to make APT a little quieter 97 | RUN set -ex; \ 98 | { \ 99 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password password 'unused'; \ 100 | echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password_again password 'unused'; \ 101 | } | debconf-set-selections; \ 102 | backupPackage='%%BACKUP_PACKAGE%%'; \ 103 | apt-get update; \ 104 | apt-get install -y \ 105 | "mariadb-server=$MARIADB_VERSION" \ 106 | $backupPackage \ 107 | socat \ 108 | ; \ 109 | rm -rf /var/lib/apt/lists/*; \ 110 | # comment out any "user" entires in the MySQL config ("docker-entrypoint.sh" or "--user" will handle user switching) 111 | sed -ri 's/^user\s/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/*; \ 112 | # purge and re-create /var/lib/mysql with appropriate ownership 113 | rm -rf /var/lib/mysql; \ 114 | mkdir -p /var/lib/mysql /var/run/mysqld; \ 115 | chown -R mysql:mysql /var/lib/mysql /var/run/mysqld; \ 116 | # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime 117 | chmod 777 /var/run/mysqld; \ 118 | # comment out a few problematic configuration values 119 | find /etc/mysql/ -name '*.cnf' -print0 \ 120 | | xargs -0 grep -lZE '^(bind-address|log)' \ 121 | | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/'; \ 122 | # don't reverse lookup hostnames, they are usually another container 123 | echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf 124 | 125 | VOLUME /var/lib/mysql 126 | 127 | COPY docker-entrypoint.sh /usr/local/bin/ 128 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat 129 | ENTRYPOINT ["docker-entrypoint.sh"] 130 | 131 | EXPOSE 3306 132 | CMD ["mysqld"] 133 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MariaDB Server Docker 2 | 3 | ## Maintained by: [MariaDB](https://mariadb.com/) 4 | 5 | This is the Git repo of docker images for MariaDB Server, [mariadb-server-docker](https://hub.docker.com/r/mariadb/server) 6 | 7 | --- 8 | 9 | - [Travis CI: 10 | ![build status badge](https://img.shields.io/travis/mariadb-corporation/mariadb-server-docker/master.svg)](https://travis-ci.org/mariadb-corporation/mariadb-server-docker/branches) 11 | 12 | --- 13 | 14 | ### Installation 15 | 16 | Include the the version number as a docker tag. 17 | 18 | To pull MariaDB Server version 10.5 run the following command: 19 | 20 | ```bash 21 | docker pull mariadb/server:10.5 22 | ``` 23 | 24 | To run MariaDB Server version 10.5 run the following command: 25 | 26 | ```bash 27 | docker run -d --name maria -eMARIADB_ROOT_PASSWORD=mypassword mariadb/server:10.5 28 | ``` 29 | 30 | ### Configuration 31 | 32 | The following environment variables can be utilized to configure behavior (one of the first three must be specified): 33 | 34 | - MARIADB_ROOT_PASSWORD : specify the password for the root user 35 | - MARIADB_ALLOW_EMPTY_PASSWORD : allow empty password for the root user 36 | - MARIADB_RANDOM_ROOT_PASSWORD : generate a random password for the root user (output to logs) 37 | - MARIADB_INITDB_SKIP_TZINFO : skip timezone setup 38 | - MARIADB_ROOT_HOST : host for root user, defaults to '%' 39 | - MARIADB_DATABASE : create a database with this name 40 | - MARIADB_USER : create a user with this name, with all privileges on MARIADB_DATABASE if specified 41 | - MARIADB_PASSWORD : password for above user 42 | 43 | For backward compatibility, environment variables starting MYSQL_ rather than MARIADB_ will also work. 44 | 45 | Custom scripts can be mapped as a host volume to /docker-entrypoint-initdb.d for execution post initialization in named / directory order. The following extensions are supported: 46 | 47 | - .sh : shell script 48 | - .sql : sql script 49 | - .sql.gz : gzip compressed sql script 50 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | shopt -s nullglob 4 | 5 | # if command starts with an option, prepend mysqld 6 | if [ "${1:0:1}" = '-' ]; then 7 | set -- mysqld "$@" 8 | fi 9 | 10 | # skip setup if they want an option that stops mysqld 11 | wantHelp= 12 | for arg; do 13 | case "$arg" in 14 | -'?'|--help|--print-defaults|-V|--version) 15 | wantHelp=1 16 | break 17 | ;; 18 | esac 19 | done 20 | 21 | # usage: file_env VAR [DEFAULT] 22 | # ie: file_env 'XYZ_DB_PASSWORD' 'example' 23 | # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of 24 | # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) 25 | file_env() { 26 | local var="$1" 27 | local fileVar="${var}_FILE" 28 | local def="${2:-}" 29 | if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then 30 | echo >&2 "error: both $var and $fileVar are set (but are exclusive)" 31 | exit 1 32 | fi 33 | local val="$def" 34 | if [ "${!var:-}" ]; then 35 | val="${!var}" 36 | elif [ "${!fileVar:-}" ]; then 37 | val="$(< "${!fileVar}")" 38 | fi 39 | export "$var"="$val" 40 | unset "$fileVar" 41 | } 42 | 43 | _check_config() { 44 | toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" ) 45 | if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then 46 | cat >&2 <<-EOM 47 | 48 | ERROR: mysqld failed while attempting to check config 49 | command was: "${toRun[*]}" 50 | 51 | $errors 52 | EOM 53 | exit 1 54 | fi 55 | } 56 | 57 | # Fetch value from server config 58 | # We use mysqld --verbose --help instead of my_print_defaults because the 59 | # latter only show values present in config files, and not server defaults 60 | _get_config() { 61 | local conf="$1"; shift 62 | "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }' 63 | } 64 | 65 | # allow the container to be started with `--user` 66 | if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then 67 | _check_config "$@" 68 | DATADIR="$(_get_config 'datadir' "$@")" 69 | mkdir -p "$DATADIR" 70 | chown -R mysql:mysql "$DATADIR" 71 | exec gosu mysql "$BASH_SOURCE" "$@" 72 | fi 73 | 74 | if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then 75 | # still need to check config, container may have started with --user 76 | _check_config "$@" 77 | # Get config 78 | DATADIR="$(_get_config 'datadir' "$@")" 79 | 80 | if [ ! -d "$DATADIR/mysql" ]; then 81 | # for backward compability support both MYSQL_ and MARIADB_ env vars 82 | file_env 'MYSQL_ROOT_PASSWORD' 83 | file_env 'MARIADB_ROOT_PASSWORD' 84 | MARIADB_ROOT_PASSWORD="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}" 85 | MARIADB_ALLOW_EMPTY_PASSWORD="${MARIADB_ALLOW_EMPTY_PASSWORD:-$MYSQL_ALLOW_EMPTY_PASSWORD}" 86 | MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-$MYSQL_RANDOM_ROOT_PASSWORD}" 87 | if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 88 | echo >&2 'error: database is uninitialized and password option is not specified ' 89 | echo >&2 ' You need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' 90 | exit 1 91 | fi 92 | 93 | mkdir -p "$DATADIR" 94 | 95 | echo 'Initializing database' 96 | # "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here) 97 | mysql_install_db --datadir="$DATADIR" --rpm "${@:2}" 98 | echo 'Database initialized' 99 | 100 | SOCKET="$(_get_config 'socket' "$@")" 101 | "$@" --skip-networking --socket="${SOCKET}" & 102 | pid="$!" 103 | 104 | mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" ) 105 | 106 | for i in {30..0}; do 107 | if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then 108 | break 109 | fi 110 | echo 'MySQL init process in progress...' 111 | sleep 1 112 | done 113 | if [ "$i" = 0 ]; then 114 | echo >&2 'MySQL init process failed.' 115 | exit 1 116 | fi 117 | 118 | if [ -z "${MARIADB_INITDB_SKIP_TZINFO:-$MYSQL_INITDB_SKIP_TZINFO}" ]; then 119 | # sed is for https://bugs.mysql.com/bug.php?id=20545 120 | mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql 121 | fi 122 | 123 | if [ ! -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then 124 | # we have to filter characters like ' and \ that will terminate the sql query or don't count 125 | # as special characters to keep the enterprise server password policy in mind. 126 | MARIADB_ROOT_PASSWORD="'" 127 | while [[ $MARIADB_ROOT_PASSWORD == *"'"* ]] || [[ $MARIADB_ROOT_PASSWORD == *"\\"* ]]; do 128 | export MARIADB_ROOT_PASSWORD="$(pwgen -1 32 -y)" 129 | done 130 | echo "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" 131 | fi 132 | 133 | 134 | rootCreate= 135 | # default root to listen for connections from anywhere 136 | file_env 'MYSQL_ROOT_HOST' 137 | file_env 'MARIADB_ROOT_HOST' '%' 138 | MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-$MYSQL_ROOT_HOST}" 139 | if [ ! -z "$MARIADB_ROOT_HOST" -a "$MARIADB_ROOT_HOST" != 'localhost' ]; then 140 | # no, we don't care if read finds a terminating character in this heredoc 141 | # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 142 | read -r -d '' rootCreate <<-EOSQL || true 143 | CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ; 144 | GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; 145 | EOSQL 146 | fi 147 | 148 | "${mysql[@]}" <<-EOSQL 149 | -- What's done in this file shouldn't be replicated 150 | -- or products like mysql-fabric won't work 151 | SET @@SESSION.SQL_LOG_BIN=0; 152 | 153 | DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ; 154 | SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ; 155 | GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; 156 | ${rootCreate} 157 | DROP DATABASE IF EXISTS test ; 158 | FLUSH PRIVILEGES ; 159 | EOSQL 160 | 161 | if [ ! -z "$MARIADB_ROOT_PASSWORD" ]; then 162 | mysql+=( -p"${MARIADB_ROOT_PASSWORD}" ) 163 | fi 164 | 165 | file_env 'MYSQL_DATABASE' 166 | file_env 'MARIADB_DATABASE' 167 | MARIADB_DATABASE="${MARIADB_DATABASE:-$MYSQL_DATABASE}" 168 | if [ "$MARIADB_DATABASE" ]; then 169 | echo "CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\` ;" | "${mysql[@]}" 170 | mysql+=( "$MARIADB_DATABASE" ) 171 | fi 172 | 173 | file_env 'MYSQL_USER' 174 | file_env 'MARIADB_USER' 175 | MARIADB_USER="${MARIADB_USER:-$MYSQL_USER}" 176 | file_env 'MYSQL_PASSWORD' 177 | file_env 'MARIADB_PASSWORD' 178 | MARIADB_PASSWORD="${MARIADB_PASSWORD:-$MYSQL_PASSWORD}" 179 | if [ "$MARIADB_USER" -a "$MARIADB_PASSWORD" ]; then 180 | echo "CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;" | "${mysql[@]}" 181 | 182 | if [ "$MARIADB_DATABASE" ]; then 183 | echo "GRANT ALL ON \`$MARIADB_DATABASE\`.* TO '$MARIADB_USER'@'%' ;" | "${mysql[@]}" 184 | fi 185 | fi 186 | 187 | echo 188 | for f in /docker-entrypoint-initdb.d/*; do 189 | case "$f" in 190 | *.sh) echo "$0: running $f"; . "$f" ;; 191 | *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; 192 | *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; 193 | *) echo "$0: ignoring $f" ;; 194 | esac 195 | echo 196 | done 197 | 198 | if ! kill -s TERM "$pid" || ! wait "$pid"; then 199 | echo >&2 'MySQL init process failed.' 200 | exit 1 201 | fi 202 | 203 | echo 204 | echo 'MySQL init process done. Ready for start up.' 205 | echo 206 | fi 207 | fi 208 | 209 | exec "$@" 210 | -------------------------------------------------------------------------------- /generate-stackbrew-library.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | declare -A aliases=( 5 | [10.4]='10 latest' 6 | [5.5]='5' 7 | ) 8 | 9 | self="$(basename "$BASH_SOURCE")" 10 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 11 | 12 | source '.architectures-lib' 13 | 14 | versions=( */ ) 15 | versions=( "${versions[@]%/}" ) 16 | 17 | # sort version numbers with highest first 18 | IFS=$'\n'; versions=( $(echo "${versions[*]}" | sort -rV) ); unset IFS 19 | 20 | # get the most recent commit which modified any of "$@" 21 | fileCommit() { 22 | git log -1 --format='format:%H' HEAD -- "$@" 23 | } 24 | 25 | # get the most recent commit which modified "$1/Dockerfile" or any file COPY'd from "$1/Dockerfile" 26 | dirCommit() { 27 | local dir="$1"; shift 28 | ( 29 | cd "$dir" 30 | fileCommit \ 31 | Dockerfile \ 32 | $(git show HEAD:./Dockerfile | awk ' 33 | toupper($1) == "COPY" { 34 | for (i = 2; i < NF; i++) { 35 | print $i 36 | } 37 | } 38 | ') 39 | ) 40 | } 41 | 42 | cat <<-EOH 43 | # this file is generated via https://github.com/mariadb-corporation/mariadb-docker-images/$(fileCommit "$self")/$self 44 | 45 | Maintainers: Tianon Gravi (@tianon), 46 | Joseph Ferguson (@yosifkit) 47 | GitRepo: https://github.com/mariadb-corporation/mariadb-docker-images.git 48 | EOH 49 | 50 | # prints "$2$1$3$1...$N" 51 | join() { 52 | local sep="$1"; shift 53 | local out; printf -v out "${sep//%/%%}%s" "$@" 54 | echo "${out#$sep}" 55 | } 56 | 57 | for version in "${versions[@]}"; do 58 | commit="$(dirCommit "$version")" 59 | 60 | fullVersion="$(git show "$commit":"$version/Dockerfile" | awk '$1 == "ENV" && $2 == "MARIADB_VERSION" { gsub(/^([0-9]+:)|[+].*$/, "", $3); print $3; exit }')" 61 | 62 | versionAliases=( $fullVersion ) 63 | if [ "$version" != "$fullVersion" ]; then 64 | versionAliases+=( $version ) 65 | fi 66 | versionAliases+=( ${aliases[$version]:-} ) 67 | 68 | from="$(git show "$commit":"$version/Dockerfile" | awk '$1 == "FROM" { print $2; exit }')" 69 | distro="${from%%:*}" # "debian", "ubuntu" 70 | suite="${from#$distro:}" # "jessie-slim", "xenial" 71 | suite="${suite%-slim}" # "jessie", "xenial" 72 | 73 | variantAliases=( "${versionAliases[@]/%/-$suite}" ) 74 | versionAliases=( "${variantAliases[@]//latest-/}" "${versionAliases[@]}" ) 75 | 76 | echo 77 | cat <<-EOE 78 | Tags: $(join ', ' "${versionAliases[@]}") 79 | Architectures: $(join ', ' $(versionArches $version)) 80 | GitCommit: $commit 81 | Directory: $version 82 | EOE 83 | done 84 | -------------------------------------------------------------------------------- /tx_sandbox/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mariadb/server:10.3 as builder 2 | ARG root_pass=secret_pass 3 | ENV MYSQL_ROOT_PASSWORD=$root_pass 4 | 5 | ARG user=sandbox 6 | ENV MYSQL_USER=$user 7 | 8 | ARG pass=highlyillogical 9 | ENV MYSQL_PASSWORD=$pass 10 | 11 | ARG db=bookstore 12 | ENV MYSQL_DATABASE=$db 13 | 14 | RUN mkdir -p /tmp/bookstore && \ 15 | mkdir -p /tmp/bookstore/csv && \ 16 | apt-get update && \ 17 | apt-get -y install curl && \ 18 | curl https://downloads.mariadb.com/sample-data/books5000light2.tar --output /tmp/bookstore/csv/bookstore.tar && \ 19 | tar -vxf /tmp/bookstore/csv/bookstore.tar --directory /tmp/bookstore/csv/ && \ 20 | cd /tmp/bookstore/csv/ && \ 21 | gunzip -v *.gz && \ 22 | sed -i 's/%CSV%/\/tmp\/bookstore\/csv\//g' /tmp/bookstore/csv/*.sql && \ 23 | sed -i 's/%DB%/bookstore/g' /tmp/bookstore/csv/*.sql 24 | 25 | FROM mariadb/server:10.3 26 | 27 | ARG root_pass=secret_pass 28 | ENV MYSQL_ROOT_PASSWORD=$root_pass 29 | 30 | ARG user=sandbox 31 | ENV MYSQL_USER=$user 32 | 33 | ARG pass=highlyillogical 34 | ENV MYSQL_PASSWORD=$pass 35 | 36 | ARG db=bookstore 37 | ENV MYSQL_DATABASE=$db 38 | 39 | COPY --from=builder /tmp/bookstore/csv /tmp/bookstore/csv/ 40 | RUN ln -s /tmp/bookstore/csv/01_load_tx_init.sql /docker-entrypoint-initdb.d &&\ 41 | ln -s /tmp/bookstore/csv/02_load_tx_ldi.sql /docker-entrypoint-initdb.d &&\ 42 | ln -s /tmp/bookstore/csv/03_load_tx_verify.sql /docker-entrypoint-initdb.d -------------------------------------------------------------------------------- /tx_sandbox/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use root/example as user/password credentials 2 | version: '3.1' 3 | 4 | services: 5 | 6 | server: 7 | hostname: server 8 | build: . 9 | ports: 10 | - "3306:3306" 11 | environment: 12 | MYSQL_RANDOM_ROOT_PASSWORD: 1 13 | #MYSQL_ROOT_PASSWORD: "secret_pass" 14 | MYSQL_USER: "sandbox" 15 | MYSQL_PASSWORD: "highlyillogical" 16 | MYSQL_DATABASE: "bookstore" 17 | adminer: 18 | hostname: adminer 19 | image: adminer 20 | restart: always 21 | ports: 22 | - 8080:8080 -------------------------------------------------------------------------------- /tx_sandbox/labs.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | * [Bookstore TX Sandbox](#Bookstore-tx-sandbox) 6 | * [Overview](#overview) 7 | * [Online Bookstore Data](#online-Bookstore-data) 8 | * [System Info](#system-info) 9 | * [Labs](#labs) 10 | * [General](#general) 11 | * [Books](#Books) 12 | * [**Q:** How many Books do we sell?](#q-how-many-Books-do-we-sell) 13 | * [**Q:** Lets try to find out who is the youngest customer.](#q-lets-try-to-find-out-who-is-the-youngest-customer) 14 | * [**Q:** Is this the youngest customer ?](#q-is-this-the-youngest-customer) 15 | * [**Q:** We are trying to position our online Bookstore towards Fantasy and Sci-Fi theme, but we are also trying to provide good variety of Books as well.](#q-we-are-trying-to-position-our-online-Bookstore-towards-fantasy-and-sci-fi-theme-but-we-are-also-trying-to-provide-good-variety-of-Books-as-well) 16 | * [**Q:** Are we making good profit from our focus categories ?](#q-are-we-making-good-profit-from-our-focus-categories) 17 | * [**Q:** Do we provide enough variety ?](#q-do-we-provide-enough-variety) 18 | * [Customers](#Customers) 19 | * [**Q:** Who is our customer ?](#q-who-is-our-customer) 20 | * [**Q:** How many Customers are male and how many are female?](#q-how-many-Customers-are-male-and-how-many-are-female) 21 | * [**Q:** Query Top Buyers](#q-query-top-buyers) 22 | * [**Q:** But do the younger people read more than seniores ?](#q-but-do-the-younger-people-read-more-than-seniores) 23 | * [**Q:** What are the reading preferencess of our top customer?](#q-what-are-the-reading-preferencess-of-our-top-customer) 24 | 25 | 26 | 27 | ## Bookstore TX Sandbox 28 | 29 | ### Overview 30 | 31 | ### Online Bookstore Data 32 | 33 | This sandbox is based on procedural generated data representing data for a typical online bookstore. 34 | In the examples below we will try to answer the typical questions every business user has at some point when his business catch some speed. 35 | Like “How am I doing?”, “What can be improved?” etc. 36 | 37 | ### System Info 38 | 39 | The data is loaded in a MariaDB Server one of the most popular open source databases in the world. It is the default database in leading Linux distributions – Arch Linux, CentOS, Debian, Fedora, Manjaro, openSUSE, Red Hat Enterprise Linux and SUSE Linux Enterprise, to name a few. 40 | 41 | ## Labs 42 | ### General 43 | Your database is prepared and the sandbox data is loaded. Lets start by choosing the database we want to work on. In this case **Bookstore** database. 44 | 45 | ```sql 46 | USE bookstore; 47 | ``` 48 | 49 | We can check what tables we have. 50 | ```sql 51 | SHOW TABLES; 52 | ``` 53 | 54 | Lets see the size of the data 55 | ```sql 56 | SELECT 'Addresses' as TableName, count(*) FROM `Addresses` UNION ALL 57 | SELECT 'Books' as TableName, count(*) FROM `Books` UNION ALL 58 | SELECT 'Cards' as TableName, count(*) FROM `Cards` UNION ALL 59 | SELECT 'Covers' as TableName, count(*) FROM `Covers` UNION ALL 60 | SELECT 'Customers' as TableName, count(*) FROM `Customers` UNION ALL 61 | SELECT 'Emails' as TableName, count(*) FROM `Emails` UNION ALL 62 | SELECT 'LoyaltyPoints' as TableName, count(*) FROM `LoyaltyPoints` UNION ALL 63 | SELECT 'MaritalStatuses' as TableName, count(*) FROM `MaritalStatuses` UNION ALL 64 | SELECT 'Phones' as TableName, count(*) FROM `Phones` UNION ALL 65 | SELECT 'TransactionTypes' as TableName, count(*) FROM `TransactionTypes` UNION ALL 66 | SELECT 'Transactions' as TableName, count(*) FROM `Transactions`; 67 | ``` 68 | 69 | ``` 70 | +------------------+----------+ 71 | | TableName | count(*) | 72 | +------------------+----------+ 73 | | Addresses | 326952 | 74 | | Books | 5000 | 75 | | Cards | 196810 | 76 | | Covers | 20 | 77 | | Customers | 245904 | 78 | | Emails | 314794 | 79 | | LoyaltyPoints | 126178 | 80 | | MaritalStatuses | 5 | 81 | | Phones | 297526 | 82 | | TransactionTypes | 3 | 83 | | Transactions | 1541044 | 84 | +------------------+----------+ 85 | ``` 86 | 87 | ### Books 88 | 89 | In this first part we will focus mainly on our main commodity - the Books. We want to know what we offer to our Customers and how can be improved. 90 | Lets start by answering our first question. 91 | #### **Q:** How many Books do we sell? 92 | ```sql 93 | SELECT COUNT(*) FROM bookstore.Books; 94 | ``` 95 | Total Books: 96 | ``` 97 | +----------+ 98 | | COUNT(*) | 99 | +----------+ 100 | | 5000 | 101 | +----------+ 102 | ``` 103 | 104 | This was easy question 5000. 105 | **!** You can experiment replacing the table name with **Customers**, **transactions** etc. 106 | 107 | #### **Q:** Lets try to find out who is the youngest customer. 108 | ```sql 109 | SELECT customer_nm,age FROM bookstore.Customers ORDER BY age LIMIT 1; 110 | ``` 111 | 112 | The result should be something like this: 113 | 114 | ``` 115 | +---------------+-----+ 116 | | customer_nm | age | 117 | +---------------+-----+ 118 | | Tiffany Green | 8 | 119 | +---------------+-----+ 120 | ``` 121 | 122 | #### **Q:** Is this the youngest customer ? 123 | 124 | ```sql 125 | SELECT count(*) FROM bookstore.Customers WHERE age=8; 126 | ``` 127 | 128 | The result should be somthing like this: 129 | 130 | ``` 131 | +----------+ 132 | | count(*) | 133 | +----------+ 134 | | 591 | 135 | +----------+ 136 | ``` 137 | Apparantly we have many Customers at that age. 138 | 139 | Lets try something harder. 140 | 141 | We are trying to position our online Bookstore towards Fantasy and Sci-Fi theme, but we are also trying to provide good variety of Books as well.Did we provide achieve those goals? 142 | 143 | #### **Q:** Do we provide enough variety ? 144 | ```sql 145 | SELECT category, COUNT(*) as Books FROM bookstore.Books GROUP BY category; 146 | ``` 147 | The **GROUP BY** statement instructs the database to grup the results by the first column 148 | The Result: 149 | ``` 150 | +-------------------+-------+ 151 | | category | Books | 152 | +-------------------+-------+ 153 | | Children Classics | 650 | 154 | | Classics | 168 | 155 | | Drama | 551 | 156 | | Fantasy | 928 | 157 | | Horror | 387 | 158 | | Humor | 306 | 159 | | Mystery | 453 | 160 | | Non-fiction | 34 | 161 | | Romance | 731 | 162 | | Sci-fi | 792 | 163 | +-------------------+-------+ 164 | ``` 165 | We have the most tiples in our focus categories Fantasy: 928 and Sci-Fi: 792 we provide good variety of books in our focus categories. 166 | 167 | **!** You can try to use the **GROUP BY** with index instead of the column name for the same result. 168 | 169 | ```sql 170 | SELECT category, COUNT(*) as Books FROM bookstore.Books GROUP BY 1; 171 | ``` 172 | 173 | Will yeald the same result. 174 | +-------------------+-------+ 175 | | category | Books | 176 | +-------------------+-------+ 177 | | Children Classics | 650 | 178 | | Classics | 168 | 179 | | Drama | 551 | 180 | | Fantasy | 928 | 181 | | Horror | 387 | 182 | | Humor | 306 | 183 | | Mystery | 453 | 184 | | Non-fiction | 34 | 185 | | Romance | 731 | 186 | | Sci-fi | 792 | 187 | +-------------------+-------+ 188 | 189 | 190 | Now lets try something more tangable. Money. 191 | 192 | #### **Q:** Are we making good profit from our focus categories ? 193 | Lets asume for a seciond that the higher the price the more profit we make. 194 | 195 | ```sql 196 | SELECT category, AVG(cover_price) as projected_profitabiliti FROM bookstore.Books GROUP BY 1; 197 | ``` 198 | As you can see the the **COUNT(*)** is replaced by **AVG(cover_price)** this will return the average cover price grouped by first column i.e. the book category. 199 | 200 | ``` 201 | +-------------------+------------------------+ 202 | | category | projected_profitabilit | 203 | +-------------------+------------------------+ 204 | | Horror | 11.111320 | 205 | | Fantasy | 23.299910 | 206 | | Drama | 13.310811 | 207 | | Classics | 22.914340 | 208 | | Sci-fi | 18.757123 | 209 | | Children Classics | 9.463908 | 210 | | Mystery | 14.242681 | 211 | | Romance | 9.781252 | 212 | | Non-fiction | 9.983043 | 213 | | Humor | 5.393195 | 214 | +-------------------+------------------------+ 215 | ``` 216 | 217 | This show the average projected_profitabiliti of the books in each categories. The precision is in thousends of cents which is too much for practical use. 218 | 219 | Lets format the **projected_profitability** in currency format. Two digits after decimal separator. 220 | ```sql 221 | SELECT category, FORMAT(AVG(cover_price),2) as projected_profitabilit FROM bookstore.Books GROUP BY 1; 222 | ``` 223 | +-------------------+------------------------+ 224 | | category | projected_profitabilit | 225 | +-------------------+------------------------+ 226 | | Children Classics | 9.25 | 227 | | Classics | 22.77 | 228 | | Drama | 13.04 | 229 | | Fantasy | 23.32 | 230 | | Horror | 11.38 | 231 | | Humor | 5.25 | 232 | | Mystery | 14.50 | 233 | | Non-fiction | 9.02 | 234 | | Romance | 9.82 | 235 | | Sci-fi | 18.78 | 236 | +-------------------+------------------------+ 237 | the result is more readable than before. 238 | 239 | It looks like Fantasy and Sci-Fi Books have also good potential for profit $23.32 and $18.78, if they sell. 240 | There is something intersting the classics have a high potential maybe we should target selling more of those with a propper promotion. 241 | 242 | As a result from this quick anlysis we already can make a decision for improvement in the future. 243 | 244 | Let try more complex queries in the next section. 245 | 246 | ### Customers 247 | 248 | In this section we will try to identify who our Customers are ? what are their preferences? how likely is for them to buy somethin out of their main focus. 249 | 250 | Lets try to make a demographical profile of our Customers. 251 | 252 | The Customers are stored in **bookstore.Customers** we should find more about our most important asset. 253 | #### **Q:** How many customers do we have? 254 | ```sql 255 | select count(*) from bookstore.Customers LIMIT 10; 256 | ``` 257 | ``` 258 | +----------+ 259 | | count(*) | 260 | +----------+ 261 | | 245904 | 262 | +----------+ 263 | ``` 264 | We are lucky our busines trives. 265 | 266 | #### **Q:** Who is our customer ? 267 | 268 | ```sql 269 | select * from bookstore.Customers LIMIT 10; 270 | ``` 271 | The query will give use what we have in this table The *LIMIT 10* statement will limit the results to 10, we only want to see a sample of the sata not the all 1.4 milion Customers. 272 | ``` 273 | +--------------------+-------------+----------------------------+-----+-----+-------+ 274 | | customer_nm | customer_id | customer_username_nm | sex | age | ms_id | 275 | +--------------------+-------------+----------------------------+-----+-----+-------+ 276 | | Donald Anthony PhD | 1 | natasha77@hutmail.con | M | 23 | 1 | 277 | | Wayne Rasmussen | 2 | mistygilbert@hutmail.con | M | 21 | 1 | 278 | | Kathleen Webb | 3 | nthompson@yupee.con | F | 32 | 2 | 279 | | Meghan Webb | 4 | sanchezkristen@hutmail.con | F | 25 | 1 | 280 | | Courtney Alexander | 5 | kathrynfrazier@shelf.con | F | 57 | 1 | 281 | | Nicole Montoya | 6 | rothjared@hutmail.con | F | 39 | 2 | 282 | | Rebecca Wilkinson | 7 | thomas80@hutmail.con | F | 76 | 2 | 283 | | Manuel Flowers | 8 | xprice@hutmail.con | M | 32 | 2 | 284 | | Lisa Bennett | 9 | kylesmith@gamail.con | F | 71 | 3 | 285 | | Erica Miller | 10 | jessicageorge@yupee.con | F | 52 | 5 | 286 | +--------------------+-------------+----------------------------+-----+-----+-------+ 287 | ``` 288 | This is random sample of 10 of our customers. 289 | 290 | It looks like we have the name, the sex, the age in this table. Those demographics we understand right away. There is also a column ms_id which is a bit criptic. This column is a key to another table. This key is sometimes called *FREIGN ID* or*FREIGN KEY*. 291 | To get the actual text that stands behind this key we need to conect those tables. This is done by the **JOIN** statement. 292 | ```sql 293 | SELECT * from bookstore.Customers JOIN bookstore.MaritalStatuses ON bookstore.Customers.ms_id = bookstore.MaritalStatuses.ms_id LIMIT 10; 294 | ``` 295 | 296 | ``` 297 | +--------------------+-------------+----------------------------+-----+-----+-------+-------+---------------+ 298 | | customer_nm | customer_id | customer_username_nm | sex | age | ms_id | ms_id | ms_type | 299 | +--------------------+-------------+----------------------------+-----+-----+-------+-------+---------------+ 300 | | Donald Anthony PhD | 1 | natasha77@hutmail.con | M | 23 | 1 | 1 | Never married | 301 | | Wayne Rasmussen | 2 | mistygilbert@hutmail.con | M | 21 | 1 | 1 | Never married | 302 | | Kathleen Webb | 3 | nthompson@yupee.con | F | 32 | 2 | 2 | Married | 303 | | Meghan Webb | 4 | sanchezkristen@hutmail.con | F | 25 | 1 | 1 | Never married | 304 | | Courtney Alexander | 5 | kathrynfrazier@shelf.con | F | 57 | 1 | 1 | Never married | 305 | | Nicole Montoya | 6 | rothjared@hutmail.con | F | 39 | 2 | 2 | Married | 306 | | Rebecca Wilkinson | 7 | thomas80@hutmail.con | F | 76 | 2 | 2 | Married | 307 | | Manuel Flowers | 8 | xprice@hutmail.con | M | 32 | 2 | 2 | Married | 308 | | Lisa Bennett | 9 | kylesmith@gamail.con | F | 71 | 3 | 3 | Widow | 309 | | Erica Miller | 10 | jessicageorge@yupee.con | F | 52 | 5 | 5 | Divorced | 310 | +--------------------+-------------+----------------------------+-----+-----+-------+-------+---------------+ 311 | ``` 312 | It is clearly visible that we cannected those two tables by the column **ms_id**, now we can exclude those columns because they have no meaning for us. 313 | In addition we had to write the full name of those columns **bookstore.Customers.ms_id** which becomes quite long. Especialy when we have to specify all the names of all the columns we want. 314 | 315 | In the next query we will remove those key columns. 316 | ```sql 317 | SELECT 318 | bookstore.Customers.customer_nm, 319 | bookstore.Customers.customer_id, 320 | bookstore.Customers.customer_username_nm, 321 | bookstore.Customers.sex, 322 | bookstore.Customers.age, 323 | bookstore.MaritalStatuses.ms_type 324 | from bookstore.Customers 325 | JOIN bookstore.MaritalStatuses 326 | ON bookstore.Customers.ms_id = bookstore.MaritalStatuses.ms_id 327 | LIMIT 10; 328 | ``` 329 | ``` 330 | +--------------------+-------------+----------------------------+-----+-----+---------------+ 331 | | customer_nm | customer_id | customer_username_nm | sex | age | ms_type | 332 | +--------------------+-------------+----------------------------+-----+-----+---------------+ 333 | | Donald Anthony PhD | 1 | natasha77@hutmail.con | M | 23 | Never married | 334 | | Wayne Rasmussen | 2 | mistygilbert@hutmail.con | M | 21 | Never married | 335 | | Kathleen Webb | 3 | nthompson@yupee.con | F | 32 | Married | 336 | | Meghan Webb | 4 | sanchezkristen@hutmail.con | F | 25 | Never married | 337 | | Courtney Alexander | 5 | kathrynfrazier@shelf.con | F | 57 | Never married | 338 | | Nicole Montoya | 6 | rothjared@hutmail.con | F | 39 | Married | 339 | | Rebecca Wilkinson | 7 | thomas80@hutmail.con | F | 76 | Married | 340 | | Manuel Flowers | 8 | xprice@hutmail.con | M | 32 | Married | 341 | | Lisa Bennett | 9 | kylesmith@gamail.con | F | 71 | Widow | 342 | | Erica Miller | 10 | jessicageorge@yupee.con | F | 52 | Divorced | 343 | +--------------------+-------------+----------------------------+-----+-----+---------------+ 344 | ``` 345 | 346 | 347 | To simplify the query we can type only: 348 | ```sql 349 | SELECT 350 | cust.customer_nm, 351 | cust.customer_id, 352 | cust.customer_username_nm, 353 | cust.sex, 354 | cust.age, 355 | ms.ms_type 356 | from bookstore.Customers cust 357 | JOIN bookstore.MaritalStatuses ms 358 | ON cust.ms_id = ms.ms_id 359 | LIMIT 10; 360 | ``` 361 | This simplified query will return identical result. The short names **cust** and **ms** in the above query are called aliases and replace reference to **bookstore.Customers** and **bookstore.MaritalStatuses** 362 | 363 | ``` 364 | +--------------------+-------------+--------------------------+-----+-----+---------------+ 365 | | customer_nm | customer_id | customer_username_nm | sex | age | ms_type | 366 | +--------------------+-------------+--------------------------+-----+-----+---------------+ 367 | | Patty Gonzales | 1297169 | bodonnell@gamail.con | F | 33 | Never married | 368 | | Rebekah Myers | 1297170 | trevinomatthew@yupee.con | F | 35 | Married | 369 | | Katherine Castillo | 1297171 | mccannlisa@gamail.con | F | 99 | Widow | 370 | | Michael Hamilton | 1297172 | rpowell@gamail.con | M | 20 | Never married | 371 | | Aimee Martin | 1297173 | michaeljoseph@yupee.con | F | 57 | Married | 372 | | Johnathan Hall | 1297174 | jamie97@hutmail.con | M | 33 | Never married | 373 | | Erin Lewis | 1297175 | nbailey@yupee.con | F | 27 | Never married | 374 | | Ashley Nelson | 1297176 | jamiegreen@shelf.con | F | 39 | Married | 375 | | Robert Wells | 1297177 | aferrell@gamail.con | M | 32 | Never married | 376 | | Samantha Herrera | 1297178 | jasonmoran@gamail.con | F | 71 | Married | 377 | +--------------------+-------------+--------------------------+-----+-----+---------------+ 378 | ``` 379 | 380 | This is sampple of individual users. We want to focus on the bigger picture. 381 | #### **Q:** How many Customers are male and how many are female? 382 | 383 | ```sql 384 | SELECT 385 | cust.sex, 386 | count(*) 387 | from bookstore.Customers cust 388 | GROUP BY 1; 389 | ``` 390 | ``` 391 | +-----+----------+ 392 | | sex | count(*) | 393 | +-----+----------+ 394 | | F | 127771 | 395 | | M | 118133 | 396 | +-----+----------+ 397 | ``` 398 | We can tell that the we have slightly more female customers, but not by much. 399 | 400 | ```sql 401 | SELECT 402 | cust.age, 403 | count(*) 404 | from bookstore.Customers cust 405 | GROUP BY 1 406 | ORDER BY cust.age; 407 | ``` 408 | ``` 409 | +-----+----------+ 410 | | age | count(*) | 411 | +-----+----------+ 412 | | 8 | 591 | 413 | | 9 | 691 | 414 | | 10 | 584 | 415 | | 11 | 813 | 416 | | 12 | 873 | 417 | | 13 | 1250 | 418 | | 14 | 1399 | 419 | | 15 | 1550 | 420 | | 16 | 1847 | 421 | | 17 | 2287 | 422 | | 18 | 2288 | 423 | | 19 | 2417 | 424 | | 20 | 2807 | 425 | | 21 | 2667 | 426 | | 22 | 2911 | 427 | | 23 | 3143 | 428 | | 24 | 2928 | 429 | | 25 | 3475 | 430 | | 26 | 3745 | 431 | | 27 | 3953 | 432 | | 28 | 3607 | 433 | | 29 | 4109 | 434 | | 30 | 3564 | 435 | | 31 | 4075 | 436 | | 32 | 3744 | 437 | | 33 | 4119 | 438 | | 34 | 4162 | 439 | | 35 | 4317 | 440 | | 36 | 4197 | 441 | | 37 | 4075 | 442 | | 38 | 3646 | 443 | | 39 | 3517 | 444 | | 40 | 3527 | 445 | | 41 | 3805 | 446 | | 42 | 3827 | 447 | | 43 | 3548 | 448 | | 44 | 4083 | 449 | | 45 | 4427 | 450 | | 46 | 4489 | 451 | | 47 | 4649 | 452 | | 48 | 4659 | 453 | | 49 | 4911 | 454 | | 50 | 4829 | 455 | | 51 | 4985 | 456 | | 52 | 4829 | 457 | | 53 | 5017 | 458 | | 54 | 5164 | 459 | | 55 | 5271 | 460 | | 56 | 4945 | 461 | | 57 | 5167 | 462 | | 58 | 5321 | 463 | | 59 | 4478 | 464 | | 60 | 3788 | 465 | | 61 | 4278 | 466 | | 62 | 3955 | 467 | | 63 | 3683 | 468 | | 64 | 3770 | 469 | | 65 | 3488 | 470 | | 66 | 2766 | 471 | | 67 | 2463 | 472 | | 68 | 2220 | 473 | | 69 | 2311 | 474 | | 70 | 2305 | 475 | | 71 | 2597 | 476 | | 72 | 2792 | 477 | | 73 | 2493 | 478 | | 74 | 2886 | 479 | | 75 | 2679 | 480 | | 76 | 2356 | 481 | | 77 | 1696 | 482 | | 78 | 1361 | 483 | | 79 | 1579 | 484 | | 80 | 1397 | 485 | | 81 | 1220 | 486 | | 82 | 1153 | 487 | | 83 | 1154 | 488 | | 84 | 644 | 489 | | 85 | 450 | 490 | | 86 | 563 | 491 | | 87 | 212 | 492 | | 88 | 433 | 493 | | 89 | 433 | 494 | | 90 | 215 | 495 | | 91 | 235 | 496 | | 92 | 149 | 497 | | 93 | 151 | 498 | | 94 | 126 | 499 | | 95 | 116 | 500 | | 96 | 122 | 501 | | 97 | 167 | 502 | | 98 | 102 | 503 | | 99 | 37 | 504 | | 100 | 49 | 505 | | 101 | 14 | 506 | | 102 | 14 | 507 | +-----+----------+ 508 | ``` 509 | Quite long list isn't it. 510 | 511 | The most orders we have from the group of 49-58 years old.It is clear that our Customers are mostly between 25 and 65 years old with clear peak around age of 55. 512 | Altho the information is in this result it is not imediately visible. 513 | We should focus on the age of the top customers with following query. 514 | 515 | ```sql 516 | SELECT 517 | cust.age, 518 | count(*) 519 | from bookstore.Customers cust 520 | GROUP BY 1 521 | ORDER BY 2 DESC LIMIT 10; 522 | ``` 523 | 524 | ``` 525 | +-----+----------+ 526 | | age | count(*) | 527 | +-----+----------+ 528 | | 58 | 5321 | 529 | | 55 | 5271 | 530 | | 57 | 5167 | 531 | | 54 | 5164 | 532 | | 53 | 5017 | 533 | | 51 | 4985 | 534 | | 56 | 4945 | 535 | | 49 | 4911 | 536 | | 50 | 4829 | 537 | | 52 | 4829 | 538 | +-----+----------+ 539 | ``` 540 | The result looks more elegant. 541 | 542 | The new construction 543 | ```sql 544 | ORDER BY 2 DESC 545 | ``` 546 | instructs the database to order the results descending as oppose to default ascending `ASC` order 547 | 548 | #### **Q:** How are our customers disctriburted by maritial statsus ? 549 | ```sql 550 | SELECT 551 | ms.ms_type, 552 | count(*) 553 | from bookstore.Customers cust 554 | JOIN bookstore.MaritalStatuses ms 555 | ON cust.ms_id = ms.ms_id 556 | GROUP BY ms.ms_type 557 | LIMIT 10; 558 | ``` 559 | As you might noticed we have not **JOIN** the MaritalStatus untill now. This is because we only need this relations when we use a column from the joined (the foreign) table. We didn't need it untill now. 560 | ``` 561 | +---------------+----------+ 562 | | ms_type | count(*) | 563 | +---------------+----------+ 564 | | Divorced | 26454 | 565 | | Married | 112979 | 566 | | Never married | 89564 | 567 | | Separated | 3886 | 568 | | Widow | 13021 | 569 | +---------------+----------+ 570 | ``` 571 | As you can see the Customers are almost evenly distributed between single and married. 572 | 573 | This conclude our demographics analisis. 574 | 575 | Lets add customer behaveour to the picture we want to know more about their buying habits. 576 | How much they buy? 577 | How much they spend? 578 | What do they buy? 579 | 580 | #### Who are our best customers? 581 | 582 | #### **Q:** Query Top Buyers 583 | 584 | ```sql 585 | SELECT 586 | count(t.order_id) 'Total Orders', 587 | SUM(t.discounted_price) 'Spent in USD', 588 | cust.customer_nm 'Name', 589 | cust.sex, 590 | cust.age, 591 | ms.ms_type 592 | FROM bookstore.Transactions as t 593 | INNER JOIN bookstore.Customers cust ON cust.customer_id = t.customer_id 594 | INNER JOIN bookstore.MaritalStatuses ms ON ms.ms_id = cust.ms_id 595 | GROUP BY 596 | t.customer_id, 597 | cust.customer_nm, 598 | cust.sex, 599 | cust.age, 600 | ms.ms_type 601 | ORDER BY 'Total Orders' desc 602 | LIMIT 10; 603 | ``` 604 | The Result 605 | ``` 606 | +--------------+--------------+--------------------+-----+-----+---------------+ 607 | | Total Orders | Spent in USD | Name | sex | age | ms_type | 608 | +--------------+--------------+--------------------+-----+-----+---------------+ 609 | | 34 | 313.92 | Donald Anthony PhD | M | 23 | Never married | 610 | | 10 | 142.16 | Wayne Rasmussen | M | 21 | Never married | 611 | | 21 | 155.02 | Kathleen Webb | F | 32 | Married | 612 | | 23 | 198.58 | Meghan Webb | F | 25 | Never married | 613 | | 48 | 371.13 | Courtney Alexander | F | 57 | Never married | 614 | | 7 | 60.96 | Nicole Montoya | F | 39 | Married | 615 | | 9 | 49.66 | Rebecca Wilkinson | F | 76 | Married | 616 | | 23 | 238.16 | Manuel Flowers | M | 32 | Married | 617 | | 16 | 193.00 | Lisa Bennett | F | 71 | Widow | 618 | | 16 | 140.93 | Erica Miller | F | 52 | Divorced | 619 | +--------------+--------------+--------------------+-----+-----+---------------+ 620 | ``` 621 | It looks like women buy more but the top spender are man after all. 622 | 623 | #### **Q:** But do the younger people read more than seniores ? 624 | Lets find out. 625 | 626 | ```sql 627 | SELECT 628 | count(t.order_id) 'Total Orders', 629 | cust.age 630 | FROM bookstore.Transactions as t 631 | INNER JOIN bookstore.Customers cust ON cust.customer_id = t.customer_id 632 | INNER JOIN bookstore.MaritalStatuses ms ON ms.ms_id = cust.ms_id 633 | GROUP BY 634 | cust.age 635 | ORDER BY count(t.order_id) desc 636 | LIMIT 10; 637 | ``` 638 | Result: 639 | ``` 640 | +--------------+-----+ 641 | | Total Orders | age | 642 | +--------------+-----+ 643 | | 33374 | 55 | 644 | | 33345 | 58 | 645 | | 32656 | 57 | 646 | | 32212 | 54 | 647 | | 31249 | 51 | 648 | | 31175 | 53 | 649 | | 30923 | 49 | 650 | | 30664 | 56 | 651 | | 30307 | 52 | 652 | | 30230 | 50 | 653 | +--------------+-----+ 654 | ``` 655 | 656 | The most orders we have from the group of 49-58 years old. 657 | 658 | Now lets focus on our top Customers and try to profile them in order to answer the following question: 659 | 660 | #### **Q:** What are the reading preferencess of our top customer? 661 | ```sql 662 | SELECT 663 | cust.customer_nm, 664 | b.category, 665 | SUM(discounted_price) disc_price 666 | FROM bookstore.Transactions AS t 667 | INNER JOIN Customers cust ON cust.customer_id = t.customer_id 668 | INNER JOIN Books b ON b.book_id = t.book_id 669 | WHERE cust.customer_id=13 670 | GROUP BY cust.customer_id,cust.customer_nm,b.category ORDER BY cust.customer_id; 671 | ``` 672 | 673 | ``` 674 | +----------------+-------------------+------------+ 675 | | customer_nm | category | disc_price | 676 | +----------------+-------------------+------------+ 677 | | Joseph Griffin | Humor | 14.80 | 678 | | Joseph Griffin | Romance | 33.37 | 679 | | Joseph Griffin | Sci-fi | 40.48 | 680 | | Joseph Griffin | Horror | 28.39 | 681 | | Joseph Griffin | Drama | 34.98 | 682 | | Joseph Griffin | Children Classics | 45.76 | 683 | | Joseph Griffin | Fantasy | 60.27 | 684 | | Joseph Griffin | Classics | 38.49 | 685 | +----------------+-------------------+------------+ 686 | ``` 687 | Here are the reading preferencess of Joseph Griffin 688 | 689 | Congratulations you completed our short tutorial. 690 | -------------------------------------------------------------------------------- /tx_sandbox/readme.md: -------------------------------------------------------------------------------- 1 | # MariaDB TX Sandbox Docker ImageDataset 2 | 3 | This sandbox data loaded in this doker image is based on procedural generated data representing a typical online bookstore data. 4 | The names of the books, authors and customers are all procedural generated. 5 | *Any matches with actual books titles and names are coinsidental.* 6 | 7 | The data is generated to illustrate the capabilities of **MariaDB AX** and **MariaDB TX** products of MariaDB Corporation. 8 | 9 | 10 | # Startup parameters 11 | 12 | ## Build and run using docker-compose 13 | ```bash 14 | docker-compose up --build 15 | ``` 16 | Navigate to [http://127.0.0.1:8080/](http://127.0.0.1:8080/?server=server&username=sandbox&db=bookstore) 17 | 18 | Fill username 19 | ```sandbox``` 20 | 21 | Fill DB name: 22 | ```bookstore``` 23 | 24 | Password is: 25 | ```highlyillogical``` 26 | 27 | Alternatively you can access the database from commandline: 28 | ```sh 29 | mysql -h127.0.0.1 -usandbox -phighlyillogical -D bookstore 30 | ``` 31 | 32 | ## Build and run using docker 33 | 34 | ### Build 35 | 36 | ``` 37 | docker build --build-arg root_pass=secret_pass -t mariadb:tx_sandbox . 38 | ``` 39 | 40 | `root_pass` holds the the password to be set for the MySQL root user 41 | 42 | ### Run 43 | 44 | ``` 45 | $ docker run --name tx_sandbox -d mariadb:tx_sandbox . 46 | ``` 47 | 48 | ... where tx_sandbox is the name you want to assign to your runnig container, tag is the tag specifying the MySQL version you want. See the list above for relevant tags. -------------------------------------------------------------------------------- /tx_sandbox/whitelist.yml: -------------------------------------------------------------------------------- 1 | generalwhitelist: #Approve CVE for any image 2 | CVE-2017-6055: XML 3 | CVE-2017-5586: OpenText 4 | images: 5 | ubuntu: #Apprive CVE only for ubuntu image, regardles of the version 6 | CVE-2017-5230: Java 7 | CVE-2017-5230: XSX 8 | alpine: 9 | CVE-2017-3261: SE 10 | CVE-2016-9840: zlib 11 | CVE-2016-9841: zlib 12 | CVE-2016-9842: zlib 13 | CVE-2016-9843: zlib -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | 4 | defaultSuite='bionic' 5 | declare -A suites=( 6 | [5.5]='trusty' 7 | [10.0]='xenial' 8 | ) 9 | 10 | declare -A dpkgArchToBashbrew=( 11 | [amd64]='amd64' 12 | [armel]='arm32v5' 13 | [armhf]='arm32v7' 14 | [arm64]='arm64v8' 15 | [i386]='i386' 16 | [ppc64el]='ppc64le' 17 | [s390x]='s390x' 18 | ) 19 | 20 | getRemoteVersion() { 21 | local version="$1"; shift # 10.4 22 | local suite="$1"; shift # bionic 23 | local dpkgArch="$1" shift # arm64 24 | 25 | echo "$( 26 | curl -fsSL "http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_MAJOR/repo/ubuntu/dists/$suite/main/binary-$dpkgArch/Packages" 2>/dev/null \ 27 | | tac|tac \ 28 | | awk -F ': ' '$1 == "Package" { pkg = $2; next } $1 == "Version" && pkg == "mariadb-server-'"$version"'" { print $2; exit }' 29 | )" 30 | } 31 | 32 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 33 | 34 | versions=( "$@" ) 35 | if [ ${#versions[@]} -eq 0 ]; then 36 | versions=( */ ) 37 | fi 38 | versions=( "${versions[@]%/}" ) 39 | 40 | travisEnv= 41 | for version in "${versions[@]}"; do 42 | suite="${suites[$version]:-$defaultSuite}" 43 | fullVersion="$(getRemoteVersion "$version" "$suite" 'amd64')" 44 | if [ -z "$fullVersion" ]; then 45 | echo >&2 "warning: cannot find $version in $suite" 46 | continue 47 | fi 48 | 49 | arches= 50 | sortedArches="$(echo "${!dpkgArchToBashbrew[@]}" | xargs -n1 | sort | xargs)" 51 | for arch in $sortedArches; do 52 | if ver="$(getRemoteVersion "$version" "$suite" "$arch")" && [ -n "$ver" ]; then 53 | arches="$arches ${dpkgArchToBashbrew[$arch]}" 54 | fi 55 | done 56 | 57 | 58 | cp Dockerfile.template "$version/Dockerfile" 59 | if [ "$backup" == 'mariadb-backup' ] && [[ "$version" < 10.3 ]]; then 60 | # 10.1 and 10.2 have mariadb major version in the package name 61 | backup="$backup-$version" 62 | fi 63 | 64 | ( 65 | set -x 66 | cp docker-entrypoint.sh "$version/" 67 | sed -i \ 68 | -e 's!%%MARIADB_VERSION%%!'"$fullVersion"'!g' \ 69 | -e 's!%%MARIADB_MAJOR%%!'"$version"'!g' \ 70 | -e 's!%%SUITE%%!'"$suite"'!g' \ 71 | -e 's!%%BACKUP_PACKAGE%%!'"$backup"'!g' \ 72 | -e 's!%%ARCHES%%!'"$arches"'!g' \ 73 | "$version/Dockerfile" 74 | ) 75 | 76 | travisEnv='\n - VERSION='"$version$travisEnv" 77 | done 78 | 79 | travis="$(awk -v 'RS=\n\n' '$1 == "env:" { $0 = "env:'"$travisEnv"'" } { printf "%s%s", $0, RS }' .travis.yml)" 80 | echo "$travis" > .travis.yml 81 | --------------------------------------------------------------------------------