|
Docker official Mysql mirror Dockerfile hosted on Github, at the following address:
https://github.com/docker-library/mysql/tree/5836bc9af9deb67b68c32bebad09a0f7513da36e/5.6
Carefully study a little of its Dockerfile, we found that the most technical content of its Dockerfile not that in itself, is nothing more than an update depot, download Mysql Server, slightly modify its configuration files.
D ENTRYPOINT corresponding docker-entrypoint.sh very interesting, this document is quite detailed, involving Mysql how to initialize, how to set a password, the key issue of how to start services.
Spent most of the day today to analyze the script, it really is a lot.
Script and results are as follows:
#! / Bin / bash
set -e
# If command starts with an option, prepend mysqld
if [ "$ {1: 0: 1}" = '-']; then
set - mysqld "$ @"
fi
if [ "$ 1" = 'mysqld']; then
# Get config
DATADIR = "$ (" $ @ "--verbose --help 2> / dev / null | awk '$ 1 ==" datadir "{print $ 2; exit}')"
if [! -d "$ DATADIR / mysql"]; then
if [-z "$ MYSQL_ROOT_PASSWORD" -a -z "$ MYSQL_ALLOW_EMPTY_PASSWORD"]; then
echo> & 2 'error: database is uninitialized and MYSQL_ROOT_PASSWORD not set'
echo> & 2 'Did you forget to add -e MYSQL_ROOT_PASSWORD = ...?'
exit 1
fi
mkdir -p "$ DATADIR"
chown -R mysql: mysql "$ DATADIR"
echo 'Running mysql_install_db'
mysql_install_db --user = mysql --datadir = "$ DATADIR" --rpm --keep-my-cnf
echo 'Finished mysql_install_db'
mysqld --user = mysql --datadir = "$ DATADIR" --skip-networking &
pid = "$!"
mysql = (mysql --protocol = socket -uroot)
for i in {30..0}; do
if echo 'SELECT 1' | "$ {mysql [@]}" &> / dev / null; then
break
fi
echo 'MySQL init process in progress ...'
sleep 1
done
if [ "$ i" = 0]; then
echo> & 2 'MySQL init process failed.'
exit 1
fi
# 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 /' | "$ {mysql [@]}" mysql
"$ {Mysql [@]}" << - EOSQL
- What's done in this file should not be replicated
- Or products like mysql-fabric will not work
SET @@ SESSION.SQL_LOG_BIN = 0;
DELETE FROM mysql.user;
CREATE USER 'root' @ '%' IDENTIFIED BY '$ {MYSQL_ROOT_PASSWORD}';
. GRANT ALL ON * * TO 'root' @ '%' WITH GRANT OPTION;
DROP DATABASE IF EXISTS test;
FLUSH PRIVILEGES;
EOSQL
if [! -z "$ MYSQL_ROOT_PASSWORD"]; then
mysql + = (-p "$ {MYSQL_ROOT_PASSWORD}")
fi
if [ "$ MYSQL_DATABASE"]; then
echo "CREATE DATABASE IF NOT EXISTS \` $ MYSQL_DATABASE \ `;" | "$ {mysql [@]}"
mysql + = ( "$ MYSQL_DATABASE")
fi
if [ "$ MYSQL_USER" -a "$ MYSQL_PASSWORD"]; then
echo "CREATE USER '" $ MYSQL_USER "' @ '%' IDENTIFIED BY '" $ MYSQL_PASSWORD "';" | "$ {mysql [@]}"
if [ "$ MYSQL_DATABASE"]; then
echo "GRANT ALL ON \` "$ MYSQL_DATABASE". \ `* TO '" $ MYSQL_USER "' @ '%';" | "$ {mysql [@]}"
fi
echo 'FLUSH PRIVILEGES;' | "$ {mysql [@]}"
fi
echo
for f in /docker-entrypoint-initdb.d/*; do
case "$ f" in
* .sh) Echo. "$ 0: running $ f"; "$ f" ;;
* .sql) Echo "$ 0: running $ f"; "$ {mysql [@]}" < "$ f" && echo ;;
*) Echo "$ 0: ignoring $ f" ;;
esac
echo
done
!! If kill -s TERM "$ pid" || wait "$ pid"; then
echo> & 2 'MySQL init process failed.'
exit 1
fi
echo
echo 'MySQL init process done. Ready for start up.'
echo
fi
chown -R mysql: mysql "$ DATADIR"
fi
exec "$ @"
As follows:
1> set -e, Manual document described as follows:
Exit immediately if a pipeline (which may consist of a single simple command), a subshell com-
mand enclosed in parentheses, or one of the commands executed as part of a command list
enclosed by braces (see SHELL GRAMMAR above) exits with a non-zero status.
Sentence statement tells bash If the results of any statement that is not true, you should quit. The advantage is to prevent errors snowball bigger cause a fatal error, and the errors should have been before it was disposed of.
The pros and cons on set -e, you can refer to two blog
(1) Unix / Linux script "set -e" role
(2) linux set command: "set -e" and "set -o pipefail"
2>
if [ "$ {1: 0: 1}" = '-']; then
set - mysqld "$ @"
fi
The script is used to determine whether the parameters back to a "-", it is considered to start mysqld is the case with arguments, if any, will mysqld as variables and parameters stored in the $ @.
On set -, Manual document described as follows:
If no arguments follow this option, then the positional parameters are unset. Otherwise, the
positional parameters are set to the args, even if some of them begin with a -.
Verify the following:
First constructed script
[Root @ localhost ~] # cat 4.sh
#! / Bin / bash
if [ "$ {1: 0: 1}" = '-']; then
set - mysqld "$ @"
fi
echo '$ @:' "$ @"
echo '$ 1:' "$ 1"
Add parameters to be verified
[Root @ localhost ~] # sh 4.sh 123
$ @: 123
$ 1: 123
[Root @ localhost ~] # sh 4.sh -123
$ @: Mysqld -123
$ 1: mysqld
[Root @ localhost ~] # sh 4.sh -123 456
$ @: Mysqld -123 456
$ 1: mysqld
Add this: the distinction between the $ @ and $ *, $ @ refers to each positional parameter is a parameter independent "," a reference to a string, which means that parameters are passed intact, while $ * refers to all positional parameters only It is a '' reference, the equivalent of a parameter.
3>
if [ "$ 1" = 'mysqld']; then
If $ 1 is mysqld, the following code is executed, and if not, the last line of the script is executed exec "$ @".
Note: Dockerfile the CMD command [ "mysqld"], CMD command is actually ENTRYPOINT parameters, such as if ENTRYPOINT command ls, the CMD command -l, the effect achieved is ls -l,
When starting container, ordered his input is actually covered CMD parameters, specifically in this case, it means that when you start the container, command-entered only in three cases will start the mysqld service: First, mysqld ( the equivalent of CMD parameter). Second, the "-" the beginning of the parameter list, so the two will be judged in the script is true. Three, mysqld + "-" for the start of the parameter list. In addition, all other commands mysql server service will not start, but directly execute the command you entered.
4>
DATADIR = "$ (" $ @ "--verbose --help 2> / dev / null | awk '$ 1 ==" datadir "{print $ 2; exit}')"
Get mysql server data directory, if we do not enter any "-" for the start of the parameter list, the $ @ to mysqld, a result of the command is as follows:
[Root @ localhost ~] # mysqld --verbose --help 2> / dev / null | awk '$ 1 == "datadir" {print $ 2; exit}'
/ Var / lib / mysql /
5>
if [! -d "$ DATADIR / mysql"]; then
If there is / var / lib / mysql / mysql directory of file, skip the intermediate steps, direct execution chown -R mysql: mysql "$ DATADIR", according to which a judgment here is that if / var / lib / mysql / mysql file exists, represents the mysql server is already installed, then you need to install (of course, if forced to install, it may be overwritten), directly to the owner modify mysql user. Many children's shoes may be curious, not the new image it? How this directory may exist? I also had the presence of such doubts, and later verified a lot, find out if the host directory to mount directly to the mirror of / var / lib / mysql, the image when you start mysql, mysql not initialized, and set the root password etc., directly start mysql service, as follows:
[Root @ localhost ~] # docker run -v / var / lib / mysql: / var / lib / mysql mysql
2015-09-24 02:08:05 0 [Note] mysqld (mysqld 5.6.26) starting as process 1 ...
2015-09-24 02:08:05 1 [Note] Plugin 'FEDERATED' is disabled.
2015-09-24 02:08:05 1 [Note] InnoDB: Using atomics to ref count buffer pool pages
2015-09-24 02:08:05 1 [Note] InnoDB: The InnoDB memory heap is disabled
2015-09-24 02:08:05 1 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2015-09-24 02:08:05 1 [Note] InnoDB: Memory barrier is not used
2015-09-24 02:08:05 1 [Note] InnoDB: Compressed tables use zlib 1.2.7
2015-09-24 02:08:05 1 [Note] InnoDB: Using Linux native AIO
2015-09-24 02:08:05 1 [Note] InnoDB: Using CPU crc32 instructions
2015-09-24 02:08:05 1 [Note] InnoDB: Initializing buffer pool, size = 128.0M
2015-09-24 02:08:05 1 [Note] InnoDB: Completed initialization of buffer pool
2015-09-24 02:08:05 1 [Note] InnoDB: Highest supported file format is Barracuda.
2015-09-24 02:08:06 1 [Note] InnoDB: 128 rollback segment (s) are active.
2015-09-24 02:08:06 1 [Note] InnoDB: Waiting for purge to start
2015-09-24 02:08:06 1 [Note] InnoDB: 5.6.26 started; log sequence number 1697388
2015-09-24 02:08:06 1 [Note] Server hostname (bind-address): '*'; port: 3306
2015-09-24 02:08:06 1 [Note] IPv6 is available.
2015-09-24 02:08:06 1 [Note] - '::' resolves to '::';
2015-09-24 02:08:06 1 [Note] Server socket created on IP: '::'.
2015-09-24 02:08:06 1 [Warning] 'user' entry 'root@localhost.localdomain' ignored in --skip-name-resolve mode.
2015-09-24 02:08:06 1 [Warning] 'user' entry '@ localhost.localdomain' ignored in --skip-name-resolve mode.
2015-09-24 02:08:06 1 [Warning] 'proxies_priv' entry '@ root@localhost.localdomain' ignored in --skip-name-resolve mode.
2015-09-24 02:08:06 1 [Note] Event Scheduler: Loaded 0 events
2015-09-24 02:08:06 1 [Note] mysqld: ready for connections.
Version: '5.6.26' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
The previous boot process involves the initialization, start, explicit set root password.
After the host of var / lib / mysql / mount to the container, let us look at the permissions of the directory on the host.
[Root @ localhost ~] # ll / var / lib / mysql /
total 110604
-rw-rw ---- 1 polkitd ssh_keys 56 Sep 14 15:46 auto.cnf
drwx ------ 2 polkitd ssh_keys 131 Sep 14 16:03 db1
drwx ------ 2 polkitd ssh_keys 131 Sep 14 16:03 db2
drwx ------ 2 polkitd ssh_keys 55 Sep 14 16:02 db3
-rw-rw ---- 1 polkitd ssh_keys 12582912 Sep 24 10:08 ibdata1
-rw-rw ---- 1 polkitd ssh_keys 50331648 Sep 24 10:08 ib_logfile0
-rw-rw ---- 1 polkitd ssh_keys 50331648 Sep 14 15:45 ib_logfile1
drwx ------ 2 polkitd ssh_keys 4096 Sep 23 14:18 mysql
drwx ------ 2 polkitd ssh_keys 4096 Sep 22 13:47 performance_schema
Owner of polkitd, is a group of ssh_keys.
Start again host the mysql service a try, actually failed.
[Root @ localhost ~] # systemctl start mysql
Failed to issue method call: Unit mysql.service failed to load: No such file or directory.
[Root @ localhost ~] # systemctl start mysqld
Job for mysqld.service failed. See 'systemctl status mysqld.service' and 'journalctl -xn' for details.
[Root @ localhost ~] # systemctl status mysqld.service
mysqld.service - SYSV: MySQL database server.
Loaded: loaded (/etc/rc.d/init.d/mysqld)
Active: failed (Result: exit-code) since Thu 2015-09-24 10:23:25 CST; 13s ago
Process: 3501 ExecStart = / etc / rc.d / init.d / mysqld start (code = exited, status = 1 / FAILURE)
Sep 24 10:23:13 localhost.localdomain systemd [1]: Starting SYSV: MySQL database server ....
Sep 24 10:23:25 localhost.localdomain mysqld [3501]: MySQL Daemon failed to start.
Sep 24 10:23:25 localhost.localdomain mysqld [3501]: Starting mysqld: [FAILED]
Sep 24 10:23:25 localhost.localdomain systemd [1]: mysqld.service: control process exited, code = exited status = 1
Sep 24 10:23:25 localhost.localdomain systemd [1]: Failed to start SYSV: MySQL database server ..
Sep 24 10:23:25 localhost.localdomain systemd [1]: Unit mysqld.service entered failed state.
Even removed the container does not work, the question about Docker mount directory, refer to another article blog, summary of Docker directory mounted.
On the settlement of this issue yet to find a way, even if the re / var / lib / mysql owner and group settings does not work, I ended up with was a crude way, direct rm -rf / var / lib / mysql /, and then restart the service.
6>
if [-z "$ MYSQL_ROOT_PASSWORD" -a -z "$ MYSQL_ALLOW_EMPTY_PASSWORD"]; then
echo> & 2 'error: database is uninitialized and MYSQL_ROOT_PASSWORD not set'
echo> & 2 'Did you forget to add -e MYSQL_ROOT_PASSWORD = ...?'
exit 1
fi
Set the mysql password of root account, which -z determine whether an empty string, -a two conditions are met, it is true. From here we can see, feel free to MYSQL_ALLOW_EMPTY_PASSWORD assign a value, can be achieved without password.
7>
mkdir -p "$ DATADIR"
chown -R mysql: mysql "$ DATADIR"
echo 'Running mysql_install_db'
mysql_install_db --user = mysql --datadir = "$ DATADIR" --rpm --keep-my-cnf
echo 'Finished mysql_install_db'
mysqld --user = mysql --datadir = "$ DATADIR" --skip-networking &
pid = "$!"
Create / var / lib / mysql, while its owner and group set to mysql, and then initialize the database, and finally start the database with the mysqld command. $! Refers to Shell last run of the background Process of PID.
8>
mysql = (mysql --protocol = socket -uroot)
for i in {30..0}; do
if echo 'SELECT 1' | "$ {mysql [@]}" &> / dev / null; then
break
fi
echo 'MySQL init process in progress ...'
sleep 1
done
if [ "$ i" = 0]; then
echo> & 2 'MySQL init process failed.'
exit 1
fi
This code is the use of mysql client test mysql service is started. There is the use of parentheses () constructor mysql variable manner quite interesting, not previously seen. Specifically verified this:
[Root @ localhost ~] # mysql = (mysql --protocol = socket -uroot)
[Root @ localhost ~] # echo $ {mysql}
mysql
[Root @ localhost ~] # echo $ {mysql [@]}
mysql --protocol = socket -uroot
This code gives 30s time to determine whether the mysql service is started, if started, then exit the loop, if not start, after the end of the loop, the variable i is 0, by the subsequent if statement, screen output, "MySQL init process failed ".
Here it is determined whether to start mysql service very interesting way,
[Root @ localhost ~] # mysql = (mysql --protocol = socket -uroot)
[Root @ localhost ~] # echo 'SELECT 1' | "$ {mysql [@]}"
1
1
[Root @ localhost ~] # mysql
Welcome to the MySQL monitor Commands end with;. Or \ g.
Your MySQL connection id is 11
Server version: 5.6.26 MySQL Community Server (GPL)
mysql> select 1;
+ --- +
| 1 |
+ --- +
| 1 |
+ --- +
1 row in set (0.01 sec)
If you stopped the mysql service, the output is as follows:
[Root @ localhost ~] # systemctl stop mysqld
[Root @ localhost ~] # echo 'SELECT 1' | "$ {mysql [@]}"
ERROR 2002 (HY000): Can not connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
Here, there is a little mystifying,
if echo 'SELECT 1' | "$ {mysql [@]}" &> / dev / null; then
break
fi
determine if conditions do not echo 'SELECT 1' | "$ {mysql [@]}" return code command it? If this is the case, the successful implementation of the $? Is 0, then the statement should not be executed break, but instead of facts and speculation. On this point let us leave.
9>
mysql_tzinfo_to_sql / usr / share / zoneinfo | sed 's / Local time zone must be set - see zic manual page / FCTY /' | "$ {mysql [@]}" mysql
Mysql modify time zone on a bug, not the bottom.
10>
"$ {Mysql [@]}" << - EOSQL
- What's done in this file should not be replicated
- Or products like mysql-fabric will not work
SET @@ SESSION.SQL_LOG_BIN = 0;
DELETE FROM mysql.user;
CREATE USER 'root' @ '%' IDENTIFIED BY '$ {MYSQL_ROOT_PASSWORD}';
. GRANT ALL ON * * TO 'root' @ '%' WITH GRANT OPTION;
DROP DATABASE IF EXISTS test;
FLUSH PRIVILEGES;
EOSQL
This is mainly used to log the client database related operations, including modifying root password, its authorization, delete the test database. SET @@ SESSION.SQL_LOG_BIN = 0 action is to stop the use of log files, this is not quite understand.
11>
if [! -z "$ MYSQL_ROOT_PASSWORD"]; then
mysql + = (-p "$ {MYSQL_ROOT_PASSWORD}")
fi
if [ "$ MYSQL_DATABASE"]; then
echo "CREATE DATABASE IF NOT EXISTS \` $ MYSQL_DATABASE \ `;" | "$ {mysql [@]}"
mysql + = ( "$ MYSQL_DATABASE")
fi
if [ "$ MYSQL_USER" -a "$ MYSQL_PASSWORD"]; then
echo "CREATE USER '" $ MYSQL_USER "' @ '%' IDENTIFIED BY '" $ MYSQL_PASSWORD "';" | "$ {mysql [@]}"
if [ "$ MYSQL_DATABASE"]; then
echo "GRANT ALL ON \` "$ MYSQL_DATABASE". \ `* TO '" $ MYSQL_USER "' @ '%';" | "$ {mysql [@]}"
fi
echo 'FLUSH PRIVILEGES;' | "$ {mysql [@]}"
fi
This code is mainly to create the database, create mysql user and authorization. In fact, this means that users can start the container to create the database by specifying MYSQL_DATABASE parameters to create a new database user MYSQL_USER and MYSQL_PASSWORD.
Wherein, mysql + = (-p "$ {MYSQL_ROOT_PASSWORD}") is used to splice variables. for example:
[Root @ localhost ~] # mysql = (mysql --protocol = socket -uroot)
[Root @ localhost ~] # MYSQL_DATABASE = docker
[Root @ localhost ~] # mysql + = ( "$ MYSQL_DATABASE")
[Root @ localhost ~] # echo $ {mysql [@]}
mysql --protocol = socket -uroot docker
12>
for f in /docker-entrypoint-initdb.d/*; do
case "$ f" in
* .sh) Echo. "$ 0: running $ f"; "$ f" ;;
* .sql) Echo "$ 0: running $ f"; "$ {mysql [@]}" < "$ f" && echo ;;
*) Echo "$ 0: ignoring $ f" ;;
esac
echo
done
Other shell scripts or sql script to be executed, can be put under /docker-entrypoint-initdb.d/ directory. Just when you start the container, the container by the -v parameter to the directory is mounted on the host directory.
13>
!! If kill -s TERM "$ pid" || wait "$ pid"; then
echo> & 2 'MySQL init process failed.'
exit 1
fi
Closed started mysql server, many people may feel curious, rather than providing mysql service it? Why close it?
The answer lies in the CMD command dockerfile [ "mysqld"], if not closed, you can not start here.
Here lies the more interesting part of the script,
, On the kill, kill command by sending a signal to the specified process to end the process.
-s mean Specify the signal to send. The signal may be given as a signal name or number. specified signal needs to be sent.
If no signal is sent, then the default value is TERM signal.
Distinction between -9 and -TERM
kill -TERM PID: TERM is a request to completely terminate it expects to receive an operation to perform self-clearing process state and exit, it is a more gentle way.
kill -9 PID:
This powerful and dangerous command to force termination of processes running when suddenly, at the end of the process is not self-cleaning. Hazards leading to system resources can not be properly released, it is generally not recommended unless other methods are ineffective.
When you use this command, it must be confirmed by ps -ef not have any remaining zombies. Only to eliminate the zombie process by terminating the parent process. If the zombie process is init adoption, the problem is more serious. Kill the init process means shutting down the system.
If your system has a zombie process and its parent process is init, and zombie process takes up a lot of system resources, you need to reboot the machine at some time to clear the process table
Second, on the || operator
About the difference between && and ||
command1 && command2: left command (command 1) returns true (ie returns 0, was successfully executed), the right of && command (Command 2) to be able to be executed.
command1 || command2: left command fails (command 1) carried out on the implementation of the right of the command (command 2).
Third, on the wait
wait command to wait for the command to complete, until its return to the terminal after the implementation.
So the logic of this script is to first shut down the mysqld process with the kill -s TERM "$ pid" the way, if you do succeed, then! Kill -s TERM "$ pid" The result is false, this time on the implementation of wait "$ pid ", wait wait mysqld closed, closed after mysqld finished, wait" $ pid "is true, then! wait" $ pid "is false. echo statement is not executed.
So far, the analysis is complete ~ |
|
|
|