docker-zabbix 入口脚本解析

导读

  • 在zabbix的docker镜像中,docker容器的入口脚本docker-entrypoint.sh是一个非常优秀的脚本文件,一个文件实现了多个zabbix组件的安装和配置,其中有非常多的优秀代码函数值得我们去借鉴,本文主要以注释的方式,对涉及到的函数功能进行解析。
  • 从这个入口函数,我总结出一个优秀以及通用的docker镜像,入口脚本的编写是非常重要的,我认为一个优秀的docker镜像应用具备有一下几个特点
  1. 使用环境变量的方式进行组件配置,我们可以通过在运行docker容器时,动态地赋值环境变量,使容器应用具有不同的功能或性能
  2. 应用配置使用文本的方式,动态地进行加载配置,不应写死在应用程序代码中
  3. 优秀的脚本编程能力,熟悉shell文本处理

脚本解析

#!/bin/bash

set -eo pipefail

set +e

# Script trace mode
# 设置是否启用调试模式,即使用set -o xtrace
if [ "${DEBUG_MODE}" == "true" ]; then
    set -o xtrace
fi

# Type of Zabbix component
# Possible values: [server, proxy, agent, frontend, java-gateway, appliance]
# 设置组件类型,通过zbx_type接收来自容器ENV中的ZBX_TYPE的变量
zbx_type=${ZBX_TYPE}

# Type of Zabbix database
# Possible values: [mysql, postgresql]
# 设置数据库类型,通过zbx_db_type接收来自容器启动时ZBX_DB_TYPE的变量内容
zbx_db_type=${ZBX_DB_TYPE}

# Type of web-server. Valid only with zbx_type = frontend
# Possible values: [apache, nginx]
# 设置zabbix-web类型,支持apache以及nginx
zbx_opt_type=${ZBX_OPT_TYPE}

# Default Zabbix installation name
# Used only by Zabbix web-interface
# 变量赋值,如果没有配置,则会采用'-'右边的默认值
ZBX_SERVER_NAME=${
   
   ZBX_SERVER_NAME:-"Zabbix docker"}
# Default Zabbix server host
ZBX_SERVER_HOST=${
   
   ZBX_SERVER_HOST:-"zabbix-server"}
# Default Zabbix server port number
ZBX_SERVER_PORT=${
   
   ZBX_SERVER_PORT:-"10051"}

# Default timezone for web interface
PHP_TZ=${
   
   PHP_TZ:-"Europe/Riga"}

#Enable PostgreSQL timescaleDB feature:
ENABLE_TIMESCALEDB=${
   
   ENABLE_TIMESCALEDB:-"false"}

# Default directories
# User 'zabbix' home directory
ZABBIX_USER_HOME_DIR="/var/lib/zabbix"
# Configuration files directory
ZABBIX_ETC_DIR="/etc/zabbix"
# Web interface www-root directory
ZBX_FRONTEND_PATH="/usr/share/zabbix"

# usage: file_env VAR [DEFAULT]
# as example: file_env 'MYSQL_PASSWORD' 'zabbix'
#    (will allow for "$MYSQL_PASSWORD_FILE" to fill in the value of "$MYSQL_PASSWORD" from a file)
# unsets the VAR_FILE afterwards and just leaving VAR
# 读取文件内容并将内容赋值给变量VAR,用于敏感变量内容赋值,比如密码,数据库配置等。
file_env() {
   
   
    local var="$1"
    local fileVar="${var}_FILE"
    local defaultValue="${2:-}"

    if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
        echo "**** Both variables $var and $fileVar are set (but are exclusive)"
        exit 1
    fi

    local val="$defaultValue"

    if [ "${!var:-}" ]; then
        val="${!var}"
        echo "** Using ${var} variable from ENV"
    elif [ "${!fileVar:-}" ]; then
        if [ ! -f "${!fileVar}" ]; then
            echo "**** Secret file \"${!fileVar}\" is not found"
            exit 1
        fi
        val="$(< "${!fileVar}")"
        echo "** Using ${var} variable from secret file"
    fi
    export "$var"="$val"
    unset "$fileVar"
}

