基于StatefulSet搭建MySQL主從

https://github.com/docker-library/mysql 可去下載構(gòu)建鏡像的文件。

1. 構(gòu)建master鏡像

1.1 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 apt-get update && apt-get install -y --no-install-recommends \
# for MYSQL_RANDOM_ROOT_PASSWORD
        pwgen \
# for mysql_ssl_rsa_setup
        openssl \
# FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db:
# File::Basename
# File::Copy
# Sys::Hostname
# Data::Dumper
        perl \
# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files
        xz-utils \
    && rm -rf /var/lib/apt/lists/*

RUN set -ex; \
# gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
    key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \
    export GNUPGHOME="$(mktemp -d)"; \
    gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \
    gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \
    gpgconf --kill all; \
    rm -rf "$GNUPGHOME"; \
    apt-key list > /dev/null

ENV MYSQL_MAJOR 8.0
ENV MYSQL_VERSION 8.0.27-1debian10

RUN echo 'deb http://repo.mysql.com/apt/debian/ buster mysql-8.0' > /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-community-client="${MYSQL_VERSION}" \
        mysql-community-server-core="${MYSQL_VERSION}" \
    && rm -rf /var/lib/apt/lists/* \
    && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \
    && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
# ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime
    && chmod 1777 /var/run/mysqld /var/lib/mysql

VOLUME /var/lib/mysql

ENV AUTO_RUN_DIR /docker-entrypoint-initdb.d

# Config files
COPY config/ /etc/mysql/
COPY docker-entrypoint.sh /usr/local/bin/
COPY init.sh $AUTO_RUN_DIR/
RUN chmod a+x $AUTO_RUN_DIR/init.sh
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat

ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 3306 33060
CMD ["mysqld"]

1.2 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
}

_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

1.3 init.sh

#!/bin/bash
mysql -uroot -p$MYSQL_ROOT_PASSWORD <<EOF
CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED WITH 'mysql_native_password' BY '$MYSQL_REPLICATION_PASSWORD';
GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%';
FLUSH PRIVILEGES ;
EOF

1.4 config

1.4.1 my.cnf

# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

#
# The MySQL  Server configuration file.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL

# Custom config should go here
!includedir /etc/mysql/conf.d/

1.4.2 conf.d/docker.cnf

[mysqld]
server-id=1
log-bin
skip-host-cache
skip-name-resolve

1.5 構(gòu)建鏡像

這里使用了阿里云個(gè)人版 容器鏡像服務(wù)

docker build -t registry.cn-shanghai.aliyuncs.com/ligan0404/mysql-master:v1.1.7 .
docker push registry.cn-shanghai.aliyuncs.com/ligan0404/mysql-master:v1.1.7

2. 構(gòu)建slave鏡像

2.1 Dockerfile

和master一樣的,在ENTRYPOINT上面加上下面的命令即可:

RUN RAND="$(date +%s | rev | cut -c 1-2)$(echo ${RANDOM})" && sed -i '/\[mysqld\]/a server-id='$RAND'\nlog-bin' /etc/mysql/conf.d/docker.cnf

2.2 docker-entrypoint.sh

和master一樣的,沒(méi)任何變化。

2.3 init.sh

構(gòu)建主從語(yǔ)句

#!/bin/bash
mysql -uroot -p$MYSQL_ROOT_PASSWORD <<EOF
CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED WITH 'mysql_native_password' BY '$MYSQL_REPLICATION_PASSWORD';
GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%';
FLUSH PRIVILEGES ;
EOF

2.4 config

2.4.1 my.cnf

和master一致,無(wú)變化。

2.4.2 conf.d/docker.cnf

沒(méi)有server-id了,通過(guò)dockerfile去隨機(jī)生成了。

[mysqld]
skip-host-cache
skip-name-resolve

2.5 構(gòu)建鏡像

docker build -t registry.cn-shanghai.aliyuncs.com/ligan0404/mysql-slave:v1.1.0 .
docker push registry.cn-shanghai.aliyuncs.com/ligan0404/mysql-slave:v1.1.0

3. 創(chuàng)建pv,pvc(nfs)

storageClassName: nfs-data 的創(chuàng)建,直接參考 NFS存儲(chǔ) 動(dòng)態(tài)創(chuàng)建 PVC PV文檔。

4. 創(chuàng)建master StatefulSet,svc

apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations: {}
  labels:
    app: mysql-master
  name: mysql-master
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql-master
  template:
    metadata:
      labels:
        app: mysql-master
    spec:
      imagePullSecrets:
      - name: ali-secret
      containers:
        - env:
            - name: MYSQL_ROOT_PASSWORD
              value: '123456'
            - name: MYSQL_REPLICATION_USER
              value: repl
            - name: MYSQL_REPLICATION_PASSWORD
              value: '123456'
          image: 'registry.cn-shanghai.aliyuncs.com/ligan0404/mysql-master:v1.0.0'
          imagePullPolicy: Always
          name: mysql-master
          ports:
            - containerPort: 3306
              name: mysql-master
              protocol: TCP
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: pv-nfs-mysql-master
  volumeClaimTemplates:
  - metadata:
      name: pv-nfs-mysql-master
    spec:
      accessModes: [ "ReadWriteMany","ReadWriteOnce"]
      resources:
        requests:
          storage: 1G
      storageClassName: nfs-data
---
apiVersion: v1
kind: Service
metadata:
  annotations: {}
  labels:
    app: mysql-master
  name: mysql-master
spec:
  ports:
    - name: mysql-master
      nodePort: 30066
      port: 3306
      protocol: TCP
      targetPort: 3306
  selector:
    app: mysql-master
  type: NodePort

5. 創(chuàng)建slave StatefulSet,svc

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations: {}
  labels:
    app: mysql-slave
  name: mysql-slave
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mysql-slave
  template:
    metadata:
      labels:
        app: mysql-slave
    spec:
      containers:
        - env:
            - name: MYSQL_ROOT_PASSWORD
              value: '123456'
            - name: MYSQL_REPLICATION_USER
              value: repl
            - name: MYSQL_REPLICATION_PASSWORD
              value: '123456'
          image: 'registry.cn-shanghai.aliyuncs.com/ligan0404/mysql-slave:v1.1.0'
          imagePullPolicy: Always
          name: mysql-slave
          ports:
            - containerPort: 3306
              name: mysql-slave
              protocol: TCP
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: pv-nfs-mysql-slave
      imagePullSecrets:
        - name: ali-secret
  volumeClaimTemplates:
  - metadata:
      name: pv-nfs-mysql-slave
    spec:
      accessModes: [ "ReadWriteMany","ReadWriteOnce"]
      resources:
        requests:
          storage: 1G
      storageClassName: nfs-data

---
apiVersion: v1
kind: Service
metadata:
  annotations: {}
  labels:
    app: mysql-slave
  name: mysql-slave
spec:
  ports:
    - name: mysql-slave
      port: 3306
      protocol: TCP
      targetPort: 3306
  selector:
    app: mysql-slave
  type: NodePort

6. 測(cè)試

master中執(zhí)行:

mysql -uroot -p
show master status;
create database test; use test; create table test_tb(id int(3),name char(10)); insert into test_tb values(001,'ok');

slave執(zhí)行:

mysql -uroot -p
show slave status\G;

show databases;
use test;
show tables;
select* from test_tb;

7. 參考資料

K8S 使用NFS存儲(chǔ) 動(dòng)態(tài)創(chuàng)建 PVC/PV 并通過(guò) Statefulset 部署 MySQL
kubernetes部署mysql
基于K8s部署MySQL cluster
在kubernetes集群中部署mysql主從
利用Kubernetes搭建mysql主從復(fù)制集群
k8s使用nfs持久存儲(chǔ)mysql數(shù)據(jù)的一次踩坑
k8s搭建mysql主從同步
使用Docker快速部署MySQL并初始數(shù)據(jù)
Dockerfile 部署MySql 8并初始化數(shù)據(jù)腳本

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374