From 86c3a3081f848fd54ce0e948549c852ea01a4f6f Mon Sep 17 00:00:00 2001 From: joy Date: Wed, 29 Oct 2025 12:47:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20scripts/containerd.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/containerd.sh | 392 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 scripts/containerd.sh diff --git a/scripts/containerd.sh b/scripts/containerd.sh new file mode 100644 index 0000000..c3468f2 --- /dev/null +++ b/scripts/containerd.sh @@ -0,0 +1,392 @@ +#!/bin/bash +set -euo pipefail + +# 企业级Containerd apt安装/卸载脚本(Ubuntu专用) +# 支持:安装指定版本、完整卸载、重复执行 +# 适用:Ubuntu 20.04/22.04/24.04 LTS + +####################################### +# 配置参数 +####################################### +DEFAULT_VERSION="1.7.28-1" +ACTION="" +CONTAINERD_VERSION="$DEFAULT_VERSION" +LOG_FILE="/var/log/containerd_apt_manage.log" +DOCKER_REPO="https://download.docker.com/linux/ubuntu" +GPG_KEY_PATH="/etc/apt/keyrings/docker.gpg" +REPO_LIST_PATH="/etc/apt/sources.list.d/docker.list" +CONFIG_PATH="/etc/containerd/config.toml" +PACKAGE_NAME="containerd.io" + +####################################### +# 日志函数(标准化输出) +####################################### +log() { + local level=$1 + local message=$2 + local timestamp=$(date +"%Y-%m-%d %H:%M:%S") + echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE" +} + +####################################### +# 帮助信息 +####################################### +usage() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --install 安装containerd(必填)" + echo " --uninstall 卸载containerd(必填)" + echo " --version VERSION 指定安装版本(格式:x.y.z-1,默认:$DEFAULT_VERSION)" + echo " --help 显示帮助" + exit 1 +} + +####################################### +# 解析参数 +####################################### +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --install) + if [[ "$ACTION" == "uninstall" ]]; then + log "ERROR" "--install与--uninstall不可同时使用" + usage + fi + ACTION="install" + shift + ;; + --uninstall) + if [[ "$ACTION" == "install" ]]; then + log "ERROR" "--install与--uninstall不可同时使用" + usage + fi + ACTION="uninstall" + shift + ;; + --version) + if [[ $# -lt 2 || "$2" == -* ]]; then + log "ERROR" "--version需要指定有效版本号(如1.7.28-1)" + usage + fi + CONTAINERD_VERSION="$2" + shift 2 + ;; + --help) + usage + ;; + *) + log "ERROR" "未知参数:$1" + usage + ;; + esac + done + + if [[ -z "$ACTION" ]]; then + log "ERROR" "必须指定--install或--uninstall" + usage + fi + + # 安装时验证版本格式,卸载时无需版本参数 + if [[ "$ACTION" == "install" && ! "$CONTAINERD_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-[0-9]+$ ]]; then + log "ERROR" "版本格式错误,正确格式:x.y.z-1(如1.7.28-1)" + exit 1 + fi +} + +####################################### +# 前置检查(通用) +####################################### +pre_check() { + log "INFO" "开始前置环境检查" + + # 检查root权限 + if [[ "$(id -u)" -ne 0 ]]; then + log "ERROR" "请使用root权限执行(sudo)" + exit 1 + fi + + # 检查Ubuntu系统 + if ! grep -q "Ubuntu" /etc/os-release; then + log "ERROR" "仅支持Ubuntu系统" + exit 1 + fi + + # 检查系统版本 + local os_version=$(grep VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"') + if ! [[ "$os_version" =~ ^20\.04$ || "$os_version" =~ ^22\.04$ || "$os_version" =~ ^24\.04$ ]]; then + log "ERROR" "仅支持Ubuntu 20.04/22.04/24.04 LTS" + exit 1 + fi + + # 检查必要工具 + local required_tools=("apt-get" "curl" "gpg" "lsb_release" "systemctl") + for tool in "${required_tools[@]}"; do + if ! command -v "$tool" &> /dev/null; then + log "INFO" "安装缺失工具:$tool" + apt-get update -qq >/dev/null + apt-get install -qq -y "$tool" >/dev/null + fi + done + + log "INFO" "前置检查通过" +} + +####################################### +# 配置Docker源(仅安装时使用) +####################################### +configure_repo() { + log "INFO" "配置Docker apt源" + + mkdir -p "$(dirname "$GPG_KEY_PATH")" + + # 下载GPG密钥(幂等处理) + if [[ ! -f "$GPG_KEY_PATH" ]]; then + log "INFO" "下载Docker GPG密钥" + if ! curl -fsSL --retry 3 --retry-delay 5 \ + "${DOCKER_REPO}/gpg" | gpg --dearmor -o "$GPG_KEY_PATH" >/dev/null 2>&1; then + log "ERROR" "GPG密钥下载失败,请检查网络" + rm -f "$GPG_KEY_PATH" + exit 1 + fi + chmod a+r "$GPG_KEY_PATH" + else + log "INFO" "Docker GPG密钥已存在,跳过下载" + fi + + # 配置源(幂等处理) + local codename=$(lsb_release -cs) + local repo_content="deb [arch=$(dpkg --print-architecture) signed-by=$GPG_KEY_PATH] $DOCKER_REPO $codename stable" + if [[ -f "$REPO_LIST_PATH" && -z "$(grep -Fxv "$repo_content" "$REPO_LIST_PATH")" ]]; then + log "INFO" "Docker源已配置,跳过更新" + else + log "INFO" "写入Docker源配置" + echo "$repo_content" | tee "$REPO_LIST_PATH" >/dev/null + apt-get update -qq >/dev/null + fi + + log "INFO" "Docker apt源配置完成" +} + +####################################### +# 验证版本可用性(仅安装时使用) +####################################### +verify_version() { + log "INFO" "验证版本${CONTAINERD_VERSION}可用性" + + # 提取可用版本(兼容带发行版后缀的格式) + local available_versions + available_versions=$(apt-cache madison "$PACKAGE_NAME" | + awk '{print $3}' | + sed 's/~.*//' | # 移除发行版后缀(如~ubuntu.24.04~noble) + sort -u) + + if ! echo "$available_versions" | grep -qxF "$CONTAINERD_VERSION"; then + log "ERROR" "版本${CONTAINERD_VERSION}不可用,可用版本如下:" + echo "$available_versions" | tee -a "$LOG_FILE" + exit 1 + fi + + log "INFO" "版本验证通过" +} + +####################################### +# 安装containerd +####################################### +install_containerd() { + log "INFO" "检查当前${PACKAGE_NAME}版本" + + # 检查是否已安装目标版本(忽略后缀) + local installed_version + if dpkg -l "$PACKAGE_NAME" &>/dev/null; then + installed_version=$(dpkg -l "$PACKAGE_NAME" | awk '/ii/ {print $3}' | sed 's/~.*//') + if [[ "$installed_version" == "$CONTAINERD_VERSION" ]]; then + log "INFO" "${PACKAGE_NAME} ${CONTAINERD_VERSION}已安装,跳过安装" + return + fi + fi + + # 安装指定版本(apt会自动匹配带后缀的兼容版本) + log "INFO" "安装${PACKAGE_NAME}=${CONTAINERD_VERSION}" + if ! apt-get install -qq -y "${PACKAGE_NAME}=${CONTAINERD_VERSION}" >/dev/null 2>&1; then + # 尝试直接安装(不指定具体后缀,由apt自动选择兼容版本) + log "WARNING" "指定版本安装失败,尝试安装兼容版本..." + if ! apt-get install -qq -y "$PACKAGE_NAME" >/dev/null 2>&1; then + log "ERROR" "安装失败,请检查源配置或版本号" + exit 1 + fi + fi + + log "INFO" "${PACKAGE_NAME}安装完成" +} + +####################################### +# 配置containerd(仅安装时使用) +####################################### +configure_containerd() { + log "INFO" "配置containerd" + + # 生成默认配置(幂等处理) + if [[ ! -f "$CONFIG_PATH" ]]; then + log "INFO" "生成默认配置文件" + containerd config default | tee "$CONFIG_PATH" >/dev/null 2>&1 + fi + + # 启用SystemdCgroup(Kubernetes必需) + if grep -q "SystemdCgroup \= false" "$CONFIG_PATH"; then + log "INFO" "启用SystemdCgroup" + sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/' "$CONFIG_PATH" + else + log "INFO" "SystemdCgroup已启用,跳过配置" + fi + + # 重启服务应用配置 + systemctl restart containerd >/dev/null 2>&1 + + log "INFO" "containerd配置完成" +} + +####################################### +# 启动服务(仅安装时使用) +####################################### +start_service() { + log "INFO" "配置containerd服务" + + if systemctl is-active --quiet containerd; then + log "INFO" "containerd服务已运行" + else + log "INFO" "启动containerd并设置开机自启" + systemctl enable --now containerd >/dev/null 2>&1 + fi + + log "INFO" "服务配置完成" +} + +####################################### +# 验证安装结果 +####################################### +verify_installation() { + log "INFO" "验证安装结果" + + # 检查服务状态 + if ! systemctl is-active --quiet containerd; then + log "ERROR" "containerd服务未运行" + exit 1 + fi + + # 检查版本匹配(忽略v前缀和后缀) + local installed_version + installed_version=$(containerd --version | awk '/containerd/ {print $3}' | cut -d'+' -f1 | sed 's/^v//') + if [[ "$installed_version" != "${CONTAINERD_VERSION%-*}" ]]; then + log "ERROR" "版本不匹配:预期${CONTAINERD_VERSION%-*},实际${installed_version}" + exit 1 + fi + + log "INFO" "安装验证通过,当前版本:${installed_version}" +} + +####################################### +# 卸载containerd(新增功能) +####################################### +uninstall_containerd() { + log "INFO" "开始卸载containerd" + + # 停止服务(幂等处理) + if systemctl is-active --quiet containerd; then + log "INFO" "停止containerd服务" + systemctl stop containerd >/dev/null 2>&1 + else + log "INFO" "containerd服务未运行,跳过停止" + fi + + # 卸载包(彻底清除配置) + if dpkg -l "$PACKAGE_NAME" &>/dev/null; then + log "INFO" "卸载${PACKAGE_NAME}包" + apt-get purge -qq -y "$PACKAGE_NAME" >/dev/null 2>&1 + apt-get autoremove -qq -y >/dev/null 2>&1 # 清理依赖 + else + log "INFO" "${PACKAGE_NAME}未安装,跳过卸载" + fi + + # 清理残留文件(幂等处理) + log "INFO" "清理残留配置" + rm -rf "$CONFIG_PATH" /var/lib/containerd /var/log/containerd + + # 可选:保留Docker源(如需安装其他Docker组件),如需清理则解除注释 + # if [[ -f "$REPO_LIST_PATH" ]]; then + # rm -f "$REPO_LIST_PATH" + # fi + # if [[ -f "$GPG_KEY_PATH" ]]; then + # rm -f "$GPG_KEY_PATH" + # fi + # apt-get update -qq >/dev/null + + # 重新加载systemd + systemctl daemon-reload >/dev/null 2>&1 + + log "INFO" "containerd卸载完成" +} + +####################################### +# 验证卸载结果 +####################################### +verify_uninstallation() { + log "INFO" "验证卸载结果" + + # 检查服务是否已移除 + if systemctl list-unit-files | grep -q "containerd.service"; then + log "WARNING" "containerd服务文件未完全清理,可能需要手动删除" + else + log "INFO" "服务文件已清理" + fi + + # 检查包是否残留 + if dpkg -l "$PACKAGE_NAME" &>/dev/null; then + log "ERROR" "卸载失败,${PACKAGE_NAME}仍存在" + exit 1 + fi + + # 检查二进制是否残留 + if command -v containerd &>/dev/null; then + log "ERROR" "卸载失败,containerd二进制文件仍存在" + exit 1 + fi + + log "INFO" "卸载验证通过" +} + +####################################### +# 主流程 +####################################### +main() { + # 初始化日志 + > "$LOG_FILE" + log "INFO" "===== Containerd管理脚本启动 =====" + + # 解析参数 + parse_args "$@" + + # 通用前置检查 + pre_check + + # 分支流程:安装或卸载 + case "$ACTION" in + install) + configure_repo + verify_version + install_containerd + configure_containerd + start_service + verify_installation + ;; + uninstall) + uninstall_containerd + verify_uninstallation + ;; + esac + + log "INFO" "===== 操作完成 =====" + log "INFO" "日志路径:$LOG_FILE" +} + +# 启动主程序 +main "$@"