opened image

Автоматизация установки серверов баз данных в Docker с интеграцией в HestiaCP и phpMyAdmin

 

Ручная установка и настройка серверов баз данных может отнять много времени, особенно если речь идет о множественных экземплярах с разными версиями. Автоматизация этого процесса значительно упростит жизнь системному администратору и сэкономит его рабочие часы. В этой статье рассматривается, как развернуть сервера MySQL и MariaDB в контейнерах Docker, используя автоматический скрипт. Этот скрипт также интегрирует базы данных в панель HestiaCP и phpMyAdmin, делая их доступными для управления и взаимодействия с веб-интерфейсом.

 

Скрипт, предложенный ниже, автоматизирует следующие задачи:

  • Проверка и установка Docker и Docker Compose (если они не установлены).
  • Создание контейнеров баз данных с выбранной версией MySQL или MariaDB: MySQL (5.7 и 8.0)  MariaDB (10.8, 10.9 и 10.11).
  • Настройка контейнеров для интеграции с HestiaCP и phpMyAdmin.
  • Удаление контейнеров и связанных с ними данных и конфигураций при необходимости.

 

Предупреждение:

Этот скрипт предназначен для автоматизации развертывания серверов баз данных в контейнерах Docker и предназначен для опытных пользователей. Все действия выполняются с учетом особенностей и стандартных конфигураций, однако, перед его применением рекомендуется внимательно ознакомиться с логикой скрипта и протестировать его на тестовой среде.

 

Пожалуйста, убедитесь, что все данные и конфигурации, затронутые скриптом, сохранены или зарезервированы. Использование этого скрипта предполагает ответственность пользователя за его применение, и любые действия, связанные с внесением изменений в существующие конфигурации, выполняются на собственный страх и риск.

​​​​​​​

#!/bin/bash

# Log file location
LOG_FILE="/home/db_installation.log"

# Logging function
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}

sed -i 's/^#precedence ::ffff:0:0\/96  10/precedence ::ffff:0:0\/96  100/' /etc/gai.conf

# Function to generate a random password
generate_password() {
    tr -dc A-Za-z0-9 </dev/urandom | head -c 16
}

# Function to check for an existing container
check_existing_container() {
    local db_version=$1
    if [ "$(docker ps -a --filter "name=${db_version}" --filter "label=zomro_add_db" --format '{{.Names}}')" ]; then
        log "Container named ${db_version} with the zomro_add_db flag is already running. Removing existing container..."
        docker rm -f ${db_version}
    fi
}

# Function to remove a container by version
remove_container() {
    local db_version=$1
    if [ "$(docker ps -a --filter "name=${db_version}" --filter "label=zomro_add_db" --format '{{.Names}}')" ]; then
        log "Removing container named ${db_version} with the zomro_add_db flag..."
        docker rm -f ${db_version}
        rm -rf /var/lib/${db_version}
        rm -rf /root/docker_${db_version}
        remove_phpmyadmin_config $db_version
        remove_hestia_mysql_config $db_version
        log "Container ${db_version} and related data removed."
    else
        log "No container named ${db_version} with the zomro_add_db flag found."
    fi
}

# Function to remove the corresponding HestiaCP MySQL configuration entry from mysql.conf using sed
remove_hestia_mysql_config() {
    local db_version=$1
    local hestia_config_file="/usr/local/hestia/conf/mysql.conf"

    if [ -f "$hestia_config_file" ]; then
        cp "$hestia_config_file" "${hestia_config_file}.bak"
        log "Backup of HestiaCP MySQL configuration created: ${hestia_config_file}.bak"

        # Exact deletion of a line with the HOST identifier
        sed -i "/HOST='${db_version}'/d" "$hestia_config_file"

        log "Removed HestiaCP MySQL configuration entry for ${db_version}."
    else
        log "HestiaCP MySQL configuration file not found."
    fi
}

# Function to remove the corresponding phpMyAdmin configuration entry
remove_phpmyadmin_config() {
    local db_version=$1
    local config_file="/etc/phpmyadmin/conf.d/01-${db_version}.php"

    if [ -f "$config_file" ]; then
        rm -f "$config_file"
        log "Removed phpMyAdmin configuration for ${db_version} located at ${config_file}."
    else
        log "No phpMyAdmin configuration found for ${db_version}."
    fi
}


# Function to check if Docker is installed
check_docker_installed() {
    if ! command -v docker &> /dev/null; then
        log "Docker is not installed. Installing Docker..."
        curl -fsSL https://get.docker.com -o get-docker.sh
        sh get-docker.sh
        systemctl start docker
        systemctl enable docker
    else
        log "Docker is already installed."
    fi
}

