如何将 CentOS 乔迁成 AlmaLinux ,且避免数据中心停机

Posted ~晨曦静竹~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将 CentOS 乔迁成 AlmaLinux ,且避免数据中心停机相关的知识,希望对你有一定的参考价值。

  CentOS 8 在线升级 AlmaLinux

  众所周知,步入到2021年红帽已不在维护CentOS了,转而取代的是伪滚动发行版 CentOS Stream,但少有Centos的运维人员对其青睐,而许多第三方应用程序(如cPanel)均不支持Stream。为此,博主对红帽这一草率的决定感到惋惜,同时也对自己初学Linux时用过的Centos将逐渐淡出人们视野而表示同情。

  不过,别担心,随后就有大佬们推出了Centos的替代分支Linux。第一个宣布的是 Rocky Linux,来自最初为我们带来 CentOS 的人。紧随其后的是 AlmaLinux两者都是当前 Red Hat Enterprise Linux 二进制兼容并得到社区支持的开源操作系统的替代品,并且已经在成为 CentOS 的事实上的替代品方面取得了长足的进步 。

  博主在Github找到了AlmaLinux的工作人员提供的Centos在线升级更新AlmaLinux的方式,可以说为已在数据中心部署了大量CentOS的运维人员带来了福音,且过程很简便。


  需求:

  CentOS 8 的运行实例
  具有 sudo 运行权限的用户

  如何将 CentOS 乔迁 AlmaLinux

  首先是更新Centos服务器环境:

	sudo dnf upgrade -y	很明显这是CentOS 8
	
	不管是哪版本,当然也可用yum:
	yum update && yum upgrade -y

在这里插入图片描述

  创建升级更新时的脚本文件路径:

	mkdir AlmaLinux
	博主是在/root下创建的
	
	进入新建目录:
	cd  AlmaLinux

  从Github上下载升级脚本:

	curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh

  若有读者在测试过程中如下图所示被墙了,可通过添加github的ip到hosts文件中来解决:
在这里插入图片描述

报错代码:
Failed to connect to raw.githubusercontent.com port 443: Connection refused

  解决方法: 访问 https://www.ipaddress.com/ ,查询 raw.githubusercontent.com 的IP
在这里插入图片描述
  添加到/etc/hosts文件中:

vim /etc/hosts

添加内容:
#Github
199.232.68.133  raw.githubusercontent.com

在这里插入图片描述
  再次执行curl下载:

	curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh

  而已下载好文件的朋友,授权执行即可:

	给almalinux-deploy.sh脚本文件授权:
	chmod u+x almalinux-deploy.sh
	
	执行:
	sudo ./almalinux-deploy.sh

在这里插入图片描述
  等待,直到出现如下消息,即说明乔迁成功!

Complete!
Run dnf distro-sync -y                                                OK
Restoring of alternatives is done                                     OK
Generating grub configuration file ...
done
All Secure Boot related packages which were released by not AlmaLinux are reinstalledOK

Migration to AlmaLinux is completed

在这里插入图片描述

  重启!
	reboot

在这里插入图片描述

  同时,我们发现新增了 AlmaLinux 8.4 的内核
  重启后发现已乔迁成功!!

在这里插入图片描述
在这里插入图片描述

  若有读者仍旧无法获取 almalinux-deploy.sh 升级脚本,也莫担心,博主提供脚本内容:
#!/bin/bash

# Description: EL to AlmaLinux migration script.
# License: GPLv3.
# Environment variables:
#   ALMA_RELEASE_URL - almalinux-release package download URL.
#   ALMA_PUBKEY_URL - RPM-GPG-KEY-AlmaLinux download URL.

set -euo pipefail

BASE_TMP_DIR='/root'
OS_RELEASE_PATH='/etc/os-release'
REDHAT_RELEASE_PATH='/etc/redhat-release'
STAGE_STATUSES_DIR='/var/run/almalinux-deploy-statuses'
ALT_ADM_DIR="/var/lib/alternatives"
BAK_DIR="/tmp/alternatives_backup"
ALT_DIR="/etc/alternatives"

# AlmaLinux OS 8.3
MINIMAL_SUPPORTED_VERSION='8.3'
VERSION='0.1.12'

BRANDING_PKGS=("centos-backgrounds" "centos-logos" "centos-indexhtml" \\
                "centos-logos-ipa" "centos-logos-httpd" \\
                "oracle-backgrounds" "oracle-logos" "oracle-indexhtml" \\
                "oracle-logos-ipa" "oracle-logos-httpd" \\
                "oracle-epel-release-el8" \\
                "redhat-backgrounds" "redhat-logos" "redhat-indexhtml" \\
                "redhat-logos-ipa" "redhat-logos-httpd" \\
                "rocky-backgrounds" "rocky-logos" "rocky-indexhtml" \\
                "rocky-logos-ipa" "rocky-logos-httpd")

