构建docker镜像执行mysql脚本_Shell脚本解读——docker官方镜像Mysql构建脚本

docker官方镜像Mysql构建脚本

概述

解读官方脚本,为了模仿官方格式,提升自己的Shell脚本的编写能力和规范编写方式。如下是原版脚本内容:

#!/bin/bash

set -eo pipefail

shopt -s nullglob

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)

# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936

# https://github.com/docker-library/postgres/pull/452

if [ -x "$f" ]; then

mysql_note "$0: running $f"

"$f"

else

mysql_note "$0: sourcing $f"

. "$f"

fi

;;

*.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 ;;

*.sql.xz) mysql_note "$0: running $f"; xzcat "$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' ] || [ "${MYSQL_MAJOR}" = '5.7' ]; 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 << /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_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 <<

# ie: docker_process_sql --dont-use-mysql-root-password --database=mydb /dev/null

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

脚本内容

定义错误捕获

#!/bin/bash

set -eo pipefail # 包括管道符,只要出现错误,脚本中断

shopt -s nullglob # 开启nullglob,确保不会将*号错误解析

定义日志输出函数

定义日志输出内容函数,并调用日志函数

mysql_log() {

# 定义type为本地变量,根据 shift 来动态获取函数后面的参数 type="$1"

local type="$1"; shift

# 将内容通过格式化输出 $type 为等级,$*为后面的其他内容

printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*"

}

mysql_note() {

# 将第一个参数传入mysql_log函数,并通过$@捕获所有尾部参数

mysql_log Note "$@"

}

mysql_warn() {

mysql_log Warn "$@" >&2

}

mysql_error() {

mysql_log ERROR "$@" >&2

exit 1

}

获取传入的ENV变量信息

该功能是将变量和值绑定到一起

# file_env 'MYSQL_ROOT_HOST' '%'

# file_env 'MYSQL_DATABASE'

file_env() {

# 获取函数变量的第一位参数 例如:file_env 'MYSQL_DATABASE'

local var="$1" // 1. var=MYSQL_DATABASE

# 将var变量拼接成fileVar变量:MYSQL_DATABASE_FILE

local fileVar="${var}_FILE" // 2. fileVar=MYSQL_DATABASE_FILE

# $2存在值,则赋值为def变量,没有则def为空

local def="${2:-}" // 3. 为空

# 判断如果${!var} 和${!fileVar},也就是MYSQL_DATABASE和MYSQL_DATABASE_FILE 不为空则进入if,mysql_error输出错误日志

if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then

mysql_error "Both $var and $fileVar are set (but are exclusive)" // 4. 进入if输出日志

fi

# 将def变量传入到局部val变量

local val="$def" // 5. val=''

# 如果${!var}也就是有值则进入函数体

if [ "${!var:-}" ]; then // var=$MYSQL_DATABASE

val="${!var}" // val=$MYSQL_DATABASE

elif [ "${!fileVar:-}" ]; then

val="$(< "${!fileVar}")"

fi

# 导入环境变量

export "$var"="$val" //也就是将MYSQL_DATABASE=xxx绑定

# 删除$fileVar变量

unset "$fileVar"

}

执行方式判断

# 如果是./执行则函数为假执行_main函数,如果是source则为真不执行_main

_is_sourced() {

# https://unix.stackexchange.com/a/215279

[ "${#FUNCNAME[@]}" -ge 2 ] \

&& [ "${FUNCNAME[0]}" = '_is_sourced' ] \

&& [ "${FUNCNAME[1]}" = 'source' ]

}

if ! _is_sourced; then

_main "$@"

fi

$FUNCNAME —— Bash 内部环境变量,它是一个包含了当前在执行调用堆栈中的所有 Shell 函数名称的数组变量。${FUNCNAME[0]} 代表当前正在执行的 Shell 函数的名称,${FUNCNAME[1]} 则代表调用函数

测试代码

1.sh

#!/bin/bash

_is_sourced() {

[ "${#FUNCNAME[@]}" -ge 2 ] && [ "${FUNCNAME[0]}" = '_is_sourced' ] && [ "${FUNCNAME[1]}" = 'source' ]

}

wsl(){

echo 1

}

if ! _is_sourced; then

wsl

fi

2.sh

#!/bin/bash

source ./1.sh

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值