k8s中使用mysql主从集群

1,825次阅读
没有评论

共计 55451 个字符,预计需要花费 139 分钟才能阅读完成。

k8s中使用mysql主从集群

RDS太贵了,除了生产用到,其他一律自建。。。本来博主自建是在ecs上进行,用二进制创建也很快,但是后面领导说要在k8s中创建,且以后缩小公用范围,将范围缩减到部门,让部门的成本中心自行买单

作为中间件平台的k8s集群,同时还得考虑集群外访问方式,不过可比其他那些有注册模式得中间件好多了,看下需求:

  • 持久化数据落盘
  • 部署模式:单实例模式,一主多从
  • 访问方式:集群内/外都可访问
  • 数据监控:mysqld_exporter
  • 读写分离:要么程序上处理读写逻辑,或者用中间件
  • 多平台架构镜像:x86和arm,都用ubuntu/debian系统镜像

standalone单实例此处就不i赘述,很久以前写过类似的样例,此篇只描述主从结构

x86平台架构镜像制作

mysql官方镜像:https://hub.docker.com/_/mysql,根据这个debian镜像坐下改造,让它初始化时创建以下用户和授权:

  • replication:用于主从复制同步
  • monitor:用于mysqld_exporter采集
  • xbk:用xbk工具备份还原(为新slave节点加快还原速度)

修改官方得docker-entrypoint.sh中的 docker_setup_db 函数,在其中加入创建用户和授权的语句

        # 创建replication用户并授权
        if [ -n "$MYSQL_REPLICATION_USER" ] && [ -n "$MYSQL_REPLICATION_PASSWORD" ]; then
                mysql_note "Creating user $MYSQL_REPLICATION_USER"
                docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD';"
                docker_process_sql --database=mysql <<<"GRANT REPLICATION SLAVE,SUPER ON *.* TO '$MYSQL_REPLICATION_USER'@'%';"
                docker_process_sql --database=mysql <<<"FLUSH PRIVILEGES ;"
        fi
        # 创建monitor用户并授权
        if [ -n "$MYSQL_MONITOR_USER" ] && [ -n "$MYSQL_MONITOR_PASSWORD" ]; then
                mysql_note "Creating user $MYSQL_MONITOR_USER"
                docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_MONITOR_USER'@'%' IDENTIFIED BY '$MYSQL_MONITOR_PASSWORD' WITH MAX_USER_CONNECTIONS 3;"
                docker_process_sql --database=mysql <<<"GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO '$MYSQL_MONITOR_USER'@'%';"
                docker_process_sql --database=mysql <<<"FLUSH PRIVILEGES ;"
        fi
        # 创建xbk用户并授权
        if [ -n "$MYSQL_XBK_USER" ] && [ -n "$MYSQL_XBK_PASSWORD" ]; then
                mysql_note "Creating user $MYSQL_XBK_USER"
                docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_XBK_USER'@'%' IDENTIFIED BY '$MYSQL_XBK_PASSWORD';"
                docker_process_sql --database=mysql <<<"GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT,SUPER ON *.* TO '$MYSQL_XBK_USER'@'%';"
                docker_process_sql --database=mysql <<<"FLUSH PRIVILEGES ;"
        fi

完整dockerfile和docker-entrypoint.sh如下

[root@k8s-master master-slave]# mkdir mysql-image
[root@k8s-master master-slave]# cd mysql-image/
# 准备docker-entrypoint.sh脚本
[root@k8s-master mysql-image]# cat docker-entrypoint.sh
#!/bin/bash
set -eo pipefail
shopt -s nullglob

# logging functions
mysql_log() {
        local type="$1"; shift
        # accept argument string or stdin
        local text="$*"; if [ "$#" -eq 0 ]; then text="$(cat)"; fi
        local dt; dt="$(date --rfc-3339=seconds)"
        printf '%s [%s] [Entrypoint]: %s\n' "$dt" "$type" "$text"
}
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
}

# arguments necessary to run "mysqld --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values)
_verboseHelpArgs=(
        --verbose --help
        --log-bin-index="$(mktemp -u)" # https://github.com/docker-library/mysql/issues/136
)

