[Linux] Ubuntu 패키지/커널 업그레이드 관련 내용
[Linux] CentOS 패키지/커널 업그레이드 관련 내용

 

◎ 자동화 스크립트
 - 아래 내용을 붙여넣기 하세요.(예. # vi /root/lab/kernel_manager.sh)

#!/bin/bash

# 1. 루트 권한 확인
if [ "$EUID" -ne 0 ]; then
  echo "❌ 이 스크립트는 root 권한(sudo)으로 실행해야 합니다."
  exit 1
fi

# 2. OS 계열 확인
if [ -f /etc/os-release ]; then
    . /etc/os-release
    OS_ID=$ID
    OS_LIKE=$ID_LIKE
else
    echo "❌ OS 정보를 확인할 수 없습니다."
    exit 1
fi

IS_DEBIAN=false
IS_REDHAT=false

if [[ "$OS_ID" == "ubuntu" || "$OS_ID" == "debian" || "$OS_LIKE" == *"debian"* ]]; then
    IS_DEBIAN=true
elif [[ "$OS_ID" == "centos" || "$OS_ID" == "rhel" || "$OS_ID" == "rocky" || "$OS_ID" == "almalinux" || "$OS_LIKE" == *"rhel"* ]]; then
    IS_REDHAT=true
else
    echo "❌ 지원하지 않는 OS 계열입니다: $OS_ID"
    exit 1
fi

CURRENT_KERNEL=$(uname -r)

# ==================================================
# 함수 모음
# ==================================================

pause() {
    echo ""
    read -p "엔터를 누르면 메인 메뉴로 돌아갑니다..."
}

# [메뉴 0] 의존성 설치
install_dependencies() {
    echo ""
    echo "=================================================="
    echo " 🛠️  시스템 의존성 및 플러그인 설치 (RedHat 계열)"
    echo "=================================================="
    echo "⏳ DNF versionlock 플러그인을 설치합니다..."
    dnf install 'dnf-command(versionlock)' -y
    echo "✅ 설치가 완료되었습니다."
    pause
}

# [안내] 필요한 파일 가이드
show_kernel_file_guide() {
    echo ""
    echo "--------------------------------------------------"
    echo " 💡 커널 수동 설치 시 필요한 파일 가이드"
    echo "--------------------------------------------------"
    if [ "$IS_DEBIAN" = true ]; then
        echo " Ubuntu/Debian (.deb) 파일들:"
        echo " 1. linux-image-[버전]-generic"
        echo " 2. linux-modules-[버전]-generic"
        echo " 3. linux-modules-extra-[버전]-generic"
        echo " 4. linux-hwe-[버전]-headers-[버전]_[버전]_all"
		echo " 5. linux-headers-[버전]-generic"
    else
        echo " RHEL/CentOS/Rocky (.rpm) 파일들:"
        echo " 1. kernel-[버전]"
        echo " 2. kernel-core-[버전]"
        echo " 3. kernel-modules-[버전]"
		echo " 4. kernel-modules-core-[버전]"
        echo " 5. kernel-devel-[버전] (선택)"
    fi
    echo "--------------------------------------------------"
}

# [메뉴 1] 커널 삭제
delete_kernel() {
    echo ""
    echo "=================================================="
    echo " 🗑️  삭제할 커널 버전 선택"
    echo "=================================================="
    
    if [ "$IS_DEBIAN" = true ]; then
        KERNEL_LIST=$(dpkg -l | grep -E '^ii  linux-image-[0-9]' | awk '{print $2}' | sed -E 's/linux-image-(unsigned-)?//' | sed 's/-generic//' | sed 's/-dbgsym//' | sort -V | uniq)
    elif [ "$IS_REDHAT" = true ]; then
        KERNEL_LIST=$(rpm -q kernel | grep -v 'not installed' | sed 's/kernel-//' | sort -V | uniq)
    fi

    if [ -z "$KERNEL_LIST" ]; then
        echo "❌ 삭제할 커널 버전을 찾을 수 없습니다."
        pause; return
    fi

    IFS=$'\n' read -r -d '' -a KERNEL_ARRAY <<< "$KERNEL_LIST"
    for i in "${!KERNEL_ARRAY[@]}"; do
        VER="${KERNEL_ARRAY[$i]}"
        MARK=""
        [[ "$CURRENT_KERNEL" == *"$VER"* ]] && MARK=" [⚠️ 현재 사용중 - 삭제불가]"
        echo "$((i+1)). $VER $MARK"
    done
    echo "q. 취소"
    read -p "▶ 번호 선택: " CHOICE
    [[ "$CHOICE" == "q" || "$CHOICE" == "Q" ]] && return

    if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || [ "$CHOICE" -lt 1 ] || [ "$CHOICE" -gt "${#KERNEL_ARRAY[@]}" ]; then
        echo "❌ 잘못된 번호입니다."; pause; return
    fi

    TARGET_VER="${KERNEL_ARRAY[$((CHOICE-1))]}"
    [[ "$CURRENT_KERNEL" == *"$TARGET_VER"* ]] && { echo "❌ 현재 커널은 삭제 불가!"; pause; return; }

    read -p "❓ 정말로 '$TARGET_VER' 관련 모든 패키지를 삭제하시겠습니까? (y/n): " CONFIRM
    [[ "$CONFIRM" != "y" && "$CONFIRM" != "Y" ]] && return

    if [ "$IS_DEBIAN" = true ]; then
        TARGET_PKGS=$(dpkg --get-selections | awk '{print $1}' | grep -E "^linux-(image|headers|modules|modules-extra)" | grep "$TARGET_VER")
        [ -n "$TARGET_PKGS" ] && { apt-get purge -y $TARGET_PKGS; apt-get autoremove --purge -y; }
    elif [ "$IS_REDHAT" = true ]; then
        TARGET_PKGS=$(rpm -qa | grep -E "^(kernel|kernel-headers|kernel-devel|kernel-modules|kernel-core)" | grep "$TARGET_VER")
        [ -n "$TARGET_PKGS" ] && { command -v dnf >/dev/null 2>&1 && dnf remove -y $TARGET_PKGS || yum remove -y $TARGET_PKGS; }
    fi
    echo "✅ 삭제 완료!"
    pause
}

# [메뉴 2] 커널 업데이트 잠금/해제
hold_kernel_upgrade() {
    echo ""
    echo "=================================================="
    echo " 🛡️  커널 업데이트 제어 및 시스템 업그레이드"
    echo "=================================================="
    
    if [ "$IS_DEBIAN" = true ]; then
        echo "현재 잠금 상태: $(apt-mark showhold | grep linux-)"
    elif [ "$IS_REDHAT" = true ]; then
        if ! command -v dnf versionlock > /dev/null; then
            echo "❌ versionlock 플러그인이 없습니다. 메뉴 0번을 먼저 실행하세요."
            pause; return
        fi
        echo "현재 잠금 상태:"
        dnf versionlock list
    fi

    echo "--------------------------------------------------"
    echo "1. 현재 커널 버전 업데이트 잠금 (Hold)"
    echo "2. 커널 업데이트 잠금 해제 (Unhold/Clear)"
    echo "3. 커널 제외 시스템 업그레이드 (Safe Upgrade)"
    echo "q. 취소"
    read -p "▶ 선택: " SUB_CHOICE

    case "$SUB_CHOICE" in
        1)
            if [ "$IS_DEBIAN" = true ]; then
                apt-mark hold linux-image-generic linux-headers-generic linux-image-$(uname -r)
            else
                dnf versionlock add kernel-$(uname -r)
            fi
            echo "✅ 업데이트 잠금 완료."
            ;;
        2)
            if [ "$IS_DEBIAN" = true ]; then
                apt-mark unhold linux-image-generic linux-headers-generic
            else
                dnf versionlock delete kernel-*
            fi
            echo "✅ 업데이트 잠금 해제 완료."
            ;;
        3)
            echo "⏳ 업그레이드를 시작합니다..."
            if [ "$IS_DEBIAN" = true ]; then
                apt-mark hold linux-image-generic linux-headers-generic
                apt update && apt upgrade -y
            else
                dnf upgrade -y --exclude=kernel*
            fi
            echo "✅ 업그레이드 완료."
            ;;
        q|Q) return ;;
    esac
    pause
}

