1. 安装脚本:
#!/usr/bin/env bash
#
# Docker 安装脚本(Ubuntu)
#
# 功能:
# - 安装 docker-ce / docker-ce-cli / containerd.io
# - 安装 docker-buildx-plugin / docker-compose-plugin
# - 可选按官方方式卸载旧 Docker 相关包
# - 可选使用国内 APT 源安装 Docker
# - 可选配置 Docker registry 国内镜像加速
# - 可选配置容器日志轮转限制
# - 可选自动检测网络环境
#
# 支持:
# - Ubuntu 20.04 / 22.04 / 24.04
#
# 用法示例:
# sudo bash install_docker.sh
# sudo bash install_docker.sh -u
# sudo bash install_docker.sh -m -r -c
# sudo bash install_docker.sh -a -c
if [ -z "${BASH_VERSION:-}" ]; then
echo "Please run this script with bash"
exit 1
fi
set -Eeuo pipefail
#==============================
# 默认参数
#==============================
UNINSTALL=0
USE_CN_SOURCE=0
ENABLE_LOG_LIMIT=0
ENABLE_REGISTRY_MIRROR=0
AUTO_DETECT=0
NEED_RELOGIN=0
#==============================
# 日志函数
#==============================
log() { echo -e "[INFO] $*"; }
warn() { echo -e "[WARN] $*"; }
error() { echo -e "[ERROR] $*" >&2; }
ok() { echo -e "[ OK ] $*"; }
#==============================
# 帮助信息
#==============================
show_help() {
cat <<'EOF'
Docker 安装脚本(Ubuntu)
用法:
install_docker.sh [options]
选项:
-u 按官方方式卸载旧 Docker 相关包后再安装
-m 使用国内 Docker APT 源安装(清华源)
-r 配置 Docker registry 国内镜像加速
-c 配置容器日志限制
-a 自动检测网络环境(国内则自动启用 -m 和 -r)
-h 显示帮助信息
说明:
- 不加 -m 时,默认使用 Docker 官方 APT 源
- 不加 -r 时,不配置 registry mirror
- -c 会配置 json-file 日志轮转:
max-size=20m
max-file=3
- 若 /etc/docker/daemon.json 已存在,会先自动备份再覆盖
- 本脚本不会自动删除 /var/lib/docker 和 /var/lib/containerd
示例:
sudo bash install_docker.sh
sudo bash install_docker.sh -u
sudo bash install_docker.sh -m -r
sudo bash install_docker.sh -a -c
sudo bash install_docker.sh -u -a -c
EOF
}
#==============================
# 错误处理
#==============================
on_error() {
local exit_code=$?
error "脚本执行失败,退出码:${exit_code}"
exit "${exit_code}"
}
trap on_error ERR
#==============================
# 权限检查
#==============================
check_root() {
if [ "$(id -u)" -ne 0 ]; then
error "请使用 root 或 sudo 运行本脚本。"
exit 1
fi
}
#==============================
# 系统检查
#==============================
detect_os() {
if [ ! -f /etc/os-release ]; then
error "无法检测系统版本:缺少 /etc/os-release"
exit 1
fi
# shellcheck disable=SC1091
. /etc/os-release
if [ "${ID:-}" != "ubuntu" ]; then
error "当前系统不是 Ubuntu(检测到 ID=${ID:-unknown}),本脚本仅支持 Ubuntu。"
exit 1
fi
CODENAME="${VERSION_CODENAME:-}"
if [ -z "$CODENAME" ]; then
case "${VERSION_ID:-}" in
"24.04") CODENAME="noble" ;;
"22.04") CODENAME="jammy" ;;
"20.04") CODENAME="focal" ;;
*)
error "无法自动识别当前 Ubuntu 代号(VERSION_ID=${VERSION_ID:-unknown})"
exit 1
;;
esac
fi
ARCH="$(dpkg --print-architecture)"
ok "检测到系统:Ubuntu ${VERSION_ID:-unknown} (${CODENAME}), arch=${ARCH}"
}
#==============================
# 参数解析
#==============================
parse_args() {
while getopts ":umrcah" opt; do
case "${opt}" in
u) UNINSTALL=1 ;;
m) USE_CN_SOURCE=1 ;;
r) ENABLE_REGISTRY_MIRROR=1 ;;
c) ENABLE_LOG_LIMIT=1 ;;
a) AUTO_DETECT=1 ;;
h)
show_help
exit 0
;;
:)
error "选项 -${OPTARG} 缺少参数"
exit 1
;;
\?)
error "未知选项: -${OPTARG}"
show_help
exit 1
;;
esac
done
}
#==============================
# 自动检测国内网络
#==============================
detect_china_network() {
local country=""
country="$(curl -fsSL --connect-timeout 3 --max-time 5 https://ipinfo.io/country 2>/dev/null | tr -d '[:space:]' || true)"
if [ "$country" = "CN" ]; then
return 0
elif [ -n "$country" ]; then
return 1
fi
country="$(curl -fsSL --connect-timeout 3 --max-time 5 https://ifconfig.co/country-iso 2>/dev/null | tr -d '[:space:]' || true)"
if [ "$country" = "CN" ]; then
return 0
elif [ -n "$country" ]; then
return 1
fi
if ! curl -fsSL --connect-timeout 3 --max-time 5 https://registry-1.docker.io/v2/ >/dev/null 2>&1; then
warn "地区判断失败,且 Docker Hub 连通性较差,按中国网络环境处理"
return 0
fi
return 1
}
apply_auto_detect() {
if [ "$AUTO_DETECT" -ne 1 ]; then
return
fi
log "开始自动检测网络环境..."
if detect_china_network; then
ok "检测结果:更像中国网络环境,自动启用国内 APT 源和 registry 镜像加速"
USE_CN_SOURCE=1
ENABLE_REGISTRY_MIRROR=1
else
ok "检测结果:更像海外网络环境,默认使用官方 APT 源,不启用 registry 镜像加速"
fi
}
#==============================
# 安装基础依赖
#==============================
install_dependencies() {
log "安装必要依赖..."
apt update
apt install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
ok "基础依赖安装完成"
}
#==============================
# 卸载旧 Docker(官方方式)
#==============================
uninstall_old_docker() {
log "按官方方式卸载旧 Docker 相关包..."
systemctl stop docker 2>/dev/null || true
systemctl stop docker.socket 2>/dev/null || true
systemctl stop containerd 2>/dev/null || true
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
apt remove -y "$pkg" || true
done
apt autoremove -y || true
rm -f /etc/apt/sources.list.d/docker.list
rm -f /etc/apt/keyrings/docker.gpg
rm -f /etc/apt/keyrings/docker.asc
warn "未自动删除 /var/lib/docker 和 /var/lib/containerd,避免误删现有镜像/容器数据"
warn "如需彻底清理,可手动执行:rm -rf /var/lib/docker /var/lib/containerd"
ok "旧 Docker 相关包清理完成"
}
#==============================
# 配置 Docker APT 源
#==============================
configure_docker_repo() {
log "配置 Docker APT 源..."
rm -f /etc/apt/sources.list.d/docker.list
rm -f /etc/apt/keyrings/docker.gpg
if [ "$USE_CN_SOURCE" -eq 1 ]; then
log "使用清华 Docker CE APT 源"
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
cat >/etc/apt/sources.list.d/docker.list <<EOF
deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu ${CODENAME} stable
EOF
else
log "使用 Docker 官方 APT 源"
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
cat >/etc/apt/sources.list.d/docker.list <<EOF
deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${CODENAME} stable
EOF
fi
chmod a+r /etc/apt/keyrings/docker.gpg
apt update
ok "Docker APT 源配置完成"
}
#==============================
# 安装 Docker
#==============================
install_docker() {
log "安装 Docker Engine / CLI / containerd / Buildx / Compose..."
apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
ok "Docker 安装完成"
}
#==============================
# 备份 daemon.json
#==============================
backup_daemon_json_if_exists() {
if [ -f /etc/docker/daemon.json ]; then
local backup_file="/etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S)"
cp -f /etc/docker/daemon.json "$backup_file"
warn "检测到已有 /etc/docker/daemon.json,已备份到:$backup_file"
fi
}
#==============================
# 写入 daemon.json
#==============================
write_daemon_json() {
mkdir -p /etc/docker
backup_daemon_json_if_exists
local need_comma=0
{
echo "{"
if [ "$ENABLE_LOG_LIMIT" -eq 1 ]; then
echo ' "log-driver": "json-file",'
echo ' "log-opts": {'
echo ' "max-size": "20m",'
echo ' "max-file": "3"'
echo -n ' }'
need_comma=1
fi
if [ "$ENABLE_REGISTRY_MIRROR" -eq 1 ]; then
if [ "$need_comma" -eq 1 ]; then
echo ","
else
echo
fi
echo ' "registry-mirrors": ['
echo ' "https://docker.m.daocloud.io",'
echo ' "https://hub-mirror.c.163.com",'
echo ' "https://mirror.baidubce.com"'
echo -n ' ]'
fi
echo
echo "}"
} >/etc/docker/daemon.json
ok "已写入 /etc/docker/daemon.json"
}
#==============================
# 启动 Docker
#==============================
enable_and_start_docker() {
log "启动 Docker 服务并设置开机自启..."
systemctl enable --now docker
ok "Docker 服务已启动"
}
#==============================
# 应用 Docker 配置
#==============================
apply_docker_config_if_needed() {
if [ "$ENABLE_LOG_LIMIT" -eq 0 ] && [ "$ENABLE_REGISTRY_MIRROR" -eq 0 ]; then
return
fi
log "写入 Docker 配置..."
write_daemon_json
log "重载并重启 Docker..."
systemctl daemon-reload
systemctl restart docker
ok "Docker 配置已生效"
}
#==============================
# 用户加入 docker 组
#==============================
add_user_to_docker_group() {
local orig_user="${SUDO_USER:-}"
if [ -n "$orig_user" ] && [ "$orig_user" != "root" ]; then
log "将用户 ${orig_user} 加入 docker 组..."
usermod -aG docker "$orig_user"
NEED_RELOGIN=1
ok "用户 ${orig_user} 已加入 docker 组"
fi
}
#==============================
# 验证安装
#==============================
verify_installation() {
echo
log "验证安装结果..."
docker --version
docker compose version
systemctl is-active docker >/dev/null
ok "Docker 当前状态:active"
echo
echo "========== 安装结果 =========="
if [ "$USE_CN_SOURCE" -eq 1 ]; then
echo "APT 源:国内清华 Docker 源"
else
echo "APT 源:Docker 官方源"
fi
if [ "$ENABLE_REGISTRY_MIRROR" -eq 1 ]; then
echo "Registry 镜像加速:已开启"
else
echo "Registry 镜像加速:未开启"
fi
if [ "$ENABLE_LOG_LIMIT" -eq 1 ]; then
echo "容器日志限制:已开启(20m x 3)"
else
echo "容器日志限制:未开启"
fi
if [ "$NEED_RELOGIN" -eq 1 ]; then
echo "提示:请退出当前终端并重新登录后,再以普通用户执行 docker 命令。"
fi
echo "测试命令:docker run hello-world"
echo "=============================="
}
#==============================
# 主流程
#==============================
main() {
parse_args "$@"
check_root
detect_os
apply_auto_detect
echo
echo "==== Docker 安装脚本启动 ===="
echo "UNINSTALL=${UNINSTALL}"
echo "USE_CN_SOURCE=${USE_CN_SOURCE}"
echo "ENABLE_REGISTRY_MIRROR=${ENABLE_REGISTRY_MIRROR}"
echo "ENABLE_LOG_LIMIT=${ENABLE_LOG_LIMIT}"
echo "AUTO_DETECT=${AUTO_DETECT}"
echo
if [ "$UNINSTALL" -eq 1 ]; then
uninstall_old_docker
fi
install_dependencies
configure_docker_repo
install_docker
enable_and_start_docker
apply_docker_config_if_needed
add_user_to_docker_group
verify_installation
}
main "$@"
2. 用户假如Docker用户组
sudo usermod -aG docker ${USER}