# 配置zabbix数据库,此部分适用于all in one模式的部署,生产中不建议使用
configure_db_mysql() {
   
   
    [ "${DB_SERVER_HOST}" != "localhost" ] && return

    echo "** Configuring local MySQL server"

    MYSQL_ALLOW_EMPTY_PASSWORD=true
    MYSQL_DATA_DIR="/var/lib/mysql"

    if [ -f "/etc/mysql/my.cnf" ]; then
        MYSQL_CONF_FILE="/etc/mysql/my.cnf"
    elif [ -f "/etc/my.cnf.d/server.cnf" ]; then
        MYSQL_CONF_FILE="/etc/my.cnf.d/server.cnf"
        DB_SERVER_SOCKET="/var/lib/mysql/mysql.sock"
    elif [ -f "/etc/my.cnf.d/mariadb-server.cnf" ]; then
        MYSQL_CONF_FILE="/etc/my.cnf.d/mariadb-server.cnf"
        DB_SERVER_SOCKET="/var/run/mysqld/mysqld.sock"
    else
        echo "**** Could not found MySQL configuration file"
        exit 1
    fi

    if [ -f "/usr/bin/mysqld" ]; then
        MYSQLD=/usr/bin/mysqld
    elif [ -f "/usr/sbin/mysqld" ]; then
        MYSQLD=/usr/sbin/mysqld
    elif [ -f "/usr/libexec/mysqld" ]; then
        MYSQLD=/usr/libexec/mysqld
    else
        echo "**** Could not found mysqld binary file"
        exit 1
    fi

    sed -Ei 's/^(bind-address|log)/#&/' "$MYSQL_CONF_FILE"

    if [ ! -d "$MYSQL_DATA_DIR/mysql" ]; then
        [ -d "$MYSQL_DATA_DIR" ] || mkdir -p "$MYSQL_DATA_DIR"

        chown -R mysql:mysql "$MYSQL_DATA_DIR"

        echo "** Installing initial MySQL database schemas"
        mysql_install_db --user=mysql --datadir="$MYSQL_DATA_DIR" 2>&1
    else
        echo "**** MySQL data directory is not empty. Using already existing installation."
        chown -R mysql:mysql "$MYSQL_DATA_DIR"
    fi

    mkdir -p /var/run/mysqld
    ln -s /var/run/mysqld /run/mysqld
    chown -R mysql:mysql /var/run/mysqld
    chown -R mysql:mysql /run/mysqld

    echo "** Starting MySQL server in background mode"

    nohup $MYSQLD --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin \
            --user=mysql --log-output=none --pid-file=/var/lib/mysql/mysqld.pid \
            --port=3306 --character-set-server=utf8 --collation-server=utf8_bin &
}

#准备系统参数,即将变量进行赋值,变量的赋值来源有两种,一种为容器启动时传进来的,另一种为默认值
prepare_system() {
   
   
    local type=$1
    local web_server=$2

    echo "** Preparing the system"
#此函数主要用于appliance模式
    if [ "$type" != "appliance" ]; then
        return
    fi

    ZBX_ADD_AGENT=${
   
   ZBX_ADD_AGENT:-"false"}
    ZBX_ADD_JAVA_GATEWAY=${
   
   ZBX_ADD_JAVA_GATEWAY:-"false"}
    ZBX_ADD_SERVER=${
   
   ZBX_ADD_SERVER:-"true"}
    [ "${ZBX_ADD_SERVER}" == "true" ] && ZBX_SERVER_HOST="localhost"
    [ "${ZBX_ADD_SERVER}" == "true" ] && ZBX_SERVER_PORT="10051"
    ZBX_MAIN_DB=${
   
   ZBX_MAIN_DB:-"mysql"}
    ZBX_ADD_PROXY=${
   
   ZBX_ADD_PROXY:-"false"}
    ZBX_PROXY_DB=${
   
   ZBX_PROXY_DB:-"sqlite3"}
    ZBX_ADD_WEB=${
   
   ZBX_ADD_WEB:-"true"}
    ZBX_WEB_SERVER=${
   
   ZBX_WEB_SERVER:-"nginx"}
    DB_SERVER_HOST=${
   
   DB_SERVER_HOST:-"localhost"}
    [ "${ZBX_ADD_JAVA_GATEWAY}" == "true" ] && ZBX_JAVAGATEWAY_ENABLE="true"
    [ "${ZBX_ADD_JAVA_GATEWAY}" == "true" ] && ZBX_JAVAGATEWAY="localhost"
    [ "${ZBX_ADD_JAVA_GATEWAY}" == "true" ] && ZBX_JAVAGATEWAYPORT="10052"

    [ "${ZBX_ADD_SERVER}" == "true" ] && configure_db_${ZBX_MAIN_DB}
}

