天涯随风
天涯随风
发布于 2026-03-13 / 0 阅读
0
0

ubuntu安装Docker环境

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}


评论