# Function to check if Docker Compose is installed
check_docker_compose_installed() {
    if ! command -v docker-compose &> /dev/null; then
        log "Docker Compose is not installed. Installing Docker Compose..."


        OS=$(uname -s | tr '[:upper:]' '[:lower:]')
        ARCH=$(uname -m)

        if [ "$ARCH" = "x86_64" ]; then
            ARCH="x86_64"
        elif [ "$ARCH" = "aarch64" ]; then
            ARCH="aarch64"
        else
            log "Unsupported architecture: $ARCH"
            exit 1
        fi

        # Link to the desired version of Docker Compose
        VERSION="v2.25.0"
        DOCKER_COMPOSE_URL="https://github.com/docker/compose/releases/download/${VERSION}/docker-compose-${OS}-${ARCH}"

        # Download and install Docker Compose
        curl -L "$DOCKER_COMPOSE_URL" -o /usr/local/bin/docker-compose
        chmod +x /usr/local/bin/docker-compose

        # Checking the installation
        if command -v docker-compose &> /dev/null; then
            log "Docker Compose installed successfully."
        else
            log "Failed to install Docker Compose."
            exit 1
        fi
    else
        log "Docker Compose is already installed."
    fi
}


# Function to add phpMyAdmin configuration for a specific database version
add_phpmyadmin_config() {
    local db_version=$1
    local port=$2
    local config_file="/etc/phpmyadmin/conf.d/01-${db_version}.php"

    log "Creating phpMyAdmin configuration for ${db_version} on port ${port}..."
    cat << EOF > "$config_file"
<?php
\$cfg['Servers'][\$i]['host'] = '${db_version}';
\$cfg['Servers'][\$i]['port'] = '${port}';
\$cfg['Servers'][\$i]['auth_type'] = 'cookie';
\$cfg['Servers'][\$i]['verbose'] = '${db_version}';

// Session termination settings
\$cfg['LoginCookieValidity'] = 1440;
\$cfg['LoginCookieStore'] = 0;
\$cfg['ShowPhpInfo'] = true;

// Interface additional settings
\$cfg['ShowChgPassword'] = true;
\$cfg['ShowDbStructureCharset'] = true;
\$cfg['ShowDbStructureCreation'] = true;
\$cfg['ShowDbStructureLastUpdate'] = true;
\$cfg['ShowDbStructureLastCheck'] = true;

// Memory and runtime settings
\$cfg['MemoryLimit'] = '512M';
\$cfg['ExecTimeLimit'] = 300;
\$cfg['UploadDir'] = '';
\$cfg['SaveDir'] = '';
EOF

    # root:www-data for config_file
    chmod 640 "$config_file"
    chown root:www-data "$config_file"

    log "phpMyAdmin configuration for ${db_version} added at ${config_file}."
}

# Checking if Docker is installed
check_docker_installed

# Checking if Docker Compose is installed
check_docker_compose_installed

# Generate passwords
MYSQL_ROOT_PASSWORD=$(generate_password)

# Prompting the user to select an action
echo "Select an action:"
echo "1) Install a MySQL/MariaDB server"
echo "2) Remove an existing MySQL/MariaDB server"
read -p "Enter the number corresponding to your choice: " action_choice

if [ "$action_choice" -eq 1 ]; then
    log "Prompting the user to select a database version to install..."
    echo "Select the database version to install:"
    echo "1) MySQL 5.7"
    echo "2) MySQL 8.0"
    echo "3) MariaDB 10.8"
    echo "4) MariaDB 10.9"
    echo "5) MariaDB 10.11"
    read -p "Enter the number corresponding to your choice: " db_choice

    case $db_choice in
        1)
            DB_IMAGE="mysql:5.7.44-oraclelinux7"
            DB_VERSION="mysql-5.7"
            DB_TYPE="mysql"
            ;;
        2)
            DB_IMAGE="mysql:8.0"
            DB_VERSION="mysql-8.0"
            DB_TYPE="mysql"
            ;;
        3)
            DB_IMAGE="mariadb:10.8"
            DB_VERSION="mariadb-10.8"
            DB_TYPE="mariadb"
            ;;
        4)
            DB_IMAGE="mariadb:10.9"
            DB_VERSION="mariadb-10.9"
            DB_TYPE="mariadb"
            ;;
        5)
            DB_IMAGE="mariadb:10.11"
            DB_VERSION="mariadb-10.11"
            DB_TYPE="mariadb"
            ;;
        *)
            log "Invalid choice. Installation aborted."
            exit 1
            ;;
    esac

    check_existing_container $DB_VERSION

    if ! grep -q "${DB_VERSION}" /etc/hosts; then
        echo "127.0.0.1 ${DB_VERSION}" >> /etc/hosts
        log "Added hostname ${DB_VERSION} to /etc/hosts"
    fi

    log "Creating Docker Compose configuration..."
    AVAILABLE_PORT=3306
    while ss -tuln | grep -q ":$AVAILABLE_PORT"; do
        AVAILABLE_PORT=$((AVAILABLE_PORT + 1))
    done
    mkdir -p /root/docker_${DB_VERSION}

    if [ "$DB_TYPE" = "mysql" ] && [ "$DB_VERSION" = "mysql-8.0" ]; then
        cat << EOF > /root/docker_${DB_VERSION}/init.sql