REMOVE_PKGS=("centos-linux-release" "centos-gpg-keys" "centos-linux-repos" \\
                "libreport-plugin-rhtsupport" "libreport-rhel" "insights-client" \\
                "libreport-rhel-anaconda-bugzilla" "libreport-rhel-bugzilla" \\
                "oraclelinux-release" "oraclelinux-release-el8" \\
                "redhat-release" "redhat-release-eula" \\
                "rocky-release" "rocky-gpg-keys" "rocky-repos" \\
                "rocky-obsolete-packages")

setup_log_files() {
    exec > >(tee /var/log/almalinux-deploy.log)
    exec 5> /var/log/almalinux-deploy.debug.log
    BASH_XTRACEFD=5
}


# Save the successful status of a stage for future continue of it
# $1 - name of a stage
save_status_of_stage() {
    if [[ 0 != "$(id -u)" ]]; then
        # the function is called in tests and should be skipped
        return 0
    fi
    local -r stage_name="${1}"
    if [[ ! -d "${STAGE_STATUSES_DIR}" ]]; then
        mkdir -p "${STAGE_STATUSES_DIR}"
    fi
    touch "${STAGE_STATUSES_DIR}/${stage_name}"
}


# Get a status of a stage for continue of it
# $1 - name of a stage
# The function returns 1 if stage isn't completed and 0 if it's completed
get_status_of_stage() {
    if [[ 0 != "$(id -u)" ]]; then
        # the function is called in tests and should be skipped
        return 1
    fi
    local -r stage_name="${1}"
    if [[ ! -d "${STAGE_STATUSES_DIR}" ]]; then
        return 1
    fi
    if [[ ! -f "${STAGE_STATUSES_DIR}/${stage_name}" ]]; then
        return 1
    fi
    return 0
}


is_migration_completed() {
    if get_status_of_stage "completed"; then
        printf '\\n\\033[0;32mMigration to AlmaLinux was already completed\\033[0m\\n'
        exit 0
    fi
}


# Reports a completed step using a green color.
#
# $1 - Message to print.
report_step_done() {
    local -r message="${1}"
    printf '\\033[0;32m%-70sOK\\033[0m\\n' "${message}"
}

# Reports a failed step using a red color.
#
# $1 - Message to print.
# $2 - Additional information to show (optional).
report_step_error() {
    local -r message="${1}"
    local -r trace="${2:-}"
    printf '\\033[0;31m%-70sERROR\\033[0m\\n' "${message}" 1>&2
    if [[ -n "${trace}" ]]; then
        echo "${trace}" | while read -r line; do
            printf '    %s\\n' "${line}" 1>&2
        done
    fi
}

# Prints program usage information.
show_usage() {
    echo -e 'Migrates an EL system to AlmaLinux\\n'
    echo -e 'Usage: almalinux-deploy.sh [OPTION]...\\n'
    echo '  -h, --help           show this message and exit'
    echo '  -v, --version        print version information and exit'
}

# Terminates the program if it is not run with root privileges
assert_run_as_root() {
    if [[ $(id -u) -ne 0 ]]; then
        report_step_error 'Check root privileges' \\
            'Migration tool must be run as root'
        exit 2
    fi
    report_step_done 'Check root privileges'
}

# Terminates the program if UEFI Secure Boot is enabled
assert_secureboot_disabled() {
    local -r message='Check Secure Boot disabled'
    if LC_ALL='C' mokutil --sb-state 2>/dev/null | grep -P '^SecureBoot\\s+enabled' 1>/dev/null; then
        report_step_error "${message}" 'Secure Boot is not supported yet'
        exit 1
    fi
    report_step_done "${message}"
}

# Prints a system architecture.
get_system_arch() {
    uname -i
}

# Reads a variable value from /etc/os-release.
#
# $1 - variable name.
#
# Returns the variable value.
get_os_release_var() {
    local -r var="${1}"
    local val
    if ! val="$(grep -oP "^${var}=\\"\\K.*?(?=\\")" "${OS_RELEASE_PATH}")"; then
        echo "Error: ${var} is not found in ${OS_RELEASE_PATH}" >&2
        exit 1
    fi
    echo "${val}"
}

