From 49d5233a32c614b011474d7fb2ce32ffaecd65a9 Mon Sep 17 00:00:00 2001 From: joy Date: Thu, 30 Oct 2025 12:37:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20scripts/containerd.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aaa --- scripts/containerd.sh | 330 +++++++++++++++--------------------------- 1 file changed, 113 insertions(+), 217 deletions(-) diff --git a/scripts/containerd.sh b/scripts/containerd.sh index 52df2f1..d15adb7 100644 --- a/scripts/containerd.sh +++ b/scripts/containerd.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -# Containerd apt安装/卸载脚本(Ubuntu专用). -# 支持:安装指定版本、完整卸载、重复执行 +# Containerd安装脚本(Ubuntu专用) +# 集成配置:默认配置生成、镜像源替换、Cgroup驱动、镜像加速 # 适用:Ubuntu 20.04/22.04/24.04 LTS ####################################### @@ -11,15 +11,17 @@ set -euo pipefail DEFAULT_VERSION="1.7.28-1" ACTION="" CONTAINERD_VERSION="$DEFAULT_VERSION" -LOG_FILE="/var/log/containerd_apt_manage.log" +LOG_FILE="/var/log/containerd_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" +CERTS_D_PATH="/etc/containerd/certs.d" +DOCKER_IO_HOSTS="${CERTS_D_PATH}/docker.io/hosts.toml" ####################################### -# 日志函数(标准化输出) +# 日志函数 ####################################### log() { local level=$1 @@ -36,7 +38,7 @@ usage() { echo "Options:" echo " --install 安装containerd(必填)" echo " --uninstall 卸载containerd(必填)" - echo " --version VERSION 指定安装版本(格式:x.y.z-1,默认:$DEFAULT_VERSION)" + echo " --version VERSION 指定版本(如1.7.28-1,默认:$DEFAULT_VERSION)" echo " --help 显示帮助" exit 1 } @@ -48,26 +50,17 @@ parse_args() { while [[ $# -gt 0 ]]; do case "$1" in --install) - if [[ "$ACTION" == "uninstall" ]]; then - log "ERROR" "--install与--uninstall不可同时使用" - usage - fi + if [[ "$ACTION" == "uninstall" ]]; then log "ERROR" "参数冲突"; usage; fi ACTION="install" shift ;; --uninstall) - if [[ "$ACTION" == "install" ]]; then - log "ERROR" "--install与--uninstall不可同时使用" - usage - fi + if [[ "$ACTION" == "install" ]]; then log "ERROR" "参数冲突"; usage; fi ACTION="uninstall" shift ;; --version) - if [[ $# -lt 2 || "$2" == -* ]]; then - log "ERROR" "--version需要指定有效版本号(如1.7.28-1)" - usage - fi + if [[ $# -lt 2 || "$2" == -* ]]; then log "ERROR" "需指定版本"; usage; fi CONTAINERD_VERSION="$2" shift 2 ;; @@ -80,45 +73,21 @@ parse_args() { ;; 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 + if [[ -z "$ACTION" ]]; then log "ERROR" "需指定--install或--uninstall"; usage; 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 - - # 检查系统版本 + log "INFO" "前置环境检查" + if [[ "$(id -u)" -ne 0 ]]; then log "ERROR" "需root权限"; exit 1; fi + 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" + log "ERROR" "仅支持Ubuntu 20.04/22.04/24.04" 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 @@ -127,65 +96,43 @@ pre_check() { apt-get install -qq -y "$tool" >/dev/null fi done - log "INFO" "前置检查通过" } ####################################### -# 配置Docker源(仅安装时使用) +# 配置Docker源 ####################################### configure_repo() { - log "INFO" "配置Docker apt源" - + log "INFO" "配置Docker源" 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" + curl -fsSL --retry 3 --retry-delay 5 "${DOCKER_REPO}/gpg" | gpg --dearmor -o "$GPG_KEY_PATH" >/dev/null 2>&1 || { + log "ERROR" "GPG密钥下载失败" exit 1 - fi + } chmod a+r "$GPG_KEY_PATH" - else - log "INFO" "Docker GPG密钥已存在,跳过下载" fi - - # 配置源(幂等处理) local codename=$(lsb_release -cs) + if [[ "$codename" == "noble" ]]; then codename="jammy"; fi # 兼容24.04 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源配置" + if [[ ! -f "$REPO_LIST_PATH" || "$(cat "$REPO_LIST_PATH")" != "$repo_content" ]]; then echo "$repo_content" | tee "$REPO_LIST_PATH" >/dev/null apt-get update -qq >/dev/null fi - - log "INFO" "Docker apt源配置完成" + log "INFO" "Docker源配置完成" } ####################################### -# 验证版本可用性(仅安装时使用) +# 验证版本可用性 ####################################### 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) - + local available_versions=$(apt-cache madison "$PACKAGE_NAME" | awk '{print $3}' | sed 's/~ubuntu.*//' | sort -u) if ! echo "$available_versions" | grep -qxF "$CONTAINERD_VERSION"; then - log "ERROR" "版本${CONTAINERD_VERSION}不可用,可用版本如下:" - echo "$available_versions" | tee -a "$LOG_FILE" + log "ERROR" "版本不可用,可用版本:$available_versions" exit 1 fi - log "INFO" "版本验证通过" } @@ -193,200 +140,149 @@ verify_version() { # 安装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 + log "INFO" "安装containerd" + local full_version=$(apt-cache madison "$PACKAGE_NAME" | grep "$CONTAINERD_VERSION" | awk '{print $3}' | head -n 1) + if [[ -z "$full_version" ]]; then log "ERROR" "未找到完整版本"; exit 1; fi + if dpkg -l "$PACKAGE_NAME" &>/dev/null && [[ "$(dpkg -l "$PACKAGE_NAME" | awk '/ii/ {print $3}')" == "$full_version" ]]; then + log "INFO" "已安装$full_version,跳过" + return 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}安装完成" + log "INFO" "安装$full_version" + apt-get install -qq -y "${PACKAGE_NAME}=${full_version}" >/dev/null 2>&1 || { + log "ERROR" "安装失败,手动执行:sudo apt-get install -y ${PACKAGE_NAME}=${full_version}" + exit 1 + } } ####################################### -# 配置containerd(仅安装时使用) +# 核心配置(严格按你的要求执行) ####################################### configure_containerd() { - log "INFO" "配置containerd" + log "INFO" "开始配置containerd" - # 生成默认配置(幂等处理) - if [[ ! -f "$CONFIG_PATH" ]]; then - log "INFO" "生成默认配置文件" - containerd config default | tee "$CONFIG_PATH" >/dev/null 2>&1 + # 1. 生成默认配置文件 + log "INFO" "生成默认配置文件" + containerd config default > "$CONFIG_PATH" 2>/dev/null || { + log "ERROR" "生成默认配置失败" + exit 1 + } + + # 2. 替换镜像源(registry.k8s.io -> 华为云) + log "INFO" "替换镜像源为华为云" + sed -i 's#registry.k8s.io#swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io#' "$CONFIG_PATH" || { + log "ERROR" "镜像源替换失败" + exit 1 + } + + # 3. 配置Cgroup驱动器(SystemdCgroup = true) + log "INFO" "配置Cgroup驱动器" + sed -i 's/SystemdCgroup\ =\ false/SystemdCgroup\ =\ true/g' "$CONFIG_PATH" || { + log "ERROR" "Cgroup配置失败" + exit 1 + } + + # 4. 配置镜像加速 + log "INFO" "配置镜像加速" + # 4.1 设置registry.config_path + local registry_block="[plugins.\"io.containerd.grpc.v1.cri\".registry]" + local config_path_line=' config_path = "/etc/containerd/certs.d"' + if ! grep -qxF "$config_path_line" "$CONFIG_PATH"; then + if ! grep -qxF "$registry_block" "$CONFIG_PATH"; then + echo -e "\n$registry_block" >> "$CONFIG_PATH" + fi + sed -i "/$registry_block/a $config_path_line" "$CONFIG_PATH" 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 + # 4.2 创建目录并写入加速配置 + mkdir -p "$(dirname "$DOCKER_IO_HOSTS")" + local hosts_content=$(cat << EOF +server = "https://docker.io" +[host."https://o2j0mc5x.mirror.aliyuncs.com"] + capabilities = ["pull", "resolve"] +server = "https://k8s.gcr.io" +[host."https://gcr.mirrors.ustc.edu.cn/google-containers/"] + capabilities = ["pull", "resolve"] +server = "https://quay.io" +[host."https://mirror.ccs.tencentyun.com"] + capabilities = ["pull", "resolve"] +EOF + ) + echo "$hosts_content" | tee "$DOCKER_IO_HOSTS" >/dev/null - # 重启服务应用配置 + # 重启服务 systemctl restart containerd >/dev/null 2>&1 - - log "INFO" "containerd配置完成" + log "INFO" "配置完成,已重启服务" } ####################################### -# 启动服务(仅安装时使用) +# 启动服务并设置开机启动 ####################################### 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" "服务配置完成" + log "INFO" "设置开机自启并启动服务" + systemctl enable --now containerd >/dev/null 2>&1 || { + log "ERROR" "服务启动失败" + exit 1 + } } ####################################### -# 验证安装结果 +# 验证安装 ####################################### verify_installation() { log "INFO" "验证安装结果" - - # 检查服务状态 - if ! systemctl is-active --quiet containerd; then - log "ERROR" "containerd服务未运行" - exit 1 + if ! systemctl is-active --quiet containerd; then log "ERROR" "服务未运行"; exit 1; fi + if ! grep -q "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io" "$CONFIG_PATH"; then + log "WARNING" "镜像源替换未生效" 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 + if ! grep -q "SystemdCgroup \= true" "$CONFIG_PATH"; then + log "WARNING" "Cgroup配置未生效" fi - - log "INFO" "安装验证通过,当前版本:${installed_version}" + if [[ ! -f "$DOCKER_IO_HOSTS" ]]; then + log "WARNING" "镜像加速配置不存在" + fi + log "INFO" "验证完成" } ####################################### -# 卸载containerd(新增功能) +# 卸载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 - - # 卸载包(彻底清除配置) + log "INFO" "卸载containerd" + systemctl stop containerd >/dev/null 2>&1 || true 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}未安装,跳过卸载" + apt-get autoremove -qq -y >/dev/null 2>&1 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 + rm -rf "$CONFIG_PATH" "$CERTS_D_PATH" /var/lib/containerd /var/log/containerd 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" "卸载验证通过" + log "INFO" "卸载完成" } ####################################### # 主流程 ####################################### main() { - # 初始化日志 > "$LOG_FILE" - log "INFO" "===== Containerd管理脚本启动 =====" - - # 解析参数 + log "INFO" "===== 脚本启动 =====" parse_args "$@" - - # 通用前置检查 pre_check - # 分支流程:安装或卸载 case "$ACTION" in install) configure_repo verify_version install_containerd - configure_containerd + configure_containerd # 执行你的所有配置步骤 start_service verify_installation ;; uninstall) uninstall_containerd - verify_uninstallation ;; esac log "INFO" "===== 操作完成 =====" - log "INFO" "日志路径:$LOG_FILE" + log "INFO" "日志:$LOG_FILE" } -# 启动主程序 main "$@"