ansible-devops/scripts/containerd.sh

393 lines
12 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 "$@"