# Detects an operational system version.
#
# $1 - operational system type.
#
# Prints OS version.
get_os_version() {
    local -r os_type="${1}"
    local os_version
    if [[ "${os_type}" == 'centos' ]]; then
        if ! os_version="$(grep -oP 'CentOS\\s+Linux\\s+release\\s+\\K(\\d+\\.\\d+)' \\
                                    "${REDHAT_RELEASE_PATH}" 2>/dev/null)"; then
            report_step_error "Detect ${os_type} version"
        fi
    else
        os_version="$(get_os_release_var 'VERSION_ID')"
    fi
    echo "${os_version}"
}

# Prints control type and version.
get_panel_info() {
    local panel_type=''
    local panel_version=''
    local -r cpanel_file='/usr/local/cpanel/cpanel'
    local -r plesk_file='/usr/local/psa/version'
    if [[ -x "${cpanel_file}" ]]; then
        panel_type='cpanel'
        panel_version=$("${cpanel_file}" -V 2>/dev/null | grep -oP '^[\\d.]+')
    elif [[ -f "${plesk_file}" ]]; then
        panel_type='plesk'
        panel_version=$(grep -oP '^[\\d.]+' "${plesk_file}" 2>/dev/null)
    fi
    echo "${panel_type} ${panel_version}"
}

# Terminates the program if a platform is not supported by AlmaLinux.
#
# $1 - Operational system id (ID).
# $2 - Operational system version (e.g. 8 or 8.3).
# $3 - System architecture (e.g. x86_64).
assert_supported_system() {
    if get_status_of_stage "assert_supported_system"; then
        return 0
    fi
    local -r os_type="${1}"
    local -r os_version="${2:0:1}"
    local -r arch="${3}"
    case "${arch}" in
        x86_64|aarch64)
            ;;
        *)
            report_step_error "Check ${arch} architecture is supported"
            exit 1
            ;;
    esac
    if [[ ${os_version} -ne ${MINIMAL_SUPPORTED_VERSION:0:1} ]]; then
        report_step_error "Check EL${os_version} is supported"
        exit 1
    fi
    os_types=("centos" "almalinux" "ol" "rhel" "rocky")
    if [[ ! " ${os_types[*]} " =~ ${os_type} ]]; then
        report_step_error "Check ${os_type} operating system is supported"
        exit 1
    fi
    report_step_done "Check ${os_type}-${os_version}.${arch} is supported"
    save_status_of_stage "assert_supported_system"
    return 0
}

# Terminates the program if a control panel is not supported by AlmaLinux.
#
# $1 - Control panel type.
# $2 - Control panel version.
assert_supported_panel() {
    if get_status_of_stage "assert_supported_panel"; then
        return 0
    fi
    local -r panel_type="${1}"
    local -r panel_version="${2}"
    local plesk_min_major=18
    local plesk_min_minor=0
    local plesk_min_micro=35
    local major
    local minor
    local micro
    local error_msg="${panel_type} version \\"${panel_version}\\" is not supported. Please update the control panel to version \\"${plesk_min_major}.${plesk_min_minor}.${plesk_min_micro}\\"."
    if [[ "${panel_type}" == 'plesk' ]]; then
    local IFS=.
read -r major minor micro << EOF
${panel_version}
EOF
        if [[ -z ${micro} ]]; then
            micro=0
        fi
        if [[ -z ${minor} ]]; then
            minor=0
        fi
        if [[ ${major} -lt ${plesk_min_major} ]]; then
            report_step_error "${error_msg}"
            exit 1
        elif [[ ${major} -eq ${plesk_min_major} && ${minor} -lt ${plesk_min_minor} ]]; then
            report_step_error "${error_msg}"
            exit 1
        elif [[ ${major} -eq ${plesk_min_major} && ${minor} -eq ${plesk_min_minor} && ${micro} -lt ${plesk_min_micro} ]]; then
            report_step_error "${error_msg}"
            exit 1
        fi
    fi
    save_status_of_stage "assert_supported_panel"
}

# Returns a latest almalinux-release RPM package download URL.
#
# $1 - AlmaLinux major version (e.g. 8).
# $2 - System architecture (e.g. x86_64).
#
# Prints almalinux-release RPM package download URL.
get_release_file_url() {
    local -r os_version="${1:0:1}"
    local -r arch="${2}"
    echo "${ALMA_RELEASE_URL:-https://repo.almalinux.org/almalinux/almalinux-release-latest-${os_version}.${arch}.rpm}"
}

# Downloads and installs the AlmaLinux public PGP key.
#
# $1 - Temporary directory path.
install_rpm_pubkey() {
    if get_status_of_stage "install_rpm_pubkey"; then
        return 0
    fi
    local -r tmp_dir="${1}"
    local -r pubkey_url="${ALMA_PUBKEY_URL:-https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux}"
    local -r pubkey_path="${tmp_dir}/RPM-GPG-KEY-AlmaLinux"
    local -r step='Download RPM-GPG-KEY-AlmaLinux'
    local output
    if ! output=$(curl -f -s -S -o "${pubkey_path}" "${pubkey_url}" 2>&1); then
        report_step_error "${step}" "${output}"
        exit 1
    else
        report_step_done "${step}"
    fi
    rpm --import "${pubkey_path}"
    report_step_done 'Import RPM-GPG-KEY-AlmaLinux to RPM DB'
    rm -f "${pubkey_path}"
    save_status_of_stage "install_rpm_pubkey"
}

# Downloads almalinux-release package.
#
# $1 - almalinux-release package download URL.
# $2 - Temporary directory path.
#
# Prints downloaded file path.
download_release_file() {
    local -r release_url="${1}"
    local -r tmp_dir="${2}"
    local -r release_path="${tmp_dir}/almalinux-release-latest.rpm"
    local output
    if ! output=$(curl -f -s -S -o "${release_path}" "${release_url}" 2>&1); then
        report_step_error 'Download almalinux-release package' "${output}"
        exit 1
    fi
    echo "${release_path}"
}

# Terminates the program if a given RPM package checksum/signature is invalid.
#
# $1 - RPM package path.
assert_valid_package() {
    local -r pkg_path="${1}"
    local output
    if ! output=$(rpm -K "${pkg_path}" 2>&1); then
        report_step_error "Verify $(basename "${pkg_path}") package" \\
            "${output}"
        exit 1
    fi
    report_step_done 'Verify almalinux-release package'
}

# Terminates the program if OS version doesn't match AlmaLinux version.
#
# $1 - OS version.
# $2 - almalinux-release package file path.
assert_compatible_os_version() {
    if get_status_of_stage "assert_compatible_os_version"; then
        return 0
    fi
    local -r os_version="${1}"
    local -r release_path="${2}"
    local alma_version
    alma_version=$(rpm -qp --queryformat '%{version}' "${release_path}")

    if [[ "${os_version:2:3}" -lt "${MINIMAL_SUPPORTED_VERSION:2:3}" ]]; then
        report_step_error "Please upgrade your OS from ${os_version} to" \\
        "at least ${MINIMAL_SUPPORTED_VERSION} and try again"
        exit 1
    fi
    if [[ "${os_version:2:3}" -gt "${alma_version:2:3}" ]]; then
        report_step_error "Version of you OS ${os_version} is not supported yet"
        exit 1
    fi
    report_step_done 'Your OS is supported'
    save_status_of_stage "assert_compatible_os_version"
}

# Backup /etc/issue* files
backup_issue() {
    if get_status_of_stage "backup_issue"; then
        return 0
    fi
    for file in $(rpm -Vf /etc/issue | cut -d' ' -f4); do
        if [[ ${file} =~ "/etc/issue" ]]; then
            cp "${file}" "${file}.bak"
        fi
    done
    save_status_of_stage "backup_issue"
}

# Restore /etc/issue* files
restore_issue() {
    if get_status_of_stage "restore_issue"; then
        return 0
    fi
    for file in /etc/issue /etc/issue.net; do
        [ ! -f "${file}.bak" ] || mv -f ${file}.bak ${file}
    done
    save_status_of_stage "restore_issue"
}

# Recursively removes a given directory.
#
# $1 - Directory path.
cleanup_tmp_dir() {
    rm -fr "${1:?}"
}

# Remove OS specific packages
remove_os_specific_packages_before_migration() {
    if get_status_of_stage "remove_os_specific_packages_before_migration"; then
        return 0
    fi
    for i in "${!REMOVE_PKGS[@]}"; do
        if ! rpm -q "${REMOVE_PKGS[i]}" &> /dev/null; then
            # remove an erased package from the list if it isn't installed
            unset "REMOVE_PKGS[i]"
        fi
    done
    if [[ "${#REMOVE_PKGS[@]}" -ne 0 ]]; then
        rpm -e --nodeps --allmatches "${REMOVE_PKGS[@]}"
    fi
    report_step_done 'Remove OS specific rpm packages'
    save_status_of_stage "remove_os_specific_packages_before_migration"
}


