考虑到项目中用到mysql的docker镜像mysql:5.7.28,为了方便后续针对该镜像做定制化,这里抽出一些时间对该镜像做一些简单的分析。
我们这里准备好如下运行脚本做测试。
docker run --detach \
--restart always \
--publish 3306:3306 \
--name mysql \
--volume /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
--env MYSQL_ROOT_PASSWORD=Gah6kuP7ohfio4 \
mysql:5.7.28 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
lwk@harbin:~/Public/project/github$ git clone git@github.com:docker-library/mysql.git
Cloning into 'mysql'...
remote: Enumerating objects: 1752, done.
remote: Counting objects: 100% (234/234), done.
remote: Compressing objects: 100% (139/139), done.
remote: Total 1752 (delta 140), reused 165 (delta 95), pack-reused 1518
Receiving objects: 100% (1752/1752), 341.43 KiB | 309.00 KiB/s, done.
Resolving deltas: 100% (826/826), done.
lwk@harbin:~/Public/project/github$
我们进入到源码目录
lwk@harbin:~/Public/project/github$ cd mysql/
lwk@harbin:~/Public/project/github/mysql$ ll
total 80
drwxrwxr-x 7 lwk lwk 4096 Mar 24 11:09 ./
drwxrwxr-x 4 lwk lwk 4096 Mar 24 11:09 ../
drwxrwxr-x 2 lwk lwk 4096 Mar 24 11:09 5.7/
drwxrwxr-x 3 lwk lwk 4096 Mar 24 11:09 8.0/
-rwxrwxr-x 1 lwk lwk 1127 Mar 24 11:09 apply-templates.sh*
-rwxrwxr-x 1 lwk lwk 2553 Mar 24 11:09 generate-stackbrew-library.sh*
drwxrwxr-x 8 lwk lwk 4096 Mar 24 11:09 .git/
-rw-rw-r-- 1 lwk lwk 157 Mar 24 11:09 .gitattributes
drwxrwxr-x 3 lwk lwk 4096 Mar 24 11:09 .github/
-rw-rw-r-- 1 lwk lwk 17 Mar 24 11:09 .gitignore
-rw-rw-r-- 1 lwk lwk 18092 Mar 24 11:09 LICENSE
-rw-rw-r-- 1 lwk lwk 2614 Mar 24 11:09 README.md
drwxrwxr-x 2 lwk lwk 4096 Mar 24 11:09 template/
-rwxrwxr-x 1 lwk lwk 134 Mar 24 11:09 update.sh*
-rw-rw-r-- 1 lwk lwk 754 Mar 24 11:09 versions.json
-rwxrwxr-x 1 lwk lwk 3969 Mar 24 11:09 versions.sh*
lwk@harbin:~/Public/project/github/mysql$
查看tag列表
lwk@harbin:~/Public/project/github/mysql$ git tag
lwk@harbin:~/Public/project/github/mysql$
我们发现没有源码管理系统中没有相应的tag列表。这个时候,我们再试着查看一下分支情况。
lwk@harbin:~/Public/project/github/mysql$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
lwk@harbin:~/Public/project/github/mysql$
我们发现只有源码系统中只有主分支。这个时候,我们只能将希望放在从git历史记录中提取出5.7.28最新的提交快照了,然后我们再基于这个历史快照点创建一个名为feature/5.7.28的分支出来。
lwk@harbin:~/Public/project/github/mysql$ git log --pretty=oneline |grep 5.7.28
5fa3526d23a846c6a2982901bc8190025af44336 Update to 5.7.28-1debian9
567028d4e177238c58760bcd69a8766a8f026e2a Switch from pgp.mit.edu to pool.sks-keyservers.net
lwk@harbin:~/Public/project/github/mysql$ git checkout -b feature/5.7.28 5fa3526d23a846
Switched to a new branch 'feature/5.7.28'
lwk@harbin:~/Public/project/github/mysql$ git branch -a
* feature/5.7.28
master
remotes/origin/HEAD -> origin/master
remotes/origin/master
lwk@harbin:~/Public/project/github/mysql$ ll
total 64
drwxrwxr-x 7 lwk lwk 4096 Mar 24 11:55 ./
drwxrwxr-x 5 lwk lwk 4096 Mar 24 11:36 ../
drwxrwxr-x 2 lwk lwk 4096 Mar 24 11:55 5.6/
drwxrwxr-x 2 lwk lwk 4096 Mar 24 11:55 5.7/
drwxrwxr-x 3 lwk lwk 4096 Mar 24 11:55 8.0/
-rwxrwxr-x 1 lwk lwk 1765 Mar 24 11:55 generate-stackbrew-library.sh*
drwxrwxr-x 8 lwk lwk 4096 Mar 24 11:55 .git/
-rw-rw-r-- 1 lwk lwk 18092 Mar 24 11:09 LICENSE
-rw-rw-r-- 1 lwk lwk 2542 Mar 24 11:55 README.md
drwxrwxr-x 2 lwk lwk 4096 Mar 24 11:55 .template.Debian/
-rw-rw-r-- 1 lwk lwk 556 Mar 24 11:55 .travis.yml
-rwxrwxr-x 1 lwk lwk 1077 Mar 24 11:55 update.sh*
lwk@harbin:~/Public/project/github/mysql$ ll 5.7/
total 28
drwxrwxr-x 2 lwk lwk 4096 Mar 24 11:55 ./
drwxrwxr-x 7 lwk lwk 4096 Mar 24 11:55 ../
-rwxrwxr-x 1 lwk lwk 12683 Mar 24 11:55 docker-entrypoint.sh*
-rw-rw-r-- 1 lwk lwk 3803 Mar 24 11:55 Dockerfile
lwk@harbin:~/Public/project/github/mysql$
看到这里,我们发现先前的设想是对的,而且我们已经成功提取出了最近的5.7.28相关的快照对应的分支,并从分支中看到了我们想要的关于5.7.28相关的docker文件docker-entrypoint.sh
与Dockerfile
,接下 来,我们来看一下这两个文件。
lwk@harbin:~/Public/project/github/mysql$ cat 5.7/Dockerfile
FROM debian:stretch-slim
# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN groupadd -r mysql && useradd -r -g mysql mysql
RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*
# add gosu for easy step-down from root
ENV GOSU_VERSION 1.7
RUN set -x \
&& apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \
&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \
&& export GNUPGHOME="$(mktemp -d)" \
&& gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
&& gpgconf --kill all \
&& rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true \
&& apt-get purge -y --auto-remove ca-certificates wget
RUN mkdir /docker-entrypoint-initdb.d
RUN apt-get update && apt-get install -y --no-install-recommends \
# for MYSQL_RANDOM_ROOT_PASSWORD
pwgen \
# for mysql_ssl_rsa_setup
openssl \
# FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db:
# File::Basename
# File::Copy
# Sys::Hostname
# Data::Dumper
perl \
&& rm -rf /var/lib/apt/lists/*
RUN set -ex; \
# gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \
export GNUPGHOME="$(mktemp -d)"; \
gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \
gpgconf --kill all; \
rm -rf "$GNUPGHOME"; \
apt-key list > /dev/null
ENV MYSQL_MAJOR 5.7
ENV MYSQL_VERSION 5.7.28-1debian9
RUN echo "deb http://repo.mysql.com/apt/debian/ stretch mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list
# 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)
# also, we set debconf keys to make APT a little quieter
RUN { \
echo mysql-community-server mysql-community-server/data-dir select ''; \
echo mysql-community-server mysql-community-server/root-pass password ''; \
echo mysql-community-server mysql-community-server/re-root-pass password ''; \
echo mysql-community-server mysql-community-server/remove-test-db select false; \
} | debconf-set-selections \
&& apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \
&& chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
# 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
&& chmod 777 /var/run/mysqld \
# comment out a few problematic configuration values
&& find /etc/mysql/ -name '*.cnf' -print0 \
| xargs -0 grep -lZE '^(bind-address|log)' \
| xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/' \
# don't reverse lookup hostnames, they are usually another container
&& echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf
VOLUME /var/lib/mysql
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 3306 33060
CMD ["mysqld"]
lwk@harbin:~/Public/project/github/mysql$
我们看到,mysql服务程序是以debian9为基础通过apt方式安装的。
接下来,我们再看一下文件docker-entrypoint.sh
做了哪些事。
lwk@harbin:~/Public/project/github/mysql$ cat 5.7/docker-entrypoint.sh
#!/bin/bash
set -eo pipefail
shopt -s nullglob
# logging functions
mysql_log() {
local type="$1"; shift
printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*"
}
mysql_note() {
mysql_log Note "$@"
}
mysql_warn() {
mysql_log Warn "$@" >&2
}
mysql_error() {
mysql_log ERROR "$@" >&2
exit 1
}
# usage: file_env VAR [DEFAULT]
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
mysql_error "Both $var and $fileVar are set (but are exclusive)"
fi
local val="$def"
if [ "${!var:-}" ]; then
val="${!var}"
elif [ "${!fileVar:-}" ]; then
val="$(< "${!fileVar}")"
fi
export "$var"="$val"
unset "$fileVar"
}
# check to see if this file is being run or sourced from another script
_is_sourced() {
# https://unix.stackexchange.com/a/215279
[ "${#FUNCNAME[@]}" -ge 2 ] \
&& [ "${FUNCNAME[0]}" = '_is_sourced' ] \
&& [ "${FUNCNAME[1]}" = 'source' ]
}
# usage: docker_process_init_files [file [file [...]]]
# ie: docker_process_init_files /always-initdb.d/*
# process initializer files, based on file extensions
docker_process_init_files() {
# mysql here for backwards compatibility "${mysql[@]}"
mysql=( docker_process_sql )
echo
local f
for f; do
case "$f" in
*.sh) mysql_note "$0: running $f"; . "$f" ;;
*.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;;
*.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;;
*) mysql_warn "$0: ignoring $f" ;;
esac
echo
done
}
mysql_check_config() {
local toRun=( "$@" --verbose --help ) errors
if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then
mysql_error $'mysqld failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors"
fi
}
# Fetch value from server config
# We use mysqld --verbose --help instead of my_print_defaults because the
# latter only show values present in config files, and not server defaults
mysql_get_config() {
local conf="$1"; shift
"$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null \
| awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }'
# match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)"
}
# Do a temporary startup of the MySQL server, for init purposes
docker_temp_server_start() {
if [ "${MYSQL_MAJOR}" = '5.6' ]; then
"$@" --skip-networking --socket="${SOCKET}" &
mysql_note "Waiting for server startup"
local i
for i in {30..0}; do
# only use the root password if the database has already been initializaed
# so that it won't try to fill in a password file when it hasn't been set yet
extraArgs=()
if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
extraArgs+=( '--dont-use-mysql-root-password' )
fi
if docker_process_sql "${extraArgs[@]}" --database=mysql <<<'SELECT 1' &> /dev/null; then
break
fi
sleep 1
done
if [ "$i" = 0 ]; then
mysql_error "Unable to start server."
fi
else
# For 5.7+ the server is ready for use as soon as startup command unblocks
if ! "$@" --daemonize --skip-networking --socket="${SOCKET}"; then
mysql_error "Unable to start server."
fi
fi
}
# Stop the server. When using a local socket file mysqladmin will block until
# the shutdown is complete.
docker_temp_server_stop() {
if ! mysqladmin --defaults-extra-file=<( _mysql_passfile ) shutdown -uroot --socket="${SOCKET}"; then
mysql_error "Unable to shut down server."
fi
}
# Verify that the minimally required password settings are set for new databases.
docker_verify_minimum_env() {
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD'
fi
}
# creates folders for the database
# also ensures permission for user mysql of run as root
docker_create_db_directories() {
local user; user="$(id -u)"
# TODO other directories that are used by default? like /var/lib/mysql-files
# see https://github.com/docker-library/mysql/issues/562
mkdir -p "$DATADIR"
if [ "$user" = "0" ]; then
# this will cause less disk access than `chown -R`
find "$DATADIR" \! -user mysql -exec chown mysql '{}' +
fi
}
# initializes the database directory
docker_init_database_dir() {
mysql_note "Initializing database files"
if [ "$MYSQL_MAJOR" = '5.6' ]; then
mysql_install_db --datadir="$DATADIR" --rpm --keep-my-cnf "${@:2}"
else
"$@" --initialize-insecure
fi
mysql_note "Database files initialized"
if command -v mysql_ssl_rsa_setup > /dev/null && [ ! -e "$DATADIR/server-key.pem" ]; then
# https://github.com/mysql/mysql-server/blob/23032807537d8dd8ee4ec1c4d40f0633cd4e12f9/packaging/deb-in/extra/mysql-systemd-start#L81-L84
mysql_note "Initializing certificates"
mysql_ssl_rsa_setup --datadir="$DATADIR"
mysql_note "Certificates initialized"
fi
}
# Loads various settings that are used elsewhere in the script
# This should be called after mysql_check_config, but before any other functions
docker_setup_env() {
# Get config
declare -g DATADIR SOCKET
DATADIR="$(mysql_get_config 'datadir' "$@")"
SOCKET="$(mysql_get_config 'socket' "$@")"
# Initialize values that might be stored in a file
file_env 'MYSQL_ROOT_HOST' '%'
file_env 'MYSQL_DATABASE'
file_env 'MYSQL_USER'
file_env 'MYSQL_PASSWORD'
file_env 'MYSQL_ROOT_PASSWORD'
declare -g DATABASE_ALREADY_EXISTS
if [ -d "$DATADIR/mysql" ]; then
DATABASE_ALREADY_EXISTS='true'
fi
}
# Execute sql script, passed via stdin
# usage: docker_process_sql [--dont-use-mysql-root-password] [mysql-cli-args]
# ie: docker_process_sql --database=mydb <<<'INSERT ...'
# ie: docker_process_sql --dont-use-mysql-root-password --database=mydb <my-file.sql
docker_process_sql() {
passfileArgs=()
if [ '--dont-use-mysql-root-password' = "$1" ]; then
passfileArgs+=( "$1" )
shift
fi
# args sent in can override this db, since they will be later in the command
if [ -n "$MYSQL_DATABASE" ]; then
set -- --database="$MYSQL_DATABASE" "$@"
fi
mysql --defaults-file=<( _mysql_passfile "${passfileArgs[@]}") --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
}
# Initializes database with timezone info and root password, plus optional extra db/user
docker_setup_db() {
# Load timezone info into database
if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then
# sed is for https://bugs.mysql.com/bug.php?id=20545
mysql_tzinfo_to_sql /usr/share/zoneinfo \
| sed 's/Local time zone must be set--see zic manual page/FCTY/' \
| docker_process_sql --dont-use-mysql-root-password --database=mysql
# tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet
fi
# Generate random root password
if [ -n "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
mysql_note "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
fi
# Sets root password and creates root users for non-localhost hosts
local rootCreate=
# default root to listen for connections from anywhere
if [ -n "$MYSQL_ROOT_HOST" ] && [ "$MYSQL_ROOT_HOST" != 'localhost' ]; then
# no, we don't care if read finds a terminating character in this heredoc
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
read -r -d '' rootCreate <<-EOSQL || true
CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
EOSQL
fi
local passwordSet=
if [ "$MYSQL_MAJOR" = '5.6' ]; then
# no, we don't care if read finds a terminating character in this heredoc (see above)
read -r -d '' passwordSet <<-EOSQL || true
DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
-- 5.5: https://github.com/mysql/mysql-server/blob/e48d775c6f066add457fa8cfb2ebc4d5ff0c7613/scripts/mysql_secure_installation.sh#L192-L210
-- 5.6: https://github.com/mysql/mysql-server/blob/06bc670db0c0e45b3ea11409382a5c315961f682/scripts/mysql_secure_installation.sh#L218-L236
-- 5.7: https://github.com/mysql/mysql-server/blob/913071c0b16cc03e703308250d795bc381627e37/client/mysql_secure_installation.cc#L792-L818
-- 8.0: https://github.com/mysql/mysql-server/blob/b93c1661d689c8b7decc7563ba15f6ed140a4eb6/client/mysql_secure_installation.cc#L726-L749
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' ;
-- https://github.com/docker-library/mysql/pull/479#issuecomment-414561272 ("This is only needed for 5.5 and 5.6")
EOSQL
else
# no, we don't care if read finds a terminating character in this heredoc (see above)
read -r -d '' passwordSet <<-EOSQL || true
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
EOSQL
fi
# tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is just now being set
docker_process_sql --dont-use-mysql-root-password --database=mysql <<-EOSQL
-- What's done in this file shouldn't be replicated
-- or products like mysql-fabric won't work
SET @@SESSION.SQL_LOG_BIN=0;
${passwordSet}
GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
FLUSH PRIVILEGES ;
${rootCreate}
DROP DATABASE IF EXISTS test ;
EOSQL
# Creates a custom database and user if specified
if [ -n "$MYSQL_DATABASE" ]; then
mysql_note "Creating database ${MYSQL_DATABASE}"
docker_process_sql --database=mysql <<<"CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;"
fi
if [ -n "$MYSQL_USER" ] && [ -n "$MYSQL_PASSWORD" ]; then
mysql_note "Creating user ${MYSQL_USER}"
docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;"
if [ -n "$MYSQL_DATABASE" ]; then
mysql_note "Giving user ${MYSQL_USER} access to schema ${MYSQL_DATABASE}"
docker_process_sql --database=mysql <<<"GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;"
fi
docker_process_sql --database=mysql <<<"FLUSH PRIVILEGES ;"
fi
}
_mysql_passfile() {
# echo the password to the "file" the client uses
# the client command will use process substitution to create a file on the fly
# ie: --defaults-file=<( _mysql_passfile )
if [ '--dont-use-mysql-root-password' != "$1" ] && [ -n "$MYSQL_ROOT_PASSWORD" ]; then
cat <<-EOF
[client]
password="${MYSQL_ROOT_PASSWORD}"
EOF
fi
}
# Mark root user as expired so the password must be changed before anything
# else can be done (only supported for 5.6+)
mysql_expire_root_user() {
if [ -n "$MYSQL_ONETIME_PASSWORD" ]; then
docker_process_sql --database=mysql <<-EOSQL
ALTER USER 'root'@'%' PASSWORD EXPIRE;
EOSQL
fi
}
# check arguments for an option that would cause mysqld to stop
# return true if there is one
_mysql_want_help() {
local arg
for arg; do
case "$arg" in
-'?'|--help|--print-defaults|-V|--version)
return 0
;;
esac
done
return 1
}
_main() {
# if command starts with an option, prepend mysqld
if [ "${1:0:1}" = '-' ]; then
set -- mysqld "$@"
fi
# skip setup if they aren't running mysqld or want an option that stops mysqld
if [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then
mysql_note "Entrypoint script for MySQL Server ${MYSQL_VERSION} started."
mysql_check_config "$@"
# Load various environment variables
docker_setup_env "$@"
docker_create_db_directories
# If container is started as root user, restart as dedicated mysql user
if [ "$(id -u)" = "0" ]; then
mysql_note "Switching to dedicated user 'mysql'"
exec gosu mysql "$BASH_SOURCE" "$@"
fi
# there's no database, so it needs to be initialized
if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
docker_verify_minimum_env
docker_init_database_dir "$@"
mysql_note "Starting temporary server"
docker_temp_server_start "$@"
mysql_note "Temporary server started."
docker_setup_db
docker_process_init_files /docker-entrypoint-initdb.d/*
mysql_expire_root_user
mysql_note "Stopping temporary server"
docker_temp_server_stop
mysql_note "Temporary server stopped"
echo
mysql_note "MySQL init process done. Ready for start up."
echo
fi
fi
exec "$@"
}
# If we are sourced from elsewhere, don't perform any further actions
if ! _is_sourced; then
_main "$@"
fi
lwk@harbin:~/Public/project/github/mysql$
我们看到,文件docker-entrypoint.sh
主要是对生成的docker容器做了些初始化工作,Docker容器启动的时候传进去的参数也会在这里被处理掉。
在Linux命令执行如下脚本即可创建一个mysql的Docker实例。
lwk@harbin:/data/docker/mysql$ docker run --detach \
> --restart always \
> --publish 3306:3306 \
> --name mysql \
> --volume /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
> --env MYSQL_ROOT_PASSWORD=Gah6kuP7ohfio4 \
> mysql:5.7.28 \
> --character-set-server=utf8mb4 \
> --collation-server=utf8mb4_unicode_ci
24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a
lwk@harbin:/data/docker/mysql$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24d838bb91df mysql:5.7.28 "docker-entrypoint.s…" 8 seconds ago Up 6 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
lwk@harbin:/data/docker/mysql$
这个时候,我们看到已经启动了一个mysql的docker实例。
我们再用docker inspect查看一下。
lwk@harbin:/data/docker/mysql$ docker inspect mysql
[
{
"Id": "24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a",
"Created": "2022-03-23T08:54:32.978883297Z",
"Path": "docker-entrypoint.sh",
"Args": [
"--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 26597,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-03-23T08:54:33.315240494Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:db39680b63ac47a1d989da7b742f7b382af34d85a68214f8977bad59c05901a6",
"ResolvConfPath": "/var/lib/docker/containers/24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a/hostname",
"HostsPath": "/var/lib/docker/containers/24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a/hosts",
"LogPath": "/var/lib/docker/containers/24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a/24d838bb91df5327834af53466d248cf091fde28d6923de66f5029d0319fb12a-json.log",
"Name": "/mysql",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/usr/share/zoneinfo/Asia/Shanghai:/etc/localtime"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"3306/tcp": [
{
"HostIp": "",
"HostPort": "3306"
}
]
},
"RestartPolicy": {
"Name": "always",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/a24ba560f93f4b532ba065051269fa2986ba0b2bd8d0170c4eda7abdda0bdfc9-init/diff:/var/lib/docker/overlay2/a31a2c5da9b51c231d4d78b37878043d0609d421b31cfff59175607265e19177/diff:/var/lib/docker/overlay2/743a94eaa9d844ff29b68e5fb7784d5f381ca9339f171f82c55d7bca34462e20/diff:/var/lib/docker/overlay2/b4ee6d62e35e82404ccb44ad4c288bacd8f84baf3393d5e2ca74271ad1ee7a66/diff:/var/lib/docker/overlay2/29b74f60917b4d40a05c9ff14f893025ec146606cde6d05dc391a8e9bea09f2d/diff:/var/lib/docker/overlay2/398ace072c15982dcab9b9c7b15cd39610f901bdfa8f1212776371f8a1c3c9bf/diff:/var/lib/docker/overlay2/387776aa58b582052607f745bd283e2e8070dfa93c5ff4681835c100b9390d8b/diff:/var/lib/docker/overlay2/5b2ccbfb57bba65c49ee3280bb35f3ee3cd257804c042a189947c4ffcb94405c/diff:/var/lib/docker/overlay2/3469db242a79018c8108b00f1dc4ff00e8a439b948c3c6591fc6ce050fa5c506/diff:/var/lib/docker/overlay2/cf951b163c28571865b1ff62958752962a32b0c5f35e22e0eab11efe1d6a0fff/diff:/var/lib/docker/overlay2/95fc9b4b73b1a1e67334599d17ef6c402b40f97a9f1565633659ce904b8f5ddd/diff:/var/lib/docker/overlay2/bf9567587ab9d4e9a64101c87e058d001baf51711e294dfb834515e4e1886049/diff",
"MergedDir": "/var/lib/docker/overlay2/a24ba560f93f4b532ba065051269fa2986ba0b2bd8d0170c4eda7abdda0bdfc9/merged",
"UpperDir": "/var/lib/docker/overlay2/a24ba560f93f4b532ba065051269fa2986ba0b2bd8d0170c4eda7abdda0bdfc9/diff",
"WorkDir": "/var/lib/docker/overlay2/a24ba560f93f4b532ba065051269fa2986ba0b2bd8d0170c4eda7abdda0bdfc9/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "bind",
"Source": "/usr/share/zoneinfo/Asia/Shanghai",
"Destination": "/etc/localtime",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "volume",
"Name": "068b674dcf99be98be576e9fb2dc0f6cd8d7e3e98636722b53b5a0d9472299e6",
"Source": "/var/lib/docker/volumes/068b674dcf99be98be576e9fb2dc0f6cd8d7e3e98636722b53b5a0d9472299e6/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "24d838bb91df",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"MYSQL_ROOT_PASSWORD=Gah6kuP7ohfio4",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.7",
"MYSQL_MAJOR=5.7",
"MYSQL_VERSION=5.7.28-1debian9"
],
"Cmd": [
"--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci"
],
"Image": "mysql:5.7.28",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "c2b5930a6963a12379fa0f31c96c9ac034bd79202964be99a0f865761523bf66",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"3306/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "3306"
},
{
"HostIp": "::",
"HostPort": "3306"
}
],
"33060/tcp": null
},
"SandboxKey": "/var/run/docker/netns/c2b5930a6963",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "51e7f168209783770db9ebd450cf5f9c8c3c34fef0b8dd4fc66b68fd00a3d1a7",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "1cd2c2db90b8c41595d080f78f4c07bc8007ec8a8fc6c9528a844793b06bd1a0",
"EndpointID": "51e7f168209783770db9ebd450cf5f9c8c3c34fef0b8dd4fc66b68fd00a3d1a7",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
lwk@harbin:/data/docker/mysql$
接下来,我们进入到容器内部看一下
lwk@harbin:/data/docker/mysql$ docker exec -it mysql /bin/bash
root@24d838bb91df:/# ll
bash: ll: command not found
root@24d838bb91df:/# ls -la
total 80
drwxr-xr-x 1 root root 4096 Mar 23 16:54 .
drwxr-xr-x 1 root root 4096 Mar 23 16:54 ..
-rwxr-xr-x 1 root root 0 Mar 23 16:54 .dockerenv
drwxr-xr-x 1 root root 4096 Dec 29 2019 bin
drwxr-xr-x 2 root root 4096 Sep 8 2019 boot
drwxr-xr-x 5 root root 340 Mar 23 16:54 dev
drwxr-xr-x 2 root root 4096 Dec 29 2019 docker-entrypoint-initdb.d
lrwxrwxrwx 1 root root 34 Dec 29 2019 entrypoint.sh -> usr/local/bin/docker-entrypoint.sh
drwxr-xr-x 1 root root 4096 Mar 23 16:54 etc
drwxr-xr-x 2 root root 4096 Sep 8 2019 home
drwxr-xr-x 1 root root 4096 Dec 24 2019 lib
drwxr-xr-x 2 root root 4096 Dec 24 2019 lib64
drwxr-xr-x 2 root root 4096 Dec 24 2019 media
drwxr-xr-x 2 root root 4096 Dec 24 2019 mnt
drwxr-xr-x 2 root root 4096 Dec 24 2019 opt
dr-xr-xr-x 386 root root 0 Mar 23 16:54 proc
drwx------ 1 root root 4096 Dec 29 2019 root
drwxr-xr-x 1 root root 4096 Dec 29 2019 run
drwxr-xr-x 2 root root 4096 Dec 24 2019 sbin
drwxr-xr-x 2 root root 4096 Dec 24 2019 srv
dr-xr-xr-x 13 root root 0 Mar 23 16:54 sys
drwxrwxrwt 1 root root 4096 Mar 23 16:54 tmp
drwxr-xr-x 1 root root 4096 Dec 24 2019 usr
drwxr-xr-x 1 root root 4096 Dec 24 2019 var
root@24d838bb91df:/#
刚才我们通过命令docker inspect
探测容器实例的时候,发现容器启动的时候执行了脚本/entrypoint.sh
。
接下来,我们探查一下mysql的配置文件目录相关信息。
root@24d838bb91df:/# ls -la /etc/mysql/
total 24
drwxr-xr-x 4 root root 4096 Dec 29 2019 .
drwxr-xr-x 1 root root 4096 Mar 23 16:54 ..
drwxr-xr-x 2 root root 4096 Dec 29 2019 conf.d
lrwxrwxrwx 1 root root 24 Dec 29 2019 my.cnf -> /etc/alternatives/my.cnf
-rw-r--r-- 1 root root 839 Jul 10 2016 my.cnf.fallback
-rw-r--r-- 1 root root 1215 Sep 27 2019 mysql.cnf
drwxr-xr-x 2 root root 4096 Dec 29 2019 mysql.conf.d
root@24d838bb91df:/#
我们看到这是一个debian系统下通过apt命令安装mysql后标准配置文件目录。
root@24d838bb91df:/# ls -la /etc/alternatives/my.cnf
lrwxrwxrwx 1 root root 20 Dec 29 2019 /etc/alternatives/my.cnf -> /etc/mysql/mysql.cnf
root@24d838bb91df:/#
我们看到my.cnf其实是mysql.cnf的软链接。接下来看一下这个文件做了哪些事。
root@24d838bb91df:/# cat /etc/mysql/my.cnf
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
root@24d838bb91df:/#
我们看到该文件将目录/etc/mysql/conf.d/
与/etc/mysql/mysql.conf.d/
包含了进来 ,也就是说,这两个目录下的配置文件都会被系统自动加载。
root@24d838bb91df:/# ls -la /etc/mysql/conf.d/
total 20
drwxr-xr-x 2 root root 4096 Dec 29 2019 .
drwxr-xr-x 4 root root 4096 Dec 29 2019 ..
-rw-r--r-- 1 root root 43 Dec 29 2019 docker.cnf
-rw-r--r-- 1 root root 8 Jul 10 2016 mysql.cnf
-rw-r--r-- 1 root root 55 Jul 10 2016 mysqldump.cnf
root@24d838bb91df:/# cat /etc/mysql/conf.d/docker.cnf
[mysqld]
skip-host-cache
skip-name-resolve
root@24d838bb91df:/# cat /etc/mysql/conf.d/mysql.cnf
[mysql]
root@24d838bb91df:/# cat /etc/mysql/conf.d/mysqldump.cnf
[mysqldump]
quick
quote-names
max_allowed_packet = 16M
root@24d838bb91df:/#
我们看到,目录/etc/mysql/conf.d/
下的文件主要涉及mysql客户端管理相关的配置。
max_allowed_packet = 16M
root@24d838bb91df:/# ls -la /etc/mysql/mysql.conf.d/
total 12
drwxr-xr-x 2 root root 4096 Dec 29 2019 .
drwxr-xr-x 4 root root 4096 Dec 29 2019 ..
-rw-r--r-- 1 root root 1610 Dec 29 2019 mysqld.cnf
root@24d838bb91df:/# cat /etc/mysql/mysql.conf.d/mysqld.cnf
# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# The MySQL Server configuration file.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
#log-error = /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address = 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
root@24d838bb91df:/#
目录/etc/mysql/mysql.conf.d/
下面的内容主要涉及mysql服务端的相关配置。
看到这里,我们可以得出如下结论,只要我们将文件/etc/mysql/mysql.cnf
映射到docker容器外部的宿主机上特定目录下的同名文件上,这个时候,对外部外部同名文件的修改都会自动被mysql容器加载,进而实现对mysql容器的定制化配置。