Docker拉取镜像慢的解决方法
前言
今天不知道怎么回事,在国内服务器拉取docker的镜像就会非常慢,可能和docker官网有关系,毕竟是在国外。
之前也说过替换docker国内源,但是尝试了一下发现还是不行,于是有了个新办法。
教程
首先感谢SuperManito在github上提供的一种方法。
1.将如下代码保存到网站目录下的以sh为后缀的文件中,可以新建一个文件,比如ceshi.sh
#!/bin/bash
## Author: SuperManito
## Modified: 2024-01-31
## License: MIT
## GitHub: https://github.com/SuperManito/LinuxMirrors
## Website: https://linuxmirrors.cn
## Docker Registry 镜像仓库列表
# 格式:"软件源名称@软件源地址"
mirror_list_registry=(
"上海交通大学@docker.mirrors.sjtug.sjtu.edu.cn"
"网易@hub-mirror.c.163.com"
"腾讯云@mirror.ccs.tencentyun.com"
"道客-DaoCloud@f1361db2.m.daocloud.io"
"微软-Azure(中国)@dockerhub.azk8s.cn"
"阿里云(杭州)@registry.cn-hangzhou.aliyuncs.com"
"阿里云(上海)@registry.cn-shanghai.aliyuncs.com"
"阿里云(青岛)@registry.cn-qingdao.aliyuncs.com"
"阿里云(北京)@registry.cn-beijing.aliyuncs.com"
"阿里云(张家口)@registry.cn-zhangjiakou.aliyuncs.com"
"阿里云(呼和浩特)@registry.cn-huhehaote.aliyuncs.com"
"阿里云(乌兰察布)@registry.cn-wulanchabu.aliyuncs.com"
"阿里云(深圳)@registry.cn-shenzhen.aliyuncs.com"
"阿里云(河源)@registry.cn-heyuan.aliyuncs.com"
"阿里云(广州)@registry.cn-guangzhou.aliyuncs.com"
"阿里云(成都)@registry.cn-chengdu.aliyuncs.com"
"阿里云(香港)@registry.cn-hongkong.aliyuncs.com"
"阿里云(日本-东京)@registry.ap-northeast-1.aliyuncs.com"
"阿里云(新加坡)@registry.ap-southeast-1.aliyuncs.com"
"阿里云(澳大利亚-悉尼)@registry.ap-southeast-2.aliyuncs.com"
"阿里云(马来西亚-吉隆坡)@registry.ap-southeast-3.aliyuncs.com"
"阿里云(印度尼西亚-雅加达)@registry.ap-southeast-5.aliyuncs.com"
"阿里云(印度-孟买)@registry.ap-south-1.aliyuncs.com"
"阿里云(德国-法兰克福)@registry.eu-central-1.aliyuncs.com"
"阿里云(英国-伦敦)@registry.eu-west-1.aliyuncs.com"
"阿里云(美国西部-硅谷)@registry.us-west-1.aliyuncs.com"
"阿里云(美国东部-弗吉尼亚)@registry.us-east-1.aliyuncs.com"
"阿里云(阿联酋-迪拜)@registry.me-east-1.aliyuncs.com"
"阿里云(hinas海纳斯)@z0nkeoyx.mirror.aliyuncs.com"
"谷歌云@mirror.gcr.io"
"官方@registry.hub.docker.com"
)
## 定义系统判定变量
SYSTEM_DEBIAN="Debian"
SYSTEM_UBUNTU="Ubuntu"
SYSTEM_KALI="Kali"
SYSTEM_REDHAT="RedHat"
SYSTEM_RHEL="RedHat"
SYSTEM_CENTOS="CentOS"
SYSTEM_CENTOS_STREAM="CentOS Stream"
SYSTEM_ROCKY="Rocky"
SYSTEM_ALMALINUX="AlmaLinux"
SYSTEM_FEDORA="Fedora"
SYSTEM_OPENCLOUDOS="OpenCloudOS"
SYSTEM_OPENEULER="openEuler"
## 定义目录和文件
File_LinuxRelease=/etc/os-release
File_RedHatRelease=/etc/redhat-release
File_OpenCloudOSRelease=/etc/opencloudos-release
File_openEulerRelease=/etc/openEuler-release
File_DebianVersion=/etc/debian_version
File_DebianSourceList=/etc/apt/sources.list
Dir_DebianExtendSource=/etc/apt/sources.list.d
Dir_YumRepos=/etc/yum.repos.d
## 定义 Docker 相关变量
DockerDir=/etc/docker
DockerConfig=$DockerDir/daemon.json
DockerConfigBackup=$DockerDir/daemon.json.bak
DockerVersionFile=docker-version.txt
DockerCEVersionFile=docker-ce-version.txt
DockerCECLIVersionFile=docker-ce-cli-version.txt
## 定义颜色变量
RED=' 33[31m'
GREEN=' 33[32m'
YELLOW=' 33[33m'
BLUE=' 33[34m'
PLAIN=' 33[0m'
BOLD=' 33[1m'
SUCCESS='[ 33[32mOK 33[0m]'
COMPLETE='[ 33[32mDONE 33[0m]'
WARN='[ 33[33mWARN 33[0m]'
ERROR='[ 33[31mERROR 33[0m]'
WORKING='[ 33[34m* 33[0m]'
function StartTitle() {
[[ -z "${SOURCE}" || -z "${SOURCE_REGISTRY}" ]] && clear
# echo -e ' +-----------------------------------+'
# echo -e " | 33[0;1;35;95m⡇ 33[0m 33[0;1;33;93m⠄ 33[0m 33[0;1;32;92m⣀⡀ 33[0m 33[0;1;36;96m⡀ 33[0;1;34;94m⢀ 33[0m 33[0;1;35;95m⡀⢀ 33[0m 33[0;1;31;91m⡷ 33[0;1;33;93m⢾ 33[0m 33[0;1;32;92m⠄ 33[0m 33[0;1;36;96m⡀⣀ 33[0m 33[0;1;34;94m⡀ 33[0;1;35;95m⣀ 33[0m 33[0;1;31;91m⢀⡀ 33[0m 33[0;1;33;93m⡀ 33[0;1;32;92m⣀ 33[0m 33[0;1;36;96m⢀⣀ 33[0m |"
# echo -e " | 33[0;1;31;91m⠧ 33[0;1;33;93m⠤ 33[0m 33[0;1;32;92m⠇ 33[0m 33[0;1;36;96m⠇⠸ 33[0m 33[0;1;34;94m⠣ 33[0;1;35;95m⠼ 33[0m 33[0;1;31;91m⠜⠣ 33[0m 33[0;1;33;93m⠇ 33[0;1;32;92m⠸ 33[0m 33[0;1;36;96m⠇ 33[0m 33[0;1;34;94m⠏ 33[0m 33[0;1;35;95m⠏ 33[0m 33[0;1;33;93m⠣⠜ 33[0m 33[0;1;32;92m⠏ 33[0m 33[0;1;34;94m⠭⠕ 33[0m |"
# echo -e ' +-----------------------------------+'
echo -e ' 欢迎使用 Docker Engine 一键安装脚本'
}
## 报错退出
function Output_Error() {
[ "$1" ] && echo -e "n$ERROR $1n"
exit 1
}
## 基础环境判断
function PermissionJudgment() {
if [ $UID -ne 0 ]; then
echo -e "n$ERROR 权限不足,请使用 Root 用户运行本脚本n"
exit 1
fi
}
## 系统判定变量
function EnvJudgment() {
## 定义系统名称
SYSTEM_NAME="$(cat $File_LinuxRelease | grep -E "^NAME=" | awk -F '=' '{print$2}' | sed "s/['"]//g")"
cat $File_LinuxRelease | grep "PRETTY_NAME=" -q
[ $? -eq 0 ] && SYSTEM_PRETTY_NAME="$(cat $File_LinuxRelease | grep -E "^PRETTY_NAME=" | awk -F '=' '{print$2}' | sed "s/['"]//g")"
## 定义系统版本号
SYSTEM_VERSION_NUMBER="$(cat $File_LinuxRelease | grep -E "^VERSION_ID=" | awk -F '=' '{print$2}' | sed "s/['"]//g")"
## 定义系统ID
SYSTEM_ID="$(cat $File_LinuxRelease | grep -E "^ID=" | awk -F '=' '{print$2}' | sed "s/['"]//g")"
## 判定当前系统派系
if [ -s $File_DebianVersion ]; then
SYSTEM_FACTIONS="${SYSTEM_DEBIAN}"
elif [ -s $File_openEulerRelease ]; then
SYSTEM_FACTIONS="${SYSTEM_OPENEULER}"
elif [ -s $File_RedHatRelease ]; then
SYSTEM_FACTIONS="${SYSTEM_REDHAT}"
elif [ -s $File_OpenCloudOSRelease ]; then
SYSTEM_FACTIONS="${SYSTEM_OPENCLOUDOS}" # 注:RedHat 判断优先级需要高于 OpenCloudOS,因为8版本基于红帽而9版本不是
else
Output_Error "无法判断当前运行环境,当前系统不在本脚本的支持范围内"
fi
## 判定系统名称、版本、版本号
case "${SYSTEM_FACTIONS}" in
"${SYSTEM_DEBIAN}")
if [ ! -x /usr/bin/lsb_release ]; then
apt-get install -y lsb-release
if [ $? -ne 0 ]; then
Output_Error "lsb-release 软件包安装失败n 本脚本需要通过 lsb_release 指令判断系统具体类型和版本,当前系统可能为精简安装,请自行安装后重新执行脚本!"
fi
fi
SYSTEM_JUDGMENT="$(lsb_release -is)"
SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(lsb_release -cs)"}"
;;
"${SYSTEM_REDHAT}")
SYSTEM_JUDGMENT="$(cat $File_RedHatRelease | awk -F ' ' '{printf$1}')"
## Red Hat Enterprise Linux
cat $File_RedHatRelease | grep -q "${SYSTEM_RHEL}"
[ $? -eq 0 ] && SYSTEM_JUDGMENT="${SYSTEM_RHEL}"
## CentOS Stream
cat $File_RedHatRelease | grep -q "${SYSTEM_CENTOS_STREAM}"
[ $? -eq 0 ] && SYSTEM_JUDGMENT="${SYSTEM_CENTOS_STREAM}"
;;
"${SYSTEM_OPENCLOUDOS}")
SYSTEM_JUDGMENT="${SYSTEM_OPENCLOUDOS}"
;;
"${SYSTEM_OPENEULER}")
SYSTEM_JUDGMENT="${SYSTEM_OPENEULER}"
;;
esac
## 判定系统处理器架构
case $(uname -m) in
x86_64)
SYSTEM_ARCH="x86_64"
SOURCE_ARCH="amd64"
;;
aarch64)
SYSTEM_ARCH="ARM64"
SOURCE_ARCH="arm64"
;;
armv7l)
SYSTEM_ARCH="ARMv7"
SOURCE_ARCH="armhf"
;;
armv6l)
SYSTEM_ARCH="ARMv6"
SOURCE_ARCH="armhf"
;;
i386 | i686)
Output_Error "Docker Engine 不支持安装在 x86_32 架构的环境上!"
;;
*)
SYSTEM_ARCH=$(uname -m)
SOURCE_ARCH=armhf
;;
esac
## 定义软件源分支名称
case "${SYSTEM_JUDGMENT}" in
"${SYSTEM_CENTOS}" | "${SYSTEM_DEBIAN}" | "${SYSTEM_UBUNTU}" | "${SYSTEM_FEDORA}")
SOURCE_BRANCH="$(echo "${SYSTEM_JUDGMENT,,}" | sed "s/ /-/g")"
;;
"${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ALMALINUX}" | "${SYSTEM_ROCKY}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}")
SOURCE_BRANCH="centos"
;;
"${SYSTEM_RHEL}")
SOURCE_BRANCH="rhel"
;;
"${SYSTEM_KALI}")
# Kali 使用 Debian 12 的 docker ce 源
SOURCE_BRANCH="debian"
SYSTEM_VERSION_CODENAME="bullseye"
;;
*)
Output_Error "当前系统不在本脚本的支持范围内"
;;
esac
## 定义软件源更新文字
case "${SYSTEM_FACTIONS}" in
"${SYSTEM_DEBIAN}")
SYNC_MIRROR_TEXT="更新软件源"
;;
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}")
SYNC_MIRROR_TEXT="生成软件源缓存"
;;
esac
}
# 检查是否安装了bc,如果没有安装,则进行安装
CheckBc() {
if ! command -v bc &> /dev/null; then
echo "bc could not be found, attempting to install it..."
sudo apt-get update
if ! sudo apt-get install -y bc; then
echo "Failed to install bc. Please install it manually and rerun the script."
exit 1
fi
fi
}
# 定义一个函数来测试镜像源的下载速度
test_speed() {
local source=$1
local image="linuxserver/freshrss" # 使用一个很小的镜像来测试速度
local start_time
# 拉取镜像前记录当前时间
start_time=$(date +%s.%N)
# 使用指定的镜像源拉取hello-world镜像
timeout 30 docker pull $source/$image > /dev/null 2>&1
# 拉取镜像后记录当前时间
local end_time=$(date +%s.%N)
# 计算下载时间(秒)
local download_time=$(echo "$end_time - $start_time" | bc -l)
echo "$download_time"
}
# 定义一个函数,用于等待一个进程在给定的时间内完成,否则返回超时
# wait_timeout() {
# local pid=$1
# local timeout=$2
# local kill_signal=TERM # 默认发送TERM信号
# # 使用timeout命令等待子进程结束,或者超时后发送信号
# timeout $timeout bash -c "while kill -0 $pid 2>/dev/null; do sleep 1; done" || kill -$kill_signal $pid
# wait $pid 2>/dev/null # 等待进程真正结束,忽略任何错误
# return $? # 返回子进程的退出状态
# }
# 定义一个函数来测试镜像源的下载速度
# test_speed() {
# local source=$1
# local image="xjxjin/alist-sync:1.0.1"
# local start_time
# local timeout_seconds=30
# # 拉取镜像前记录当前时间
# start_time=$(date +%s.%N)
# # 将docker pull放入后台运行
# docker pull "$source/$image" > /dev/null 2>&1 &
# local pull_pid=$! # 获取后台进程的PID
# # 等待docker pull完成或者超时
# if ! wait_timeout $pull_pid $timeout_seconds; then
# # 如果超时,则设置download_time为30秒(作为超时指示)
# local download_time=30
# echo "下载超时"
# else
# # 拉取镜像后记录当前时间
# local end_time=$(date +%s.%N)
# # 计算下载时间(秒)
# local download_time=$(echo "$end_time - $start_time" | bc -l)
# fi
# echo "$download_time"
# }
function ChooseMirrors() {
## 打印软件源列表
function PrintMirrorsList() {
local tmp_mirror_name tmp_mirror_url arr_num default_mirror_name_length tmp_mirror_name_length tmp_spaces_nums a i j
## 计算字符串长度
function StringLength() {
local text=$1
echo "${#text}"
}
echo -e ''
local list_arr=()
local list_arr_sum="$(eval echo ${#$1[@]})"
for ((a = 0; a < $list_arr_sum; a++)); do
list_arr[$a]="$(eval echo ${$1[a]})"
done
if [ -x /usr/bin/printf ]; then
for ((i = 0; i < ${#list_arr[@]}; i++)); do
tmp_mirror_name=$(echo "${list_arr[i]}" | awk -F '@' '{print$1}') # 软件源名称
# tmp_mirror_url=$(echo "${list_arr[i]}" | awk -F '@' '{print$2}') # 软件源地址
arr_num=$((i + 1))
default_mirror_name_length=${2:-"30"} # 默认软件源名称打印长度
## 补齐长度差异(中文的引号在等宽字体中占1格而非2格)
[[ $(echo "${tmp_mirror_name}" | grep -c "“") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "“")
[[ $(echo "${tmp_mirror_name}" | grep -c "”") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "”")
[[ $(echo "${tmp_mirror_name}" | grep -c "‘") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "‘")
[[ $(echo "${tmp_mirror_name}" | grep -c "’") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "’")
# 非一般字符长度
tmp_mirror_name_length=$(StringLength $(echo "${tmp_mirror_name}" | sed "s| ||g" | sed "s|[0-9a-zA-Z.=:_()'"-/!·]||g;"))
## 填充空格
tmp_spaces_nums=$(($(($default_mirror_name_length - ${tmp_mirror_name_length} - $(StringLength "${tmp_mirror_name}"))) / 2))
for ((j = 1; j <= ${tmp_spaces_nums}; j++)); do
tmp_mirror_name="${tmp_mirror_name} "
done
printf " ❖ %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s %4sn" "${tmp_mirror_name}" "$arr_num)"
done
else
for ((i = 0; i < ${#list_arr[@]}; i++)); do
tmp_mirror_name=$(echo "${list_arr[i]}" | awk -F '@' '{print$1}') # 软件源名称
tmp_mirror_url=$(echo "${list_arr[i]}" | awk -F '@' '{print$2}') # 软件源地址
arr_num=$((i + 1))
echo -e " ❖ $arr_num. ${tmp_mirror_url} | ${tmp_mirror_name}"
done
fi
}
function Title() {
local system_name="${SYSTEM_PRETTY_NAME:-"${SYSTEM_NAME} ${SYSTEM_VERSION_NUMBER}"}"
local arch=""${DEVICE_ARCH}""
local date="$(date "+%Y-%m-%d %H:%M:%S")"
local timezone="$(timedatectl status 2>/dev/null | grep "Time zone" | awk -F ':' '{print$2}' | awk -F ' ' '{print$1}')"
echo -e ''
echo -e " 运行环境 ${BLUE}${system_name} ${arch}${PLAIN}"
echo -e " 系统时间 ${BLUE}${date} ${timezone}${PLAIN}"
}
Title
local mirror_list_name
if [[ -z "${SOURCE_REGISTRY}" ]]; then
mirror_list_name="mirror_list_registry"
PrintMirrorsList "${mirror_list_name}" 44
local CHOICE_C=$(echo -e "n${BOLD}└─ 请选择并输入你想使用的 Docker Registry 源 [ 1-$(eval echo ${#$mirror_list_name[@]}) ]:${PLAIN}")
# 初始化一个数组来存储每个源的速度
declare -A speed_array
declare -A speed_index_array # 用来存储每个源在列表中的索引
local fastest_mirrors=()
# 测试每个源的速度并打印结果
echo -e "n${BOLD}测试中,请稍候...${PLAIN}"
local tmp_mirror_name tmp_mirror_url arr_num default_mirror_name_length tmp_mirror_name_length tmp_spaces_nums a i j
## 计算字符串长度
echo -e ''
local list_arr=()
local list_arr_sum="$(eval echo ${#${mirror_list_name}[@]})"
for ((a = 0; a < $list_arr_sum; a++)); do
list_arr[$a]="$(eval echo ${${mirror_list_name}[a]})"
done
if [ -x /usr/bin/printf ]; then
for ((i = 0; i < ${#list_arr[@]}; i++)); do
tmp_mirror_name=$(echo "${list_arr[i]}" | awk -F '@' '{print$1}') # 软件源名称
tmp_mirror_url=$(echo "${list_arr[i]}" | awk -F '@' '{print$2}') # 软件源地址
local speed=$(test_speed "$tmp_mirror_url")
speed_array[$tmp_mirror_name]=$speed
speed_index_array[$tmp_mirror_name]=$((i+1))
# local speed=$(test_speed "$tmp_mirror_url")
arr_num=$((i + 1))
default_mirror_name_length=${2:-"30"} # 默认软件源名称打印长度
## 补齐长度差异(中文的引号在等宽字体中占1格而非2格)
[[ $(echo "${tmp_mirror_name}" | grep -c "“") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "“")
[[ $(echo "${tmp_mirror_name}" | grep -c "”") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "”")
[[ $(echo "${tmp_mirror_name}" | grep -c "‘") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "‘")
[[ $(echo "${tmp_mirror_name}" | grep -c "’") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "’")
# 非一般字符长度
tmp_mirror_name_length=$(StringLength $(echo "${tmp_mirror_name}" | sed "s| ||g" | sed "s|[0-9a-zA-Z.=:_()'"-/!·]||g;"))
## 填充空格
tmp_spaces_nums=$(($(($default_mirror_name_length - ${tmp_mirror_name_length} - $(StringLength "${tmp_mirror_name}"))) / 2))
for ((j = 1; j <= ${tmp_spaces_nums}; j++)); do
tmp_mirror_name="${tmp_mirror_name} "
done
# speed_index_array[$tmp_mirror_name]=$((i+1)) # 存储源的id值
if (( $(echo "scale=1; $speed < 1" | bc -l) )); then
printf "源%2s %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s 下载速度: %s 秒n" "$arr_num" "${tmp_mirror_name}" "0${speed}"
# speed_index_array[$source]=$((i+1))
speed_index_array[$tmp_mirror_name]="$(printf "源%2s %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s n" "$arr_num" "${tmp_mirror_name}")"
else
speed_index_array[$tmp_mirror_name]="$(printf "源%2s %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s n" "$arr_num" "${tmp_mirror_name}")"
printf "源%2s %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s 下载速度: %s 秒n" "$arr_num" "${tmp_mirror_name}" "${speed}"
fi
done
else
for ((i = 0; i < ${#list_arr[@]}; i++)); do
tmp_mirror_name=$(echo "${list_arr[i]}" | awk -F '@' '{print$1}') # 软件源名称
tmp_mirror_url=$(echo "${list_arr[i]}" | awk -F '@' '{print$2}') # 软件源地址
arr_num=$((i + 1))
echo -e " ❖ $arr_num. ${tmp_mirror_url} | ${tmp_mirror_name}"
done
fi
# 使用sort命令的-k选项对速度和源的配对进行排序,-t选项定义字段分隔符为空格
# 注意:这里我们使用process substitution <(...)来避免使用临时文件
sorted_pairs=$(for source in "${!speed_array[@]}"; do echo "${speed_array[$source]} $source ${speed_index_array[$source]}"; done | sort -k1,1n -t' ' -s)
# 提取速度最小的三个源
local count=0
echo ""
echo "速度最快的三个源:"
while IFS=' ' read -r speed tmp_mirror_name arr_num && [[ $count -lt 3 ]]; do
default_mirror_name_length=${2:-"30"} # 默认软件源名称打印长度
## 补齐长度差异(中文的引号在等宽字体中占1格而非2格)
[[ $(echo "${tmp_mirror_name}" | grep -c "“") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "“")
[[ $(echo "${tmp_mirror_name}" | grep -c "”") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "”")
[[ $(echo "${tmp_mirror_name}" | grep -c "‘") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "‘")
[[ $(echo "${tmp_mirror_name}" | grep -c "’") -gt 0 ]] && let default_mirror_name_length+=$(echo "${tmp_mirror_name}" | grep -c "’")
# 非一般字符长度
tmp_mirror_name_length=$(StringLength $(echo "${tmp_mirror_name}" | sed "s| ||g" | sed "s|[0-9a-zA-Z.=:_()'"-/!·]||g;"))
## 填充空格
tmp_spaces_nums=$(($(($default_mirror_name_length - ${tmp_mirror_name_length} - $(StringLength "${tmp_mirror_name}"))) / 2))
for ((j = 1; j <= ${tmp_spaces_nums}; j++)); do
tmp_mirror_name="${tmp_mirror_name} "
done
if (( $(echo "scale=1; $speed < 1" | bc -l) )); then
printf "源%2s %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s ${RED}下载速度: %s${PLAIN} 秒n" "$arr_num" "${tmp_mirror_name}" "0${speed}"
else
printf "源%2s %-$(($default_mirror_name_length + ${tmp_mirror_name_length}))s ${RED}下载速度: %s${PLAIN} 秒n" "$arr_num" "${tmp_mirror_name}" "${speed}"
fi
((count++))
done <<< "$sorted_pairs"
while true; do
read -p "${CHOICE_C}" INPUT
case "${INPUT}" in
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
local tmp_source="$(eval echo ${${mirror_list_name}[$(($INPUT - 1))]})"
if [[ -z "${tmp_source}" ]]; then
echo -e "n$WARN 请输入有效的数字序号!"
else
SOURCE_REGISTRY="$(eval echo ${${mirror_list_name}[$(($INPUT - 1))]} | awk -F '@' '{print$2}')"
echo "${SOURCE_REGISTRY}"
# exit
break
fi
;;
*)
echo -e "n$WARN 请输入数字序号以选择你想使用的软件源!"
;;
esac
done
fi
}
## 关闭防火墙和SELinux
function CloseFirewall() {
if [ ! -x /usr/bin/systemctl ]; then
return
fi
if [[ "$(systemctl is-active firewalld)" == "active" ]]; then
if [[ -z "${CLOSE_FIREWALL}" ]]; then
local CHOICE
CHOICE=$(echo -e "n${BOLD}└─ 是否关闭防火墙和 SELinux ? [Y/n] ${PLAIN}")
read -rp "${CHOICE}" INPUT
[[ -z "${INPUT}" ]] && INPUT=Y
case "${INPUT}" in
[Yy] | [Yy][Ee][Ss])
CLOSE_FIREWALL="true"
;;
[Nn] | [Nn][Oo]) ;;
*)
echo -e "n$WARN 输入错误,默认不关闭!"
;;
esac
fi
if [[ "${CLOSE_FIREWALL}" == "true" ]]; then
local SelinuxConfig=/etc/selinux/config
systemctl disable --now firewalld >/dev/null 2>&1
[ -s $SelinuxConfig ] && sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" $SelinuxConfig && setenforce 0 >/dev/null 2>&1
fi
fi
}
## 安装 Docker Engine
function DockerEngine() {
## 修改 Docker Registry 源
function RegistryMirror() {
if [[ "${REGISTRY_SOURCEL}" != "registry.hub.docker.com" ]]; then
if [ -d $DockerDir ] && [ -e $DockerConfig ]; then
if [ -e $DockerConfigBackup ]; then
if [[ "${IGNORE_BACKUP_TIPS}" == "false" ]]; then
local CHOICE_BACKUP=$(echo -e "n${BOLD}└─ 检测到已备份的 Docker 配置文件,是否跳过覆盖备份? [Y/n] ${PLAIN}")
read -p "${CHOICE_BACKUP}" INPUT
[[ -z "${INPUT}" ]] && INPUT=Y
case $INPUT in
[Yy] | [Yy][Ee][Ss]) ;;
[Nn] | [Nn][Oo])
echo ''
cp -rvf $DockerConfig $DockerConfigBackup 2>&1
;;
*)
echo -e "n$WARN 输入错误,默认不覆盖!"
;;
esac
fi
else
cp -rvf $DockerConfig $DockerConfigBackup 2>&1
echo -e "n$COMPLETE 已备份原有 Docker 配置文件至 $DockerConfigBackupn"
fi
sleep 2s
else
mkdir -p $DockerDir >/dev/null 2>&1
touch $DockerConfig
fi
echo -e '{n "registry-mirrors": ["https://SOURCE"]n}' >$DockerConfig
sed -i "s|SOURCE|${SOURCE_REGISTRY}|g" $DockerConfig
systemctl daemon-reload
fi
}
RegistryMirror
systemctl stop docker >/dev/null 2>&1
systemctl enable --now docker >/dev/null 2>&1
}
## 重启Docker
function RestartDocker() {
# 询问用户是否需要重启Docker服务以应用配置更改
local CHOICE_BACKUP=$(echo -e "n${BOLD}└─ 是否重启Docker以使配置文件生效? [Y/n] ${PLAIN}")
read -p "${CHOICE_BACKUP}" INPUT
[[ -z "${INPUT}" ]] && INPUT=Y
case $INPUT in
[Yy]|[Yy][Ee][Ss])
echo ''
echo "重启Docker服务以应用配置更改..."
systemctl restart docker
echo "重启Docker服务完成"
;;
[Nn]|[Nn][Oo])
echo "Docker服务未重启。配置更改将不会立即生效。"
;;
*)
# echo "未知输入,Docker服务未重启。配置更改将不会立即生效。"
echo "Docker服务未重启。配置更改将不会立即生效。"
;;
esac
}
## 查看版本并验证安装结果
function CheckVersion() {
if [ -x /usr/bin/docker ]; then
echo -en "n验证安装版本:"
docker -v
VERIFICATION_DOCKER=$?
if [ ${VERIFICATION_DOCKER} -eq 0 ]; then
echo -e "n$COMPLETE 安装完成"
else
echo -e "n$ERROR 安装失败"
case "${SYSTEM_FACTIONS}" in
"${SYSTEM_DEBIAN}")
echo -e "n检查源文件:cat $Dir_DebianExtendSource/docker.list"
echo -e '请尝试手动执行安装命令: apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginn'
echo ''
;;
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}")
echo -e "n检查源文件:cat $Dir_YumRepos/docker.repo"
echo -e '请尝试手动执行安装命令: yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginn'
;;
esac
exit 1
fi
if [[ $(systemctl is-active docker) != "active" ]]; then
sleep 2
systemctl disable --now docker >/dev/null 2>&1
sleep 2
systemctl enable --now docker >/dev/null 2>&1
sleep 2
if [[ $(systemctl is-active docker) != "active" ]]; then
echo -e "n$ERROR 检测到 Docker 服务启动异常,可能由于重复安装导致"
echo -e "n${YELLOW} 请执行 "systemctl start docker" 或 "service docker start" 命令尝试启动,如若报错请尝试重新执行本脚本${PLAIN}"
fi
fi
else
echo -e "n$ERROR 安装失败n"
fi
}
## 运行结束
function RunEnd() {
echo -e "n ------ 脚本执行结束 ------"
# echo -e ' 33[0;1;35;95m┌─ 33[0;1;31;91m── 33[0;1;33;93m── 33[0;1;32;92m── 33[0;1;36;96m── 33[0;1;34;94m── 33[0;1;35;95m── 33[0;1;31;91m── 33[0;1;33;93m── 33[0;1;32;92m── 33[0;1;36;96m── 33[0;1;34;94m── 33[0;1;35;95m── 33[0;1;31;91m── 33[0;1;33;93m── 33[0;1;32;92m── 33[0;1;36;96m┐ 33[0m'
# echo -e ' 33[0;1;31;91m│▞ 33[0;1;33;93m▀▖ 33[0m 33[0;1;32;92m▙▗ 33[0;1;36;96m▌ 33[0m 33[0;1;31;91m▗ 33[0;1;33;93m▐ 33[0m 33[0;1;34;94m│ 33[0m'
# echo -e ' 33[0;1;33;93m│▚ 33[0;1;32;92m▄ 33[0m 33[0;1;36;96m▌ 33[0m 33[0;1;34;94m▌▛ 33[0;1;35;95m▀▖ 33[0;1;31;91m▞▀ 33[0;1;33;93m▖▙ 33[0;1;32;92m▀▖ 33[0;1;36;96m▌▘ 33[0;1;34;94m▌▝ 33[0;1;35;95m▀▖ 33[0;1;31;91m▛▀ 33[0;1;33;93m▖▄ 33[0;1;32;92m▜▀ 33[0m 33[0;1;36;96m▞ 33[0;1;34;94m▀▖ 33[0;1;35;95m│ 33[0m'
# echo -e ' 33[0;1;32;92m│▖ 33[0m 33[0;1;36;96m▌ 33[0;1;34;94m▌ 33[0m 33[0;1;35;95m▌▙ 33[0;1;31;91m▄▘ 33[0;1;33;93m▛▀ 33[0m 33[0;1;32;92m▌ 33[0m 33[0;1;34;94m▌ 33[0m 33[0;1;35;95m▌▞ 33[0;1;31;91m▀▌ 33[0;1;33;93m▌ 33[0m 33[0;1;32;92m▌▐ 33[0;1;36;96m▐ 33[0m 33[0;1;34;94m▖▌ 33[0m 33[0;1;35;95m▌ 33[0;1;31;91m│ 33[0m'
# echo -e ' 33[0;1;36;96m│▝ 33[0;1;34;94m▀ 33[0m 33[0;1;35;95m▝▀ 33[0;1;31;91m▘▌ 33[0m 33[0;1;32;92m▝▀ 33[0;1;36;96m▘▘ 33[0m 33[0;1;35;95m▘ 33[0m 33[0;1;31;91m▘▝ 33[0;1;33;93m▀▘ 33[0;1;32;92m▘ 33[0m 33[0;1;36;96m▘▀ 33[0;1;34;94m▘▀ 33[0m 33[0;1;35;95m▝ 33[0;1;31;91m▀ 33[0m 33[0;1;33;93m│ 33[0m'
# echo -e ' 33[0;1;34;94m└─ 33[0;1;35;95m── 33[0;1;31;91m── 33[0;1;33;93m── 33[0;1;32;92m── 33[0;1;36;96m── 33[0;1;34;94m── 33[0;1;35;95m── 33[0;1;31;91m── 33[0;1;33;93m── 33[0;1;32;92m── 33[0;1;36;96m── 33[0;1;34;94m── 33[0;1;35;95m── 33[0;1;31;91m── 33[0;1;33;93m── 33[0;1;32;92m┘ 33[0m'
# echo -e " 33[1;34mPowered by linuxmirrors.cn 33[0mn"
}
function PrintXJXJin() {
echo -e "n ------ xjxjin ------"
echo -e ' 33[0;1;35m┌─ 33[0;1;31m── 33[0;1;33m── 33[0;1;32m── 33[0;1;36m── 33[0;1;34m── 33[0;1;35m── 33[0;1;31m── 33[0;1;33m── 33[0;1;32m── 33[0;1;36m── 33[0;1;34m── 33[0;1;35m── 33[0;1;31m── 33[0;1;33m── 33[0;1;32m── 33[0m'
echo -e ' 33[0;1;31m│ 33[0;1;33m▓ 33[0m 33[0;1;32mX 33[0;1;36mj 33[0;1;34mx 33[0;1;35mJ 33[0;1;31mx 33[0;1;33m▓ 33[0m 33[0;1;34m│'
echo -e ' 33[0;1;33m│ 33[0;1;32mx 33[0;1;36mj 33[0;1;34mX 33[0;1;35mj 33[0;1;31mX 33[0;1;33mj 33[0;1;32mx 33[0m 33[0;1;36m▓ 33[0;1;34m│'
echo -e ' 33[0;1;32m│ 33[0;1;36m▓ 33[0m 33[0;1;34mX 33[0;1;35mj 33[0;1;31mX 33[0;1;33mj 33[0;1;32mX 33[0;1;36mj 33[0m 33[0;1;34m▓ 33[0m 33[0;1;32m│'
echo -e ' 33[0;1;36m│ 33[0;1;34m▓ 33[0m 33[0;1;35mX 33[0;1;31mj 33[0;1;33mX 33[0;1;32mj 33[0;1;36mX 33[0;1;34mj 33[0m 33[0;1;35m▓ 33[0m 33[0;1;36m│'
echo -e ' 33[0;1;34m└─ 33[0;1;35m── 33[0;1;31m── 33[0;1;33m── 33[0;1;32m── 33[0;1;36m── 33[0;1;34m── 33[0;1;35m── 33[0;1;31m── 33[0;1;33m── 33[0;1;32m── 33[0;1;36m── 33[0;1;34m── 33[0;1;35m── 33[0;1;31m── 33[0;1;33m── 33[0;1;32m── 33[0m'
echo -e " 33[1;34mPowered by linuxmirrors.cn 33[0mn"
}
## 处理命令选项
function CommandOptions() {
## 命令帮助
function Output_Help_Info() {
echo -e "
命令选项(参数名/含义/参数值):
--source 指定 Docker CE 源地址 地址
--source-registry 指定 Docker Registry 源地址 地址
--codename 指定 Debian 系操作系统的版本代号 代号名称
--install-latested 控制是否安装最新版本的 Docker Engine true 或 false
--ignore-backup-tips 忽略覆盖备份提示 无
问题报告 https://github.com/SuperManito/LinuxMirrors/issues
"
}
## 判断参数
while [ $# -gt 0 ]; do
case "$1" in
## 指定 Docker CE 软件源地址
--source)
if [ "$2" ]; then
echo "$2" | grep -Eq "(|)|[|]|{|}"
if [ $? -eq 0 ]; then
Output_Error "检测到无效参数值 ${BLUE}$2${PLAIN} ,请输入有效的地址!"
else
SOURCE="$(echo "$2" | sed -e 's,^http[s]?://,,g' -e 's,/$,,')"
shift
fi
else
Output_Error "检测到 ${BLUE}$1${PLAIN} 为无效参数,请在该参数后指定软件源地址!"
fi
;;
## 指定 Docker Registry 仓库地址
--source-registry)
if [ "$2" ]; then
echo "$2" | grep -Eq "(|)|[|]|{|}"
if [ $? -eq 0 ]; then
Output_Error "检测到无效参数值 ${BLUE}$2${PLAIN} ,请输入有效的地址!"
else
SOURCE_REGISTRY="$(echo "$2" | sed -e 's,^http[s]?://,,g' -e 's,/$,,')"
shift
fi
else
Output_Error "检测到 ${BLUE}$1${PLAIN} 为无效参数,请在该参数后指定软件源地址!"
fi
;;
## 指定 Debian 版本代号
--codename)
if [ "$2" ]; then
DEBIAN_CODENAME="$2"
shift
else
Output_Error "检测到 ${BLUE}$1${PLAIN} 为无效参数,请在该参数后指定版本代号!"
fi
;;
## 安装最新版本
--install-latested)
if [ "$2" ]; then
case "$2" in
[Tt]rue | [Ff]alse)
INSTALL_LATESTED_DOCKER="${2,,}"
shift
;;
*)
Output_Error "检测到 ${BLUE}$2${PLAIN} 为无效参数值,请在该参数后指定 true 或 false 作为参数值!"
;;
esac
else
Output_Error "检测到 ${BLUE}$1${PLAIN} 为无效参数,请在该参数后指定 true 或 false 作为参数值!"
fi
;;
## 忽略覆盖备份提示
--ignore-backup-tips)
IGNORE_BACKUP_TIPS="true"
;;
## 命令帮助
--help)
Output_Help_Info
exit
;;
*)
Output_Error "检测到 ${BLUE}$1${PLAIN} 为无效参数,请确认后重新输入!"
;;
esac
shift
done
## 给部分命令选项赋予默认值
IGNORE_BACKUP_TIPS="${IGNORE_BACKUP_TIPS:-"false"}"
}
## 组合函数
function Combin_Function() {
## 基础环境判断
PermissionJudgment
## 系统判定变量
# EnvJudgment
## 检查bc是否安装
CheckBc
## 欢迎使用 Docker Engine 一键安装脚本
StartTitle
## 打印软件源列表
ChooseMirrors
## 关闭防火墙和SELinux
CloseFirewall
## 安装 Docker Engine
DockerEngine
# 重启docker
RestartDocker
## 查看版本并验证安装结果
CheckVersion
## 运行结束
RunEnd
}
CommandOptions "$@"
Combin_Function
2.将其中的linuxserver/freshrss
更换为自己想要的docker项目名。
3.用shell链接工具比如finalshell连接自己的服务器。
4.终端中输入 bash <(curl -sSL 域名地址/ceshi.sh)
5.按步骤运行脚本就可以了,最后就可以在自己的docker中看到已经拉取成功的项目名,比如dockerhub.azk8s.cn/linuxserver/freshrss
类似这样的。
6.在脚本中找到是哪家的镜像地址,最后在终端中输入对应的数字最后重启docker就可以了。
结语
这种虽然很麻烦,但是是目前能够拉取镜像最快的方法了。
如果还不能解决问题,就去https://github.com/SuperManito/LinuxMirrors项目地址里找到最新的方法。
提示:本文最后更新于2024年 6月 6日,如有错误或者已经失效,请留言告知。
THE END