mysql_check_config() {
        local toRun=( "$@" "${_verboseHelpArgs[@]}" ) 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
        "$@" "${_verboseHelpArgs[@]}" 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 --default-time-zone=SYSTEM --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 initialized
                        # 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 --default-time-zone=SYSTEM --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 <<-'EOF'
                        Database is uninitialized and password option is not specified
                            You need to specify one of the following:
                            - MYSQL_ROOT_PASSWORD
                            - MYSQL_ALLOW_EMPTY_PASSWORD
                            - MYSQL_RANDOM_ROOT_PASSWORD
                EOF
        fi

        # This will prevent the CREATE USER from failing (and thus exiting with a half-initialized database)
        if [ "$MYSQL_USER" = 'root' ]; then
                mysql_error <<-'EOF'
                        MYSQL_USER="root", MYSQL_USER and MYSQL_PASSWORD are for configuring a regular user and cannot be used for the root user
                            Remove MYSQL_USER="root" and use one of the following to control the root user password:
                            - MYSQL_ROOT_PASSWORD
                            - MYSQL_ALLOW_EMPTY_PASSWORD
                            - MYSQL_RANDOM_ROOT_PASSWORD
                EOF
        fi

        # warn when missing one of MYSQL_USER or MYSQL_PASSWORD
        if [ -n "$MYSQL_USER" ] && [ -z "$MYSQL_PASSWORD" ]; then
                mysql_warn 'MYSQL_USER specified, but missing MYSQL_PASSWORD; MYSQL_USER will not be created'
        elif [ -z "$MYSQL_USER" ] && [ -n "$MYSQL_PASSWORD" ]; then
                mysql_warn 'MYSQL_PASSWORD specified, but missing MYSQL_USER; MYSQL_PASSWORD will be ignored'
        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}" --default-time-zone=SYSTEM
        else
                "$@" --initialize-insecure --default-time-zone=SYSTEM
        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-extra-file=<( _mysql_passfile "${passfileArgs[@]}") --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" --comments "$@"
}

# 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
        fi

        # 创建replication用户并授权
        if [ -n "$MYSQL_REPLICATION_USER" ] && [ -n "$MYSQL_REPLICATION_PASSWORD" ]; then
                mysql_note "Creating user $MYSQL_REPLICATION_USER"
                docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD';"
                docker_process_sql --database=mysql <<<"GRANT REPLICATION SLAVE,SUPER ON *.* TO '$MYSQL_REPLICATION_USER'@'%';"
                docker_process_sql --database=mysql <<<"FLUSH PRIVILEGES ;"
        fi
        # 创建monitor用户并授权
        if [ -n "$MYSQL_MONITOR_USER" ] && [ -n "$MYSQL_MONITOR_PASSWORD" ]; then
                mysql_note "Creating user $MYSQL_MONITOR_USER"
                docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_MONITOR_USER'@'%' IDENTIFIED BY '$MYSQL_MONITOR_PASSWORD' WITH MAX_USER_CONNECTIONS 3;"
                docker_process_sql --database=mysql <<<"GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO '$MYSQL_MONITOR_USER'@'%';"
                docker_process_sql --database=mysql <<<"FLUSH PRIVILEGES ;"
        fi
        # 创建xbk用户并授权
        if [ -n "$MYSQL_XBK_USER" ] && [ -n "$MYSQL_XBK_PASSWORD" ]; then
                mysql_note "Creating user $MYSQL_XBK_USER"
                docker_process_sql --database=mysql <<<"CREATE USER '$MYSQL_XBK_USER'@'%' IDENTIFIED BY '$MYSQL_XBK_PASSWORD';"
                docker_process_sql --database=mysql <<<"GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT,SUPER ON *.* TO '$MYSQL_XBK_USER'@'%';"
                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-extra-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

                        # check dir permissions to reduce likelihood of half-initialized database
                        ls /docker-entrypoint-initdb.d/ > /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
# 官方dockerfile
[root@k8s-master mysql-image]# cat dockerfile
#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#

