前置要求
1. 脚本概述
安装时会将所有二进制文件通过循环创建软链接的方式放到 /usr/bin 目录下,卸载时也会一并删除无侵入式安装。
获取版本时已经将 20.x 以下的版本给过滤掉了,往下的版本实在是太老了不建议再安装了。
请注意,卸载的时候会删除所有 docker 数据,请斟酌查看脚本并修改是否保留数据,注释掉删除语句即可。
DOCKER_INSTALL_DIR
:Docker 的安装目录(默认为/app/docker
)。DOCKER_USR_BIN
:Docker 二进制文件的软链接路径(默认为/usr/bin
)。DOCKER_URL
:Docker 二进制安装包的下载路径(https://download.docker.com/linux/static/stable/x86_64/)。DOCKER_DATA_DIR
:Docker 数据目录(默认为/data/docker
)。DOCKER_DOWNLOAD_DIR
:临时目录用于存放下载的 Docker 二进制安装包(默认为/tmp/docker_install
)。
#!/bin/bash
# Docker 安装目录和相关路径
DOCKER_INSTALL_DIR="/app/docker"
DOCKER_USR_BIN="/usr/bin"
DOCKER_URL="https://download.docker.com/linux/static/stable/x86_64/"
DOCKER_DATA_DIR="/data/docker"
DOCKER_DOWNLOAD_DIR="/tmp/docker_install"
# 创建临时目录
mkdir -p "$DOCKER_DOWNLOAD_DIR"
print_separator() {
printf '%*s\n' "${COLUMNS:-80}" '' | tr ' ' -
}
# 检查系统中是否已有 Docker 安装,并输出当前版本
check_existing_docker() {
if command -v docker &> /dev/null; then
current_version=$(docker --version | grep -oP 'Docker version \K[0-9]+\.[0-9]+\.[0-9]+')
echo ""
echo "检测到系统中已安装 Docker 版本: $current_version"
echo "为了确保安装正确的版本,请先卸载当前 Docker。"
echo "建议使用卸载选项来清除现有安装,然后重新运行该脚本进行安装。"
echo ""
exit 1 # 停止脚本运行
else
echo ""
echo "未检测到系统中已安装 Docker,可以继续安装。"
fi
}
# 获取可用的 Docker 版本(联网)
list_docker_versions() {
echo "正在获取可用的 Docker 版本..."
# 使用 curl 获取页面内容,并从中提取版本号,只保留 20.x.x 及以上的版本
page_content=$(curl -s "$DOCKER_URL")
versions=$(echo "$page_content" | grep -oP 'docker-\K[2-9][0-9]+\.[0-9]+\.[0-9]+' | sort -rV | uniq)
if [[ -z "$versions" ]]; then
echo "未找到 Docker 版本。请检查您的网络连接或 Docker URL。"
else
echo "可用的 Docker 版本:"
echo "$versions"
fi
}
# 列出本地已下载的 Docker 版本
list_local_docker_versions() {
echo "已下载的 Docker 版本:"
local_versions=$(ls "$DOCKER_DOWNLOAD_DIR" | grep -oP 'docker-\K[0-9]+\.[0-9]+\.[0-9]+(?=\.tgz)' | sort -rV | uniq)
if [[ -z "$local_versions" ]]; then
echo "未找到本地 Docker 安装包。请先使用联网安装功能下载。"
else
echo "$local_versions"
fi
}
# 下载 Docker 到本地
download_docker() {
version=$1
echo "正在下载 Docker 版本 $version..."
# 下载并检查返回的 HTTP 状态码
curl -L "${DOCKER_URL}docker-$version.tgz" -o "$DOCKER_DOWNLOAD_DIR/docker-$version.tgz"
if [[ $? -ne 0 ]]; then
echo "错误: 下载 Docker 版本 $version 失败。请检查网络连接或版本号是否正确。"
exit 1 # 退出脚本
fi
}
# 检查版本号是否在列表中(通用函数)
check_version_exists() {
version=$1
available_versions=$2
if [[ "$available_versions" =~ "$version" ]]; then
return 0 # 版本存在
else
return 1 # 版本不存在
fi
}
# 安装 Docker
install_docker() {
version=$1
# 解压并移动到目标安装目录
echo "正在将 Docker 版本 $version 安装到 $DOCKER_INSTALL_DIR..."
mkdir -p "$DOCKER_INSTALL_DIR"
mkdir -p "$DOCKER_DATA_DIR"
# 解压并检查解压是否成功
tar -xzf "$DOCKER_DOWNLOAD_DIR/docker-$version.tgz" -C "$DOCKER_INSTALL_DIR" --strip-components=1
if [[ $? -ne 0 ]]; then
echo "错误: 解压 Docker 版本 $version 时出错。文件可能已损坏或格式不正确。"
exit 1 # 退出脚本
fi
# 创建软连接,将 docker 目录下的所有文件链接到 /usr/bin
echo "正在为 Docker 二进制文件创建软链接..."
for bin_file in "$DOCKER_INSTALL_DIR"/*; do
if [ -f "$bin_file" ]; then
filename=$(basename "$bin_file")
ln -sf "$bin_file" "$DOCKER_USR_BIN/$filename"
fi
done
echo "Docker $version 安装成功。"
# 创建docker组,给docker.service使用
groupadd -g 999 docker
# 创建 docker.service 文件
create_docker_service_file
# 设置 Docker 数据目录权限
chmod -R 755 "$DOCKER_DATA_DIR"
# 刷新 systemd 配置并启动 Docker
echo "正在重新加载 systemd 并启动 Docker 服务..."
systemctl daemon-reload
systemctl start docker
systemctl enable docker
if [[ $? -ne 0 ]]; then
echo "错误: Docker 服务启动失败。请查看日志了解详细信息。"
exit 1
fi
echo "Docker 服务已启动并设置为开机自启。"
# 调用分隔符
print_separator
# 添加 Docker 版本信息输出
docker_version_output=$(docker version)
echo "$docker_version_output"
}
# 创建 Docker 服务文件 /usr/lib/systemd/system/docker.service
create_docker_service_file() {
echo "正在创建 /usr/lib/systemd/system/docker.service 文件..."
cat << EOF | sudo tee /usr/lib/systemd/system/docker.service > /dev/null
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
# After=network-online.target firewalld.service containerd.service
# Wants=network-online.target
# Requires=docker.socket containerd.service
[Service]
# 代理
# Environment="HTTP_PROXY=http://172.31.0.1:7890/"
# Environment="HTTPS_PROXY=http://172.31.0.1:7890/"
# Environment="NO_PROXY=localhost,10.*,172.*,192.*"
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd --data-root=$DOCKER_DATA_DIR --group=docker
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3
# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
echo "docker.service 文件创建成功。"
}
# 卸载 Docker
uninstall_docker() {
echo "正在卸载 Docker..."
# 停止 Docker 服务
systemctl stop docker
# 删除软链接
echo "正在删除 Docker 二进制文件的软链接..."
for bin_file in "$DOCKER_INSTALL_DIR"/*; do
if [ -f "$bin_file" ]; then
filename=$(basename "$bin_file")
rm -f "$DOCKER_USR_BIN/$filename"
fi
done
# 兼容旧版的删除
rm -rf /usr/bin/containerd*
rm -rf /usr/bin/containerd-shim-runc-v2*
rm -rf /usr/bin/ctr*
rm -rf /usr/bin/docker*
rm -rf /usr/bin/dockerd*
rm -rf /usr/bin/docker-init*
# 删除安装目录
rm -rf "$DOCKER_INSTALL_DIR"
# 删除数据目录
rm -rf "$DOCKER_DATA_DIR"
# 删除 Docker 数据目录软链接(如果有的话)
rm -rf /var/lib/docker
rm -rf /var/run/docker
rm -rf /etc/docker
rm -rf /usr/lib/systemd/system/docker.service
rm -rf /lib/systemd/system/docker.service
rm -rf /etc/systemd/system/docker.service
# 删除docker组
sudo groupdel docker
systemctl daemon-reload
echo "Docker 卸载成功。"
}
# 脚本主逻辑
main() {
echo "Docker 安装脚本"
echo "1) 列出可用的 Docker 版本(联网)"
echo "2) 安装 Docker(联网)"
echo "3) 安装 Docker(本地)"
echo "4) 卸载 Docker"
echo "5) 退出"
read -p "请选择一个选项 [1-5]: " option
case $option in
1)
list_docker_versions
;;
2)
list_docker_versions
read -p "请输入要安装的 Docker 版本: " version
available_versions=$(list_docker_versions)
if check_version_exists "$version" "$available_versions"; then
download_docker "$version"
# 检查是否已安装 Docker
check_existing_docker
install_docker "$version"
else
echo "错误: 输入的版本号 $version 不存在于可用版本列表中。"
fi
;;
3)
# 检查是否已安装 Docker
check_existing_docker
list_local_docker_versions
read -p "请输入要安装的本地 Docker 版本: " version
local_versions=$(list_local_docker_versions)
if check_version_exists "$version" "$local_versions"; then
install_docker "$version"
else
echo "错误: 输入的版本号 $version 不存在于本地已下载的版本列表中。"
fi
;;
4)
uninstall_docker
;;
5)
exit 0
;;
*)
echo "无效选项。"
;;
esac
}
# 运行主函数
main
2. 使用步骤
2.1 列出可用的 Docker 版本(联网)
[root@localhost shell]# ./docker-install.sh
Docker 安装脚本
1) 列出可用的 Docker 版本(联网)
2) 安装 Docker(联网)
3) 安装 Docker(本地)
4) 卸载 Docker
5) 退出
请选择一个选项 [1-5]: 1
正在获取可用的 Docker 版本...
可用的 Docker 版本:
27.2.1
27.2.0
27.1.2
27.1.1
..............忽略输出
2.2 安装 Docker(联网)
[root@localhost shell]# ./docker-install.sh
Docker 安装脚本
1) 列出可用的 Docker 版本(联网)
2) 安装 Docker(联网)
3) 安装 Docker(本地)
4) 卸载 Docker
5) 退出
请选择一个选项 [1-5]: 2
正在获取可用的 Docker 版本...
可用的 Docker 版本:
27.2.1
27.2.0
24.0.9
20.10.1
20.10.0
..............忽略输出
请输入要安装的 Docker 版本: 24.0.9
正在下载 Docker 版本 24.0.9...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 66.9M 100 66.9M 0 0 13.3M 0 0:00:04 0:00:04 --:--:-- 15.2M
未检测到系统中已安装 Docker,可以继续安装。
正在将 Docker 版本 24.0.9 安装到 /app/docker...
正在为 Docker 二进制文件创建软链接...
Docker 24.0.9 安装成功。
正在创建 /usr/lib/systemd/system/docker.service 文件...
docker.service 文件创建成功。
正在重新加载 systemd 并启动 Docker 服务...
Docker 服务已启动并设置为开机自启。
--------------------------------------------------------------------------------
Client:
Version: 24.0.9
API version: 1.43
Go version: go1.20.13
Git commit: 2936816
Built: Thu Feb 1 00:47:46 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 24.0.9
API version: 1.43 (minimum version 1.12)
Go version: go1.20.13
Git commit: fca702d
Built: Thu Feb 1 00:49:16 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.7.13
GitCommit: 7c3aca7a610df76212171d200ca3811ff6096eb8
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0
2.3 安装 Docker(本地)
由于网络限制导致 Docker 在线安装困难,我已为你准备了几个较新的 Docker 版本。你可以将它们下载放置到 /tmp/docker_install 目录中,脚本会自动识别并从本地安装这些版本。
[root@localhost shell]# ./docker-install.sh
Docker 安装脚本
1) 列出可用的 Docker 版本(联网)
2) 安装 Docker(联网)
3) 安装 Docker(本地)
4) 卸载 Docker
5) 退出
请选择一个选项 [1-5]: 3
未检测到系统中已安装 Docker,可以继续安装。
已下载的 Docker 版本:
24.0.9
23.0.6
20.10.24
请输入要安装的本地 Docker 版本: 20.10.24
正在将 Docker 版本 20.10.24 安装到 /app/docker...
正在为 Docker 二进制文件创建软链接...
Docker 20.10.24 安装成功。
正在创建 /usr/lib/systemd/system/docker.service 文件...
docker.service 文件创建成功。
正在重新加载 systemd 并启动 Docker 服务...
Docker 服务已启动并设置为开机自启。
--------------------------------------------------------------------------------
Client:
Version: 20.10.24
API version: 1.41
Go version: go1.19.7
Git commit: 297e128
Built: Tue Apr 4 18:17:06 2023
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.24
API version: 1.41 (minimum version 1.12)
Go version: go1.19.7
Git commit: 5d6db84
Built: Tue Apr 4 18:23:02 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.6.20
GitCommit: 2806fc1057397dbaeefbea0e4e17bddfbd388f38
runc:
Version: 1.1.5
GitCommit: v1.1.5-0-gf19387a6
docker-init:
Version: 0.19.0
GitCommit: de40ad0
2.4 卸载 Docker
[root@localhost shell]# ./docker-install.sh
Docker 安装脚本
1) 列出可用的 Docker 版本(联网)
2) 安装 Docker(联网)
3) 安装 Docker(本地)
4) 卸载 Docker
5) 退出
请选择一个选项 [1-5]: 4
正在卸载 Docker...
正在删除 Docker 二进制文件的软链接...
Docker 卸载成功。
3. 后续拓展
根据配置文件自定义一键多节点安装
访问docker网站失败的情况下预准备安装包方式部署
4. 写在最后
是不是很神奇哈哈一个脚本完成很实用的功能,实测在ubuntu和centos是能够正常运行的,至于其他系统我还没有测试过。欢迎给我留言好用我会继续拓展的。