# [메뉴 3] 특정 커널 버전 설치 (확장판)
install_specific_kernel() {
    echo "=================================================="
    echo " ⬇️  커널 설치 옵션 선택"
    echo "=================================================="
    echo "1. 온라인 리포지토리 목록에서 선택 (최근 15개)"
    echo "2. 커널 버전 명칭 직접 입력 (온라인 검색)"
    echo "3. 로컬 폴더의 패키지 파일로 설치 (.deb 또는 .rpm)"
    echo "q. 취소"
    echo "--------------------------------------------------"
    read -p "▶ 선택: " INST_OPT

    case "$INST_OPT" in
        1)
            # 기존 번호 선택 로직
            if [ "$IS_DEBIAN" = true ]; then
                K_SEARCH=$(apt-cache search linux-image- | grep -E 'linux-image-[0-9]' | grep 'generic' | grep -v -E 'dbgsym|unsigned' | awk '{print $1}' | sed 's/linux-image-//' | sort -V | tail -n 15)
            else
                K_SEARCH=$(dnf list --showduplicates kernel | grep kernel | awk '{print $2}' | sort -V | tail -n 15)
            fi
            IFS=$'\n' read -r -d '' -a AVAIL_ARRAY <<< "$K_SEARCH"
            for i in "${!AVAIL_ARRAY[@]}"; do echo "$((i+1)). ${AVAIL_ARRAY[$i]}"; done
			echo "q. 취소"
            read -p "▶ 번호 선택: " K_CHOICE
			[[ "$K_CHOICE" == "q" || "$K_CHOICE" == "Q" ]] && return
            TARGET_VER="${AVAIL_ARRAY[$((K_CHOICE-1))]}"
            ;;
        2)
            echo "리포지토리에 존재하는 정확한 버전명을 입력하세요."
			echo "q. 취소"
            read -p "▶ 버전 입력: " TARGET_VER
			[[ "$TARGET_VER" == "q" || "$TARGET_VER" == "Q" ]] && return
            ;;
        3)
            show_kernel_file_guide
			echo "q. 취소"
            read -p "▶ 패키지 파일이 있는 폴더 경로 입력: " DIR_PATH
			[[ "$DIR_PATH" == "q" || "$DIR_PATH" == "Q" ]] && return
            if [ ! -d "$DIR_PATH" ]; then echo "❌ 존재하지 않는 경로입니다."; pause; return; fi
            echo "⏳ '$DIR_PATH' 내의 패키지를 설치합니다..."
            if [ "$IS_DEBIAN" = true ]; then
                dpkg -i "$DIR_PATH"/*.deb || apt-get install -f -y
            else
                dnf localinstall -y "$DIR_PATH"/*.rpm
            fi
            echo "✅ 로컬 설치 시도 완료."; pause; return
            ;;
        q|Q) return ;;
        *) echo "❌ 잘못된 선택입니다."; pause; return ;;
    esac

    [ -z "$TARGET_VER" ] && return

    echo "⏳ '$TARGET_VER' 설치 시도 중..."
    if [ "$IS_DEBIAN" = true ]; then
        apt install -y linux-image-${TARGET_VER} linux-headers-${TARGET_VER} linux-modules-extra-${TARGET_VER}
    else
        dnf install -y kernel-${TARGET_VER} kernel-devel-${TARGET_VER} kernel-headers-${TARGET_VER}
    fi
    pause
}

# [메뉴 4] GRUB 업데이트 및 기본 커널 선택 (Ubuntu/Debian 고정 강화 버전)
update_grub_menu() {
    echo ""
    echo "=================================================="
    echo " ⚙️  GRUB 업데이트 및 기본 부팅 커널 선택"
    echo "=================================================="
    echo "현재 설치된 커널 목록:"
    
    if [ "$IS_DEBIAN" = true ]; then
        BOOT_K_LIST=$(dpkg -l | grep -E '^ii  linux-image-[0-9]' | awk '{print $2}' | sed -E 's/linux-image-(unsigned-)?//' | sed 's/-generic//' | sort -V -r)
    elif [ "$IS_REDHAT" = true ]; then
        BOOT_K_LIST=$(rpm -q kernel --queryformat '%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort -V -r)
    fi

    IFS=$'\n' read -r -d '' -a BOOT_ARRAY <<< "$BOOT_K_LIST"

    for i in "${!BOOT_ARRAY[@]}"; do
        VER="${BOOT_ARRAY[$i]}"
        MARK=""
        [[ "$CURRENT_KERNEL" == *"$VER"* ]] && MARK=" [현재 부팅됨]"
        echo "$((i+1)). $VER $MARK"
    done
    echo "u. 선택 없이 단순히 GRUB만 업데이트"
    echo "q. 취소"
    echo "--------------------------------------------------"
    read -p "▶ 번호 선택: " B_CHOICE

    if [[ "$B_CHOICE" == "q" || "$B_CHOICE" == "Q" ]]; then return; fi

    if [[ "$B_CHOICE" == "u" || "$B_CHOICE" == "U" ]]; then
        echo "⏳ GRUB 구성 갱신 중..."
    else
        if ! [[ "$B_CHOICE" =~ ^[0-9]+$ ]] || [ "$B_CHOICE" -lt 1 ] || [ "$B_CHOICE" -gt "${#BOOT_ARRAY[@]}" ]; then
            echo "❌ 잘못된 번호입니다."; pause; return
        fi

        SELECTED_K="${BOOT_ARRAY[$((B_CHOICE-1))]}"
        echo "⏳ '$SELECTED_K' 버전을 기본 커널로 고정 중..."

        if [ "$IS_DEBIAN" = true ]; then
            # 1. /etc/default/grub 설정 변경
            sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT="gnulinux-advanced-$(lsblk -no UUID $(df /boot | tail -1 | awk '{print $1}'))>gnulinux-'$SELECTED_K'-advanced-$(lsblk -no UUID $(df /boot | tail -1 | awk '{print $1}'))"/' /etc/default/grub 2>/dev/null
            
            # 위 방식이 실패할 경우를 대비한 2번째 직관적 방법 (문자열 매칭)
            # "1 > 2" 형태 (두 번째 메뉴의 세 번째 항목 등)
            # 여기서는 가장 확실한 '문자열 지정 방식'으로 덮어씁니다.
            sed -i "s/^GRUB_DEFAULT=.*/GRUB_DEFAULT=\"Advanced options for Ubuntu>Ubuntu, with Linux $SELECTED_K-generic\"/" /etc/default/grub
            
        elif [ "$IS_REDHAT" = true ]; then
            grubby --set-default=/boot/vmlinuz-$SELECTED_K
        fi
        echo "✅ 기본 커널 설정이 '$SELECTED_K'로 변경되었습니다."
    fi

    # 최종 GRUB 갱신
    if [ "$IS_DEBIAN" = true ]; then
        update-grub
    elif [ "$IS_REDHAT" = true ]; then
        GRUB_PATH="/boot/grub2/grub.cfg"
        [ -f "/boot/efi/EFI/$OS_ID/grub.cfg" ] && GRUB_PATH="/boot/efi/EFI/$OS_ID/grub.cfg"
        [ -f "/boot/efi/EFI/redhat/grub.cfg" ] && GRUB_PATH="/boot/efi/EFI/redhat/grub.cfg"
        [ -f "/boot/efi/EFI/rocky/grub.cfg" ] && GRUB_PATH="/boot/efi/EFI/rocky/grub.cfg"
        [ -f "/boot/efi/EFI/almalinux/grub.cfg" ] && GRUB_PATH="/boot/efi/EFI/almalinux/grub.cfg"
        grub2-mkconfig -o $GRUB_PATH
    fi
    echo "✅ 완료! 이제 재부팅하면 선택한 커널로 로드됩니다."
    pause
}