FROM debian:buster-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
# https://github.com/tianon/gosu/releases
ENV GOSU_VERSION 1.14
RUN set -eux; \
        savedAptMark="$(apt-mark showmanual)"; \
        apt-get update; \
        apt-get install -y --no-install-recommends ca-certificates wget; \
        rm -rf /var/lib/apt/lists/*; \
        dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
        wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
        wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
        export GNUPGHOME="$(mktemp -d)"; \
        gpg --batch --keyserver hkps://keys.openpgp.org --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; \
        apt-mark auto '.*' > /dev/null; \
        [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
        apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
        chmod +x /usr/local/bin/gosu; \
        gosu --version; \
        gosu nobody true

RUN mkdir /docker-entrypoint-initdb.d

RUN set -eux; \
        apt-get update; \
        apt-get install -y --no-install-recommends \
                bzip2 \
                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 \
                xz-utils \
                zstd \
        ; \
        rm -rf /var/lib/apt/lists/*

RUN set -eux; \
# gpg: key 3A79BD29: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
        key='859BE8D7C586F538430B19C2467B942D3A79BD29'; \
        export GNUPGHOME="$(mktemp -d)"; \
        gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \
        mkdir -p /etc/apt/keyrings; \
        gpg --batch --export "$key" > /etc/apt/keyrings/mysql.gpg; \
        gpgconf --kill all; \
        rm -rf "$GNUPGHOME"

ENV MYSQL_MAJOR 5.7
ENV MYSQL_VERSION 5.7.40-1debian10

RUN echo 'deb [ signed-by=/etc/apt/keyrings/mysql.gpg ] http://repo.mysql.com/apt/debian/ buster mysql-5.7' > /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}" \
# 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 \
        && 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 1777 /var/run/mysqld /var/lib/mysql

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"]

如果不想自己从头编译,则可以用下面dockerfile

[root@k8s-master mysql-image]# cat dockerfile
FROM mysql:5.7.40
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -sf usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat

# 开始编译镜像
[root@k8s-master mysql-image]# docker build . -t mysql-x86:5.7.40

部署主从

准备configmap和statefulset创建主从

[root@k8s-master master-slave]# kubectl create ns mysql
[root@k8s-master master-slave]# cat mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
data:
  master.cnf: |
    # Apply this config only on the master.
    [mysqld]
    log-bin
  slave.cnf: |
    # Apply this config only on slaves.
    [mysqld]
    super-read-only
[root@k8s-master master-slave]# kubectl apply -f mysql-configmap.yaml

[root@k8s-master master-slave]# cat mysql-sts.yaml
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  replicas: 2
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: init-mysql
        image: mysql-x86:5.7.40
        command:
        - bash
        - "-c"
        - |
          set -ex
          # Generate mysql server-id from pod ordinal index.
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf.d/server-id.cnf
          # Add an offset to avoid reserved server-id=0 value.
          echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
          # Copy appropriate conf.d files from config-map to emptyDir.
          if [[ $ordinal -eq 0 ]]; then
            cp /mnt/config-map/master.cnf /mnt/conf.d/
          else
            cp /mnt/config-map/slave.cnf /mnt/conf.d/
          fi
        volumeMounts:
        - name: conf
          mountPath: /mnt/conf.d
        - name: config-map
          mountPath: /mnt/config-map
      - name: clone-mysql
        image: registry.cn-shanghai.aliyuncs.com/soulchild/xtrabackup:2.4
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: root_pass
        command:
        - bash
        - "-c"
        - |
          set -ex
          # Skip the clone if data already exists.
          [[ -d /var/lib/mysql/mysql ]] && exit 0
          # Skip the clone on master (ordinal index 0).
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          [[ $ordinal -eq 0 ]] && exit 0
          # Clone data from previous peer.
          ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
          # Prepare the backup.
          xtrabackup --prepare --target-dir=/var/lib/mysql
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
      containers:
      - name: mysql
        image: mysql-x86:5.7.40
        env:
        - name: MYSQL_ROOT_HOST
          value: '127.0.0.1'
        - name: MYSQL_ROOT_PASSWORD
          value: "abcd123456"
        - name: MYSQL_REPLICATION_USER
          value: replication
        - name: MYSQL_REPLICATION_PASSWORD
          value: "abcd123456"
        - name: MYSQL_MONITOR_USER
          value: monitor
        - name: MYSQL_MONITOR_PASSWORD
          value: "abcd123456"
        - name: MYSQL_XBK_USER
          value: xbk
        - name: MYSQL_XBK_PASSWORD
          value: "abcd123456"

        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping", "-u${MYSQL_MONITOR_USER}", "-p${MYSQL_MONITOR_PASSWORD}"]
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          exec:
            # Check we can execute queries over TCP (skip-networking is off).
            command: ["mysqladmin", "ping", "-u${MYSQL_MONITOR_USER}", "-p${MYSQL_MONIOTR_PASSWORD}"]
          initialDelaySeconds: 5
          periodSeconds: 2
          timeoutSeconds: 1
      - name: xtrabackup
        image: registry.cn-shanghai.aliyuncs.com/soulchild/xtrabackup:2.4
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "abcd123456"
        - name: MYSQL_REPLICATION_USER
          value: replication
        - name: MYSQL_REPLICATION_PASSWORD
          value: "abcd123456"
        - name: MYSQL_MONITOR_USER
          value: monitor
        - name: MYSQL_MONITOR_PASSWORD
          value: "abcd123456"
        - name: MYSQL_XBK_USER
          value: xbk
        - name: MYSQL_XBK_PASSWORD
          value: "abcd123456"
        ports:
        - name: xtrabackup
          containerPort: 3307
        command:
        - bash
        - "-c"
        - |
          set -ex
          cd /var/lib/mysql

          # Determine binlog position of cloned data, if any.
          if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
            # XtraBackup already generated a partial "CHANGE MASTER TO" query
            # because we're cloning from an existing slave. (Need to remove the tailing semicolon!)
            cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
            # Ignore xtrabackup_binlog_info in this case (it's useless).
            rm -f xtrabackup_slave_info xtrabackup_binlog_info
          elif [[ -f xtrabackup_binlog_info ]]; then
            # We're cloning directly from master. Parse binlog position.
            [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
            rm -f xtrabackup_binlog_info xtrabackup_slave_info
            echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
                  MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
          fi

          # Check if we need to complete a clone by starting replication.
          if [[ -f change_master_to.sql.in ]]; then
            echo "Waiting for mysqld to be ready (accepting connections)"
            until mysql -h 127.0.0.1 -u${MYSQL_REPLICATION_USER} -p${MYSQL_REPLICATION_PASSWORD} -e "SELECT 1"; do sleep 1; done

            echo "Initializing replication from clone position"
            mysql -h 127.0.0.1 -u${MYSQL_REPLICATION_USER} -p${MYSQL_REPLICATION_PASSWORD}\
                  -e "$(<change_master_to.sql.in), \
                          MASTER_HOST='mysql-0.mysql', \
                          MASTER_USER='${MYSQL_REPLICATION_USER}', \
                          MASTER_PASSWORD='${MYSQL_REPLICATION_PASSWORD}', \
                          MASTER_CONNECT_RETRY=10; \
                        START SLAVE;" || exit 1
            # In case of container restart, attempt this at-most-once.
            mv change_master_to.sql.in change_master_to.sql.orig
          fi

          # Start a server to send backups when requested by peers.
          exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
            "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=${MYSQL_XBK_USER} --password=${MYSQL_XBK_PASSWORD}"
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
      - name: mysqld-exporter
        image: prom/mysqld-exporter:v0.12.1
        args:
        - --collect.info_schema.tables
        - --collect.info_schema.innodb_tablespaces
        - --collect.info_schema.innodb_metrics
        - --collect.global_status
        - --collect.global_variables
        - --collect.slave_status
        - --collect.info_schema.processlist
        - --collect.perf_schema.tablelocks
        - --collect.perf_schema.eventsstatements
        - --collect.perf_schema.eventsstatementssum
        - --collect.perf_schema.eventswaits
        - --collect.auto_increment.columns
        - --collect.binlog_size
        - --collect.perf_schema.tableiowaits
        - --collect.perf_schema.indexiowaits
        - --collect.info_schema.userstats
        - --collect.info_schema.clientstats
        - --collect.info_schema.tablestats
        - --collect.info_schema.schemastats
        - --collect.perf_schema.file_events
        - --collect.perf_schema.file_instances
        - --collect.perf_schema.replication_group_member_stats
        - --collect.perf_schema.replication_applier_status_by_worker
        - --collect.slave_hosts
        - --collect.info_schema.innodb_cmp
        - --collect.info_schema.innodb_cmpmem
        - --collect.info_schema.query_response_time
        - --collect.engine_tokudb_status
        - --collect.engine_innodb_status
        ports:
        - containerPort: 9104
          protocol: TCP
        env:
        - name: DATA_SOURCE_NAME
          value: "monitor:abcd123456@(127.0.0.1:3306)/"
      volumes:
      - name: conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: mysql
  volumeClaimTemplates:
  - metadata:
      name: data
      annotations:
        volume.beta.kubernetes.io/storage-class: "nfs-storage"
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 5Gi

创建主从资源实例

[root@k8s-master master-slave]# kubectl apply -f mysql-sts.yaml
[root@k8s-master master-slave]# kubectl get -f mysql-sts.yaml
NAME                     READY   AGE
statefulset.apps/mysql   2/2     61m

[root@k8s-master master-slave]# kubectl get pod -n mysql -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysql-0   3/3     Running   0          62m   10.100.235.248   k8s-master   <none>           <none>
mysql-1   3/3     Running   1          62m   10.100.235.229   k8s-master   <none>           <none>

测试主从同步

测试主从数据同步

# 登录主库
[root@k8s-master master-slave]# kubectl -n mysql exec -it mysql-0 -c mysql -- /bin/bash
root@mysql-0:/#
root@mysql-0:/# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2413
Server version: 5.7.35-log MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+------------------------+
| Database               |
+------------------------+
| information_schema     |
| mysql                  |
| performance_schema     |
| sys                    |
| xtrabackup_backupfiles |
+------------------------+
5 rows in set (0.01 sec)

mysql> create database xadocker;
Query OK, 1 row affected (0.01 sec)

mysql> use xadocker;
Database changed
mysql> create table test_tb(id int(4),name char(10));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_tb values(0001,'xadocker');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_tb values(0002,'xadocker2');
Query OK, 1 row affected (0.00 sec)

# 登录从库查看数据是否同步
[root@k8s-master master-slave]# kubectl -n mysql exec -it mysql-1 -c mysql -- /bin/bash
root@mysql-1:/# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2558
Server version: 5.7.35 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+------------------------+
| Database               |
+------------------------+
| information_schema     |
| mysql                  |
| performance_schema     |
| sys                    |
| xadocker               |
| xtrabackup_backupfiles |
+------------------------+
6 rows in set (0.02 sec)

mysql> use xadocker;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> select * from test_tb;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | xadocker  |
|    2 | xadocker2 |
+------+-----------+
2 rows in set (0.00 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: mysql-0.mysql
                  Master_User: replication
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-0-bin.000003
          Read_Master_Log_Pos: 1074
               Relay_Log_File: mysql-1-relay-bin.000002
                Relay_Log_Pos: 1242
        Relay_Master_Log_File: mysql-0-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1074
              Relay_Log_Space: 1451
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 100
                  Master_UUID: 1725e679-6008-11ed-8fa6-d604459b68a9
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

扩容从库实例后测试数据同步

[root@k8s-master master-slave]# kubectl scale sts mysql -n mysql --replicas=3
statefulset.apps/mysql scaled
[root@k8s-master master-slave]# kubectl -n mysql exec -it mysql-2 -c mysql -- /bin/bash
root@mysql-2:/# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 42
Server version: 5.7.35 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use xadocker;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from test_tb;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | xadocker  |
|    2 | xadocker2 |
+------+-----------+
2 rows in set (0.01 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: mysql-0.mysql
                  Master_User: replication
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-0-bin.000003
          Read_Master_Log_Pos: 1074
               Relay_Log_File: mysql-2-relay-bin.000002
                Relay_Log_Pos: 322
        Relay_Master_Log_File: mysql-0-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1074
              Relay_Log_Space: 531
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 100
                  Master_UUID: 1725e679-6008-11ed-8fa6-d604459b68a9
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

集群内外暴露主从实例服务

在应用中有两种方式实现主从读写分离:

  • 暴露主库的代理地址和暴露从库实例代理地址,开发人员在程序中封装读写调用地址即可
  • 提供数据库代理中间件负责处理读写分离,比如sqlproxy/mycat等

提供读写两个地址或域名

第一种方式运维侧处理起来比较简单

# 对于写,则程序调用第一个实例的域名:mysql-0.mysql.svc.cluster.local
# 而对于读,则可以再创建一个svc来提供域名: mysql-read.mysql.svc.cluster.local
[root@k8s-master master-slave]# cat mysql-service.yaml
# Headless service for stable DNS entries of StatefulSet members.
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  clusterIP: None
  selector:
    app: mysql
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
  name: mysql-read
  namespace: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql

但是这种方式如何提供集群外部使用呢?因为集群外部无法解析域名,对于mysql-read这个好处理,只需要增加nodeport或loadbalance就可以了,但是对于写该如何操作?

其实这个依然还是通过svc来处理,方式是让这个svc只提供一个pod的转发,可以看下目前创建出来的sts实例labels

[root@k8s-master mysql-exporter]# kubectl get pod -n mysql --show-labels
NAME      READY   STATUS    RESTARTS   AGE   LABELS
mysql-0   3/3     Running   0          97m   app=mysql,controller-revision-hash=mysql-7cb768ff95,statefulset.kubernetes.io/pod-name=mysql-0
mysql-1   3/3     Running   1          96m   app=mysql,controller-revision-hash=mysql-7cb768ff95,statefulset.kubernetes.io/pod-name=mysql-1
mysql-2   3/3     Running   1          22m   app=mysql,controller-revision-hash=mysql-7cb768ff95,statefulset.kubernetes.io/pod-name=mysql-2

从上面pod的labels可以看出,每个pod都打赏了statefulset.kubernetes.io/pod-name=xxxk/v,而value值正好是pod name,由于sts的网络标识不变的特性,则可以利用这点来创建svc

[root@k8s-master master-slave]# cat mysql-write-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-write
  namespace: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql
    statefulset.kubernetes.io/pod-name: mysql-0

[root@k8s-master master-slave]# kubectl apply -f mysql-write-svc.yaml
service/mysql-write configured
[root@k8s-master master-slave]# kubectl get -f mysql-write-svc.yaml
NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
mysql-write   ClusterIP   10.96.193.60   <none>        3306/TCP   15s
[root@k8s-master master-slave]# kubectl describe -f mysql-write-svc.yaml
Name:              mysql-write
Namespace:         mysql
Labels:            app=mysql
Annotations:       Selector:  app=mysql,statefulset.kubernetes.io/pod-name=mysql-0
Type:              ClusterIP
IP:                10.96.193.60
Port:              mysql  3306/TCP
TargetPort:        3306/TCP
Endpoints:         10.100.235.248:3306
Session Affinity:  None
Events:            <none>

# 此时暴露到集群外就可以采用nodepore或loadbalance的方式,此处略

提供读写代理

埋个坑,后续补充上

prometheus-operator监控mysql

测试获取mysqld_exporter数据

在前面博主已将每个mysqld_exporter运行在pod中,可以测试查看下获取数据

[root@k8s-master master-slave]# kubectl get pods -n mysql -o wide
NAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
mysql-0   3/3     Running   0          106s   10.100.235.243   k8s-master   <none>           <none>
mysql-1   3/3     Running   0          95s    10.100.235.230   k8s-master   <none>           <none>
mysql-2   3/3     Running   0          87s    10.100.235.204   k8s-master   <none>           <none>

[root@k8s-master master-slave]# curl -s 10.100.235.243:9104/metrics | head -n 20
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 3.4808e-05
go_gc_duration_seconds{quantile="0.25"} 5.086e-05
go_gc_duration_seconds{quantile="0.5"} 0.000624944
go_gc_duration_seconds{quantile="0.75"} 0.000657479
go_gc_duration_seconds{quantile="1"} 0.000753488
go_gc_duration_seconds_sum 0.002710554
go_gc_duration_seconds_count 6
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 8
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.12.7"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 2.827152e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter

为监控端口创建svc和servicemonitor

[root@k8s-master master-slave]# cat mysql-monitor-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-monitor
  namespace: mysql
  labels:
    app: mysql-ms
spec:
  ports:
  - name: monitor
    protocol: TCP
    port: 9104
  selector:
    app: mysql

[root@k8s-master master-slave]# cat mysql-exporter-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: mysqld-exporter-ms
  namespace: monitoring
spec:
  jobLabel: mysqld-exporter-ms
  endpoints:
  - port: monitor
    interval: 30s
    scheme: http
  namespaceSelector:
    matchNames:
    - mysql
  selector:
    matchLabels:
      app: mysql-ms

grafana上导入dashboard ID: 7371

由于博主这边得svc是采集了master和slave,而该原图标中instance变量不太符合当前得环境取值,需要调整下,博主将instance变量删除,增加以下三个变量:

  • job (用于区分多套ms集群)
    • label_values({name=~"(mysql_binlog_files|mysql_slave_status_seconds_behind_master)"}, job)
  • masterPod (用于获取master得pod名称)
    • label_values({name=~"(mysql_binlog_files)"}, pod)
  • slavePod(用于获取slave得pod名称)
    • label_values({name=~"(mysql_slave_status_master_server_id)"}, pod)
k8s中使用mysql主从集群
{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "datasource",
          "uid": "grafana"
        },
        "enable": true,
        "hide": false,
        "iconColor": "#e0752d",
        "limit": 100,
        "name": "PMM Annotations",
        "showIn": 0,
        "tags": [
          "pmm_annotation"
        ],
        "target": {
          "limit": 100,
          "matchAny": false,
          "tags": [
            "pmm_annotation"
          ],
          "type": "tags"
        },
        "type": "tags"
      }
    ]
  },
  "description": "Dashboard from Percona Monitoring and Management project. https://github.com/percona/grafana-dashboards",
  "editable": true,
  "fiscalYearStartMonth": 0,
  "gnetId": 7371,
  "graphTooltip": 1,
  "id": 34,
  "links": [
    {
      "icon": "dashboard",
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "QAN"
      ],
      "targetBlank": false,
      "title": "Query Analytics",
      "type": "link",
      "url": "/graph/dashboard/db/_pmm-query-analytics"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "OS"
      ],
      "targetBlank": false,
      "title": "OS",
      "type": "dashboards"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "MySQL"
      ],
      "targetBlank": false,
      "title": "MySQL",
      "type": "dashboards"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "MongoDB"
      ],
      "targetBlank": false,
      "title": "MongoDB",
      "type": "dashboards"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "HA"
      ],
      "targetBlank": false,
      "title": "HA",
      "type": "dashboards"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "Cloud"
      ],
      "targetBlank": false,
      "title": "Cloud",
      "type": "dashboards"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "Insight"
      ],
      "targetBlank": false,
      "title": "Insight",
      "type": "dashboards"
    },
    {
      "asDropdown": true,
      "includeVars": true,
      "keepTime": true,
      "tags": [
        "PMM"
      ],
      "targetBlank": false,
      "title": "PMM",
      "type": "dashboards"
    }
  ],
  "liveNow": false,
  "panels": [
    {
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "decimals": 0,
          "mappings": [
            {
              "options": {
                "0": {
                  "text": "No"
                },
                "1": {
                  "text": "Yes"
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "rgba(161, 18, 18, 0.9)"
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 0.5
              },
              {
                "color": "rgba(36, 112, 33, 0.97)",
                "value": 1
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 0,
        "y": 0
      },
      "id": 26,
      "interval": "$interval",
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "center",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.2.4",
      "targets": [
        {
          "calculatedInterval": "10m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "exemplar": false,
          "expr": "mysql_slave_status_slave_io_running{job=~\"${job}\",pod=~\"${slavePod}\"}",
          "instant": false,
          "interval": "1m",
          "intervalFactor": 1,
          "legendFormat": "{{pod}}",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "title": "IO Thread Running",
      "type": "stat"
    },
    {
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "decimals": 0,
          "mappings": [
            {
              "options": {
                "0": {
                  "text": "No"
                },
                "1": {
                  "text": "Yes"
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "rgba(161, 18, 18, 0.9)"
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 0.5
              },
              {
                "color": "rgba(36, 112, 33, 0.97)",
                "value": 1
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 6,
        "y": 0
      },
      "id": 17,
      "interval": "$interval",
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.2.4",
      "targets": [
        {
          "calculatedInterval": "10m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "exemplar": true,
          "expr": "mysql_slave_status_slave_sql_running{job=~\"${job}\",pod=~\"${slavePod}\"}",
          "instant": false,
          "interval": "1m",
          "intervalFactor": 1,
          "legendFormat": "{{pod}}",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "title": "SQL Thread Running",
      "transformations": [],
      "type": "stat"
    },
    {
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "decimals": 0,
          "mappings": [
            {
              "options": {
                "0": {
                  "text": "N/A"
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "rgba(50, 172, 45, 0.97)"
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 0.5
              },
              {
                "color": "rgba(245, 54, 54, 0.9)",
                "value": 1
              }
            ]
          },
          "unit": "none"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 12,
        "y": 0
      },
      "id": 39,
      "interval": "$interval",
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.2.4",
      "targets": [
        {
          "calculatedInterval": "10m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "mysql_slave_status_last_errno{job=~\"${job}\",pod=~\"${slavePod}\"}",
          "interval": "5m",
          "intervalFactor": 1,
          "legendFormat": "{{pod}}",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "title": "Replication Error No",
      "type": "stat"
    },
    {
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "decimals": 0,
          "mappings": [
            {
              "options": {
                "0": {
                  "text": "No"
                },
                "1": {
                  "text": "Yes"
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "rgba(50, 172, 45, 0.97)"
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 0.5
              },
              {
                "color": "rgba(245, 54, 54, 0.9)",
                "value": 1
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 18,
        "y": 0
      },
      "id": 27,
      "interval": "$interval",
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.2.4",
      "targets": [
        {
          "calculatedInterval": "10m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "mysql_global_variables_read_only{job=\"$job\"}",
          "interval": "5m",
          "intervalFactor": 1,
          "legendFormat": "{{pod}}",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "title": "Read Only",
      "type": "stat"
    },
    {
      "aliasColors": {
        "Lag": "#E24D42"
      },
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "decimals": 0,
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 24,
        "x": 0,
        "y": 4
      },
      "hiddenSeries": false,
      "id": 16,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "hideEmpty": false,
        "max": true,
        "min": true,
        "rightSide": true,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "$$hashKey": "object:420",
          "alias": "Lag",
          "color": "#E24D42",
          "yaxis": 1
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "exemplar": false,
          "expr": "mysql_slave_status_seconds_behind_master{job=~\"${job}\",pod=~\"${slavePod}\"}",
          "format": "time_series",
          "instant": false,
          "interval": "$interval",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Lag",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "thresholds": [],
      "timeRegions": [],
      "title": "MySQL Replication Delay",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "transformations": [],
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:433",
          "format": "short",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:434",
          "format": "short",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 12,
        "x": 0,
        "y": 11
      },
      "hiddenSeries": false,
      "id": 33,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "max": true,
        "min": true,
        "rightSide": false,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "alias": "Size",
          "color": "#1F78C1"
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "mysql_binlog_size_bytes{job=~\"${job}\",pod=~\"${masterPod}\"} ",
          "interval": "$interval",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Size",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "thresholds": [],
      "timeRegions": [],
      "title": "Binlogs Size",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:710",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:711",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "aliasColors": {},
      "bars": true,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "decimals": 2,
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 12,
        "x": 12,
        "y": 11
      },
      "hiddenSeries": false,
      "id": 35,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "max": true,
        "min": true,
        "rightSide": false,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": false,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "alias": "Size",
          "color": "#1F78C1"
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "increase(mysql_binlog_size_bytes{job=~\"${job}\",pod=~\"${masterPod}\"}[1h])",
          "interval": "1h",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Size",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 3600
        }
      ],
      "thresholds": [],
      "timeFrom": "24h",
      "timeRegions": [],
      "title": "Binlog Data Written Hourly",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:871",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:872",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "decimals": 0,
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 12,
        "x": 0,
        "y": 18
      },
      "hiddenSeries": false,
      "id": 34,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "max": true,
        "min": true,
        "rightSide": false,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "alias": "Count",
          "color": "#E0752D"
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "mysql_binlog_size_bytes{job=~\"${job}\",pod=~\"${masterPod}\"} ",
          "interval": "$interval",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Count",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "thresholds": [],
      "timeRegions": [],
      "title": "Binlogs Count",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:1448",
          "format": "none",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:1449",
          "format": "none",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "aliasColors": {},
      "bars": true,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "decimals": 0,
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 12,
        "x": 12,
        "y": 18
      },
      "hiddenSeries": false,
      "id": 36,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "max": true,
        "min": true,
        "rightSide": false,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": false,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "alias": "Count",
          "color": "#E0752D"
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "increase(mysql_binlog_file_number{job=~\"${job}\",pod=~\"${masterPod}\"}[1h])",
          "interval": "1h",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Count",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 3600
        }
      ],
      "thresholds": [],
      "timeFrom": "24h",
      "timeRegions": [],
      "title": "Binlogs fiile Created Hourly",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:1928",
          "format": "none",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:1929",
          "format": "none",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 12,
        "x": 0,
        "y": 25
      },
      "hiddenSeries": false,
      "id": 37,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "max": true,
        "min": true,
        "rightSide": true,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "alias": "Size",
          "color": "#BA43A9"
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "mysql_slave_status_relay_log_space{job=~\"${job}\",pod=~\"${slavePod}\"}",
          "interval": "$interval",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Size",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 300
        }
      ],
      "thresholds": [],
      "timeRegions": [],
      "title": "Relay Log Space",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:2011",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:2012",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "aliasColors": {},
      "bars": true,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "prometheus",
        "uid": "P70940297EF37E8D3"
      },
      "decimals": 2,
      "editable": true,
      "error": false,
      "fill": 2,
      "fillGradient": 0,
      "grid": {},
      "gridPos": {
        "h": 7,
        "w": 12,
        "x": 12,
        "y": 25
      },
      "hiddenSeries": false,
      "id": 38,
      "legend": {
        "alignAsTable": true,
        "avg": true,
        "current": false,
        "max": true,
        "min": true,
        "rightSide": true,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": false,
      "linewidth": 2,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "9.2.4",
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [
        {
          "alias": "Size",
          "color": "#BA43A9"
        }
      ],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "calculatedInterval": "2m",
          "datasource": {
            "type": "prometheus",
            "uid": "P70940297EF37E8D3"
          },
          "datasourceErrors": {},
          "editorMode": "code",
          "errors": {},
          "expr": "increase(mysql_slave_status_relay_log_space{job=~\"${job}\",pod=~\"${slavePod}\"}[1h])",
          "interval": "1h",
          "intervalFactor": 1,
          "legendFormat": "{{pod}} Size",
          "metric": "",
          "range": true,
          "refId": "A",
          "step": 3600
        }
      ],
      "thresholds": [],
      "timeFrom": "24h",
      "timeRegions": [],
      "title": "Relay Log Written Hourly",
      "tooltip": {
        "msResolution": false,
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:2253",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        },
        {
          "$$hashKey": "object:2254",
          "format": "bytes",
          "logBase": 1,
          "min": 0,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    }
  ],
  "refresh": "1m",
  "schemaVersion": 37,
  "style": "dark",
  "tags": [
    "Percona",
    "MySQL"
  ],
  "templating": {
    "list": [
      {
        "allFormat": "glob",
        "auto": true,
        "auto_count": 200,
        "auto_min": "1s",
        "current": {
          "selected": false,
          "text": "auto",
          "value": "$__auto_interval_interval"
        },
        "datasource": "P70940297EF37E8D3",
        "hide": 0,
        "includeAll": false,
        "label": "Interval",
        "multi": false,
        "multiFormat": "glob",
        "name": "interval",
        "options": [
          {
            "selected": true,
            "text": "auto",
            "value": "$__auto_interval_interval"
          },
          {
            "selected": false,
            "text": "1s",
            "value": "1s"
          },
          {
            "selected": false,
            "text": "5s",
            "value": "5s"
          },
          {
            "selected": false,
            "text": "1m",
            "value": "1m"
          },
          {
            "selected": false,
            "text": "5m",
            "value": "5m"
          },
          {
            "selected": false,
            "text": "1h",
            "value": "1h"
          },
          {
            "selected": false,
            "text": "6h",
            "value": "6h"
          },
          {
            "selected": false,
            "text": "1d",
            "value": "1d"
          }
        ],
        "query": "1s,5s,1m,5m,1h,6h,1d",
        "refresh": 2,
        "skipUrlSync": false,
        "type": "interval"
      },
      {
        "allFormat": "glob",
        "current": {
          "selected": false,
          "text": "mysql-monitor",
          "value": "mysql-monitor"
        },
        "datasource": {
          "type": "prometheus",
          "uid": "P70940297EF37E8D3"
        },
        "definition": "label_values({__name__=~\"(mysql_binlog_files|mysql_slave_status_seconds_behind_master)\"}, job)",
        "hide": 0,
        "includeAll": false,
        "label": "job",
        "multi": false,
        "multiFormat": "regex values",
        "name": "job",
        "options": [],
        "query": {
          "query": "label_values({__name__=~\"(mysql_binlog_files|mysql_slave_status_seconds_behind_master)\"}, job)",
          "refId": "StandardVariableQuery"
        },
        "refresh": 1,
        "refresh_on_load": false,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query",
        "useTags": false
      },
      {
        "current": {
          "selected": false,
          "text": "All",
          "value": "$__all"
        },
        "datasource": {
          "type": "prometheus",
          "uid": "P70940297EF37E8D3"
        },
        "definition": "label_values({__name__=~\"(mysql_binlog_files)\"}, pod)",
        "hide": 0,
        "includeAll": true,
        "label": "master pod",
        "multi": false,
        "name": "masterPod",
        "options": [],
        "query": {
          "query": "label_values({__name__=~\"(mysql_binlog_files)\"}, pod)",
          "refId": "StandardVariableQuery"
        },
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 0,
        "type": "query"
      },
      {
        "current": {
          "selected": true,
          "text": [
            "All"
          ],
          "value": [
            "$__all"
          ]
        },
        "datasource": {
          "type": "prometheus",
          "uid": "P70940297EF37E8D3"
        },
        "definition": "label_values({__name__=~\"(mysql_slave_status_master_server_id)\"}, pod)",
        "hide": 0,
        "includeAll": true,
        "label": "slave pod",
        "multi": true,
        "name": "slavePod",
        "options": [],
        "query": {
          "query": "label_values({__name__=~\"(mysql_slave_status_master_server_id)\"}, pod)",
          "refId": "StandardVariableQuery"
        },
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 0,
        "type": "query"
      }
    ]
  },
  "time": {
    "from": "now-3h",
    "to": "now"
  },
  "timepicker": {
    "collapse": false,
    "enable": true,
    "hidden": false,
    "notice": false,
    "now": true,
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ],
    "status": "Stable",
    "time_options": [
      "5m",
      "15m",
      "1h",
      "6h",
      "12h",
      "24h",
      "2d",
      "7d",
      "30d"
    ],
    "type": "timepicker"
  },
  "timezone": "browser",
  "title": "MySQL Replication",
  "uid": "_9zrwMHmk",
  "version": 5,
  "weekStart": ""
}

ARM架构平台镜像提供

找了下官方,似乎只有8.0起的arm镜像,没有5.x,看啦只能自己编译一个,参考后续文章~~~~

正文完
 1
xadocker
版权声明:本站原创文章,由 xadocker 2022-11-04发表,共计55451字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)