#!/bin/bash
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
BOLD='\033[1m'
CYAN='\033[0;36m'
PURPLE='\033[0;35m'
display_header() {
clear
echo -e "${BOLD}${CYAN}======================================${NC}"
echo -e "${BOLD}${CYAN}| Docker国内自适应安装工具 |${NC}"
echo -e "${BOLD}${CYAN}======================================${NC}"
echo -e "${BOLD}${YELLOW}版本: 2.3 | 国内镜像适配 | 严格版本安装${NC}"
echo ""
}
check_root() {
if [ $EUID -ne 0 ]; then
echo -e "${RED}请先切换到root用户:${NC}"
echo "1. 使用以下命令切换:"
echo " sudo -i"
echo "2. 输入root密码"
echo "3. 再次执行本脚本"
exit 1
fi
}
confirm() {
read -p "$1 [Y/N]: " yn
yn=${yn:-y}
case $yn in
[Yy]* ) return 0;;
* ) return 1;;
esac
}
wait_for_key_press() {
read -n 1 -s -r -p "按任意键继续..."
echo ""
}
log_message() {
local message="$1"
mkdir -p /var/log
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> /var/log/docker_install_adapt.log
}
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
VERSION=$VERSION_ID
echo -e "${GREEN}✓ 检测到系统: $NAME $VERSION ($ID)${NC}"
log_message "检测到系统: $NAME $VERSION ($ID)"
case $OS in
ubuntu|debian|centos|rhel|fedora|almalinux|rocky|arch|manjaro)
return 0
;;
*)
echo -e "${RED}✗ 不支持的系统: $OS${NC}"
log_message "不支持的系统: $OS"
return 1
;;
esac
else
echo -e "${RED}✗ 无法检测操作系统${NC}"
log_message "无法检测操作系统"
return 1
fi
}
check_network_and_select_mirror() {
echo -e "${PURPLE}检查网络连接并选择最快镜像源...${NC}"
local mirrors=(
"中科大:https://mirrors.ustc.edu.cn"
"阿里云:https://mirrors.aliyun.com"
"清华大学:https://mirrors.tuna.tsinghua.edu.cn"
"华为云:https://repo.huaweicloud.com"
)
local fastest_mirror=""
local fastest_name=""
local fastest_time=999999
local connected=false
echo -e "${CYAN}测试国内镜像源连接速度...${NC}"
echo -n "测试基本网络连接... "
if ping -c 2 www.baidu.com >/dev/null 2>&1; then
echo -e "${GREEN}正常${NC}"
else
echo -e "${YELLOW}警告:ping测试失败,但将继续尝试HTTP连接${NC}"
fi
for mirror_info in "${mirrors[@]}"; do
local name=$(echo "$mirror_info" | cut -d':' -f1)
local url=$(echo "$mirror_info" | cut -d':' -f2-)
echo -n "测试 $name ... "
local start_time=$(date +%s%N)
if curl --connect-timeout 5 -s --head --ipv4 "$url" >/dev/null 2>&1 || \
curl --connect-timeout 5 -s --head "$url" >/dev/null 2>&1 || \
wget --timeout=5 --spider "$url" >/dev/null 2>&1; then
local end_time=$(date +%s%N)
local time_ms=$(( (end_time - start_time) / 1000000 ))
echo -e "${GREEN}${time_ms}ms${NC}"
connected=true
if [ $time_ms -lt $fastest_time ]; then
fastest_time=$time_ms
fastest_mirror="$url"
fastest_name="$name"
fi
else
echo -e "${RED}超时${NC}"
fi
done
if [ "$connected" = false ]; then
echo -e "${RED}✗ 所有国内镜像源连接失败,请检查网络设置${NC}"
log_message "所有国内镜像源连接失败"
return 1
fi
echo -e "${GREEN}✓ 选择最快镜像源: $fastest_name${NC}"
echo -e "${CYAN}镜像源地址: $fastest_mirror${NC}"
DOCKER_MIRROR="$fastest_mirror"
DOCKER_MIRROR_NAME="$fastest_name"
log_message "选择镜像源: $fastest_name ($fastest_mirror)"
return 0
}
get_architecture() {
local arch=$(uname -m)
case $arch in
x86_64|amd64)
echo "amd64"
;;
aarch64|arm64)
echo "arm64"
;;
armv7l|armhf)
echo "armhf"
;;
*)
echo "$arch"
;;
esac
}
clean_old_docker() {
echo -e "${PURPLE}清理旧版本Docker...${NC}"
log_message "开始清理旧版本Docker"
case $OS in
ubuntu|debian)
apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
rm -rf /var/lib/docker /var/lib/containerd /etc/docker 2>/dev/null || true
rm -f /etc/apt/sources.list.d/docker.list 2>/dev/null || true
rm -f /usr/share/keyrings/docker-archive-keyring.gpg 2>/dev/null || true
;;
centos|rhel|almalinux|rocky)
yum remove -y docker docker-client docker-client-latest docker-common \
docker-latest docker-latest-logrotate docker-logrotate docker-engine 2>/dev/null || true
rm -rf /var/lib/docker /var/lib/containerd /etc/docker 2>/dev/null || true
rm -f /etc/yum.repos.d/docker-ce.repo 2>/dev/null || true
;;
fedora)
dnf remove -y docker docker-client docker-client-latest docker-common \
docker-latest docker-latest-logrotate docker-logrotate docker-engine 2>/dev/null || true
rm -rf /var/lib/docker /var/lib/containerd /etc/docker 2>/dev/null || true
rm -f /etc/yum.repos.d/docker-ce.repo 2>/dev/null || true
;;
arch|manjaro)
pacman -Rns docker docker-compose --noconfirm 2>/dev/null || true
rm -rf /var/lib/docker /var/lib/containerd /etc/docker 2>/dev/null || true
;;
esac
echo -e "${GREEN}✓ 旧版本清理完成${NC}"
log_message "旧版本Docker清理完成"
}
install_dependencies() {
echo -e "${PURPLE}安装系统依赖包...${NC}"
log_message "开始安装系统依赖包"
case $OS in
ubuntu|debian)
if ! command -v apt-get >/dev/null; then
echo -e "${RED}✗ apt-get 命令不可用${NC}"
log_message "apt-get 命令不可用"
return 1
fi
apt-get update -y || {
echo -e "${YELLOW}⚠ apt-get update 失败,尝试使用中科大源更新${NC}"
echo "deb http://mirrors.ustc.edu.cn/debian/ $VERSION main contrib non-free non-free-firmware" > /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/debian/ $VERSION-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/debian-security/ $VERSION-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list
apt-get update -y || {
echo -e "${RED}✗ 无法更新软件包列表${NC}"
log_message "无法更新软件包列表"
return 1
}
}
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
;;
centos|rhel|almalinux|rocky)
yum install -y yum-utils device-mapper-persistent-data lvm2
;;
fedora)
dnf install -y dnf-plugins-core
;;
arch|manjaro)
pacman -Sy --noconfirm curl wget
;;
esac
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 依赖包安装完成${NC}"
log_message "系统依赖包安装完成"
return 0
else
echo -e "${RED}✗ 依赖包安装失败${NC}"
log_message "系统依赖包安装失败"
return 1
fi
}
add_docker_gpg_key() {
echo -e "${PURPLE}添加Docker GPG密钥...${NC}"
log_message "开始添加Docker GPG密钥"
mkdir -p /etc/apt/keyrings /usr/share/keyrings
local key_added=false
local key_urls=()
if [[ "$DOCKER_MIRROR" == *"ustc"* ]]; then
key_urls+=("https://mirrors.ustc.edu.cn/docker-ce/linux/$OS/gpg")
elif [[ "$DOCKER_MIRROR" == *"aliyun"* ]]; then
key_urls+=("https://mirrors.aliyun.com/docker-ce/linux/$OS/gpg")
elif [[ "$DOCKER_MIRROR" == *"tuna"* ]]; then
key_urls+=("https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/$OS/gpg")
elif [[ "$DOCKER_MIRROR" == *"huaweicloud"* ]]; then
key_urls+=("https://repo.huaweicloud.com/docker-ce/linux/$OS/gpg")
fi
key_urls+=("https://mirrors.ustc.edu.cn/docker-ce/linux/$OS/gpg")
key_urls+=("https://mirrors.aliyun.com/docker-ce/linux/$OS/gpg")
key_urls+=("https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/$OS/gpg")
key_urls+=("https://repo.huaweicloud.com/docker-ce/linux/$OS/gpg")
for key_url in "${key_urls[@]}"; do
echo -n "尝试从 $key_url 添加密钥... "
if curl -fsSL "$key_url" | gpg --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 2>/dev/null; then
echo -e "${GREEN}成功${NC}"
key_added=true
break
else
echo -e "${YELLOW}失败${NC}"
fi
done
if [ "$key_added" = false ]; then
echo -e "${RED}✗ 无法添加Docker GPG密钥${NC}"
log_message "无法添加Docker GPG密钥"
return 1
fi
echo -e "${GREEN}✓ Docker GPG密钥添加成功${NC}"
log_message "Docker GPG密钥添加成功"
return 0
}
add_docker_repo() {
echo -e "${PURPLE}添加Docker仓库...${NC}"
log_message "开始添加Docker仓库"
case $OS in
ubuntu|debian)
local arch=$(get_architecture)
local codename=$(lsb_release -cs 2>/dev/null || echo "$VERSION")
if [ "$OS" = "debian" ]; then
case $VERSION in
12)
codename="bookworm"
;;
13)
codename="trixie"
;;
esac
fi
local repo_url="$DOCKER_MIRROR/docker-ce/linux/$OS"
echo "deb [arch=$arch signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] $repo_url $codename stable" \
> /etc/apt/sources.list.d/docker.list
if ! apt-get update -y; then
echo -e "${RED}✗ 无法更新Docker仓库,请检查网络连接或尝试其他镜像源${NC}"
log_message "无法更新Docker仓库"
return 1
fi
;;
centos|rhel|almalinux|rocky)
local repo_url="$DOCKER_MIRROR/docker-ce/linux/centos/docker-ce.repo"
yum-config-manager --add-repo $repo_url
;;
fedora)
local repo_url="$DOCKER_MIRROR/docker-ce/linux/fedora/docker-ce.repo"
dnf config-manager --add-repo $repo_url
;;
arch|manjaro)
echo -e "${GREEN}✓ Arch Linux使用官方仓库${NC}"
return 0
;;
esac
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Docker仓库添加成功 (使用: $DOCKER_MIRROR_NAME)${NC}"
log_message "Docker仓库添加成功 (使用: $DOCKER_MIRROR_NAME)"
return 0
else
echo -e "${RED}✗ Docker仓库添加失败${NC}"
log_message "Docker仓库添加失败"
return 1
fi
}
install_docker_engine() {
echo -e "${PURPLE}安装Docker引擎...${NC}"
log_message "开始安装Docker引擎"
case $OS in
ubuntu|debian)
if apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin; then
echo -e "${GREEN}✓ Docker引擎安装成功${NC}"
log_message "Docker引擎安装成功"
return 0
else
echo -e "${RED}✗ Docker引擎安装失败,请检查网络连接或尝试其他镜像源${NC}"
log_message "Docker引擎安装失败"
return 1
fi
;;
centos|rhel|almalinux|rocky)
yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
fedora)
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
arch|manjaro)
pacman -S docker docker-compose --noconfirm
;;
esac
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Docker引擎安装成功${NC}"
log_message "Docker引擎安装成功"
return 0
else
echo -e "${RED}✗ Docker引擎安装失败${NC}"
log_message "Docker引擎安装失败"
return 1
fi
}
configure_docker_mirror() {
echo -e "${PURPLE}配置Docker镜像加速器...${NC}"
log_message "开始配置Docker镜像加速器"
local daemon_file="/etc/docker/daemon.json"
mkdir -p /etc/docker
cat > "$daemon_file" << EOF
{
"registry-mirrors": [
"https://bf47d92356c24b9aa8d3e9b16b5d5887.mirror.swr.myhuaweicloud.com"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
},
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef:c0::/80",
"experimental":true,
"ip6tables":true
}
EOF
systemctl daemon-reload 2>/dev/null || true
systemctl restart docker 2>/dev/null || service docker restart 2>/dev/null
echo -e "${GREEN}✓ Docker镜像加速器配置完成${NC}"
log_message "Docker镜像加速器配置完成,使用国内镜像"
}
start_docker_service() {
echo -e "${PURPLE}启动Docker服务...${NC}"
log_message "启动Docker服务"
systemctl start docker 2>/dev/null || service docker start 2>/dev/null
systemctl enable docker 2>/dev/null || chkconfig docker on 2>/dev/null
sleep 3
if systemctl is-active --quiet docker 2>/dev/null || service docker status >/dev/null 2>&1; then
echo -e "${GREEN}✓ Docker服务启动成功${NC}"
log_message "Docker服务启动成功"
echo -e "${CYAN}\nDocker版本信息:${NC}"
docker --version
docker compose version 2>/dev/null || docker-compose --version 2>/dev/null || echo "docker-compose: 未安装"
return 0
else
echo -e "${RED}✗ Docker服务启动失败${NC}"
log_message "Docker服务启动失败"
return 1
fi
}
add_user_to_docker_group() {
local current_user=$(who | awk '{print $1}' | head -1)
if [ -z "$current_user" ]; then
current_user=$(whoami)
fi
if [ "$current_user" != "root" ]; then
if confirm "是否将用户 '$current_user' 添加到docker组?(避免每次使用sudo)"; then
if getent group docker >/dev/null; then
usermod -aG docker "$current_user"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 用户 $current_user 已添加到docker组${NC}"
echo -e "${YELLOW}⚠ 需要重新登录或执行 'newgrp docker' 使更改生效${NC}"
log_message "用户 $current_user 已添加到docker组"
else
echo -e "${RED}✗ 添加用户到docker组失败${NC}"
log_message "添加用户到docker组失败"
fi
else
echo -e "${RED}✗ docker组不存在,请先安装Docker${NC}"
fi
fi
else
echo -e "${YELLOW}当前为root用户,无需添加到docker组${NC}"
fi
}
show_installation_summary() {
echo -e "${CYAN}\n=== 安装总结 ===${NC}"
echo -e "${GREEN}✓ Docker安装完成!${NC}"
echo ""
echo -e "${PURPLE}已安装组件:${NC}"
echo " • Docker引擎"
echo " • Docker CLI"
echo " • Containerd"
echo " • Docker Compose插件"
echo ""
echo -e "${PURPLE}服务状态:${NC}"
systemctl status docker --no-pager -l 2>/dev/null | head -10 || \
service docker status 2>/dev/null | head -10 || \
echo " 服务状态无法获取"
echo ""
echo -e "${PURPLE}常用命令:${NC}"
echo " docker version # 查看Docker版本"
echo " docker info # 查看Docker信息"
echo " docker ps # 查看运行中的容器"
echo " docker ps -a # 查看所有容器"
echo " docker images # 查看镜像"
echo " docker run hello-world # 运行测试容器"
echo " docker-compose version # 查看Docker Compose版本"
echo ""
echo -e "${PURPLE}镜像加速器:${NC}"
if [ -f "/etc/docker/daemon.json" ]; then
grep -A5 "registry-mirrors" /etc/docker/daemon.json || echo " 使用默认配置"
else
echo " 使用默认配置"
fi
echo ""
echo -e "${YELLOW}注意:如果当前用户已添加到docker组,需要重新登录生效${NC}"
}
uninstall_docker() {
echo -e "${CYAN}\n=== 卸载Docker ===${NC}"
log_message "开始卸载Docker"
if ! confirm "确定要卸载Docker吗?此操作将删除所有容器和镜像"; then
echo -e "${YELLOW}已取消卸载${NC}"
log_message "取消卸载Docker"
wait_for_key_press
return 0
fi
echo -e "${PURPLE}停止Docker服务...${NC}"
systemctl stop docker 2>/dev/null || service docker stop 2>/dev/null
systemctl disable docker 2>/dev/null || chkconfig docker off 2>/dev/null
echo -e "${PURPLE}卸载Docker包...${NC}"
case $OS in
ubuntu|debian)
apt-get purge -y docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-ce-rootless-extras
apt-get autoremove -y
;;
centos|rhel|almalinux|rocky)
yum remove -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
fedora)
dnf remove -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
arch|manjaro)
pacman -Rns docker docker-compose --noconfirm
;;
esac
echo -e "${PURPLE}删除Docker数据...${NC}"
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
rm -f /etc/docker/daemon.json
rm -f /usr/share/keyrings/docker-archive-keyring.gpg
rm -f /etc/apt/sources.list.d/docker.list 2>/dev/null
rm -f /etc/yum.repos.d/docker-ce.repo 2>/dev/null
case $OS in
ubuntu|debian)
apt-get update
;;
esac
echo -e "${GREEN}✓ Docker卸载完成${NC}"
log_message "Docker卸载完成"
wait_for_key_press
}
check_docker_status() {
echo -e "${CYAN}\n=== Docker状态检查 ===${NC}"
if command -v docker >/dev/null; then
echo -e "${GREEN}✓ Docker已安装${NC}"
docker --version
echo -e "${CYAN}\n服务状态:${NC}"
systemctl status docker --no-pager -l 2>/dev/null | head -15 || \
service docker status 2>/dev/null | head -15 || \
echo " 无法获取服务状态"
echo -e "${CYAN}\n运行中的容器:${NC}"
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || \
echo " 没有运行中的容器或Docker服务未运行"
echo -e "${CYAN}\n所有镜像:${NC}"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}" 2>/dev/null | head -10 || \
echo " 无法获取镜像列表"
echo -e "${CYAN}\n系统信息:${NC}"
docker info 2>/dev/null | grep -E "(Server Version|Containers|Images|Docker Root Dir|Registry Mirrors)" || \
echo " 无法获取Docker信息"
else
echo -e "${RED}✗ Docker未安装${NC}"
fi
wait_for_key_press
}
test_network_connection() {
echo -e "${CYAN}\n=== 网络连接测试 ===${NC}"
local test_urls=("中科大镜像站 https://mirrors.ustc.edu.cn" "阿里云镜像站 https://mirrors.aliyun.com" "清华大学镜像站 https://mirrors.tuna.tsinghua.edu.cn" "华为云镜像站 https://repo.huaweicloud.com")
for url_info in "${test_urls[@]}"; do
local name=$(echo "$url_info" | awk '{print $1}')
local url=$(echo "$url_info" | awk '{print $2}')
echo -n "测试 $name ... "
if curl --connect-timeout 5 -s --head "$url" >/dev/null 2>&1; then
echo -e "${GREEN}✓ 可用${NC}"
else
echo -e "${RED}✗ 不可用${NC}"
fi
done
wait_for_key_press
}
install_docker() {
echo -e "${CYAN}\n=== 开始安装Docker ===${NC}"
log_message "开始安装Docker"
if ! check_network_and_select_mirror; then
echo -e "${RED}安装中止:网络连接不可用${NC}"
log_message "安装中止:网络连接不可用"
wait_for_key_press
return 1
fi
clean_old_docker
if ! install_dependencies; then
echo -e "${RED}安装中止:依赖包安装失败${NC}"
log_message "安装中止:依赖包安装失败"
wait_for_key_press
return 1
fi
if ! add_docker_gpg_key; then
echo -e "${RED}安装中止:GPG密钥添加失败${NC}"
log_message "安装中止:GPG密钥添加失败"
wait_for_key_press
return 1
fi
if ! add_docker_repo; then
echo -e "${RED}安装中止:仓库添加失败${NC}"
log_message "安装中止:仓库添加失败"
wait_for_key_press
return 1
fi
if ! install_docker_engine; then
echo -e "${RED}安装中止:Docker引擎安装失败${NC}"
log_message "安装中止:Docker引擎安装失败"
wait_for_key_press
return 1
fi
configure_docker_mirror
if ! start_docker_service; then
echo -e "${RED}安装中止:Docker服务启动失败${NC}"
log_message "安装中止:Docker服务启动失败"
wait_for_key_press
return 1
fi
add_user_to_docker_group
show_installation_summary
log_message "Docker安装完成"
wait_for_key_press
return 0
}
main() {
check_root
mkdir -p /var/log
display_header
if ! detect_os; then
echo -e "${RED}脚本中止:不支持的操作系统${NC}"
exit 1
fi
while true; do
display_header
echo -e "${PURPLE}当前系统: $OS $VERSION${NC}"
echo -e "${PURPLE}系统架构: $(get_architecture)${NC}"
echo ""
echo -e "\n${GREEN}请选择要执行的操作:${NC}"
echo -e " ${GREEN}1)${NC} 安装Docker"
echo -e " ${GREEN}2)${NC} 卸载Docker"
echo -e " ${GREEN}3)${NC} 检查Docker状态"
echo -e " ${GREEN}4)${NC} 使用代理加速"
echo -e " ${GREEN}5)${NC} 测试网络连接"
echo -e " ${GREEN}6)${NC} 显示系统信息"
echo -e " ${GREEN}0)${NC} 退出"
read -p "请输入数字选择 [0-6]: " choice
case $choice in
1)
install_docker
;;
2)
uninstall_docker
;;
3)
check_docker_status
;;
4)
echo -e "${CYAN}\n=== 使用代理加速 ===${NC}"
echo -e "正在安装Docker加速脚本..."
bash -c "mkdir -p /etc/docker && curl -o /etc/docker/docker_pull_wrapper.sh https://gitee.com/qs0010/docker-acceleration-script/raw/master/docker_pull_wrapper.sh && chmod +x /etc/docker/docker_pull_wrapper.sh && echo -e '\nalias docker=/etc/docker/docker_pull_wrapper.sh' >> ~/.bashrc" && source ~/.bashrc
echo -e "${GREEN}✓ Docker加速脚本安装成功!${NC}"
echo -e "${YELLOW}现在可以直接使用 'docker pull' 命令享受加速服务${NC}"
wait_for_key_press
;;
5)
test_network_connection
;;
6)
echo -e "${CYAN}\n=== 系统信息 ===${NC}"
echo "操作系统: $OS $VERSION"
echo "系统架构: $(get_architecture)"
echo "内核版本: $(uname -r)"
echo "主机名: $(hostname)"
echo "内存: $(free -h | awk '/^Mem:/ {print $2}')"
echo "磁盘: $(df -h / | awk 'NR==2 {print $4}') 可用"
wait_for_key_press
;;
0)
echo -e "${GREEN}\n=== 脚本执行完成 ===${NC}"
echo -e "${GREEN}操作日志: /var/log/docker_install_adapt.log${NC}"
log_message "脚本执行完成"
exit 0
;;
*)
echo -e "${RED}无效选择,请重新输入${NC}"
sleep 1
;;
esac
done
}
main