# ==================================================
# 메인 루프
# ==================================================
while true; do
    clear
    echo "=================================================="
    echo " 🐧 종합 커널 관리 도구"
    echo "=================================================="
    echo " - OS 계열 : $OS_ID ($OS_LIKE)"
    echo " - 현재 커널: $CURRENT_KERNEL"
    echo "=================================================="
    
    if [ "$IS_REDHAT" = true ]; then
        echo " 0. 🛠️  [RedHat 전용] dnf versionlock 플러그인 설치"
    fi
    
    echo " 1. 🗑️  커널 삭제 (번호 선택)"
    echo " 2. 🛡️  커널 업데이트 잠금/해제 및 안전 업그레이드"
    echo " 3. ⬇️  특정 커널 버전 설치 (번호 선택)"
    echo " 4. ⚙️  부팅 커널 선택 및 GRUB 갱신"
    echo " q. 🚪 종료"
    echo "=================================================="
    read -p "▶ 선택: " MAIN_CHOICE

    case "$MAIN_CHOICE" in
        0) [ "$IS_REDHAT" = true ] && install_dependencies || echo "❌ 잘못된 입력입니다." ;;
        1) delete_kernel ;;
        2) hold_kernel_upgrade ;;
        3) install_specific_kernel ;;
        4) update_grub_menu ;;
        q|Q) exit 0 ;;
        *) echo "❌ 잘못된 입력입니다."; sleep 1 ;;
    esac
done

 

kernel_manager.sh
0.01MB

 

 

 - 파일이 만들어진 폴더로 이동하고 아래 명령어를 실행합니다.

/root/lab # chmod +x kernel_manager.sh
/root/lab # ./kernel_manager.sh

 

==================================================
 🐧 종합 커널 관리 도구
==================================================
 - OS 계열 : ubuntu (debian)
 - 현재 커널: 6.8.0-110-generic
==================================================
 1. 🗑️  커널 삭제 (번호 선택)
 2. 🛡️  커널 업데이트 잠금/해제 및 안전 업그레이드
 3. ⬇️  특정 커널 버전 설치 (번호 선택)
 4. ⚙️  부팅 커널 선택 및 GRUB 갱신
 q. 🚪 종료
==================================================
▶ 선택:

 

==================================================
 🐧 종합 커널 관리 도구
==================================================
 - OS 계열 : rocky (rhel centos fedora)
 - 현재 커널: 5.14.0-427.31.1.el9_4.x86_64
==================================================
 0. 🛠️  [RedHat 전용] dnf versionlock 플러그인 설치
 1. 🗑️  커널 삭제 (번호 선택)
 2. 🛡️  커널 업데이트 잠금/해제 및 안전 업그레이드
 3. ⬇️  특정 커널 버전 설치 (번호 선택)
 4. ⚙️  부팅 커널 선택 및 GRUB 갱신
 q. 🚪 종료
==================================================
▶ 선택:

 

반응형

+ Recent posts