# Remove not needed Red Hat directories
remove_not_needed_redhat_dirs() {
    if get_status_of_stage "remove_not_needed_redhat_dirs"; then
        return 0
    fi
    [ -d /usr/share/doc/redhat-release ] && rm -r /usr/share/doc/redhat-release
    [ -d /usr/share/redhat-release ] && rm -r /usr/share/redhat-release
    save_status_of_stage "remove_not_needed_redhat_dirs"
}


# Install package almalinux-release
install_almalinux_release_package() {
    if get_status_of_stage "install_almalinux_release_package"; then
        return 0
    fi
    local -r release_path="${1}"
    rpm -Uvh "${release_path}"
    report_step_done 'Install almalinux-release package'
    save_status_of_stage "install_almalinux_release_package"
}


# Remove brand packages and install the same AlmaLinux packages
replace_brand_packages() {
    if get_status_of_stage "replace_brand_packages"; then
        return 0
    fi
    local alma_pkgs=()
    local alma_pkg
    local output
    local pkg_name
    # replace GUI packages
    for i in "${!BRANDING_PKGS[@]}"; do
        pkg_name="${BRANDING_PKGS[i]}"
        if rpm -q "${pkg_name}" &>/dev/null; then
            # shellcheck disable=SC2001
            case "${pkg_name}" in
                oracle-epel-release-el8)
                    alma_pkg="epel-release"
                    ;;
                *)
                    # shellcheck disable=SC2001
                    alma_pkg="$(echo "${pkg_name}" | sed 's#centos\\|oracle\\|redhat\\|rocky#almalinux#')"
                    ;;
            esac
            alma_pkgs+=("${alma_pkg}")
        else
            unset "BRANDING_PKGS[i]"
        fi
    done
    if [[ "${#BRANDING_PKGS[@]}" -ne 0 ]]; then
        rpm -e --nodeps --allmatches "${BRANDING_PKGS[@]}"
        report_step_done "Remove ${BRANDING_PKGS[*]} packages"
    fi
    if [[ "${#alma_pkgs[@]}" -ne 0 ]]; then
        if ! output=$(dnf install -y "${alma_pkgs[@]}" 2>&1); then
            report_step_error "Install ${alma_pkgs[*]} packages" "${output}"
        fi
        report_step_done "Install ${alma_pkgs[*]} packages"
    fi
    save_status_of_stage "replace_brand_packages"
}


# Converts a CentOS like system to AlmaLinux
#
# $1 - almalinux-release RPM package path.
migrate_from_centos() {
    if get_status_of_stage "migrate_from_centos"; then
        return 0
    fi
    local -r release_path="${1}"
    # replace OS packages with almalinux-release
    # and OS centos-specific packages
    remove_os_specific_packages_before_migration
    remove_not_needed_redhat_dirs
    install_almalinux_release_package "${release_path}"
    replace_brand_packages
    save_status_of_stage "migrate_from_centos"
}

# Executes the 'dnf distro-sync -y' command.
#
distro_sync() {
    if get_status_of_stage "distro_sync"; then
        return 0
    fi
    local -r step='Run dnf distro-sync -y'
    local ret_code=0
    local dnf_repos="--enablerepo=powertools"
    # create needed repo
    if [ "${panel_type}" == "plesk" ]; then
        plesk installer --select-release-current --show-components --skip-cleanup
        dnf_repos+=",PLESK_*-dist"
    fi
    dnf check-update || {
        ret_code=${?}
        if [[ ${ret_code} -ne 0 ]] && [[ ${ret_code} -ne 100 ]]; then
            report_step_error "${step}. Exit code: ${ret_code}"
            exit ${ret_code}
        fi
    }
    dnf distro-sync -y "${dnf_repos}" || {
        ret_code=${?}
        report_step_error "${step}. Exit code: ${ret_code}"
        exit ${ret_code}
    }
    # remove unnecessary repo
    if [ "${panel_type}" == "plesk" ]; then
        plesk installer --select-release-current --show-components
    fi
    report_step_done "${step}"
    save_status_of_stage "distro_sync"
}

install_kernel() {
    if get_status_of_stage "install_kernel"; then
        return 0
    以上是关于如何将 CentOS 乔迁成 AlmaLinux ,且避免数据中心停机的主要内容,如果未能解决你的问题,请参考以下文章

CentOS的替代者AlmaLinux Beta版已发布

AlmaLinux:CentOS的最佳替代

CentOS 替代项目 AlmaLinux 的最新消息来了

CloudLinux将其CentOS衍生项目Lenix更名为AlmaLinux

CentOS 消亡?不怕,替代品 AlmaLinux 将获商业支持!

CentOS 8 move to AlmaLinux 8