#此函数用于对特殊字符进行处理,使用反斜杠\对字符进行转义,如变量为[test],处理后则为\[test\]
escape_spec_char() {
   
   
    local var_value=$1

    var_value="${var_value//\\/\\\\}"
    var_value="${var_value//[$'\n']/}"
    var_value="${var_value//\//\\/}"
    var_value="${var_value//./\\.}"
    var_value="${var_value//\*/\\*}"
    var_value="${var_value//^/\\^}"
    var_value="${var_value//\$/\\\$}"
    var_value="${var_value//\&/\\\&}"
    var_value="${var_value//\[/\\[}"
    var_value="${var_value//\]/\\]}"

    echo "$var_value"
}

# 更新配置文件
# 参数1:配置文件路径
# 参数2:变量名称
# 参数3:变量值
# 参数4:是否为多实例
# 在这函数里面,使用了sed字符流处理工具实现了对配置文件的更新和修改
update_config_var() {
   
   
    local config_path=$1
    local var_name=$2
    local var_value=$3
    local is_multiple=$4
# 检查配置文件是否存在
    if [ ! -f "$config_path" ]; then
        echo "**** Configuration file '$config_path' does not exist"
        return
    fi

    echo -n "** Updating '$config_path' parameter \"$var_name\": '$var_value'... "
# 如果没有传入第3个参数,即参数值,则将该参数配置从配置文件中进行移除
# ie: before: VAR=test
#     after : 
    # Remove configuration parameter definition in case of unset parameter value
    if [ -z "$var_value" ]; then
# 删除以变量名称为开头所在的行
        sed -i -e "/^$var_name=/d" "$config_path"
        echo "removed"
        return
    fi
# 如果传入第3个参数为一对空的双引号"",则将参数后面的值抹去
# ie: before: VAR=test
#     after : VAR=
    # Remove value from configuration parameter in case of double quoted parameter value
    if [ "$var_value" == '""' ]; then
# sed -i -e '/^A=/s/=.*/=/' test.conf
# 将=后面的值全部替换为=
        sed -i -e "/^$var_name=/s/=.*/=/" "$config_path"
        echo "undefined"
        return
    fi

    # Use full path to a file for TLS related configuration parameters
    if [[ $var_name =~ ^TLS.*File$ ]]; then
        var_value=$ZABBIX_USER_HOME_DIR/enc/$var_value
    fi

    # Escaping characters in parameter value
    var_value=$(escape_spec_char "$var_value")

# 判断在参数文件中是否有该变量,如果有则进行更新
    if [ "$(grep -E "^$var_name=" $config_path)" ] && [ "$is_multiple" != "true" ]; then
        sed -i -e "/^$var_name=/s/=.*/=$var_value/" "$config_path"
        echo "updated"
# 判断在参数文件中,以[# 变量名称]的数量有多少个
    elif [ "$(grep -Ec "^# $var_name=" $config_path)" -gt 1 ]; then
# 在匹配的行之前插入变量值
# ie: before # VAR=
#     after  VAR=new_value
#            # VAR=
        sed -i -e  "/^[#;] $var_name=$/i\\$var_name=$var_value" "$config_path"
        echo "added first occurrence"
    else
# 匹配在参数文件中,以# 或者, 变量名= 所在行下面新增一行变量=值
# 这里的&为模式匹配保存下来的内容,后面加上换行符,意味着新增一行
# ie:before # VAR=demo
#     after  # VAR=demo
#            VAR=new_value
        sed -i -e "/^[#;] $var_name=/s/.*/&\n$var_name=$var_value/" "$config_path"
        echo "added"
    fi

}

update_config_multiple_var() {
   
   
    local config_path=$1
    local var_name=$2
    local var_value=$3

    var_value="${var_value%\"}"
    var_value="${var_value#\"}"

    local IFS=,
    local OPT_LIST=($var_value)

    for value in "${OPT_LIST[@]}"; do
        update_config_var $config_path $var_name $value true
    done
}

# Check prerequisites for MySQL database
# 检查Mysql参数并根据类型赋值相应的mysql变量参数
check_variables_mysql() {
   
   
    local type=$1

    DB_SERVER_HOST=${
   
   DB_SERVER_HOST:-"mysql-server"}
    DB_SERVER_PORT=${
   
   DB_SERVER_PORT:-"3306"}
    USE_DB_ROOT_USER=false
    CREATE_ZBX_DB_USER=false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值