添加 scripts/containerd.sh

This commit is contained in:
joy 2025-10-29 12:47:17 +08:00
parent 3bebc27ff2
commit 86c3a3081f
1 changed files with 392 additions and 0 deletions

392
scripts/containerd.sh Normal file
View File

@ -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
# 启用SystemdCgroupKubernetes必需
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 "$@"