完成 72绵阳项目 71雄安集团监管平台 大量优化更新
This commit is contained in:
@@ -15,7 +15,7 @@ cat /usr/local/etc/wdd/agent-wdd-config.yaml
|
||||
/usr/local/bin/agent-wdd base selinux
|
||||
/usr/local/bin/agent-wdd base sysconfig
|
||||
|
||||
/usr/local/bin/agent-wdd zsh
|
||||
/usr/local/bin/agent-wdd zsh cn
|
||||
|
||||
# 首先需要下载所有的依赖!
|
||||
|
||||
@@ -56,8 +56,7 @@ done
|
||||
export server=172.16.100.62
|
||||
|
||||
scp /usr/local/bin/agent-wdd root@${server}:/usr/local/bin/agent-wdd
|
||||
ssh root@${server} "/usr/local/bin/agent-wdd base ssh config"
|
||||
ssh root@${server} "/usr/local/bin/agent-wdd base ssh key"
|
||||
ssh root@${server} "/usr/local/bin/agent-wdd base ssh config && /usr/local/bin/agent-wdd base ssh key"
|
||||
|
||||
|
||||
# 安装docker-compose
|
||||
@@ -66,12 +65,35 @@ chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# ssh root@${server} "/usr/local/bin/agent-wdd base tools"
|
||||
|
||||
# APT代理加速
|
||||
scp /root/wdd/apt-change.sh root@${server}:/root/wdd/apt-change.sh
|
||||
ssh root@${server} "bash /root/wdd/apt-change.sh -y"
|
||||
|
||||
|
||||
ssh root@${server} "echo \"\"> /etc/apt/apt.conf.d/01proxy"
|
||||
ssh root@${server} "printf '%s\n' \
|
||||
'Acquire::http::Proxy \"http://10.22.57.8:3142\";' \
|
||||
'Acquire::https::Proxy \"http://10.22.57.8:3142\";' \
|
||||
| tee /etc/apt/apt.conf.d/01proxy >/dev/null"
|
||||
ssh root@${server} "apt-get update"
|
||||
ssh root@${server} "apt-get install -y parted"
|
||||
|
||||
# 磁盘初始化
|
||||
ssh root@${server} "mkdir /root/wdd"
|
||||
scp /root/wdd/disk.sh root@${server}:/root/wdd/
|
||||
ssh root@${server} "bash /root/wdd/disk.sh"
|
||||
|
||||
# master节点安装docker
|
||||
bash /root/wdd/docker.sh
|
||||
|
||||
# 在线安装docker 通过APT代理
|
||||
scp /etc/apt/keyrings/docker.gpg root@${server}:/root/wdd/
|
||||
scp /root/wdd/docker.sh root@${server}:/root/wdd/
|
||||
|
||||
ssh root@${server} "bash /root/wdd/docker.sh"
|
||||
ssh root@${server} "docker info"
|
||||
ssh root@${server} "docker compose version"
|
||||
|
||||
# 复制文件-docker
|
||||
scp /root/wdd/docker-amd64-20.10.15.tgz root@${server}:/root/wdd/docker-amd64-20.10.15.tgz
|
||||
scp /root/wdd/docker-compose-v2.18.0-linux-amd64 root@${server}:/root/wdd/
|
||||
@@ -81,7 +103,6 @@ ssh root@${server} "/usr/local/bin/agent-wdd info all"
|
||||
ssh root@${server} "cat /usr/local/etc/wdd/agent-wdd-config.yaml"
|
||||
|
||||
|
||||
|
||||
ssh root@${server} "/usr/local/bin/agent-wdd base swap"
|
||||
ssh root@${server} "/usr/local/bin/agent-wdd base firewall"
|
||||
ssh root@${server} "/usr/local/bin/agent-wdd base selinux"
|
||||
@@ -101,19 +122,34 @@ ssh root@${server} "docker info"
|
||||
|
||||
wget https://oss.demo.uavcmlc.com/cmlc-installation/tmp/nginx=1.27.0=2025-03-11=402.tar.gz && docker load < nginx=1.27.0=2025-03-11=402.tar.gz && docker run -it --rm harbor.cdcyy.com.cn/cmii/nginx:1.27.0
|
||||
|
||||
ssh root@${server} "rm /root/wdd/*.sh"
|
||||
|
||||
# 主节点执行 安装harbor仓库
|
||||
/usr/local/bin/agent-wdd base harbor install
|
||||
|
||||
# 安装rke kubectl
|
||||
mv /root/wdd/rke_amd64 /usr/local/bin/rke
|
||||
mv /root/wdd/rke_linux-amd64 /usr/local/bin/rke
|
||||
chmod +x /usr/local/bin/rke
|
||||
|
||||
mv /root/wdd/kubectl /usr/local/bin/kubectl
|
||||
mv /root/wdd/kubectl_v1.30.14_amd64 /usr/local/bin/kubectl
|
||||
chmod +x /usr/local/bin/kubectl
|
||||
|
||||
|
||||
# 安装 k8s-证书
|
||||
|
||||
mkdir /root/.kube
|
||||
cp ./kube_config_cluster.yml /root/.kube/config
|
||||
|
||||
curl -s https://172.29.137.125
|
||||
# 环境测试
|
||||
DEFAULT_HTTP_BACKEND_IP=$(kubectl -n ingress-nginx get svc default-http-backend -o jsonpath='{.spec.clusterIP}')
|
||||
|
||||
# master节点
|
||||
curl -s "http://${DEFAULT_HTTP_BACKEND_IP}"x
|
||||
|
||||
# worker节点
|
||||
ssh root@"$server" "DEFAULT_HTTP_BACKEND_IP='$DEFAULT_HTTP_BACKEND_IP' bash -s" <<'EOF'
|
||||
echo "DEFAULT_HTTP_BACKEND_IP=$DEFAULT_HTTP_BACKEND_IP"
|
||||
|
||||
curl -s "http://${DEFAULT_HTTP_BACKEND_IP}"
|
||||
echo
|
||||
EOF
|
||||
@@ -1,112 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# 定义脚本参数
|
||||
DOCKER_VERSION="20.10" # 在这里修改期望的版本
|
||||
UBUNTU_IDS=("18.04" "20.04" "22.04" "24.04")
|
||||
ALIYUN_MIRROR="https://mirrors.aliyun.com"
|
||||
DOCKER_COMPOSE_VERSION="2.26.1"
|
||||
|
||||
# 1. 检测Ubuntu环境
|
||||
check_ubuntu() {
|
||||
if ! command -v lsb_release &> /dev/null || [[ $(lsb_release -is) != "Ubuntu" ]]; then
|
||||
echo "错误:本脚本仅支持Ubuntu系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local version_id=$(lsb_release -rs)
|
||||
if [[ ! " ${UBUNTU_IDS[*]} " =~ " ${version_id} " ]]; then
|
||||
echo "错误:不支持的Ubuntu版本 ${version_id},支持版本:${UBUNTU_IDS[*]}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 2. 替换阿里云源
|
||||
set_aliyun_mirror() {
|
||||
sudo sed -i "s/archive.ubuntu.com/mirrors.aliyun.com/g" /etc/apt/sources.list
|
||||
sudo sed -i "s/security.ubuntu.com/mirrors.aliyun.com/g" /etc/apt/sources.list
|
||||
sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates
|
||||
}
|
||||
|
||||
# 3. 准备Docker仓库
|
||||
prepare_docker_env() {
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL $ALIYUN_MIRROR/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
|
||||
local codename=$(lsb_release -cs)
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] $ALIYUN_MIRROR/docker-ce/linux/ubuntu $codename stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
sudo apt-get update
|
||||
}
|
||||
|
||||
# 4. 版本解析优化版本
|
||||
get_docker_version() {
|
||||
local target_version=""
|
||||
if [[ $DOCKER_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||
# 提取大版本下最高小版本
|
||||
target_version=$(apt-cache madison docker-ce \
|
||||
| awk -F'|' '{gsub(/ /,"",$2); print $2}' \
|
||||
| grep -E "^[0-9]+:${DOCKER_VERSION}([.-]|\~\w+)" \
|
||||
| sort -rV \
|
||||
| head -1)
|
||||
elif [[ $DOCKER_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
# 精确版本匹配
|
||||
target_version=$(apt-cache madison docker-ce \
|
||||
| awk -F'|' '{gsub(/ /,"",$2); print $2}' \
|
||||
| grep -E "^[0-9]+:${DOCKER_VERSION}.*$(lsb_release -cs)" )
|
||||
fi
|
||||
|
||||
[ -z "$target_version" ] && echo "错误:找不到Docker版本 $DOCKER_VERSION" && exit 1
|
||||
echo "$target_version" | sed 's/^[0-9]+://' # 去除前缀
|
||||
}
|
||||
|
||||
# 5. 主流程
|
||||
main() {
|
||||
check_ubuntu
|
||||
echo "-- 设置阿里云源 --"
|
||||
set_aliyun_mirror
|
||||
|
||||
echo "-- 准备Docker仓库 --"
|
||||
prepare_docker_env
|
||||
|
||||
echo "-- 解析Docker版本 --"
|
||||
local full_version=$(get_docker_version)
|
||||
echo "选择版本:$full_version"
|
||||
|
||||
echo "-- 安装组件 --"
|
||||
sudo apt-get install -y \
|
||||
docker-ce-cli="$full_version" \
|
||||
docker-ce="$full_version" \
|
||||
docker-ce-rootless-extras="$full_version" \
|
||||
containerd.io \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin
|
||||
|
||||
echo "-- 安装docker-compose --"
|
||||
sudo curl -sSL "https://get.daocloud.io/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m`" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
echo "-- 禁用自动更新 --"
|
||||
sudo apt-mark hold docker-ce docker-ce-cli containerd.io
|
||||
|
||||
echo "-- 启动服务 --"
|
||||
sudo systemctl enable docker && sudo systemctl start docker
|
||||
|
||||
echo -e "\n=== 安装完成 ==="
|
||||
docker --version
|
||||
docker-compose --version
|
||||
}
|
||||
|
||||
main
|
||||
|
||||
|
||||
|
||||
|
||||
请写一个shell,基于上述的部分安装逻辑,实现如下的功能
|
||||
脚本前面提取变量 docker的版本号 20.10.15 或 20.10(安装小版本最高的版本)
|
||||
1. 检测当前主机是否是ubuntu环境,本脚本支支持Ubuntu
|
||||
2. 获取本机的版本号,支持ubuntu18.04 20.04 22.04 24.04的版本
|
||||
3. 根据ubuntu版本修改,apt的镜像源为阿里源
|
||||
4. 在线安装符合变量版本的docker,在线安装docker-compose,安装常用的插件
|
||||
5. 禁止docker自动更新
|
||||
84
998-常用脚本/a-Agent-WDD运行/b-高级磁盘-disk.sh
Normal file
84
998-常用脚本/a-Agent-WDD运行/b-高级磁盘-disk.sh
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# 用户配置部分
|
||||
DISK="/dev/sdb" # 要操作的物理磁盘(请根据实际情况修改)
|
||||
MOUNT_PATH="/var/lib/docker" # 挂载点路径(目录会自动创建)
|
||||
FS_TYPE="ext4" # 文件系统类型(支持ext4/xfs,默认ext4)
|
||||
|
||||
#----------------------------------------------------------
|
||||
# 核心逻辑(建议非必要不修改)
|
||||
#----------------------------------------------------------
|
||||
|
||||
function check_prerequisites() {
|
||||
# 必须root权限运行检查
|
||||
[[ $EUID -ne 0 ]] && echo -e "\033[31m错误:必须使用root权限运行此脚本\033[0m" && exit 1
|
||||
|
||||
# 磁盘存在性检查
|
||||
[[ ! -b "$DISK" ]] && echo -e "\033[31m错误:磁盘 $DISK 不存在\033[0m" && exit 1
|
||||
|
||||
# 文件系统类型校验
|
||||
if [[ "$FS_TYPE" != "ext4" && "$FS_TYPE" != "xfs" ]]; then
|
||||
echo -e "\033[31m错误:不支持的磁盘格式 $FS_TYPE,仅支持 ext4/xfs\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function prepare_disk() {
|
||||
local partition="${DISK}1"
|
||||
|
||||
echo -e "\033[34m正在初始化磁盘分区...\033[0m"
|
||||
parted "$DISK" --script mklabel gpt
|
||||
parted "$DISK" --script mkpart primary 0% 100%
|
||||
parted "$DISK" --script set 1 lvm on
|
||||
partprobe "$DISK" # 确保系统识别新分区表
|
||||
|
||||
echo -e "\033[34m正在创建LVM结构...\033[0m"
|
||||
pvcreate "$partition"
|
||||
vgcreate datavg "$partition"
|
||||
lvcreate -y -l 100%FREE -n lvdata datavg
|
||||
}
|
||||
|
||||
function format_and_mount() {
|
||||
echo -e "\033[34m格式化逻辑卷...\033[0m"
|
||||
if [[ "$FS_TYPE" == "ext4" ]]; then
|
||||
mkfs.ext4 -F "/dev/datavg/lvdata"
|
||||
else
|
||||
mkfs.xfs -f "/dev/datavg/lvdata"
|
||||
fi
|
||||
|
||||
echo -e "\033[34m设置挂载配置...\033[0m"
|
||||
mkdir -p "$MOUNT_PATH"
|
||||
UUID=$(blkid -s UUID -o value "/dev/datavg/lvdata")
|
||||
echo "UUID=$UUID $MOUNT_PATH $FS_TYPE defaults 0 0" | tee -a /etc/fstab >/dev/null
|
||||
mount -a
|
||||
}
|
||||
|
||||
function verify_result() {
|
||||
echo -e "\n\033[1;36m最终验证结果:\033[0m"
|
||||
lsblk -f "$DISK"
|
||||
echo -e "\n磁盘空间使用情况:"
|
||||
df -hT "$MOUNT_PATH"
|
||||
}
|
||||
|
||||
# 主执行流程
|
||||
check_prerequisites
|
||||
prepare_disk
|
||||
format_and_mount
|
||||
verify_result
|
||||
|
||||
echo -e "\n\033[32m操作执行完毕,请仔细核查上述输出信息\033[0m"
|
||||
|
||||
|
||||
|
||||
#请写一个shell脚本,脚本前面有变量可以设置 物理磁盘名称 挂载点路径 磁盘格式化的形式,脚本实现如下的功能
|
||||
#1.将物理磁盘的盘符修改为gpt格式
|
||||
#2.将物理磁盘全部空间创建一个分区,分区格式为lvm
|
||||
#3.将分区分配给逻辑卷datavg
|
||||
#4.将datavg所有可用的空间分配给逻辑卷lvdata
|
||||
#5.将逻辑卷格式化为变量磁盘格式化的形式(支持xfs和ext4的格式,默认为ext4)
|
||||
#6.创建变量挂载点路径
|
||||
#7.写入/etc/fatab,将逻辑卷挂载到变量挂载点,执行全部挂在操作
|
||||
#8.执行lsblk和df -TH查看分区是否正确挂载
|
||||
|
||||
|
||||
594
998-常用脚本/a-Agent-WDD运行/c-联网-docker安装.sh
Normal file
594
998-常用脚本/a-Agent-WDD运行/c-联网-docker安装.sh
Normal file
@@ -0,0 +1,594 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# Metadata
|
||||
# ==============================================================================
|
||||
# Author : Smith Wang (Refactor by ChatGPT)
|
||||
# Version : 2.0.0
|
||||
# License : MIT
|
||||
# Description : Configure Docker APT repository (mirror) and install Docker on
|
||||
# Ubuntu (18.04/20.04/22.04/24.04) with robust offline handling.
|
||||
#
|
||||
# Modules :
|
||||
# - Logging & Error Handling
|
||||
# - Environment & Dependency Checks
|
||||
# - Public Network Reachability Detection
|
||||
# - Docker GPG Key Installation (Online/Offline)
|
||||
# - Docker APT Repo Configuration
|
||||
# - Docker Installation & Service Setup
|
||||
#
|
||||
# Notes :
|
||||
# - This script DOES NOT modify Ubuntu APT sources (/etc/apt/sources.list)
|
||||
# - This script DOES NOT set APT proxy (assumed handled elsewhere)
|
||||
# - If public network is NOT reachable and local GPG key is missing, script
|
||||
# will NOT proceed (per your requirement).
|
||||
#
|
||||
# ShellCheck : Intended clean for bash v5+ with: shellcheck -x <script>
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Global Constants
|
||||
# ==============================================================================
|
||||
readonly SCRIPT_NAME="$(basename "$0")"
|
||||
readonly SCRIPT_VERSION="2.0.0"
|
||||
|
||||
# Default mirror for Docker repo (you asked: only focus on docker source)
|
||||
readonly DEFAULT_DOCKER_APT_MIRROR="https://mirrors.aliyun.com/docker-ce/linux/ubuntu"
|
||||
|
||||
# Default keyring location (recommended by modern Ubuntu)
|
||||
readonly DEFAULT_KEYRING_PATH="/etc/apt/keyrings/docker.gpg"
|
||||
|
||||
# Exit codes
|
||||
readonly EC_OK=0
|
||||
readonly EC_GENERAL=1
|
||||
readonly EC_UNSUPPORTED_OS=10
|
||||
readonly EC_DEPENDENCY=11
|
||||
readonly EC_OFFLINE_NO_KEY=20
|
||||
readonly EC_APT_FAILURE=30
|
||||
|
||||
# ==============================================================================
|
||||
# Configurable Variables (Environment Overrides)
|
||||
# ==============================================================================
|
||||
# You may export these before running:
|
||||
# DOCKER_VERSION="20.10" # or "20.10.15" (optional)
|
||||
# DOCKER_APT_MIRROR="https://..."
|
||||
# DOCKER_KEYRING_PATH="/root/wdd/docker.gpg"
|
||||
# LOCAL_DOCKER_GPG="/path/to/docker.gpg" (optional)
|
||||
# LOG_LEVEL="DEBUG|INFO|WARN|ERROR"
|
||||
DOCKER_VERSION="${DOCKER_VERSION:-20.10}"
|
||||
DOCKER_APT_MIRROR="${DOCKER_APT_MIRROR:-$DEFAULT_DOCKER_APT_MIRROR}"
|
||||
DOCKER_KEYRING_PATH="${DOCKER_KEYRING_PATH:-$DEFAULT_KEYRING_PATH}"
|
||||
LOCAL_DOCKER_GPG="${LOCAL_DOCKER_GPG:-/root/wdd/docker.gpg}"
|
||||
LOG_LEVEL="${LOG_LEVEL:-INFO}"
|
||||
|
||||
# ==============================================================================
|
||||
# Function Call Graph (ASCII)
|
||||
# ==============================================================================
|
||||
# main
|
||||
# |
|
||||
# +--> init_traps
|
||||
# |
|
||||
# +--> check_platform
|
||||
# |
|
||||
# +--> ensure_prerequisites
|
||||
# |
|
||||
# +--> detect_public_network
|
||||
# | |
|
||||
# | +--> can_fetch_url_head
|
||||
# |
|
||||
# +--> ensure_docker_gpg_key
|
||||
# | |
|
||||
# | +--> install_key_from_online
|
||||
# | | |
|
||||
# | | +--> require_cmd (curl, gpg)
|
||||
# | |
|
||||
# | +--> install_key_from_local
|
||||
# |
|
||||
# +--> configure_docker_repo
|
||||
# |
|
||||
# +--> install_docker_packages
|
||||
# | |
|
||||
# | +--> resolve_docker_version
|
||||
# |
|
||||
# +--> pin_docker_packages
|
||||
# |
|
||||
# +--> enable_docker_service
|
||||
# ==============================================================================
|
||||
|
||||
# ==============================================================================
|
||||
# Logging
|
||||
# ==============================================================================
|
||||
|
||||
### Map log level string to numeric value.
|
||||
### @param level_str string Level string (DEBUG/INFO/WARN/ERROR)
|
||||
### @return 0 Always returns 0; outputs numeric level to stdout
|
||||
### @require none
|
||||
log_level_to_num() {
|
||||
case "${1:-INFO}" in
|
||||
DEBUG) echo 10 ;;
|
||||
INFO) echo 20 ;;
|
||||
WARN) echo 30 ;;
|
||||
ERROR) echo 40 ;;
|
||||
*) echo 20 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
### Unified logger with level gating.
|
||||
### @param level string Log level
|
||||
### @param message string Message
|
||||
### @return 0 Always returns 0
|
||||
### @require date
|
||||
log() {
|
||||
local level="${1:?level required}"
|
||||
shift
|
||||
local message="${*:-}"
|
||||
local now
|
||||
now="$(date '+%F %T')"
|
||||
|
||||
local current_level_num wanted_level_num
|
||||
current_level_num="$(log_level_to_num "$LOG_LEVEL")"
|
||||
wanted_level_num="$(log_level_to_num "$level")"
|
||||
|
||||
if [ "$wanted_level_num" -lt "$current_level_num" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# > Keep format stable for parsing by log collectors
|
||||
printf '%s [%s] %s: %s\n' "$now" "$level" "$SCRIPT_NAME" "$message" >&2
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Error Handling & Traps
|
||||
# ==============================================================================
|
||||
|
||||
### Trap handler for unexpected errors.
|
||||
### @param exit_code int Exit code from failing command
|
||||
### @return 0 Always returns 0
|
||||
### @require none
|
||||
on_error() {
|
||||
local exit_code="${1:-$EC_GENERAL}"
|
||||
log ERROR "Unhandled error occurred (exit_code=${exit_code})."
|
||||
exit "$exit_code"
|
||||
}
|
||||
|
||||
### Trap handler for script exit.
|
||||
### @param exit_code int Exit code
|
||||
### @return 0 Always returns 0
|
||||
### @require none
|
||||
on_exit() {
|
||||
local exit_code="${1:-$EC_OK}"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
log INFO "Done."
|
||||
else
|
||||
log WARN "Exited with code ${exit_code}."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
### Initialize traps (ERR/INT/TERM/EXIT).
|
||||
### @return 0 Success
|
||||
### @require none
|
||||
init_traps() {
|
||||
trap 'on_error $?' ERR
|
||||
trap 'log WARN "Interrupted (SIGINT)"; exit 130' INT
|
||||
trap 'log WARN "Terminated (SIGTERM)"; exit 143' TERM
|
||||
trap 'on_exit $?' EXIT
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Privilege Helpers
|
||||
# ==============================================================================
|
||||
|
||||
### Run a command as root (uses sudo if not root).
|
||||
### @param cmd string Command to run
|
||||
### @return 0 Success; non-zero on failure
|
||||
### @require sudo (if not root)
|
||||
run_root() {
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
# shellcheck disable=SC2068
|
||||
"$@"
|
||||
else
|
||||
# shellcheck disable=SC2068
|
||||
sudo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Dependency Checks
|
||||
# ==============================================================================
|
||||
|
||||
### Ensure a command exists in PATH.
|
||||
### @param cmd_name string Command name
|
||||
### @return 0 If exists; 1 otherwise
|
||||
### @require none
|
||||
require_cmd() {
|
||||
local cmd_name="${1:?cmd required}"
|
||||
if ! command -v "$cmd_name" >/dev/null 2>&1; then
|
||||
log ERROR "Missing dependency: ${cmd_name}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Platform Check
|
||||
# ==============================================================================
|
||||
|
||||
### Check OS is Ubuntu and supported versions.
|
||||
### @return 0 Supported; exits otherwise
|
||||
### @require lsb_release, awk
|
||||
check_platform() {
|
||||
require_cmd lsb_release || exit "$EC_DEPENDENCY"
|
||||
|
||||
local distro version
|
||||
distro="$(lsb_release -is 2>/dev/null || true)"
|
||||
version="$(lsb_release -rs 2>/dev/null || true)"
|
||||
|
||||
if [ "$distro" != "Ubuntu" ]; then
|
||||
log ERROR "Unsupported OS: ${distro}. This script supports Ubuntu only."
|
||||
exit "$EC_UNSUPPORTED_OS"
|
||||
fi
|
||||
|
||||
case "$version" in
|
||||
18.04|20.04|22.04|24.04) ;;
|
||||
*)
|
||||
log ERROR "Unsupported Ubuntu version: ${version}. Supported: 18.04/20.04/22.04/24.04"
|
||||
exit "$EC_UNSUPPORTED_OS"
|
||||
;;
|
||||
esac
|
||||
|
||||
log INFO "Platform OK: ${distro} ${version}"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# APT Prerequisites
|
||||
# ==============================================================================
|
||||
|
||||
### Install required packages for repository/key management and Docker installation.
|
||||
### @return 0 Success; exits on apt failures
|
||||
### @require apt-get
|
||||
ensure_prerequisites() {
|
||||
require_cmd apt-get || exit "$EC_DEPENDENCY"
|
||||
|
||||
log INFO "Installing prerequisites (does NOT modify APT sources or proxy)..."
|
||||
# > apt update must work via your existing proxy+mirror scripts
|
||||
if ! run_root apt-get update; then
|
||||
log ERROR "apt-get update failed. Check APT proxy / mirror configuration."
|
||||
exit "$EC_APT_FAILURE"
|
||||
fi
|
||||
|
||||
# > Keep dependencies minimal; curl/gpg used only for online key fetch.
|
||||
if ! run_root apt-get install -y ca-certificates gnupg lsb-release; then
|
||||
log ERROR "Failed to install prerequisites."
|
||||
exit "$EC_APT_FAILURE"
|
||||
fi
|
||||
|
||||
log INFO "Prerequisites installed."
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Public Network Reachability
|
||||
# ==============================================================================
|
||||
|
||||
### Check whether we can fetch HTTP headers from a URL (lightweight reachability).
|
||||
### @param test_url string URL to test
|
||||
### @return 0 Reachable; 1 otherwise
|
||||
### @require curl (optional; if missing returns 1)
|
||||
can_fetch_url_head() {
|
||||
local test_url="${1:?url required}"
|
||||
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
log WARN "curl not found; cannot test public network reachability via HTTP."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# > Use short timeout to avoid hanging in restricted networks
|
||||
curl -fsSI --max-time 3 "$test_url" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
### Detect whether public network access is available for Docker key fetch.
|
||||
### @return 0 Online; 1 Offline/Uncertain
|
||||
### @require none
|
||||
detect_public_network() {
|
||||
local test_url="${DOCKER_APT_MIRROR%/}/gpg"
|
||||
|
||||
log INFO "Detecting public network reachability: HEAD ${test_url}"
|
||||
if can_fetch_url_head "$test_url"; then
|
||||
log INFO "Public network reachable for Docker mirror."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log WARN "Public network NOT reachable (or curl missing). Will try local GPG key."
|
||||
return 1
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Docker GPG Key Management
|
||||
# ==============================================================================
|
||||
|
||||
### Install Docker GPG key from online source (mirror).
|
||||
### @param gpg_url string GPG URL
|
||||
### @param keyring_path string Keyring output path
|
||||
### @return 0 Success; non-zero on failure
|
||||
### @require curl, gpg, install, mkdir, chmod
|
||||
install_key_from_online() {
|
||||
local gpg_url="${1:?gpg_url required}"
|
||||
local keyring_path="${2:?keyring_path required}"
|
||||
|
||||
require_cmd curl || return 1
|
||||
require_cmd gpg || return 1
|
||||
|
||||
# > Write to temp then atomically install to avoid partial files
|
||||
local tmp_dir tmp_gpg
|
||||
tmp_dir="$(mktemp -d)"
|
||||
tmp_gpg="${tmp_dir}/docker.gpg"
|
||||
|
||||
log INFO "Fetching Docker GPG key online: ${gpg_url}"
|
||||
curl -fsSL --max-time 10 "$gpg_url" | gpg --dearmor -o "$tmp_gpg"
|
||||
|
||||
run_root mkdir -p "$(dirname "$keyring_path")"
|
||||
run_root install -m 0644 "$tmp_gpg" "$keyring_path"
|
||||
run_root chmod a+r "$keyring_path" || true
|
||||
|
||||
rm -rf "$tmp_dir"
|
||||
log INFO "Docker GPG key installed: ${keyring_path}"
|
||||
return 0
|
||||
}
|
||||
|
||||
### Install Docker GPG key from local file (offline-friendly).
|
||||
### @param local_gpg_path string Local GPG file path
|
||||
### @param keyring_path string Keyring output path
|
||||
### @return 0 Success; 1 if local key missing; non-zero on other failures
|
||||
### @require install, mkdir, chmod
|
||||
install_key_from_local() {
|
||||
local local_gpg_path="${1:?local_gpg_path required}"
|
||||
local keyring_path="${2:?keyring_path required}"
|
||||
|
||||
if [ ! -f "$local_gpg_path" ]; then
|
||||
log WARN "Local Docker GPG key not found: ${local_gpg_path}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
run_root mkdir -p "$(dirname "$keyring_path")"
|
||||
run_root install -m 0644 "$local_gpg_path" "$keyring_path"
|
||||
run_root chmod a+r "$keyring_path" || true
|
||||
|
||||
log INFO "Docker GPG key installed from local: ${local_gpg_path} -> ${keyring_path}"
|
||||
return 0
|
||||
}
|
||||
|
||||
### Ensure Docker GPG key exists, using online if reachable; otherwise local-only.
|
||||
### Offline policy: if local key missing -> DO NOT proceed (exit).
|
||||
### @param is_online int 0 online; 1 offline
|
||||
### @return 0 Success; exits with EC_OFFLINE_NO_KEY when offline and no local key
|
||||
### @require none
|
||||
ensure_docker_gpg_key() {
|
||||
local is_online="${1:?is_online required}"
|
||||
|
||||
# > If keyring already exists, reuse it (idempotent)
|
||||
if [ -f "$DOCKER_KEYRING_PATH" ]; then
|
||||
log INFO "Docker keyring already exists: ${DOCKER_KEYRING_PATH}"
|
||||
run_root chmod a+r "$DOCKER_KEYRING_PATH" || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
# > Determine local key candidate paths (priority order)
|
||||
local script_dir local_candidate
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
if [ -n "$LOCAL_DOCKER_GPG" ]; then
|
||||
local_candidate="$LOCAL_DOCKER_GPG"
|
||||
elif [ -f "${script_dir}/docker.gpg" ]; then
|
||||
local_candidate="${script_dir}/docker.gpg"
|
||||
else
|
||||
local_candidate=""
|
||||
fi
|
||||
|
||||
local gpg_url
|
||||
gpg_url="${DOCKER_APT_MIRROR%/}/gpg"
|
||||
|
||||
if [ "$is_online" -eq 0 ]; then
|
||||
# Online: try online key fetch first; if fails, fallback to local if present.
|
||||
log DEBUG "Online mode: attempt online key install, fallback to local."
|
||||
if install_key_from_online "$gpg_url" "$DOCKER_KEYRING_PATH"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -n "$local_candidate" ] && install_key_from_local "$local_candidate" "$DOCKER_KEYRING_PATH"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log ERROR "Failed to install Docker GPG key (online fetch failed and no usable local key)."
|
||||
exit "$EC_DEPENDENCY"
|
||||
fi
|
||||
|
||||
# Offline: strictly local only; if missing -> do not proceed
|
||||
log INFO "Offline mode: install Docker GPG key from local only."
|
||||
if [ -n "$local_candidate" ] && install_key_from_local "$local_candidate" "$DOCKER_KEYRING_PATH"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log ERROR "Offline and local Docker GPG key is missing. Will NOT proceed (per policy)."
|
||||
exit "$EC_OFFLINE_NO_KEY"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Docker Repo Configuration
|
||||
# ==============================================================================
|
||||
|
||||
### Configure Docker APT repository list file.
|
||||
### @return 0 Success; exits on apt update failures
|
||||
### @require dpkg, lsb_release, tee, apt-get
|
||||
configure_docker_repo() {
|
||||
require_cmd dpkg || exit "$EC_DEPENDENCY"
|
||||
require_cmd lsb_release || exit "$EC_DEPENDENCY"
|
||||
require_cmd tee || exit "$EC_DEPENDENCY"
|
||||
|
||||
local codename arch list_file
|
||||
codename="$(lsb_release -cs)"
|
||||
arch="$(dpkg --print-architecture)"
|
||||
list_file="/etc/apt/sources.list.d/docker.list"
|
||||
|
||||
log INFO "Configuring Docker APT repo: ${DOCKER_APT_MIRROR} (${codename}, ${arch})"
|
||||
# > Only touch docker repo; do not touch system sources.list
|
||||
run_root tee "$list_file" >/dev/null <<EOF
|
||||
deb [arch=${arch} signed-by=${DOCKER_KEYRING_PATH}] ${DOCKER_APT_MIRROR} ${codename} stable
|
||||
EOF
|
||||
|
||||
if ! run_root apt-get update; then
|
||||
log ERROR "apt-get update failed after configuring Docker repo."
|
||||
exit "$EC_APT_FAILURE"
|
||||
fi
|
||||
|
||||
log INFO "Docker APT repo configured: ${list_file}"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Docker Installation
|
||||
# ==============================================================================
|
||||
|
||||
### Resolve Docker package version string from APT cache.
|
||||
### @param docker_version string Desired version ("20.10" or "20.10.15")
|
||||
### @return 0 Success and echoes full apt version string; exits if not found
|
||||
### @require apt-cache, awk, grep, sort, head
|
||||
resolve_docker_version() {
|
||||
local docker_version="${1:?docker_version required}"
|
||||
|
||||
require_cmd apt-cache || exit "$EC_DEPENDENCY"
|
||||
require_cmd awk || exit "$EC_DEPENDENCY"
|
||||
require_cmd grep || exit "$EC_DEPENDENCY"
|
||||
require_cmd sort || exit "$EC_DEPENDENCY"
|
||||
require_cmd head || exit "$EC_DEPENDENCY"
|
||||
|
||||
local resolved=""
|
||||
# > apt-cache madison output includes epoch, keep it for apt-get install
|
||||
if [[ "$docker_version" =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||
# Pick newest patch/build for that major.minor
|
||||
resolved="$(
|
||||
apt-cache madison docker-ce \
|
||||
| awk -F'|' '{gsub(/ /,"",$2); print $2}' \
|
||||
| grep -E "^[0-9]+:${docker_version}([.-]|\~)" \
|
||||
| sort -rV \
|
||||
| head -1 || true
|
||||
)"
|
||||
elif [[ "$docker_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
resolved="$(
|
||||
apt-cache madison docker-ce \
|
||||
| awk -F'|' '{gsub(/ /,"",$2); print $2}' \
|
||||
| grep -E "^[0-9]+:${docker_version}.*" \
|
||||
| head -1 || true
|
||||
)"
|
||||
else
|
||||
log ERROR "Invalid DOCKER_VERSION format: ${docker_version} (expect 20.10 or 20.10.15)"
|
||||
exit "$EC_GENERAL"
|
||||
fi
|
||||
|
||||
if [ -z "$resolved" ]; then
|
||||
log ERROR "Cannot find Docker version '${docker_version}' from APT. Check repo/mirror and apt proxy."
|
||||
exit "$EC_APT_FAILURE"
|
||||
fi
|
||||
|
||||
echo "$resolved"
|
||||
return 0
|
||||
}
|
||||
|
||||
### Install Docker packages via APT.
|
||||
### @return 0 Success; exits on failure
|
||||
### @require apt-get, systemctl
|
||||
install_docker_packages() {
|
||||
require_cmd apt-get || exit "$EC_DEPENDENCY"
|
||||
|
||||
local full_version
|
||||
full_version="$(resolve_docker_version "$DOCKER_VERSION")"
|
||||
|
||||
log INFO "Installing Docker packages: docker-ce=${full_version}"
|
||||
# > Compose: use docker-compose-plugin (no curl downloading binaries)
|
||||
if ! run_root apt-get install -y \
|
||||
"docker-ce=${full_version}" \
|
||||
"docker-ce-cli=${full_version}" \
|
||||
"docker-ce-rootless-extras=${full_version}" \
|
||||
containerd.io \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin; then
|
||||
log ERROR "Docker installation failed."
|
||||
exit "$EC_APT_FAILURE"
|
||||
fi
|
||||
|
||||
# > Optional: provide docker-compose legacy command compatibility
|
||||
if ! command -v docker-compose >/dev/null 2>&1; then
|
||||
if [ -x /usr/libexec/docker/cli-plugins/docker-compose ]; then
|
||||
run_root ln -sf /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose || true
|
||||
fi
|
||||
fi
|
||||
|
||||
log INFO "Docker packages installed."
|
||||
}
|
||||
|
||||
### Pin Docker packages to avoid unintended upgrades.
|
||||
### @return 0 Success; non-zero on failures (non-fatal)
|
||||
### @require apt-mark
|
||||
pin_docker_packages() {
|
||||
if ! command -v apt-mark >/dev/null 2>&1; then
|
||||
log WARN "apt-mark not found; skip pinning."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log INFO "Holding Docker packages (prevent auto-upgrade)..."
|
||||
run_root apt-mark hold \
|
||||
docker-ce docker-ce-cli docker-ce-rootless-extras containerd.io \
|
||||
docker-buildx-plugin docker-compose-plugin >/dev/null 2>&1 || true
|
||||
return 0
|
||||
}
|
||||
|
||||
### Enable and start Docker service, then verify versions.
|
||||
### @return 0 Success; exits on failure to enable docker
|
||||
### @require systemctl, docker
|
||||
enable_docker_service() {
|
||||
require_cmd systemctl || exit "$EC_DEPENDENCY"
|
||||
|
||||
log INFO "Enabling and starting docker service..."
|
||||
run_root systemctl enable --now docker
|
||||
|
||||
# > Verification should not hard-fail the whole script
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
docker --version || true
|
||||
docker compose version || true
|
||||
fi
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose --version || true
|
||||
fi
|
||||
|
||||
log INFO "Docker service enabled."
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Main
|
||||
# ==============================================================================
|
||||
|
||||
### Main entrypoint.
|
||||
### @return 0 Success; non-zero on failure
|
||||
### @require none
|
||||
main() {
|
||||
init_traps
|
||||
log INFO "Starting Docker installer (v${SCRIPT_VERSION})..."
|
||||
|
||||
check_platform
|
||||
ensure_prerequisites
|
||||
|
||||
local is_online=1
|
||||
if detect_public_network; then
|
||||
is_online=0
|
||||
fi
|
||||
|
||||
ensure_docker_gpg_key "$is_online"
|
||||
configure_docker_repo
|
||||
install_docker_packages
|
||||
pin_docker_packages
|
||||
enable_docker_service
|
||||
|
||||
log INFO "All tasks completed successfully."
|
||||
exit "$EC_OK"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user