ALTER USER 'root'@'localhost' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD';
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EOF

        cat << EOF > /root/docker_${DB_VERSION}/docker-compose.yml
services:
  ${DB_VERSION}:
    image: $DB_IMAGE
    container_name: ${DB_VERSION}
    ports:
      - "${AVAILABLE_PORT}:3306"
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
    command: --default-authentication-plugin=mysql_native_password --bind-address=0.0.0.0
    volumes:
      - /var/lib/${DB_VERSION}:/var/lib/mysql
      - /root/docker_${DB_VERSION}/init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: always
    labels:
      zomro_add_db: "true"
EOF

    else
        if [ "$DB_TYPE" = "mysql" ]; then
            cat << EOF > /root/docker_${DB_VERSION}/init.sql
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '$MYSQL_ROOT_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EOF
        elif [ "$DB_TYPE" = "mariadb" ]; then
            cat << EOF > /root/docker_${DB_VERSION}/init.sql
CREATE OR REPLACE USER 'root'@'%' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EOF
        fi

        cat << EOF > /root/docker_${DB_VERSION}/docker-compose.yml
services:
  ${DB_VERSION}:
    image: $DB_IMAGE
    container_name: ${DB_VERSION}
    ports:
      - "${AVAILABLE_PORT}:3306"
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      MYSQL_ROOT_HOST: '%'
    command: --bind-address=0.0.0.0
    volumes:
      - /var/lib/${DB_VERSION}:/var/lib/mysql
      - /root/docker_${DB_VERSION}/init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: always
    labels:
      zomro_add_db: "true"
EOF

    fi

    if [ -d "/var/lib/${DB_VERSION}" ]; then
        BACKUP_DIR="/var/lib/${DB_VERSION}_backup_$(date +%Y%m%d%H%M%S)"
        mv /var/lib/${DB_VERSION} $BACKUP_DIR
        log "Backup created: ${BACKUP_DIR}"
    else
        log "Data directory not found. Skipping backup creation."
    fi

    rm -rf /var/lib/${DB_VERSION}

    log "Starting Docker Compose for ${DB_VERSION}..."
    docker-compose -f /root/docker_${DB_VERSION}/docker-compose.yml up -d

    log "Waiting for the database to be ready..."
    RETRIES=30
    for i in $(seq 1 $RETRIES); do
        if docker exec ${DB_VERSION} mysql -u root -p$MYSQL_ROOT_PASSWORD -e "SELECT VERSION();" >/dev/null 2>&1; then
            log "Database is ready."
            break
        else
            log "Database is not ready yet. Retrying in 5 seconds..."
            sleep 10
        fi
        if [ "$i" -eq "$RETRIES" ]; then
            log "Failed to connect to the database after $RETRIES attempts."
            exit 1
        fi
    done

    log "Adding database access to HestiaCP..."
    v-add-database-host mysql ${DB_VERSION} root $MYSQL_ROOT_PASSWORD '' '' '' $AVAILABLE_PORT

    add_phpmyadmin_config "${DB_VERSION}" "${AVAILABLE_PORT}"

    RED='\033[0;31m'
    NC='\033[0m'

    log "Installation of ${DB_VERSION} server completed successfully."
    echo -e "${RED}"
    echo "==========================================="
    echo "            ACCESS DETAILS"
    echo "-------------------------------------------"
    echo "Host: ${DB_VERSION}"
    echo "Port: $AVAILABLE_PORT"
    echo "User: root"
    echo "Password: $MYSQL_ROOT_PASSWORD"
    echo "==========================================="
    echo -e "${NC}"

elif [ "$action_choice" -eq 2 ]; then
    log "Prompting the user to select a database version to remove..."
    echo "Select the database version to remove:"
    echo "1) MySQL 5.7"
    echo "2) MySQL 8.0"
    echo "3) MariaDB 10.8"
    echo "4) MariaDB 10.9"
    echo "5) MariaDB 10.11"
    read -p "Enter the number corresponding to your choice: " db_remove_choice

    case $db_remove_choice in
        1)
            DB_VERSION="mysql-5.7"
            ;;
        2)
            DB_VERSION="mysql-8.0"
            ;;
        3)
            DB_VERSION="mariadb-10.8"
            ;;
        4)
            DB_VERSION="mariadb-10.9"
            ;;
        5)
            DB_VERSION="mariadb-10.11"
            ;;
        *)
            log "Invalid choice. Removal aborted."
            exit 1
            ;;
    esac

    remove_container $DB_VERSION

else
    log "Invalid action. Exiting."
    exit 1
fi

exit 0

 

Подготовка к автоматизации


Для начала работы необходимо убедиться, что ваш сервер поддерживает Docker и Docker Compose. Скрипт автоматически проверяет наличие этих компонентов и, при необходимости, выполняет их установку. Docker обеспечивает изоляцию процессов, позволяя каждому экземпляру базы данных работать в своем собственном контейнере, а Docker Compose облегчает управление конфигурациями многоконтейнерных приложений.

 

Порядок выполнения скрипта


Установка Docker и Docker Compose

 

  • Сначала скрипт проверяет, установлены ли Docker и Docker Compose. Если нет — производит их загрузку и установку, активирует службу Docker и настраивает автоматический запуск.
  • Эта проверка исключает необходимость вручную отслеживать наличие нужных утилит на сервере, что особенно полезно для администраторов, работающих с множественными системами или версиями ОС.

 

Генерация и удаление контейнеров для MySQL и MariaDB

 

  • Скрипт предоставляет интерфейс для выбора версии сервера баз данных: MySQL (5.7 и 8.0) или MariaDB (10.8, 10.9 и 10.11).
  • После выбора версии происходит генерация Docker Compose конфигурации, с которой и запускается контейнер.
  • Если контейнер с данным именем уже существует, скрипт удаляет его, что помогает избежать конфликтов версий и ошибок при развертывании.
  • Для каждой версии создается отдельный файл и уникальный порт для подключения, а также резервная копия папки данных в случае существования предыдущих данных.

 

 

 

Создание и настройка конфигурации phpMyAdmin

 

  • После успешного создания контейнера скрипт добавляет конфигурацию для phpMyAdmin, чтобы база данных была доступна для администрирования через веб-интерфейс.
  • Конфигурация включает параметры доступа: хост, порт и метод аутентификации.
  • Устанавливаются дополнительные настройки, такие как лимиты времени выполнения запросов и использование cookie для аутентификации, что добавляет гибкость в работе с phpMyAdmin.

 

 

 

 

Добавление конфигурации в HestiaCP

 

  • HestiaCP, будучи популярной панелью управления, требует интеграции с базами данных для более простого управления ими. Скрипт добавляет хост базы данных в конфигурационный файл HestiaCP, делая его доступным для приложений и пользователей панели.
  • Для этого скрипт использует команду v-add-database-host, которая добавляет запись в HestiaCP и назначает ей порт, выбранный при создании контейнера. Таким образом, вам не придется добавлять базы данных вручную — все конфигурации добавляются автоматически.

 

 

Интерфейс выбора действий (установка или удаление)

  • После выполнения всех проверок и установок скрипт предлагает интерфейс выбора: установить новый сервер базы данных или удалить уже существующий.
  • При выборе удаления скрипт удаляет контейнер и связанные с ним конфигурационные файлы, а также очищает данные в HestiaCP и phpMyAdmin. Удаление происходит аккуратно: сначала проверяются существующие записи, затем они безопасно удаляются.

 

 

​​​​​​​

 

Вывод учетных данных

По завершении установки скрипт выводит доступ к базе данных:

  • IP-адрес,
  • порт,
  • имя пользователя,
  • пароль.

 

 

Эта информация позволяет быстро приступить к работе, не тратя времени на поиск учетных данных в системе.

 

Заключение


Используя данный скрипт, вы можете автоматизировать процесс установки баз данных в Docker, не отвлекаясь на ручные операции. Это решение подходит для различных сценариев, начиная от тестовых окружений до развертывания баз данных в производственных средах. Скрипт также может быть расширен для работы с другими версиями или типами баз данных, что делает его удобным и универсальным инструментом для системного администратора.

 

Также предлагаем рассмотреть другие полезные статьи: