DockerProxy_Install.sh 126 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703
  1. #!/usr/bin/env bash
  2. #===============================================================================
  3. #
  4. # FILE: DockerProxy_Install.sh
  5. #
  6. # USAGE: ./DockerProxy_Install.sh
  7. #
  8. # DESCRIPTION: 自建Docker镜像加速服务,基于官方 registry 一键部署Docker、K8s、Quay、Ghcr、Nvcr镜像加速\管理服务.支持免服务器部署到Render.
  9. #
  10. # ORGANIZATION: DingQz dqzboy.com 浅时光博客
  11. #===============================================================================
  12. echo
  13. cat << EOF
  14. ██████╗ ██████╗ ██████╗██╗ ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗██╗ ██╗
  15. ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗ ██╔══██╗██╔══██╗██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝
  16. ██║ ██║██║ ██║██║ █████╔╝ █████╗ ██████╔╝ ██████╔╝██████╔╝██║ ██║ ╚███╔╝ ╚████╔╝
  17. ██║ ██║██║ ██║██║ ██╔═██╗ ██╔══╝ ██╔══██╗ ██╔═══╝ ██╔══██╗██║ ██║ ██╔██╗ ╚██╔╝
  18. ██████╔╝╚██████╔╝╚██████╗██║ ██╗███████╗██║ ██║ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗ ██║
  19. ╚═════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
  20. 博客: dqzboy.com 浅时光博客
  21. 项目地址: https://github.com/dqzboy/Docker-Proxy
  22. EOF
  23. echo "----------------------------------------------------------------------------------------------------------"
  24. echo -e "\033[32mVPS 推荐\033[0m(\033[34mRackNerd 高性价比便宜VPS\033[0m):\033[34;4m https://dqzboy.github.io/proxyui/racknerd \033[0m"
  25. echo "----------------------------------------------------------------------------------------------------------"
  26. echo
  27. echo
  28. GREEN="\033[0;32m"
  29. RED="\033[31m"
  30. YELLOW="\033[33m"
  31. RESET="\033[0m"
  32. BLUE="\033[0;34m"
  33. MAGENTA="\033[0;35m"
  34. CYAN="\033[0;36m"
  35. WHITE="\033[1;37m"
  36. BLACK="\033[0;30m"
  37. PINK="\033[0;95m"
  38. LIGHT_GREEN="\033[1;32m"
  39. LIGHT_RED="\033[1;31m"
  40. LIGHT_YELLOW="\033[1;33m"
  41. LIGHT_BLUE="\033[1;34m"
  42. LIGHT_MAGENTA="\033[1;35m"
  43. LIGHT_CYAN="\033[1;36m"
  44. LIGHT_PINK="\033[1;95m"
  45. BRIGHT_CYAN="\033[96m"
  46. BOLD="\033[1m"
  47. UNDERLINE="\033[4m"
  48. BLINK="\033[5m"
  49. REVERSE="\033[7m"
  50. INFO="[${GREEN}INFO${RESET}]"
  51. ERROR="[${RED}ERROR${RESET}]"
  52. WARN="[${YELLOW}WARN${RESET}]"
  53. function INFO() {
  54. echo -e "${INFO} ${1}"
  55. }
  56. function ERROR() {
  57. echo -e "${ERROR} ${1}"
  58. }
  59. function WARN() {
  60. echo -e "${WARN} ${1}"
  61. }
  62. function PROMPT_Y_N() {
  63. echo -e "[${LIGHT_GREEN}y${RESET}/${LIGHT_BLUE}n${RESET}]: "
  64. }
  65. PROMPT_YES_NO=$(PROMPT_Y_N)
  66. function SEPARATOR() {
  67. echo -e "${INFO}${BOLD}${LIGHT_BLUE}======================== ${1} ========================${RESET}"
  68. }
  69. SPINNER_CHARS=('⣾' '⣽' '⣻' '⢿' '⡿' '⣟' '⣯' '⣷')
  70. SPINNER_DELAY=0.1
  71. function cleanup() {
  72. trap - SIGINT SIGTERM
  73. stop_spinner
  74. echo
  75. exit 1
  76. }
  77. function start_spinner() {
  78. local msg="$1"
  79. local temp_dir="/tmp/spinner"
  80. local pid_file="${temp_dir}/pid"
  81. local msg_file="${temp_dir}/message"
  82. mkdir -p "$temp_dir"
  83. echo "$msg" > "$msg_file"
  84. trap cleanup SIGINT SIGTERM
  85. (
  86. trap 'exit 0' TERM
  87. local i=0
  88. while true; do
  89. if [ -f "$msg_file" ]; then
  90. msg=$(cat "$msg_file")
  91. printf "\r${LIGHT_BLUE}%s${RESET} ${LIGHT_YELLOW}%s${RESET} " "${SPINNER_CHARS[i]}" "$msg"
  92. i=$(( (i + 1) % ${#SPINNER_CHARS[@]} ))
  93. sleep $SPINNER_DELAY
  94. else
  95. exit 0
  96. fi
  97. done
  98. ) & disown
  99. echo $! > "$pid_file"
  100. }
  101. function stop_spinner() {
  102. local temp_dir="/tmp/spinner"
  103. local pid_file="${temp_dir}/pid"
  104. local msg_file="${temp_dir}/message"
  105. if [ -f "$pid_file" ]; then
  106. local spinner_pid=$(cat "$pid_file")
  107. rm -f "$msg_file"
  108. rm -f "$pid_file"
  109. kill -TERM "$spinner_pid" 2>/dev/null
  110. wait "$spinner_pid" 2>/dev/null
  111. printf "\r%-60s\r" " "
  112. echo -ne "\033[0m"
  113. fi
  114. rm -rf "$temp_dir" 2>/dev/null
  115. trap - SIGINT SIGTERM
  116. }
  117. # 检查是否以root权限运行
  118. if [[ $EUID -ne 0 ]]; then
  119. ERROR "此脚本必须以root权限运行!"
  120. exit 1
  121. fi
  122. PROXY_DIR="/data/registry-proxy"
  123. mkdir -p ${PROXY_DIR}
  124. cd "${PROXY_DIR}"
  125. GITRAW="https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main"
  126. CNGITRAW="https://gitee.com/boydqz/Docker-Proxy/raw/main"
  127. # docker registry
  128. IMAGE_NAME="dqzboy/registry"
  129. UI_IMAGE_NAME="dqzboy/docker-registry-ui"
  130. DOCKER_COMPOSE_FILE="docker-compose.yaml"
  131. # HubCMD-UI
  132. CMDUI_IMAGE_NAME="dqzboy/hubcmd-ui"
  133. CMDUI_COMPOSE_FILE="${GITRAW}/hubcmdui/${DOCKER_COMPOSE_FILE}"
  134. # Registry Domain prefix
  135. REGISTRY_SLD="ui、hub、gcr、ghcr、k8sgcr、k8s、quay、mcr、elastic、nvcr"
  136. RECORDS=("ui" "hub" "gcr" "ghcr" "k8sgcr" "k8s" "quay" "mcr" "elastic" "nvcr")
  137. attempts=0
  138. maxAttempts=3
  139. # registry services
  140. function REGISTRY_MENU() {
  141. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  142. echo -e "${GREEN}1)${RESET} ${BOLD}docker hub${RESET}"
  143. echo -e "${GREEN}2)${RESET} ${BOLD}gcr${RESET}"
  144. echo -e "${GREEN}3)${RESET} ${BOLD}ghcr${RESET}"
  145. echo -e "${GREEN}4)${RESET} ${BOLD}quay${RESET}"
  146. echo -e "${GREEN}5)${RESET} ${BOLD}k8s-gcr${RESET}"
  147. echo -e "${GREEN}6)${RESET} ${BOLD}k8s${RESET}"
  148. echo -e "${GREEN}7)${RESET} ${BOLD}mcr${RESET}"
  149. echo -e "${GREEN}8)${RESET} ${BOLD}elastic${RESET}"
  150. echo -e "${GREEN}9)${RESET} ${BOLD}nvcr${RESET}"
  151. echo -e "${GREEN}10)${RESET} ${BOLD}all${RESET}"
  152. echo -e "${GREEN}0)${RESET} ${BOLD}exit${RESET}"
  153. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  154. }
  155. function REGISTRY_SER_MENU() {
  156. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  157. echo -e "${GREEN}1)${RESET} ${BOLD}docker hub${RESET}"
  158. echo -e "${GREEN}2)${RESET} ${BOLD}gcr${RESET}"
  159. echo -e "${GREEN}3)${RESET} ${BOLD}ghcr${RESET}"
  160. echo -e "${GREEN}4)${RESET} ${BOLD}quay${RESET}"
  161. echo -e "${GREEN}5)${RESET} ${BOLD}k8s-gcr${RESET}"
  162. echo -e "${GREEN}6)${RESET} ${BOLD}k8s${RESET}"
  163. echo -e "${GREEN}7)${RESET} ${BOLD}mcr${RESET}"
  164. echo -e "${GREEN}8)${RESET} ${BOLD}elastic${RESET}"
  165. echo -e "${GREEN}9)${RESET} ${BOLD}nvcr${RESET}"
  166. echo -e "${GREEN}0)${RESET} ${BOLD}exit${RESET}"
  167. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  168. }
  169. # 定义Docker容器服务名称
  170. CONTAINER_SERVICES() {
  171. services=(
  172. "dockerhub"
  173. "gcr"
  174. "ghcr"
  175. "quay"
  176. "k8sgcr"
  177. "k8s"
  178. "mcr"
  179. "elastic"
  180. "nvcr"
  181. )
  182. }
  183. REGISTRY_FILES() {
  184. files=(
  185. "dockerhub registry-hub.yml"
  186. "gcr registry-gcr.yml"
  187. "ghcr registry-ghcr.yml"
  188. "quay registry-quay.yml"
  189. "k8sgcr registry-k8sgcr.yml"
  190. "k8s registry-k8s.yml"
  191. "mcr registry-mcr.yml"
  192. "elastic registry-elastic.yml"
  193. "nvcr registry-nvcr.yml"
  194. )
  195. }
  196. function CHECK_OS() {
  197. SEPARATOR "检查环境"
  198. OSVER=$(cat /etc/os-release | grep -o '[0-9]' | head -n 1)
  199. if [ -f /etc/os-release ]; then
  200. . /etc/os-release
  201. else
  202. echo "无法确定发行版"
  203. exit 1
  204. fi
  205. case "$ID" in
  206. "centos")
  207. repo_type="centos"
  208. ;;
  209. "debian")
  210. repo_type="debian"
  211. ;;
  212. "rhel")
  213. repo_type="rhel"
  214. ;;
  215. "ubuntu")
  216. repo_type="ubuntu"
  217. ;;
  218. "opencloudos")
  219. repo_type="centos"
  220. ;;
  221. "rocky")
  222. repo_type="centos"
  223. ;;
  224. *)
  225. WARN "此脚本目前不支持您的系统: $ID"
  226. exit 1
  227. ;;
  228. esac
  229. INFO "System release:: $NAME"
  230. INFO "System version: $VERSION"
  231. INFO "System ID: $ID"
  232. INFO "System ID Like: $ID_LIKE"
  233. }
  234. function CHECK_PACKAGE_MANAGER() {
  235. if command -v dnf &> /dev/null; then
  236. package_manager="dnf"
  237. elif command -v yum &> /dev/null; then
  238. package_manager="yum"
  239. elif command -v apt &> /dev/null; then
  240. package_manager="apt"
  241. elif command -v apt-get &> /dev/null; then
  242. package_manager="apt-get"
  243. else
  244. ERROR "不受支持的软件包管理器."
  245. exit 1
  246. fi
  247. }
  248. function CHECK_PKG_MANAGER() {
  249. if command -v rpm &> /dev/null; then
  250. pkg_manager="rpm"
  251. elif command -v dpkg &> /dev/null; then
  252. pkg_manager="dpkg"
  253. elif command -v apt &> /dev/null; then
  254. pkg_manager="apt"
  255. else
  256. ERROR "无法确定包管理系统."
  257. exit 1
  258. fi
  259. }
  260. function CHECK_COMPOSE_CMD() {
  261. if command -v docker &> /dev/null && docker compose version &> /dev/null; then
  262. DOCKER_COMPOSE_CMD="docker compose"
  263. elif command -v docker-compose &> /dev/null; then
  264. DOCKER_COMPOSE_CMD="docker-compose"
  265. else
  266. WARN "未检查到Docker Compose客户端工具,请通过脚本安装部署!"
  267. fi
  268. }
  269. function CHECKMEM() {
  270. memory_usage=$(free | awk '/^Mem:/ {printf "%.2f", $3/$2 * 100}')
  271. memory_usage=${memory_usage%.*}
  272. if [[ $memory_usage -gt 90 ]]; then
  273. read -e -p "$(WARN "内存占用率${LIGHT_RED}高于 70%($memory_usage%)${RESET} 是否继续安装? ${PROMPT_YES_NO}")" continu
  274. if [ "$continu" == "n" ] || [ "$continu" == "N" ]; then
  275. exit 1
  276. fi
  277. else
  278. INFO "内存资源充足.请继续 ${LIGHT_GREEN}($memory_usage%)${RESET}"
  279. fi
  280. }
  281. function CHECKFIRE() {
  282. systemctl stop firewalld &> /dev/null
  283. systemctl disable firewalld &> /dev/null
  284. systemctl stop iptables &> /dev/null
  285. systemctl disable iptables &> /dev/null
  286. ufw disable &> /dev/null
  287. systemctl disable ufw &> /dev/null
  288. WARN "服务器防火墙已被禁用."
  289. if [[ "$repo_type" == "centos" || "$repo_type" == "rhel" ]]; then
  290. if sestatus | grep "SELinux status" | grep -q "enabled"; then
  291. INFO "SELinux 已启用。禁用 SELinux..."
  292. setenforce 0
  293. sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
  294. WARN "SELinux 已被禁用."
  295. else
  296. WARN "SELinux 已被禁用."
  297. fi
  298. fi
  299. }
  300. function CHECKBBR() {
  301. kernel_version=$(uname -r | awk -F "-" '{print $1}')
  302. read -e -p "$(WARN "是否开启${BRIGHT_CYAN}BBR${RESET},优化网络带宽提高网络性能? ${PROMPT_YES_NO}")" choice_bbr
  303. case $choice_bbr in
  304. y | Y)
  305. version_compare=$(echo "${kernel_version} 4.9" | awk '{if ($1 >= $2) print "yes"; else print "no"}')
  306. if [ "$version_compare" != "yes" ]; then
  307. WARN "你的内核版本小于4.9,无法启动BBR,需要你手动升级内核"
  308. exit 0
  309. fi
  310. sysctl net.ipv4.tcp_available_congestion_control | grep -q "bbr"
  311. if [ $? -eq 0 ]; then
  312. INFO "你的服务器已经启动 ${BRIGHT_CYAN}BBR${RESET}"
  313. else
  314. INFO "开启BBR中..."
  315. modprobe tcp_bbr
  316. if [ $? -eq 0 ]; then
  317. INFO "${BRIGHT_CYAN}BBR${RESET} 模块${LIGHT_GREEN}添加成功${RESET}"
  318. else
  319. ERROR "${BRIGHT_CYAN}BBR${RESET} 模块${LIGHT_RED}添加失败${RESET},请执行 ${LIGHT_CYAN}sysctl -p${RESET} 检查."
  320. exit 1
  321. fi
  322. if [ ! -d /etc/modules-load.d/ ]; then
  323. mkdir -p /etc/modules-load.d/
  324. fi
  325. if [ ! -f /etc/modules-load.d/tcp_bbr.conf ]; then
  326. touch /etc/modules-load.d/tcp_bbr.conf
  327. fi
  328. if ! grep -q "tcp_bbr" /etc/modules-load.d/tcp_bbr.conf ; then
  329. echo 'tcp_bbr' >> /etc/modules-load.d/tcp_bbr.conf
  330. fi
  331. for setting in "net.core.default_qdisc=fq" "net.ipv4.tcp_congestion_control=bbr"; do
  332. if ! grep -q "$setting" /etc/sysctl.conf; then
  333. echo "$setting" >> /etc/sysctl.conf
  334. fi
  335. done
  336. sysctl -p &> /dev/null
  337. if [ $? -ne 0 ]; then
  338. ERROR "应用sysctl设置过程中发生了一个错误,请执行 ${LIGHT_CYAN}sysctl -p${RESET} 检查."
  339. exit 2
  340. fi
  341. lsmod | grep tcp_bbr &> /dev/null
  342. if [ $? -eq 0 ]; then
  343. INFO "${BRIGHT_CYAN}BBR${RESET} 已经${LIGHT_GREEN}成功开启${RESET}"
  344. else
  345. ERROR "${BRIGHT_CYAN}BBR${RESET} 开启${LIGHT_RED}失败${RESET},请执行 ${LIGHT_CYAN}sysctl -p${RESET} 检查."
  346. exit 3
  347. fi
  348. WARN "如果 ${BRIGHT_CYAN}BBR${RESET} 开启后${LIGHT_YELLOW}未生效${RESET},请执行 ${LIGHT_BLUE}reboot${RESET} 重启服务器使其BBR模块生效"
  349. fi
  350. ;;
  351. n | N)
  352. INFO "不开启BBR"
  353. ;;
  354. *)
  355. WARN "输入了无效的选择。请重新输入${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  356. CHECKBBR
  357. ;;
  358. esac
  359. }
  360. function INSTALL_PACKAGE(){
  361. SEPARATOR "安装依赖"
  362. INFO "检查依赖安装情况,请稍等 ..."
  363. TIMEOUT=300
  364. PACKAGES_APT=(
  365. lsof jq wget apache2-utils tar
  366. )
  367. PACKAGES_YUM=(
  368. epel-release lsof jq wget yum-utils httpd-tools tar
  369. )
  370. if [ "$package_manager" = "dnf" ] || [ "$package_manager" = "yum" ]; then
  371. for package in "${PACKAGES_YUM[@]}"; do
  372. if $pkg_manager -q "$package" &>/dev/null; then
  373. INFO "${LIGHT_GREEN}已经安装${RESET} $package ..."
  374. else
  375. INFO "${LIGHT_CYAN}正在安装${RESET} $package ..."
  376. start_spinner "安装 $package 中..."
  377. start_time=$(date +%s)
  378. $package_manager -y install "$package" --skip-broken > /dev/null 2>&1
  379. install_status=$?
  380. stop_spinner
  381. if [ $install_status -ne 0 ]; then
  382. ERROR "$package 安装失败。请检查系统安装源,然后再次运行此脚本!请尝试手动执行安装: ${LIGHT_BLUE}$package_manager -y install $package${RESET}"
  383. exit 1
  384. fi
  385. fi
  386. done
  387. elif [ "$package_manager" = "apt" ] || [ "$package_manager" = "apt-get" ];then
  388. start_spinner "正在检查依赖安装情况..."
  389. dpkg --configure -a &>/dev/null
  390. $package_manager -y update &>/dev/null
  391. stop_spinner
  392. for package in "${PACKAGES_APT[@]}"; do
  393. if $pkg_manager -s "$package" &>/dev/null; then
  394. INFO "已经安装 $package ..."
  395. else
  396. INFO "正在安装 $package ..."
  397. start_spinner "安装 $package 中..."
  398. $package_manager install -y $package > /dev/null 2>&1
  399. install_status=$?
  400. stop_spinner
  401. if [ $install_status -ne 0 ]; then
  402. ERROR "安装 $package 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装: ${LIGHT_BLUE}$package_manager -y install $package${RESET}"
  403. exit 1
  404. fi
  405. fi
  406. done
  407. else
  408. ERROR "无法确定包管理系统,脚本无法继续执行,请检查!"
  409. exit 1
  410. fi
  411. }
  412. function INSTALL_CADDY() {
  413. SEPARATOR "安装Caddy"
  414. start_caddy() {
  415. systemctl enable caddy.service &>/dev/null
  416. systemctl restart caddy.service
  417. status=$(systemctl is-active caddy)
  418. if [ "$status" = "active" ]; then
  419. INFO "Caddy 服务运行正常,请继续..."
  420. else
  421. ERROR "Caddy 服务未运行,请查看日志报错,定位问题后再次执行脚本!"
  422. ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------"
  423. journalctl -u caddy.service --no-pager
  424. ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------"
  425. exit 1
  426. fi
  427. }
  428. check_caddy() {
  429. if pgrep "caddy" > /dev/null; then
  430. INFO "Caddy 已在运行."
  431. else
  432. WARN "Caddy 未运行。尝试启动 Caddy..."
  433. start_attempts=3
  434. for ((i=1; i<=$start_attempts; i++)); do
  435. start_caddy
  436. if pgrep "caddy" > /dev/null; then
  437. INFO "Caddy 已成功启动."
  438. break
  439. else
  440. if [ $i -eq $start_attempts ]; then
  441. ERROR "Caddy 在尝试 $start_attempts 后无法启动。请检查配置"
  442. exit 1
  443. else
  444. WARN "在 $i 时间内启动 Caddy 失败。重试..."
  445. fi
  446. fi
  447. done
  448. fi
  449. }
  450. if [ "$package_manager" = "dnf" ]; then
  451. if which caddy &>/dev/null; then
  452. INFO "Caddy 已经安装."
  453. else
  454. INFO "正在安装Caddy程序,请稍候..."
  455. start_spinner "安装Caddy中..."
  456. $package_manager -y install 'dnf-command(copr)' &>/dev/null
  457. $package_manager -y copr enable @caddy/caddy &>/dev/null
  458. stop_spinner
  459. while [ $attempts -lt $maxAttempts ]; do
  460. start_spinner "安装Caddy服务..."
  461. $package_manager -y install caddy &>/dev/null
  462. stop_spinner
  463. if [ $? -ne 0 ]; then
  464. ((attempts++))
  465. WARN "正在尝试安装Caddy >>> (Attempt: $attempts)"
  466. if [ $attempts -eq $maxAttempts ]; then
  467. ERROR "Caddy installation failed. Please try installing manually."
  468. echo "命令: $package_manager -y install 'dnf-command(copr)' && $package_manager -y copr enable @caddy/caddy && $package_manager -y install caddy"
  469. exit 1
  470. fi
  471. else
  472. INFO "检测到服务 Caddy 已安装"
  473. break
  474. fi
  475. done
  476. fi
  477. check_caddy
  478. elif [ "$package_manager" = "yum" ]; then
  479. if which caddy &>/dev/null; then
  480. INFO "Caddy 已经安装."
  481. else
  482. INFO "正在安装Caddy程序,请稍候..."
  483. start_spinner "安装Caddy中..."
  484. $package_manager -y install yum-plugin-copr &>/dev/null
  485. $package_manager -y copr enable @caddy/caddy &>/dev/null
  486. stop_spinner
  487. while [ $attempts -lt $maxAttempts ]; do
  488. start_spinner "安装Caddy服务..."
  489. $package_manager -y install caddy &>/dev/null
  490. stop_spinner
  491. if [ $? -ne 0 ]; then
  492. ((attempts++))
  493. WARN "正在尝试安装Caddy >>> (Attempt: $attempts)"
  494. if [ $attempts -eq $maxAttempts ]; then
  495. ERROR "Caddy installation failed. Please try installing manually."
  496. echo "命令: $package_manager -y install 'dnf-command(copr)' && $package_manager -y copr enable @caddy/caddy && $package_manager -y install caddy"
  497. exit 1
  498. fi
  499. else
  500. INFO "检测到服务 Caddy 已安装"
  501. break
  502. fi
  503. done
  504. fi
  505. check_caddy
  506. elif [ "$package_manager" = "apt" ] || [ "$package_manager" = "apt-get" ];then
  507. dpkg --configure -a &>/dev/null
  508. if $pkg_manager -s "caddy" &>/dev/null; then
  509. INFO "检测到服务 Caddy 已安装,跳过..."
  510. else
  511. INFO "安装 Caddy 请稍等 ..."
  512. start_spinner "安装Caddy中..."
  513. $package_manager -y update &>/dev/null
  514. $package_manager install -y debian-keyring debian-archive-keyring apt-transport-https &>/dev/null
  515. curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg &>/dev/null
  516. curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list &>/dev/null
  517. $package_manager -y update &>/dev/null
  518. $package_manager install -y caddy &>/dev/null
  519. stop_spinner
  520. while [ $attempts -lt $maxAttempts ]; do
  521. start_spinner "安装Caddy服务..."
  522. $package_manager -y install caddy &>/dev/null
  523. stop_spinner
  524. if [ $? -ne 0 ]; then
  525. ((attempts++))
  526. WARN "正在尝试安装Caddy >>> (Attempt: $attempts)"
  527. if [ $attempts -eq $maxAttempts ]; then
  528. ERROR "Caddy installation failed. Please try installing manually."
  529. echo "命令: $package_manager -y install update && $package_manager -y install caddy"
  530. exit 1
  531. fi
  532. else
  533. INFO "检测到服务 Caddy 已安装"
  534. break
  535. fi
  536. done
  537. fi
  538. check_caddy
  539. else
  540. WARN "无法确定包管理系统."
  541. exit 1
  542. fi
  543. }
  544. function CONFIG_CADDY() {
  545. SEPARATOR "配置Caddy"
  546. while true; do
  547. INFO "${LIGHT_GREEN}>>> 域名解析主机记录(即域名前缀):${RESET} ${LIGHT_CYAN}${REGISTRY_SLD}${RESET}"
  548. WARN "${LIGHT_GREEN}>>> 只需选择你部署的服务进行解析即可${RESET},${LIGHT_YELLOW}无需将上面提示中所有的主机记录进行解析${RESET}"
  549. read -e -p "$(WARN "是否配置Caddy,实现自动HTTPS? 执行前需在DNS服务商对部署服务解析主机记录 ${PROMPT_YES_NO}")" caddy_conf
  550. case "$caddy_conf" in
  551. y|Y )
  552. read -e -p "$(INFO "请输入你的域名${LIGHT_BLUE}[例: baidu.com]${RESET} ${LIGHT_RED}不可为空${RESET}: ")" caddy_domain
  553. read -e -p "$(INFO "请输入要配置的${LIGHT_MAGENTA}主机记录${RESET},用逗号分隔${LIGHT_BLUE}[例: ui,hub]${RESET}: ")" selected_records
  554. # 验证输入的主机记录
  555. local valid_records=("${RECORDS[@]}")
  556. IFS=',' read -r -a records_array <<< "$selected_records"
  557. local invalid_records=()
  558. for record in "${records_array[@]}"; do
  559. if ! [[ " ${valid_records[@]} " =~ " ${record} " ]]; then
  560. invalid_records+=("$record")
  561. fi
  562. done
  563. if [[ ${#invalid_records[@]} -gt 0 ]]; then
  564. ERROR "无效的主机记录: ${LIGHT_RED}${invalid_records[@]}${RESET}"
  565. INFO "请输入有效的主机记录: ${LIGHT_GREEN}${REGISTRY_SLD}${RESET}"
  566. continue
  567. fi
  568. declare -A record_templates
  569. record_templates[ui]="ui.$caddy_domain {
  570. reverse_proxy localhost:50000 {
  571. header_up Host {host}
  572. header_up Origin {scheme}://{host}
  573. header_up X-Forwarded-For {remote_addr}
  574. header_up X-Forwarded-Proto {scheme}
  575. header_up X-Forwarded-Ssl on
  576. header_up X-Forwarded-Port {server_port}
  577. header_up X-Forwarded-Host {host}
  578. }
  579. }"
  580. record_templates[hub]="hub.$caddy_domain {
  581. reverse_proxy localhost:51000 {
  582. header_up Host {host}
  583. header_up X-Real-IP {remote_addr}
  584. header_up X-Forwarded-For {remote_addr}
  585. header_up X-Nginx-Proxy true
  586. }
  587. }"
  588. record_templates[ghcr]="ghcr.$caddy_domain {
  589. reverse_proxy localhost:52000 {
  590. header_up Host {host}
  591. header_up X-Real-IP {remote_addr}
  592. header_up X-Forwarded-For {remote_addr}
  593. header_up X-Nginx-Proxy true
  594. }
  595. }"
  596. record_templates[gcr]="gcr.$caddy_domain {
  597. reverse_proxy localhost:53000 {
  598. header_up Host {host}
  599. header_up X-Real-IP {remote_addr}
  600. header_up X-Forwarded-For {remote_addr}
  601. header_up X-Nginx-Proxy true
  602. }
  603. }"
  604. record_templates[k8sgcr]="k8sgcr.$caddy_domain {
  605. reverse_proxy localhost:54000 {
  606. header_up Host {host}
  607. header_up X-Real-IP {remote_addr}
  608. header_up X-Forwarded-For {remote_addr}
  609. header_up X-Nginx-Proxy true
  610. }
  611. }"
  612. record_templates[k8s]="k8s.$caddy_domain {
  613. reverse_proxy localhost:55000 {
  614. header_up Host {host}
  615. header_up X-Real-IP {remote_addr}
  616. header_up X-Forwarded-For {remote_addr}
  617. header_up X-Nginx-Proxy true
  618. }
  619. }"
  620. record_templates[quay]="quay.$caddy_domain {
  621. reverse_proxy localhost:56000 {
  622. header_up Host {host}
  623. header_up X-Real-IP {remote_addr}
  624. header_up X-Forwarded-For {remote_addr}
  625. header_up X-Nginx-Proxy true
  626. }
  627. }"
  628. record_templates[mcr]="mcr.$caddy_domain {
  629. reverse_proxy localhost:57000 {
  630. header_up Host {host}
  631. header_up X-Real-IP {remote_addr}
  632. header_up X-Forwarded-For {remote_addr}
  633. header_up X-Nginx-Proxy true
  634. }
  635. }"
  636. record_templates[elastic]="elastic.$caddy_domain {
  637. reverse_proxy localhost:58000 {
  638. header_up Host {host}
  639. header_up X-Real-IP {remote_addr}
  640. header_up X-Forwarded-For {remote_addr}
  641. header_up X-Nginx-Proxy true
  642. }
  643. }"
  644. record_templates[nvcr]="nvcr.$caddy_domain {
  645. reverse_proxy localhost:59000 {
  646. header_up Host {host}
  647. header_up X-Real-IP {remote_addr}
  648. header_up X-Forwarded-For {remote_addr}
  649. header_up X-Nginx-Proxy true
  650. }
  651. }"
  652. > /etc/caddy/Caddyfile
  653. for record in "${records_array[@]}"; do
  654. if [[ -n "${record_templates[$record]}" ]]; then
  655. echo "${record_templates[$record]}" >> /etc/caddy/Caddyfile
  656. fi
  657. done
  658. start_attempts=3
  659. for ((i=1; i<=$start_attempts; i++)); do
  660. start_caddy
  661. if pgrep "caddy" > /dev/null; then
  662. INFO "重新载入配置成功. Caddy服务启动完成"
  663. break
  664. else
  665. if [ $i -eq $start_attempts ]; then
  666. ERROR "Caddy 在尝试 $start_attempts 后无法启动。请检查配置"
  667. exit 1
  668. else
  669. WARN "第 $i 次启动 Caddy 失败。重试..."
  670. fi
  671. fi
  672. done
  673. break;;
  674. n|N )
  675. WARN "退出配置 Caddy 操作。"
  676. break;;
  677. * )
  678. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  679. esac
  680. done
  681. }
  682. function INSTALL_NGINX() {
  683. SEPARATOR "安装Nginx"
  684. start_nginx() {
  685. systemctl enable nginx &>/dev/null
  686. systemctl restart nginx
  687. status=$(systemctl is-active nginx)
  688. if [ "$status" = "active" ]; then
  689. INFO "Nginx 服务运行正常,请继续..."
  690. else
  691. ERROR "Nginx 服务未运行,请查看日志报错,定位问题后再次执行脚本!"
  692. ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------"
  693. journalctl -u nginx.service --no-pager
  694. ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------"
  695. exit 1
  696. fi
  697. }
  698. check_nginx() {
  699. if pgrep "nginx" > /dev/null; then
  700. INFO "Nginx 已在运行."
  701. else
  702. WARN "Nginx 未运行。尝试启动 Nginx..."
  703. start_attempts=3
  704. for ((i=1; i<=$start_attempts; i++)); do
  705. start_nginx
  706. if pgrep "nginx" > /dev/null; then
  707. INFO "Nginx 已成功启动."
  708. break
  709. else
  710. if [ $i -eq $start_attempts ]; then
  711. ERROR "Nginx 在尝试 $start_attempts 次后无法启动。请检查配置"
  712. exit 1
  713. else
  714. WARN "第 $i 次启动 Nginx 失败。重试..."
  715. fi
  716. fi
  717. done
  718. fi
  719. }
  720. if [ "$package_manager" = "dnf" ] || [ "$package_manager" = "yum" ]; then
  721. if which nginx &>/dev/null; then
  722. INFO "Nginx 已经安装."
  723. else
  724. INFO "正在安装Nginx程序,请稍候..."
  725. NGINX="nginx-1.24.0-1.el${OSVER}.ngx.x86_64.rpm"
  726. start_spinner "下载Nginx安装包..."
  727. rm -f ${NGINX}
  728. wget http://nginx.org/packages/centos/${OSVER}/x86_64/RPMS/${NGINX} &>/dev/null
  729. stop_spinner
  730. while [ $attempts -lt $maxAttempts ]; do
  731. start_spinner "安装Nginx服务..."
  732. $package_manager -y install ${NGINX} &>/dev/null
  733. stop_spinner
  734. if [ $? -ne 0 ]; then
  735. ((attempts++))
  736. WARN "正在尝试安装Nginx >>> (Attempt: $attempts)"
  737. if [ $attempts -eq $maxAttempts ]; then
  738. ERROR "Nginx installation failed. Please try installing manually."
  739. rm -f ${NGINX}
  740. echo "命令: wget http://nginx.org/packages/centos/${OSVER}/x86_64/RPMS/${NGINX} && $package_manager -y install ${NGINX}"
  741. exit 1
  742. fi
  743. else
  744. INFO "检测到服务 Nginx 已安装"
  745. rm -f ${NGINX}
  746. break
  747. fi
  748. done
  749. fi
  750. check_nginx
  751. elif [ "$package_manager" = "apt" ] || [ "$package_manager" = "apt-get" ];then
  752. dpkg --configure -a &>/dev/null
  753. if $pkg_manager -s "nginx" &>/dev/null; then
  754. INFO "检测到服务 Nginx 已安装,跳过..."
  755. else
  756. INFO "安装 Nginx 请稍等 ..."
  757. while [ $attempts -lt $maxAttempts ]; do
  758. start_spinner "安装Nginx服务..."
  759. $package_manager -y update &>/dev/null
  760. $package_manager install -y nginx > /dev/null 2>&1
  761. stop_spinner
  762. if [ $? -ne 0 ]; then
  763. ((attempts++))
  764. WARN "正在尝试安装Nginx >>> (Attempt: $attempts)"
  765. if [ $attempts -eq $maxAttempts ]; then
  766. ERROR "Nginx installation failed. Please try installing manually."
  767. echo "命令: $package_manager install -y nginx"
  768. exit 1
  769. fi
  770. else
  771. INFO "检测到服务 Nginx 已安装"
  772. break
  773. fi
  774. done
  775. fi
  776. check_nginx
  777. else
  778. WARN "无法确定包管理系统."
  779. exit 1
  780. fi
  781. }
  782. function CONFIG_NGINX() {
  783. SEPARATOR "配置Nginx"
  784. while true; do
  785. WARN "自行安装的 Nginx ${LIGHT_RED}请谨慎执行此操作${RESET},${LIGHT_BLUE}以防覆盖原有配置${RESET}"
  786. INFO "${LIGHT_GREEN}>>> 域名解析主机记录(即域名前缀):${RESET} ${LIGHT_CYAN}${REGISTRY_SLD}${RESET}"
  787. WARN "${LIGHT_GREEN}>>> 只需选择你部署的服务进行解析即可${RESET},${LIGHT_YELLOW}无需将上面提示中所有的主机记录进行解析${RESET}"
  788. read -e -p "$(WARN "是否配置 Nginx?配置完成后需在DNS服务商解析主机记录 ${PROMPT_YES_NO}")" nginx_conf
  789. case "$nginx_conf" in
  790. y|Y )
  791. read -e -p "$(INFO "请输入你的域名${LIGHT_BLUE}[例: baidu.com]${RESET} ${LIGHT_RED}不可为空${RESET}: ")" nginx_domain
  792. read -e -p "$(INFO "请输入要配置的${LIGHT_MAGENTA}主机记录${RESET},用逗号分隔${LIGHT_BLUE}[例: ui,hub]${RESET}: ")" selected_records
  793. # 验证输入的主机记录
  794. local valid_records=("${RECORDS[@]}")
  795. IFS=',' read -r -a records_array <<< "$selected_records"
  796. local invalid_records=()
  797. for record in "${records_array[@]}"; do
  798. if ! [[ " ${valid_records[@]} " =~ " ${record} " ]]; then
  799. invalid_records+=("$record")
  800. fi
  801. done
  802. if [[ ${#invalid_records[@]} -gt 0 ]]; then
  803. ERROR "无效的主机记录: ${LIGHT_RED}${invalid_records[@]}${RESET}"
  804. INFO "请输入有效的主机记录: ${LIGHT_GREEN}${REGISTRY_SLD}${RESET}"
  805. continue
  806. fi
  807. declare -A record_templates
  808. record_templates[ui]="server {
  809. listen 80;
  810. #listen 443 ssl;
  811. server_name ui.$nginx_domain;
  812. #ssl_certificate /path/to/your_domain_name.crt;
  813. #ssl_certificate_key /path/to/your_domain_name.key;
  814. #ssl_session_timeout 1d;
  815. #ssl_session_cache shared:SSL:50m;
  816. #ssl_session_tickets off;
  817. #ssl_protocols TLSv1.2 TLSv1.3;
  818. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  819. #ssl_prefer_server_ciphers on;
  820. #ssl_buffer_size 8k;
  821. proxy_connect_timeout 600;
  822. proxy_send_timeout 600;
  823. proxy_read_timeout 600;
  824. send_timeout 600;
  825. location / {
  826. proxy_pass http://localhost:50000;
  827. proxy_set_header Host \$host;
  828. proxy_set_header Origin \$scheme://\$host;
  829. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  830. proxy_set_header X-Forwarded-Proto \$scheme;
  831. proxy_set_header X-Forwarded-Ssl on;
  832. proxy_set_header X-Forwarded-Port \$server_port;
  833. proxy_set_header X-Forwarded-Host \$host;
  834. }
  835. }"
  836. record_templates[hub]="server {
  837. listen 80;
  838. #listen 443 ssl;
  839. server_name hub.$nginx_domain;
  840. #ssl_certificate /path/to/your_domain_name.crt;
  841. #ssl_certificate_key /path/to/your_domain_name.key;
  842. #ssl_session_timeout 1d;
  843. #ssl_session_cache shared:SSL:50m;
  844. #ssl_session_tickets off;
  845. #ssl_protocols TLSv1.2 TLSv1.3;
  846. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  847. #ssl_prefer_server_ciphers on;
  848. #ssl_buffer_size 8k;
  849. proxy_connect_timeout 600;
  850. proxy_send_timeout 600;
  851. proxy_read_timeout 600;
  852. send_timeout 600;
  853. location / {
  854. proxy_pass http://localhost:51000;
  855. proxy_set_header Host \$host;
  856. proxy_set_header X-Real-IP \$remote_addr;
  857. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  858. proxy_set_header X-Nginx-Proxy true;
  859. proxy_buffering off;
  860. proxy_redirect off;
  861. }
  862. }"
  863. record_templates[ghcr]="server {
  864. listen 80;
  865. #listen 443 ssl;
  866. server_name ghcr.$nginx_domain;
  867. #ssl_certificate /path/to/your_domain_name.crt;
  868. #ssl_certificate_key /path/to/your_domain_name.key;
  869. #ssl_session_timeout 1d;
  870. #ssl_session_cache shared:SSL:50m;
  871. #ssl_session_tickets off;
  872. #ssl_protocols TLSv1.2 TLSv1.3;
  873. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  874. #ssl_prefer_server_ciphers on;
  875. #ssl_buffer_size 8k;
  876. proxy_connect_timeout 600;
  877. proxy_send_timeout 600;
  878. proxy_read_timeout 600;
  879. send_timeout 600;
  880. location / {
  881. proxy_pass http://localhost:52000;
  882. proxy_set_header Host \$host;
  883. proxy_set_header X-Real-IP \$remote_addr;
  884. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  885. proxy_set_header X-Nginx-Proxy true;
  886. proxy_buffering off;
  887. proxy_redirect off;
  888. }
  889. }"
  890. record_templates[gcr]="server {
  891. listen 80;
  892. #listen 443 ssl;
  893. server_name gcr.$nginx_domain;
  894. #ssl_certificate /path/to/your_domain_name.crt;
  895. #ssl_certificate_key /path/to/your_domain_name.key;
  896. #ssl_session_timeout 1d;
  897. #ssl_session_cache shared:SSL:50m;
  898. #ssl_session_tickets off;
  899. #ssl_protocols TLSv1.2 TLSv1.3;
  900. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  901. #ssl_prefer_server_ciphers on;
  902. #ssl_buffer_size 8k;
  903. proxy_connect_timeout 600;
  904. proxy_send_timeout 600;
  905. proxy_read_timeout 600;
  906. send_timeout 600;
  907. location / {
  908. proxy_pass http://localhost:53000;
  909. proxy_set_header Host \$host;
  910. proxy_set_header X-Real-IP \$remote_addr;
  911. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  912. proxy_set_header X-Nginx-Proxy true;
  913. proxy_buffering off;
  914. proxy_redirect off;
  915. }
  916. }"
  917. record_templates[k8sgcr]="server {
  918. listen 80;
  919. #listen 443 ssl;
  920. server_name k8sgcr.$nginx_domain;
  921. #ssl_certificate /path/to/your_domain_name.crt;
  922. #ssl_certificate_key /path/to/your_domain_name.key;
  923. #ssl_session_timeout 1d;
  924. #ssl_session_cache shared:SSL:50m;
  925. #ssl_session_tickets off;
  926. #ssl_protocols TLSv1.2 TLSv1.3;
  927. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  928. #ssl_prefer_server_ciphers on;
  929. #ssl_buffer_size 8k;
  930. proxy_connect_timeout 600;
  931. proxy_send_timeout 600;
  932. proxy_read_timeout 600;
  933. send_timeout 600;
  934. location / {
  935. proxy_pass http://localhost:54000;
  936. proxy_set_header Host \$host;
  937. proxy_set_header X-Real-IP \$remote_addr;
  938. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  939. proxy_set_header X-Nginx-Proxy true;
  940. proxy_buffering off;
  941. proxy_redirect off;
  942. }
  943. }"
  944. record_templates[k8s]="server {
  945. listen 80;
  946. #listen 443 ssl;
  947. server_name k8s.$nginx_domain;
  948. #ssl_certificate /path/to/your_domain_name.crt;
  949. #ssl_certificate_key /path/to/your_domain_name.key;
  950. #ssl_session_timeout 1d;
  951. #ssl_session_cache shared:SSL:50m;
  952. #ssl_session_tickets off;
  953. #ssl_protocols TLSv1.2 TLSv1.3;
  954. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  955. #ssl_prefer_server_ciphers on;
  956. #ssl_buffer_size 8k;
  957. proxy_connect_timeout 600;
  958. proxy_send_timeout 600;
  959. proxy_read_timeout 600;
  960. send_timeout 600;
  961. location / {
  962. proxy_pass http://localhost:55000;
  963. proxy_set_header Host \$host;
  964. proxy_set_header X-Real-IP \$remote_addr;
  965. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  966. proxy_set_header X-Nginx-Proxy true;
  967. proxy_buffering off;
  968. proxy_redirect off;
  969. }
  970. }"
  971. record_templates[quay]="server {
  972. listen 80;
  973. #listen 443 ssl;
  974. server_name quay.$nginx_domain;
  975. #ssl_certificate /path/to/your_domain_name.crt;
  976. #ssl_certificate_key /path/to/your_domain_name.key;
  977. #ssl_session_timeout 1d;
  978. #ssl_session_cache shared:SSL:50m;
  979. #ssl_session_tickets off;
  980. #ssl_protocols TLSv1.2 TLSv1.3;
  981. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  982. #ssl_prefer_server_ciphers on;
  983. #ssl_buffer_size 8k;
  984. proxy_connect_timeout 600;
  985. proxy_send_timeout 600;
  986. proxy_read_timeout 600;
  987. send_timeout 600;
  988. location / {
  989. proxy_pass http://localhost:56000;
  990. proxy_set_header Host \$host;
  991. proxy_set_header X-Real-IP \$remote_addr;
  992. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  993. proxy_set_header X-Nginx-Proxy true;
  994. proxy_buffering off;
  995. proxy_redirect off;
  996. }
  997. }"
  998. record_templates[mcr]="server {
  999. listen 80;
  1000. #listen 443 ssl;
  1001. server_name mcr.$nginx_domain;
  1002. #ssl_certificate /path/to/your_domain_name.crt;
  1003. #ssl_certificate_key /path/to/your_domain_name.key;
  1004. #ssl_session_timeout 1d;
  1005. #ssl_session_cache shared:SSL:50m;
  1006. #ssl_session_tickets off;
  1007. #ssl_protocols TLSv1.2 TLSv1.3;
  1008. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  1009. #ssl_prefer_server_ciphers on;
  1010. #ssl_buffer_size 8k;
  1011. proxy_connect_timeout 600;
  1012. proxy_send_timeout 600;
  1013. proxy_read_timeout 600;
  1014. send_timeout 600;
  1015. location / {
  1016. proxy_pass http://localhost:57000;
  1017. proxy_set_header Host \$host;
  1018. proxy_set_header X-Real-IP \$remote_addr;
  1019. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1020. proxy_set_header X-Nginx-Proxy true;
  1021. proxy_buffering off;
  1022. proxy_redirect off;
  1023. }
  1024. }"
  1025. record_templates[elastic]="server {
  1026. listen 80;
  1027. #listen 443 ssl;
  1028. server_name elastic.$nginx_domain;
  1029. #ssl_certificate /path/to/your_domain_name.crt;
  1030. #ssl_certificate_key /path/to/your_domain_name.key;
  1031. #ssl_session_timeout 1d;
  1032. #ssl_session_cache shared:SSL:50m;
  1033. #ssl_session_tickets off;
  1034. #ssl_protocols TLSv1.2 TLSv1.3;
  1035. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  1036. #ssl_prefer_server_ciphers on;
  1037. #ssl_buffer_size 8k;
  1038. proxy_connect_timeout 600;
  1039. proxy_send_timeout 600;
  1040. proxy_read_timeout 600;
  1041. send_timeout 600;
  1042. location / {
  1043. proxy_pass http://localhost:58000;
  1044. proxy_set_header Host \$host;
  1045. proxy_set_header X-Real-IP \$remote_addr;
  1046. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1047. proxy_set_header X-Nginx-Proxy true;
  1048. proxy_buffering off;
  1049. proxy_redirect off;
  1050. }
  1051. }"
  1052. record_templates[nvcr]="server {
  1053. listen 80;
  1054. #listen 443 ssl;
  1055. server_name nvcr.$nginx_domain;
  1056. #ssl_certificate /path/to/your_domain_name.crt;
  1057. #ssl_certificate_key /path/to/your_domain_name.key;
  1058. #ssl_session_timeout 1d;
  1059. #ssl_session_cache shared:SSL:50m;
  1060. #ssl_session_tickets off;
  1061. #ssl_protocols TLSv1.2 TLSv1.3;
  1062. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  1063. #ssl_prefer_server_ciphers on;
  1064. #ssl_buffer_size 8k;
  1065. proxy_connect_timeout 600;
  1066. proxy_send_timeout 600;
  1067. proxy_read_timeout 600;
  1068. send_timeout 600;
  1069. location / {
  1070. proxy_pass http://localhost:59000;
  1071. proxy_set_header Host \$host;
  1072. proxy_set_header X-Real-IP \$remote_addr;
  1073. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1074. proxy_set_header X-Nginx-Proxy true;
  1075. proxy_buffering off;
  1076. proxy_redirect off;
  1077. }
  1078. }"
  1079. > /etc/nginx/conf.d/docker-proxy.conf
  1080. for record in "${records_array[@]}"; do
  1081. if [[ -n "${record_templates[$record]}" ]]; then
  1082. echo "${record_templates[$record]}" >> /etc/nginx/conf.d/docker-proxy.conf
  1083. fi
  1084. done
  1085. start_attempts=3
  1086. for ((i=1; i<=$start_attempts; i++)); do
  1087. start_nginx
  1088. if pgrep "nginx" > /dev/null; then
  1089. INFO "重新载入配置成功. Nginx服务启动完成"
  1090. break
  1091. else
  1092. if [ $i -eq $start_attempts ]; then
  1093. ERROR "Nginx 在尝试 $start_attempts 后无法启动。请检查配置"
  1094. exit 1
  1095. else
  1096. WARN "第 $i 次启动 Nginx 失败。重试..."
  1097. fi
  1098. fi
  1099. done
  1100. break;;
  1101. n|N )
  1102. WARN "退出配置 Nginx 操作。"
  1103. break;;
  1104. * )
  1105. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1106. esac
  1107. done
  1108. }
  1109. function CHECK_DOCKER() {
  1110. status=$(systemctl is-active docker)
  1111. if [ "$status" = "active" ]; then
  1112. INFO "Docker 服务运行正常,请继续..."
  1113. else
  1114. ERROR "Docker 服务未运行,请查看日志报错,定位问题后再次执行脚本!"
  1115. ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------"
  1116. journalctl -u docker.service --no-pager
  1117. ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------"
  1118. exit 1
  1119. fi
  1120. }
  1121. function INSTALL_DOCKER() {
  1122. repo_file="docker-ce.repo"
  1123. url="https://download.docker.com/linux/$repo_type"
  1124. MAX_ATTEMPTS=3
  1125. attempt=0
  1126. success=false
  1127. if [ "$repo_type" = "centos" ] || [ "$repo_type" = "rhel" ]; then
  1128. if ! command -v docker &> /dev/null;then
  1129. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  1130. attempt=$((attempt + 1))
  1131. WARN "Docker 未安装,正在进行安装..."
  1132. start_spinner "添加Docker仓库..."
  1133. yum-config-manager --add-repo $url/$repo_file &>/dev/null
  1134. stop_spinner
  1135. start_spinner "安装Docker服务..."
  1136. $package_manager -y install docker-ce &>/dev/null
  1137. stop_spinner
  1138. if [ $? -eq 0 ]; then
  1139. success=true
  1140. break
  1141. fi
  1142. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1143. done
  1144. if $success; then
  1145. INFO "Docker 安装成功,版本为:$(docker --version)"
  1146. start_spinner "启动Docker服务..."
  1147. systemctl restart docker &>/dev/null
  1148. stop_spinner
  1149. CHECK_DOCKER
  1150. systemctl enable docker &>/dev/null
  1151. else
  1152. ERROR "Docker 安装失败,请尝试手动安装"
  1153. exit 1
  1154. fi
  1155. else
  1156. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1157. systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
  1158. fi
  1159. elif [ "$repo_type" == "ubuntu" ]; then
  1160. if ! command -v docker &> /dev/null;then
  1161. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  1162. attempt=$((attempt + 1))
  1163. WARN "Docker 未安装,正在进行安装..."
  1164. start_spinner "添加Docker仓库..."
  1165. curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null
  1166. add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null
  1167. start_spinner "安装Docker服务..."
  1168. $package_manager -y install docker-ce docker-ce-cli containerd.io &>/dev/null
  1169. stop_spinner
  1170. if [ $? -eq 0 ]; then
  1171. success=true
  1172. break
  1173. fi
  1174. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1175. done
  1176. if $success; then
  1177. INFO "Docker 安装成功,版本为:$(docker --version)"
  1178. systemctl restart docker &>/dev/null
  1179. CHECK_DOCKER
  1180. systemctl enable docker &>/dev/null
  1181. else
  1182. ERROR "Docker 安装失败,请尝试手动安装"
  1183. exit 1
  1184. fi
  1185. else
  1186. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1187. systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
  1188. fi
  1189. elif [ "$repo_type" == "debian" ]; then
  1190. if ! command -v docker &> /dev/null;then
  1191. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  1192. attempt=$((attempt + 1))
  1193. WARN "Docker 未安装,正在进行安装..."
  1194. start_spinner "添加Docker仓库..."
  1195. curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null
  1196. add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null
  1197. start_spinner "安装Docker服务..."
  1198. $package_manager -y install docker-ce docker-ce-cli containerd.io &>/dev/null
  1199. stop_spinner
  1200. if [ $? -eq 0 ]; then
  1201. success=true
  1202. break
  1203. fi
  1204. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1205. done
  1206. if $success; then
  1207. INFO "Docker 安装成功,版本为:$(docker --version)"
  1208. systemctl restart docker &>/dev/null
  1209. CHECK_DOCKER
  1210. systemctl enable docker &>/dev/null
  1211. else
  1212. ERROR "Docker 安装失败,请尝试手动安装"
  1213. exit 1
  1214. fi
  1215. else
  1216. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1217. systemctl restart docker &>/dev/null
  1218. CHECK_DOCKER
  1219. fi
  1220. else
  1221. ERROR "不支持的操作系统."
  1222. exit 1
  1223. fi
  1224. }
  1225. function INSTALL_COMPOSE() {
  1226. SEPARATOR "安装Docker Compose"
  1227. TAG=`curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r '.tag_name'`
  1228. url="https://github.com/docker/compose/releases/download/$TAG/docker-compose-$(uname -s)-$(uname -m)"
  1229. MAX_ATTEMPTS=3
  1230. attempt=0
  1231. success=false
  1232. save_path="/usr/local/bin"
  1233. chmod +x $save_path/docker-compose &>/dev/null
  1234. if ! command -v docker-compose &> /dev/null || [ -z "$(docker-compose --version)" ]; then
  1235. WARN "Docker Compose 未安装或安装不完整,正在进行安装..."
  1236. while [ $attempt -lt $MAX_ATTEMPTS ]; do
  1237. attempt=$((attempt + 1))
  1238. start_spinner "下载Docker Compose..."
  1239. wget --continue -q $url -O $save_path/docker-compose
  1240. stop_spinner
  1241. if [ $? -eq 0 ]; then
  1242. chmod +x $save_path/docker-compose
  1243. version_check=$(docker-compose --version)
  1244. if [ -n "$version_check" ]; then
  1245. success=true
  1246. chmod +x $save_path/docker-compose
  1247. break
  1248. else
  1249. WARN "Docker Compose 下载的文件不完整,正在尝试重新下载 (尝试次数: $attempt)"
  1250. rm -f $save_path/docker-compose
  1251. fi
  1252. fi
  1253. ERROR "Docker Compose 下载失败,正在尝试重新下载 (尝试次数: $attempt)"
  1254. done
  1255. if $success; then
  1256. INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)"
  1257. else
  1258. ERROR "Docker Compose 下载失败,请尝试手动安装docker-compose"
  1259. exit 1
  1260. fi
  1261. else
  1262. chmod +x $save_path/docker-compose
  1263. INFO "Docker Compose 已经安装,版本为:$(docker-compose --version)"
  1264. fi
  1265. }
  1266. function INSTALL_DOCKER_CN() {
  1267. MAX_ATTEMPTS=3
  1268. attempt=0
  1269. success=false
  1270. cpu_arch=$(uname -m)
  1271. save_path="/opt/docker_tgz"
  1272. mkdir -p $save_path
  1273. docker_ver="docker-27.1.2.tgz"
  1274. case $cpu_arch in
  1275. "arm64")
  1276. url="https://raw.gitcode.com/dqzboy/docker/blobs/2ce4d6bc245ab1c4525b3e6f55db7d710681e56f/$docker_ver"
  1277. ;;
  1278. "aarch64")
  1279. url="https://raw.gitcode.com/dqzboy/docker/blobs/2ce4d6bc245ab1c4525b3e6f55db7d710681e56f/$docker_ver"
  1280. ;;
  1281. "x86_64")
  1282. url="https://raw.gitcode.com/dqzboy/docker/blobs/179729785ed2c4a8c99aeb546fb6ac2864d7da5c/$docker_ver"
  1283. ;;
  1284. *)
  1285. ERROR "不支持的CPU架构: $cpu_arch"
  1286. exit 1
  1287. ;;
  1288. esac
  1289. if ! command -v docker &> /dev/null; then
  1290. while [ $attempt -lt $MAX_ATTEMPTS ]; do
  1291. attempt=$((attempt + 1))
  1292. WARN "Docker 未安装,正在进行安装..."
  1293. start_spinner "安装Docker服务..."
  1294. wget -P "$save_path" "$url" &>/dev/null
  1295. stop_spinner
  1296. if [ $? -eq 0 ]; then
  1297. success=true
  1298. break
  1299. fi
  1300. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1301. done
  1302. if $success; then
  1303. tar -xzf $save_path/$docker_ver -C $save_path
  1304. \cp $save_path/docker/* /usr/bin/ &>/dev/null
  1305. rm -rf $save_path
  1306. INFO "Docker 安装成功,版本为:$(docker --version)"
  1307. cat > /usr/lib/systemd/system/docker.service <<EOF
  1308. [Unit]
  1309. Description=Docker Application Container Engine
  1310. Documentation=https://docs.docker.com
  1311. After=network-online.target firewalld.service
  1312. Wants=network-online.target
  1313. [Service]
  1314. Type=notify
  1315. ExecStart=/usr/bin/dockerd
  1316. ExecReload=/bin/kill -s HUP
  1317. LimitNOFILE=infinity
  1318. LimitNPROC=infinity
  1319. LimitCORE=infinity
  1320. TimeoutStartSec=0
  1321. Delegate=yes
  1322. KillMode=process
  1323. Restart=on-failure
  1324. StartLimitBurst=3
  1325. StartLimitInterval=60s
  1326. [Install]
  1327. WantedBy=multi-user.target
  1328. EOF
  1329. systemctl daemon-reload
  1330. systemctl restart docker &>/dev/null
  1331. CHECK_DOCKER
  1332. systemctl enable docker &>/dev/null
  1333. else
  1334. ERROR "Docker 安装失败,请尝试手动安装"
  1335. exit 1
  1336. fi
  1337. else
  1338. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1339. systemctl restart docker &>/dev/null
  1340. CHECK_DOCKER
  1341. fi
  1342. }
  1343. function INSTALL_COMPOSE_CN() {
  1344. SEPARATOR "安装Docker Compose"
  1345. MAX_ATTEMPTS=3
  1346. attempt=0
  1347. cpu_arch=$(uname -m)
  1348. success=false
  1349. save_path="/usr/local/bin"
  1350. case $cpu_arch in
  1351. "arm64")
  1352. url="https://raw.gitcode.com/dqzboy/docker/blobs/b7be39a4442a103749c769ca48740e8e1a93a16c/docker-compose-linux-aarch64"
  1353. ;;
  1354. "aarch64")
  1355. url="https://raw.gitcode.com/dqzboy/docker/blobs/b7be39a4442a103749c769ca48740e8e1a93a16c/docker-compose-linux-aarch64"
  1356. ;;
  1357. "x86_64")
  1358. url="https://raw.gitcode.com/dqzboy/docker/blobs/df1b7935ced481a20d16141d97e163823ee793f5/docker-compose-linux-x86_64"
  1359. ;;
  1360. *)
  1361. ERROR "不支持的CPU架构: $cpu_arch"
  1362. exit 1
  1363. ;;
  1364. esac
  1365. chmod +x $save_path/docker-compose &>/dev/null
  1366. if ! command -v docker-compose &> /dev/null || [ -z "$(docker-compose --version)" ]; then
  1367. WARN "Docker Compose 未安装或安装不完整,正在进行安装..."
  1368. while [ $attempt -lt $MAX_ATTEMPTS ]; do
  1369. attempt=$((attempt + 1))
  1370. start_spinner "下载Docker Compose..."
  1371. wget --continue -q $url -O $save_path/docker-compose
  1372. stop_spinner
  1373. if [ $? -eq 0 ]; then
  1374. chmod +x $save_path/docker-compose
  1375. version_check=$(docker-compose --version)
  1376. if [ -n "$version_check" ]; then
  1377. success=true
  1378. chmod +x $save_path/docker-compose
  1379. break
  1380. else
  1381. WARN "Docker Compose 下载的文件不完整,正在尝试重新下载 (尝试次数: $attempt)"
  1382. rm -f $save_path/docker-compose
  1383. fi
  1384. fi
  1385. ERROR "Docker Compose 下载失败,正在尝试重新下载 (尝试次数: $attempt)"
  1386. done
  1387. if $success; then
  1388. INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)"
  1389. else
  1390. ERROR "Docker Compose 下载失败,请尝试手动安装docker-compose"
  1391. exit 1
  1392. fi
  1393. else
  1394. chmod +x $save_path/docker-compose
  1395. INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)"
  1396. fi
  1397. }
  1398. function update_docker_registry_url() {
  1399. local container_name=$1
  1400. if [[ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then
  1401. sed -i "s@- DOCKER_REGISTRY_URL=.*@- DOCKER_REGISTRY_URL=http://${container_name}:5000@g" ${PROXY_DIR}/${DOCKER_COMPOSE_FILE}
  1402. else
  1403. ERROR "文件 ${LIGHT_CYAN}${PROXY_DIR}/${DOCKER_COMPOSE_FILE} ${RESET} ${LIGHT_RED}不存在${RESET},导致容器无法应用新配置"
  1404. exit 1
  1405. fi
  1406. }
  1407. function CONFIG_FILES() {
  1408. while true; do
  1409. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" install_docker_reg
  1410. case "$install_docker_reg" in
  1411. 1 )
  1412. files=(
  1413. "dockerhub reg-docker-hub ${GITRAW}/config/registry-hub.yml"
  1414. "gcr reg-gcr ${GITRAW}/config/registry-gcr.yml"
  1415. "ghcr reg-ghcr ${GITRAW}/config/registry-ghcr.yml"
  1416. "quay reg-quay ${GITRAW}/config/registry-quay.yml"
  1417. "k8sgcr reg-k8s-gcr ${GITRAW}/config/registry-k8sgcr.yml"
  1418. "k8s reg-k8s ${GITRAW}/config/registry-k8s.yml"
  1419. "mcr reg-mcr ${GITRAW}/config/registry-mcr.yml"
  1420. "elastic reg-elastic ${GITRAW}/config/registry-elastic.yml"
  1421. "nvcr reg-nvcr ${GITRAW}/config/registry-nvcr.yml"
  1422. )
  1423. break;;
  1424. 2 )
  1425. files=(
  1426. "dockerhub reg-docker-hub ${CNGITRAW}/config/registry-hub.yml"
  1427. "gcr reg-gcr ${CNGITRAW}/config/registry-gcr.yml"
  1428. "ghcr reg-ghcr ${CNGITRAW}/config/registry-ghcr.yml"
  1429. "quay reg-quay ${CNGITRAW}/config/registry-quay.yml"
  1430. "k8sgcr reg-k8s-gcr ${CNGITRAW}/config/registry-k8sgcr.yml"
  1431. "k8s reg-k8s ${CNGITRAW}/config/registry-k8s.yml"
  1432. "mcr reg-mcr ${CNGITRAW}/config/registry-mcr.yml"
  1433. "elastic reg-elastic ${CNGITRAW}/config/registry-elastic.yml"
  1434. "nvcr reg-nvcr ${CNGITRAW}/config/registry-nvcr.yml"
  1435. )
  1436. break;;
  1437. * )
  1438. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  1439. esac
  1440. done
  1441. }
  1442. function DOWN_CONFIG() {
  1443. selected_names=()
  1444. selected_files=()
  1445. selected_containers=()
  1446. REGISTRY_MENU
  1447. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all下载所有${RESET} > ")" choices_reg
  1448. while true; do
  1449. if [[ "$choices_reg" =~ ^[0-9]+([[:space:]][0-9]+)*$ ]]; then
  1450. valid=true
  1451. for choice in $choices_reg; do
  1452. if ((choice < 0 || choice > 10)); then
  1453. valid=false
  1454. break
  1455. fi
  1456. done
  1457. if $valid; then
  1458. break
  1459. fi
  1460. fi
  1461. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-10 ${RESET}序号"
  1462. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all下载所有${RESET} > ")" choices_reg
  1463. done
  1464. if [[ "$choices_reg" == "10" ]]; then
  1465. for file in "${files[@]}"; do
  1466. file_name=$(echo "$file" | cut -d' ' -f1)
  1467. container_name=$(echo "$file" | cut -d' ' -f2)
  1468. file_url=$(echo "$file" | cut -d' ' -f3-)
  1469. selected_names+=("$file_name")
  1470. selected_containers+=("$container_name")
  1471. selected_files+=("$file_url")
  1472. wget -NP ${PROXY_DIR}/ $file_url &>/dev/null
  1473. done
  1474. selected_all=true
  1475. elif [[ "$choices_reg" == "0" ]]; then
  1476. WARN "退出下载配置! ${LIGHT_YELLOW}首次安装如果没有配置无法启动Registry服务,只能启动Registry-UI服务${RESET}"
  1477. return
  1478. else
  1479. for choice in ${choices_reg}; do
  1480. if ((choice > 0 && choice < 10)); then
  1481. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  1482. container_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  1483. file_url=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f3-)
  1484. selected_names+=("$file_name")
  1485. selected_containers+=("$container_name")
  1486. selected_files+=("$file_url")
  1487. wget -NP ${PROXY_DIR}/ $file_url &>/dev/null
  1488. fi
  1489. done
  1490. selected_all=false
  1491. # 非更新配置操作则执行下面步骤
  1492. if [[ "$main_choice" != "4" ]]; then
  1493. first_selected_container=${selected_containers[0]}
  1494. update_docker_registry_url "$first_selected_container"
  1495. fi
  1496. fi
  1497. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_BLUE}Proxy代理缓存过期时间${RESET} ${MAGENTA}单位:ns、us、ms、s、m、h.默认ns,0不清除缓存${RESET}"
  1498. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  1499. while [[ "$modify_cache" != "y" && "$modify_cache" != "n" ]]; do
  1500. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  1501. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  1502. done
  1503. if [[ "$modify_cache" == "y" ]]; then
  1504. while true; do
  1505. read -e -p "$(INFO "请输入新的缓存时间值: ")" new_ttl
  1506. for file_url in "${selected_files[@]}"; do
  1507. yml_name=$(basename "$file_url")
  1508. sed -ri "s/ttl: 168h/ttl: ${new_ttl}/g" ${PROXY_DIR}/${yml_name} &>/dev/null
  1509. done
  1510. break
  1511. done
  1512. fi
  1513. }
  1514. # 一键部署调此函数
  1515. function PROXY_HTTP() {
  1516. read -e -p "$(INFO "是否添加代理(科学上网)? ${PROMPT_YES_NO}")" modify_config
  1517. case $modify_config in
  1518. [Yy]* )
  1519. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1520. while [[ -z "$url" ]]; do
  1521. WARN "代理${LIGHT_YELLOW}地址不能为空${RESET},请重新输入!"
  1522. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1523. done
  1524. sed -i "s@#- http=http://host:port@- http_proxy=http://${url}@g" ${PROXY_DIR}/${DOCKER_COMPOSE_FILE}
  1525. sed -i "s@#- https=http://host:port@- https_proxy=http://${url}@g" ${PROXY_DIR}/${DOCKER_COMPOSE_FILE}
  1526. INFO "你配置代理地址为: ${CYAN}http://${url}${RESET}"
  1527. ;;
  1528. [Nn]* )
  1529. WARN "跳过添加代理配置"
  1530. ;;
  1531. * )
  1532. ERROR "无效的输入。请重新输入${LIGHT_GREEN}Y or N ${RESET}的选项"
  1533. PROXY_HTTP
  1534. ;;
  1535. esac
  1536. }
  1537. # 7) 本机Docker代理,调此函数
  1538. function DOCKER_PROXY_HTTP() {
  1539. WARN "${BOLD}${LIGHT_GREEN}提示:${RESET} ${LIGHT_CYAN}配置本机Docker服务走代理,加速本机Docker镜像下载${RESET}"
  1540. read -e -p "$(INFO "是否添加本机Docker服务代理? ${PROMPT_YES_NO}")" modify_proxy
  1541. case $modify_proxy in
  1542. [Yy]* )
  1543. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1544. while [[ -z "$url" ]]; do
  1545. WARN "代理${LIGHT_YELLOW}地址不能为空${RESET},请重新输入。"
  1546. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1547. done
  1548. INFO "你配置代理地址为: ${CYAN}http://${url}${RESET}"
  1549. ;;
  1550. [Nn]* )
  1551. WARN "退出本机Docker服务代理配置"
  1552. main_menu
  1553. ;;
  1554. * )
  1555. ERROR "无效的输入。请重新输入${LIGHT_GREEN}Y or N ${RESET}的选项"
  1556. DOCKER_PROXY_HTTP
  1557. ;;
  1558. esac
  1559. }
  1560. function CHECK_DOCKER_PROXY() {
  1561. local url=$1
  1562. local http_proxy=$(docker info 2>/dev/null | grep -i "HTTP Proxy" | awk -F ': ' '{print $2}')
  1563. local https_proxy=$(docker info 2>/dev/null | grep -i "HTTPS Proxy" | awk -F ': ' '{print $2}')
  1564. if [[ "$http_proxy" == "http://$url" && "$https_proxy" == "http://$url" ]]; then
  1565. INFO "Docker 代理${LIGHT_GREEN}配置成功${RESET},当前 HTTP Proxy: ${LIGHT_CYAN}$http_proxy${RESET}, HTTPS Proxy: ${LIGHT_CYAN}$https_proxy${RESET}"
  1566. else
  1567. ERROR "Docker 代理${LIGHT_RED}配置失败${RESET},请检查配置并重新执行配置"
  1568. DOCKER_PROXY_HTTP
  1569. fi
  1570. }
  1571. function ADD_DOCKERD_PROXY() {
  1572. mkdir -p /etc/systemd/system/docker.service.d
  1573. # 设置代理的函数
  1574. set_proxy_config() {
  1575. cat > /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
  1576. [Service]
  1577. Environment="HTTP_PROXY=http://$url"
  1578. Environment="HTTPS_PROXY=http://$url"
  1579. EOF
  1580. systemctl daemon-reload
  1581. systemctl restart docker &>/dev/null
  1582. CHECK_DOCKER
  1583. CHECK_DOCKER_PROXY "$url"
  1584. }
  1585. # 检查并设置代理配置
  1586. if [ ! -f /etc/systemd/system/docker.service.d/http-proxy.conf ]; then
  1587. # 如果配置文件不存在,直接设置代理
  1588. set_proxy_config
  1589. else
  1590. # 如果配置文件存在,检查是否有相同的代理配置
  1591. if ! grep -q "HTTP_PROXY=http://$url" /etc/systemd/system/docker.service.d/http-proxy.conf || \
  1592. ! grep -q "HTTPS_PROXY=http://$url" /etc/systemd/system/docker.service.d/http-proxy.conf; then
  1593. # 配置文件存在,但没有相同的代理配置,添加新的代理配置
  1594. set_proxy_config
  1595. else
  1596. WARN "已经存在相同的代理配置,${LIGHT_RED}请勿重复配置${RESET}"
  1597. fi
  1598. fi
  1599. }
  1600. function DEL_DOCKERD_PROXY() {
  1601. check_proxy_config() {
  1602. systemctl daemon-reload
  1603. systemctl restart docker &>/dev/null
  1604. CHECK_DOCKER
  1605. }
  1606. WARN "${BOLD}${LIGHT_GREEN}提示:${RESET} ${LIGHT_CYAN}移除本机Docker服务走代理,Docker镜像下载可能会失败!${RESET}"
  1607. read -e -p "$(INFO "是否移除本机Docker服务代理? ${PROMPT_YES_NO}")" del_proxy
  1608. case $del_proxy in
  1609. [Yy]* )
  1610. # 检查并设置代理配置
  1611. if [ ! -f /etc/systemd/system/docker.service.d/http-proxy.conf ]; then
  1612. # 如果配置文件不存在,打印提示
  1613. INFO "本机Docker服务未配置代理"
  1614. else
  1615. # 如果配置文件存在,则进行删除并重启Docker服务
  1616. rm -f /etc/systemd/system/docker.service.d/http-proxy.conf &>/dev/null
  1617. check_proxy_config
  1618. INFO "本机Docker服务代理已移除"
  1619. fi
  1620. ;;
  1621. [Nn]* )
  1622. WARN "退出移除本机Docker服务代理配置"
  1623. main_menu
  1624. ;;
  1625. * )
  1626. ERROR "无效的输入。请重新输入${LIGHT_GREEN}Y or N ${RESET}的选项"
  1627. DOCKER_PROXY_HTTP
  1628. ;;
  1629. esac
  1630. }
  1631. # 一键部署、安装指定容器加速服务时调用START_CONTAINER
  1632. function START_CONTAINER() {
  1633. CHECK_COMPOSE_CMD
  1634. if [ "$modify_config" = "y" ] || [ "$modify_config" = "Y" ]; then
  1635. ADD_DOCKERD_PROXY
  1636. else
  1637. INFO "拉取服务镜像并启动服务中..."
  1638. fi
  1639. # DOWN_CONFIG函数执行后判断selected_all变量
  1640. if [ "$selected_all" = true ]; then
  1641. $DOCKER_COMPOSE_CMD up -d --force-recreate
  1642. # 检查命令执行是否成功
  1643. if [ $? -ne 0 ]; then
  1644. ERROR "Docker 容器${LIGHT_RED}启动失败${RESET},请通过查看日志确认启动失败原因"
  1645. exit 1
  1646. fi
  1647. else
  1648. $DOCKER_COMPOSE_CMD up -d "${selected_names[@]}" registry-ui
  1649. # 检查命令执行是否成功
  1650. if [ $? -ne 0 ]; then
  1651. ERROR "Docker 容器${LIGHT_RED}启动失败${RESET},请通过查看日志确认启动失败原因"
  1652. exit 1
  1653. else
  1654. INFO "容器${LIGHT_GREEN}安装完成${RESET},并${LIGHT_GREEN}成功启动${RESET}"
  1655. fi
  1656. fi
  1657. }
  1658. # 使用函数UPDATE_CONFIG时调用RESTART_CONTAINER
  1659. function RESTART_CONTAINER() {
  1660. CHECK_COMPOSE_CMD
  1661. # DOWN_CONFIG函数执行后判断selected_all变量
  1662. if [ "$selected_all" = true ]; then
  1663. $DOCKER_COMPOSE_CMD restart
  1664. # 检查命令执行是否成功
  1665. if [ $? -ne 0 ]; then
  1666. ERROR "Docker 容器启动失败,请通过查看日志确认启动失败原因"
  1667. exit 1
  1668. fi
  1669. else
  1670. $DOCKER_COMPOSE_CMD restart "${selected_names[@]}"
  1671. # 检查命令执行是否成功
  1672. if [ $? -ne 0 ]; then
  1673. ERROR "Docker 容器启动失败,请通过查看日志确认启动失败原因"
  1674. exit 1
  1675. fi
  1676. fi
  1677. }
  1678. function INSTALL_DOCKER_PROXY() {
  1679. SEPARATOR "部署Docker Proxy"
  1680. CONFIG_FILES
  1681. if [[ "$install_docker_reg" == "1" ]]; then
  1682. wget -NP ${PROXY_DIR}/ ${GITRAW}/${DOCKER_COMPOSE_FILE} &>/dev/null
  1683. elif [[ "$install_docker_reg" == "2" ]]; then
  1684. wget -NP ${PROXY_DIR}/ ${CNGITRAW}/${DOCKER_COMPOSE_FILE} &>/dev/null
  1685. fi
  1686. DOWN_CONFIG
  1687. PROXY_HTTP
  1688. START_CONTAINER
  1689. }
  1690. function STOP_REMOVE_CONTAINER() {
  1691. CHECK_COMPOSE_CMD
  1692. if [[ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then
  1693. INFO "停止和移除所有容器"
  1694. $DOCKER_COMPOSE_CMD -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" down --remove-orphans
  1695. else
  1696. WARN "${LIGHT_YELLOW}容器目前未处于运行状态,无需进行删除操作!${RESET}"
  1697. exit 1
  1698. fi
  1699. }
  1700. function UPDATE_CONFIG() {
  1701. while true; do
  1702. read -e -p "$(WARN "是否更新配置,更新前请确保您已备份现有配置,此操作不可逆? ${PROMPT_YES_NO}")" update_conf
  1703. case "$update_conf" in
  1704. y|Y )
  1705. CONFIG_FILES
  1706. DOWN_CONFIG
  1707. RESTART_CONTAINER
  1708. break;;
  1709. n|N )
  1710. WARN "退出配置更新操作。"
  1711. break;;
  1712. * )
  1713. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1714. esac
  1715. done
  1716. }
  1717. function REMOVE_NONE_TAG() {
  1718. docker images | grep "^${IMAGE_NAME}.*<none>" | awk '{print $3}' | xargs -r docker rmi
  1719. images=$(docker images ${IMAGE_NAME} --format '{{.Repository}}:{{.Tag}}')
  1720. latest=$(echo "$images" | sort -V | tail -n1)
  1721. for image in $images
  1722. do
  1723. if [ "$image" != "$latest" ];then
  1724. docker rmi $image
  1725. fi
  1726. done
  1727. }
  1728. function PACKAGE() {
  1729. while true; do
  1730. read -e -p "$(INFO "是否执行软件包安装? (${LIGHT_YELLOW}首次部署需安装依赖${RESET}) ${PROMPT_YES_NO}")" choice_package
  1731. case "$choice_package" in
  1732. y|Y )
  1733. INSTALL_PACKAGE
  1734. break;;
  1735. n|N )
  1736. WARN "跳过软件包安装步骤"
  1737. break;;
  1738. * )
  1739. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1740. esac
  1741. done
  1742. }
  1743. function INSTALL_WEB() {
  1744. while true; do
  1745. SEPARATOR "安装WEB服务"
  1746. read -e -p "$(INFO "是否安装WEB服务? (用来通过域名方式访问加速服务) ${PROMPT_YES_NO}")" choice_service
  1747. if [[ "$choice_service" =~ ^[YyNn]$ ]]; then
  1748. if [[ "$choice_service" == "Y" || "$choice_service" == "y" ]]; then
  1749. while true; do
  1750. read -e -p "$(INFO "选择安装的WEB服务。安装${LIGHT_CYAN}Caddy可自动开启HTTPS${RESET} [Nginx/Caddy]: ")" web_service
  1751. if [[ "$web_service" =~ ^(nginx|Nginx|caddy|Caddy)$ ]]; then
  1752. if [[ "$web_service" == "nginx" || "$web_service" == "Nginx" ]]; then
  1753. INSTALL_NGINX
  1754. CONFIG_NGINX
  1755. break
  1756. elif [[ "$web_service" == "caddy" || "$web_service" == "Caddy" ]]; then
  1757. INSTALL_CADDY
  1758. CONFIG_CADDY
  1759. break
  1760. fi
  1761. else
  1762. WARN "请输入 ${LIGHT_CYAN}nginx${RESET} 或 ${LIGHT_BLUE}caddy${RESET}"
  1763. fi
  1764. done
  1765. break
  1766. else
  1767. WARN "跳过WEB服务安装步骤"
  1768. break
  1769. fi
  1770. else
  1771. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  1772. fi
  1773. done
  1774. }
  1775. function PROMPT(){
  1776. PUBLIC_IP=$(curl -s https://ifconfig.me)
  1777. ALL_IPS=$(hostname -I)
  1778. INTERNAL_IP=$(echo "$ALL_IPS" | awk '$1!="127.0.0.1" && $1!="::1" && $1!="docker0" {print $1}')
  1779. echo
  1780. INFO "=================感谢您的耐心等待,安装已经完成=================="
  1781. INFO
  1782. INFO "请用浏览器访问 UI 面板(此地址只是UI,非加速地址): "
  1783. INFO "公网访问地址: ${UNDERLINE}http://$PUBLIC_IP:50000${RESET}"
  1784. INFO "内网访问地址: ${UNDERLINE}http://$INTERNAL_IP:50000${RESET}"
  1785. INFO
  1786. INFO "加速服务安装路径: ${LIGHT_BLUE}${PROXY_DIR}${RESET}"
  1787. INFO
  1788. INFO "加速服务对应监听端口如下(参考信息):"
  1789. INFO "DockerHub:51000 │ GHCR:52000 │ GCR:53000 │ K8S-GCR:54000"
  1790. INFO "K8S:55000 │ Quay:56000 │ MCR:57000 │ Elastic:58000 │ NVCR:59000"
  1791. INFO
  1792. INFO "作者博客: https://dqzboy.com"
  1793. INFO "项目交流: https://t.me/Docker_Proxy"
  1794. INFO "代码仓库: https://github.com/dqzboy/Docker-Proxy"
  1795. INFO "合作联系: https://t.me/WiseAidBot"
  1796. INFO
  1797. INFO "若用云服务器并设域名及证书,需在安全组开放80、443端口;否则开放对应服务监听端口"
  1798. INFO
  1799. INFO "VPS推荐(AFF): https://dqzboy.github.io/proxyui/racknerd"
  1800. INFO
  1801. INFO "================================================================"
  1802. }
  1803. function INSTALL_PROXY() {
  1804. ALL_IN_ONE() {
  1805. CHECK_OS
  1806. CHECK_PACKAGE_MANAGER
  1807. CHECK_PKG_MANAGER
  1808. CHECK_COMPOSE_CMD
  1809. CHECKMEM
  1810. CHECKFIRE
  1811. CHECKBBR
  1812. PACKAGE
  1813. INSTALL_WEB
  1814. while true; do
  1815. SEPARATOR "安装Docker"
  1816. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" deploy_docker
  1817. case "$deploy_docker" in
  1818. 1 )
  1819. INSTALL_DOCKER
  1820. INSTALL_COMPOSE
  1821. break;;
  1822. 2 )
  1823. INSTALL_DOCKER_CN
  1824. INSTALL_COMPOSE_CN
  1825. break;;
  1826. * )
  1827. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  1828. esac
  1829. done
  1830. INSTALL_DOCKER_PROXY
  1831. PROMPT
  1832. }
  1833. ADD_DOCKER_SERVICE() {
  1834. WARN "提示: 此操作是在你的服务器${LIGHT_CYAN}已经部署对应组件${RESET}后才可执行,否则执行过程将会出现${LIGHT_RED}各种报错!${RESET}"
  1835. INSTALL_DOCKER_PROXY
  1836. }
  1837. SEPARATOR "安装服务"
  1838. echo -e "1) 一键${BOLD}${LIGHT_GREEN}部署所有${RESET}服务"
  1839. echo -e "2) ${BOLD}${LIGHT_CYAN}安装指定${RESET}容器服务"
  1840. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  1841. echo -e "0) ${BOLD}退出脚本${RESET}"
  1842. echo "---------------------------------------------------------------"
  1843. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" proxy_install
  1844. case $proxy_install in
  1845. 1)
  1846. ALL_IN_ONE
  1847. ;;
  1848. 2)
  1849. ADD_DOCKER_SERVICE
  1850. INSTALL_PROXY
  1851. ;;
  1852. 3)
  1853. main_menu
  1854. ;;
  1855. 0)
  1856. exit 1
  1857. ;;
  1858. *)
  1859. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  1860. INSTALL_PROXY
  1861. ;;
  1862. esac
  1863. }
  1864. function REMOVE_CMDUI() {
  1865. CHECK_COMPOSE_CMD
  1866. CMDUI_NAME="hubcmd-ui"
  1867. CMDUI_DIR="${PROXY_DIR}/hubcmdui"
  1868. if [ -d "${CMDUI_DIR}" ]; then
  1869. if [ -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" ]; then
  1870. INFO "停止和移除HubCMD-UI容器"
  1871. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" down --remove-orphans
  1872. rm -rf "${CMDUI_DIR}"
  1873. else
  1874. WARN "${LIGHT_YELLOW}文件${CMDUI_DIR}/${DOCKER_COMPOSE_FILE} 不存在,无需进行删除操作!${RESET}"
  1875. fi
  1876. else
  1877. WARN "${LIGHT_YELLOW}目录 ${CMDUI_DIR} 不存在,无需进行删除操作!${RESET}"
  1878. fi
  1879. docker images | grep "^${CMDUI_IMAGE_NAME}.*<none>" | awk '{print $3}' | xargs -r docker rmi
  1880. images=$(docker images ${CMDUI_IMAGE_NAME} --format '{{.Repository}}:{{.Tag}}')
  1881. latest=$(echo "$images" | sort -V | tail -n1)
  1882. for image in $images; do
  1883. if [ "$image" != "$latest" ]; then
  1884. docker rmi $image
  1885. fi
  1886. done
  1887. # 强制移除所有相关镜像
  1888. docker rmi --force $(docker images -q ${CMDUI_IMAGE_NAME}) &>/dev/null
  1889. }
  1890. function HUBCMDUI() {
  1891. CHECK_COMPOSE_CMD
  1892. CMDUI_NAME="hubcmd-ui"
  1893. CMDUI_DIR="${PROXY_DIR}/hubcmdui"
  1894. CMDUI_PROMPT() {
  1895. PUBLIC_IP=$(curl -s https://ifconfig.me)
  1896. ALL_IPS=$(hostname -I)
  1897. INTERNAL_IP=$(echo "$ALL_IPS" | awk '$1!="127.0.0.1" && $1!="::1" && $1!="docker0" {print $1}')
  1898. echo
  1899. INFO "=================感谢您的耐心等待,安装已经完成=================="
  1900. INFO
  1901. INFO "请用浏览器访问 HubCMD-UI 面板: "
  1902. INFO "公网访问地址: ${UNDERLINE}http://$PUBLIC_IP:30080${RESET}"
  1903. INFO "内网访问地址: ${UNDERLINE}http://$INTERNAL_IP:30080${RESET}"
  1904. INFO
  1905. INFO "后端访问地址: 地址后面跟admin,例: ${UNDERLINE}http://$INTERNAL_IP:30080/admin${RESET}"
  1906. INFO "默认账号密码: ${LIGHT_GREEN}root${RESET}/${LIGHT_CYAN}admin@123${RESET}"
  1907. INFO
  1908. INFO "服务安装路径: ${LIGHT_BLUE}${CMDUI_DIR}${RESET}"
  1909. INFO
  1910. INFO "作者博客: https://dqzboy.com"
  1911. INFO "项目交流: https://t.me/Docker_Proxy"
  1912. INFO "代码仓库: https://github.com/dqzboy/Docker-Proxy"
  1913. INFO "合作联系: https://t.me/WiseAidBot"
  1914. INFO
  1915. INFO "VPS推荐(AFF): https://dqzboy.github.io/proxyui/racknerd"
  1916. INFO
  1917. INFO "================================================================"
  1918. }
  1919. INSTALL_HUBCMDUI() {
  1920. mkdir -p ${CMDUI_DIR}
  1921. INFO "正在安装HubCMD-UI服务,请稍等!安装路径 ${LIGHT_CYAN}${CMDUI_DIR}${RESET}"
  1922. if [[ -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then
  1923. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${CMDUI_NAME}$"; then
  1924. INFO "${CMDUI_NAME} 已经安装并启动,无需重复执行安装!"
  1925. else
  1926. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" up -d
  1927. fi
  1928. else
  1929. wget -NP ${CMDUI_DIR}/ ${CMDUI_COMPOSE_FILE} &>/dev/null
  1930. if [ $? -ne 0 ]; then
  1931. WARN "下载${LIGHT_YELLOW}docker-compose.yaml 文件失败${RESET},请稍后重试!"
  1932. HUBCMDUI
  1933. fi
  1934. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" up -d
  1935. if [ $? -eq 0 ]; then
  1936. CMDUI_PROMPT
  1937. exit 1
  1938. else
  1939. WARN "服务安装失败,请稍后重试!"
  1940. HUBCMDUI
  1941. fi
  1942. fi
  1943. }
  1944. UPDATE_HUBCMDUI() {
  1945. if [ -d "${CMDUI_DIR}" ]; then
  1946. if [ -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" ]; then
  1947. INFO "正在更新HubCMD-UI容器"
  1948. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" pull
  1949. if [ $? -ne 0 ]; then
  1950. WARN "HubCMD-UI ${LIGHT_YELLOW}镜像拉取失败${RESET},请稍后重试!"
  1951. HUBCMDUI
  1952. fi
  1953. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" up -d --force-recreate
  1954. if [ $? -ne 0 ]; then
  1955. WARN "HubCMD-UI ${LIGHT_YELLOW}服务启动失败${RESET},请稍后重试!"
  1956. HUBCMDUI
  1957. else
  1958. INFO "HubCMD-UI ${LIGHT_GREEN}服务更新并启动完成${RESET}"
  1959. fi
  1960. else
  1961. WARN "${LIGHT_YELLOW}文件${CMDUI_DIR}/${DOCKER_COMPOSE_FILE} 不存在,无法进行更新操作!${RESET}"
  1962. fi
  1963. else
  1964. WARN "${LIGHT_YELLOW}目录 ${CMDUI_DIR} 不存在,无法进行更新操作!${RESET}"
  1965. fi
  1966. }
  1967. UNINSTALL_HUBCMDUI() {
  1968. WARN "${LIGHT_RED}注意:${RESET} ${LIGHT_YELLOW}请执行删除之前确定是否需要备份配置文件${RESET}"
  1969. while true; do
  1970. read -e -p "$(INFO "本人${LIGHT_RED}已知晓后果,确认删除${RESET}服务? ${PROMPT_YES_NO}")" delcmdui
  1971. case "$delcmdui" in
  1972. y|Y )
  1973. REMOVE_CMDUI
  1974. break;;
  1975. n|N )
  1976. WARN "退出执行卸载服务"
  1977. break;;
  1978. * )
  1979. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1980. esac
  1981. done
  1982. }
  1983. SEPARATOR "HubCMD-UI管理"
  1984. echo -e "1) ${BOLD}${LIGHT_GREEN}安装${RESET}HubCMD-UI"
  1985. echo -e "2) ${BOLD}${LIGHT_YELLOW}卸载${RESET}HubCMD-UI"
  1986. echo -e "3) ${BOLD}${LIGHT_CYAN}更新${RESET}HubCMD-UI"
  1987. echo -e "4) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  1988. echo -e "0) ${BOLD}退出脚本${RESET}"
  1989. echo "---------------------------------------------------------------"
  1990. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" cmdui_choice
  1991. case $cmdui_choice in
  1992. 1)
  1993. INSTALL_HUBCMDUI
  1994. HUBCMDUI
  1995. ;;
  1996. 2)
  1997. UNINSTALL_HUBCMDUI
  1998. HUBCMDUI
  1999. ;;
  2000. 3)
  2001. UPDATE_HUBCMDUI
  2002. HUBCMDUI
  2003. ;;
  2004. 4)
  2005. main_menu
  2006. ;;
  2007. 0)
  2008. exit 1
  2009. ;;
  2010. *)
  2011. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-4${RESET}的选项."
  2012. HUBCMDUI
  2013. ;;
  2014. esac
  2015. }
  2016. function COMP_INST() {
  2017. SEPARATOR "安装组件"
  2018. echo -e "1) ${BOLD}安装${LIGHT_GREEN}环境依赖${RESET}"
  2019. echo -e "2) ${BOLD}安装${LIGHT_CYAN}Docker${RESET}"
  2020. echo -e "3) ${BOLD}安装${LIGHT_MAGENTA}Compose${RESET}"
  2021. echo -e "4) ${BOLD}安装${GREEN}Nginx${RESET}"
  2022. echo -e "5) ${BOLD}安装${LIGHT_BLUE}Caddy${RESET}"
  2023. echo -e "6) ${BOLD}配置${LIGHT_YELLOW}Nginx${RESET}"
  2024. echo -e "7) ${BOLD}配置${CYAN}Caddy${RESET}"
  2025. echo -e "8) ${BOLD}安装${BLUE}HubCMD-UI${RESET}"
  2026. echo -e "9) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2027. echo -e "0) ${BOLD}退出脚本${RESET}"
  2028. echo "---------------------------------------------------------------"
  2029. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" comp_choice
  2030. case $comp_choice in
  2031. 1)
  2032. CHECK_OS
  2033. CHECK_PACKAGE_MANAGER
  2034. CHECK_PKG_MANAGER
  2035. CHECKMEM
  2036. PACKAGE
  2037. COMP_INST
  2038. ;;
  2039. 2)
  2040. CHECK_OS
  2041. CHECK_PACKAGE_MANAGER
  2042. CHECK_PKG_MANAGER
  2043. while true; do
  2044. SEPARATOR "安装Docker"
  2045. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" deploy_docker
  2046. case "$deploy_docker" in
  2047. 1 )
  2048. INSTALL_DOCKER
  2049. break;;
  2050. 2 )
  2051. INSTALL_DOCKER_CN
  2052. break;;
  2053. * )
  2054. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  2055. esac
  2056. done
  2057. COMP_INST
  2058. ;;
  2059. 3)
  2060. CHECK_OS
  2061. CHECK_PACKAGE_MANAGER
  2062. CHECK_PKG_MANAGER
  2063. CHECK_COMPOSE_CMD
  2064. while true; do
  2065. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" deploy_compose
  2066. case "$deploy_compose" in
  2067. 1 )
  2068. INSTALL_COMPOSE
  2069. break;;
  2070. 2 )
  2071. INSTALL_COMPOSE_CN
  2072. break;;
  2073. * )
  2074. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  2075. esac
  2076. done
  2077. COMP_INST
  2078. ;;
  2079. 4)
  2080. CHECK_OS
  2081. CHECK_PACKAGE_MANAGER
  2082. CHECK_PKG_MANAGER
  2083. INSTALL_NGINX
  2084. COMP_INST
  2085. ;;
  2086. 5)
  2087. CHECK_OS
  2088. CHECK_PACKAGE_MANAGER
  2089. CHECK_PKG_MANAGER
  2090. INSTALL_CADDY
  2091. COMP_INST
  2092. ;;
  2093. 6)
  2094. CONFIG_NGINX
  2095. COMP_INST
  2096. ;;
  2097. 7)
  2098. CONFIG_CADDY
  2099. COMP_INST
  2100. ;;
  2101. 8)
  2102. HUBCMDUI
  2103. COMP_INST
  2104. ;;
  2105. 9)
  2106. main_menu
  2107. ;;
  2108. 0)
  2109. exit 1
  2110. ;;
  2111. *)
  2112. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-8${RESET}的选项."
  2113. COMP_INST
  2114. ;;
  2115. esac
  2116. }
  2117. function SVC_MGMT() {
  2118. CHECK_COMPOSE_CMD
  2119. RESTART_SERVICE() {
  2120. CONTAINER_SERVICES
  2121. selected_services=()
  2122. WARN "重启服务请在${LIGHT_GREEN}${DOCKER_COMPOSE_FILE}${RESET}文件存储目录下执行脚本.默认安装路径: ${LIGHT_BLUE}${PROXY_DIR}${RESET}"
  2123. REGISTRY_MENU
  2124. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" restart_service
  2125. while true; do
  2126. if [[ "$restart_service" =~ ^[0-9]+([[:space:]][0-9]+)*$ ]]; then
  2127. valid=true
  2128. for choice in $restart_service; do
  2129. if ((choice < 0 || choice > 10)); then
  2130. valid=false
  2131. break
  2132. fi
  2133. done
  2134. if $valid; then
  2135. break
  2136. fi
  2137. fi
  2138. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-10 ${RESET}序号"
  2139. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" restart_service
  2140. done
  2141. if [[ "$restart_service" == "10" ]]; then
  2142. for service_name in "${services[@]}"; do
  2143. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2144. selected_services+=("$service_name")
  2145. else
  2146. WARN "服务 ${service_name}未运行,跳过重启。"
  2147. fi
  2148. done
  2149. if [ ${#selected_services[@]} -eq 0 ]; then
  2150. WARN "选择的服务未运行,无需进行重启"
  2151. else
  2152. INFO "更新的服务: ${selected_services[*]}"
  2153. fi
  2154. elif [[ "$restart_service" == "0" ]]; then
  2155. WARN "退出重启服务!"
  2156. SVC_MGMT
  2157. else
  2158. for choice in ${restart_service}; do
  2159. if ((choice > 0 && choice < 10)); then
  2160. service_name="${services[$((choice -1))]}"
  2161. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2162. selected_services+=("$service_name")
  2163. else
  2164. WARN "服务 ${service_name} 未运行,跳过重启。"
  2165. fi
  2166. else
  2167. ERROR "无效的选择: $choice. 请重新${LIGHT_GREEN}选择0-9${RESET}的选项"
  2168. RESTART_SERVICE # 选择无效重新调用当前函数进行选择
  2169. fi
  2170. done
  2171. if [ ${#selected_services[@]} -eq 0 ]; then
  2172. WARN "选择的服务未运行,无需进行重启"
  2173. else
  2174. INFO "更新的服务: ${selected_services[*]}"
  2175. fi
  2176. fi
  2177. }
  2178. UPDATE_SERVICE() {
  2179. CONTAINER_SERVICES
  2180. selected_services=()
  2181. WARN "更新服务请在${LIGHT_GREEN}${DOCKER_COMPOSE_FILE}${RESET}文件存储目录下执行脚本.默认安装路径: ${LIGHT_BLUE}${PROXY_DIR}${RESET}"
  2182. REGISTRY_MENU
  2183. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" update_service
  2184. while true; do
  2185. if [[ "$update_service" =~ ^[0-9]+([[:space:]][0-9]+)*$ ]]; then
  2186. valid=true
  2187. for choice in $update_service; do
  2188. if ((choice < 0 || choice > 10)); then
  2189. valid=false
  2190. break
  2191. fi
  2192. done
  2193. if $valid; then
  2194. break
  2195. fi
  2196. fi
  2197. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-10 ${RESET}序号"
  2198. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" update_service
  2199. done
  2200. if [[ "$update_service" == "10" ]]; then
  2201. for service_name in "${services[@]}"; do
  2202. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2203. selected_services+=("$service_name")
  2204. else
  2205. WARN "服务 ${service_name}未运行,跳过更新。"
  2206. fi
  2207. done
  2208. if [ ${#selected_services[@]} -eq 0 ]; then
  2209. WARN "选择的服务未运行,无法进行更新"
  2210. else
  2211. INFO "更新的服务: ${selected_services[*]}"
  2212. fi
  2213. elif [[ "$update_service" == "0" ]]; then
  2214. WARN "退出更新服务!"
  2215. SVC_MGMT
  2216. else
  2217. for choice in ${update_service}; do
  2218. if ((choice > 0 && choice < 10)); then
  2219. service_name="${services[$((choice -1))]}"
  2220. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2221. selected_services+=("$service_name")
  2222. else
  2223. WARN "服务 ${service_name} 未运行,跳过更新。"
  2224. fi
  2225. else
  2226. ERROR "无效的选择: $choice. 请重新${LIGHT_GREEN}选择0-9${RESET}的选项"
  2227. UPDATE_SERVICE # 选择无效重新调用当前函数进行选择
  2228. fi
  2229. done
  2230. if [ ${#selected_services[@]} -eq 0 ]; then
  2231. WARN "选择的服务未运行,无法进行更新"
  2232. else
  2233. INFO "更新的服务: ${selected_services[*]}"
  2234. fi
  2235. fi
  2236. }
  2237. CONTAIENR_LOGS() {
  2238. CONTAINER_SERVICES
  2239. selected_services=()
  2240. REGISTRY_SER_MENU
  2241. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all选择所有${RESET} > ")" restart_service
  2242. if [[ "$restart_service" == "0" ]]; then
  2243. WARN "退出查看容器服务日志操作!"
  2244. SVC_MGMT
  2245. else
  2246. for choice in ${restart_service}; do
  2247. if [[ $choice =~ ^[0-9]+$ ]] && ((choice >0 && choice <= ${#services[@]})); then
  2248. service_name="${services[$((choice -1))]}"
  2249. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2250. selected_services+=("$service_name")
  2251. else
  2252. WARN "服务 ${service_name} 未运行,无法查看容器日志。"
  2253. fi
  2254. else
  2255. ERROR "无效的选择: $choice. 请重新${LIGHT_GREEN}选择0-9${RESET}的选项"
  2256. CONTAIENR_LOGS # 选择无效重新调用当前函数进行选择
  2257. fi
  2258. done
  2259. if [ ${#selected_services[@]} -eq 0 ]; then
  2260. WARN "选择的服务未运行,无法查看日志"
  2261. else
  2262. INFO "查看日志的服务: ${selected_services[*]}"
  2263. fi
  2264. fi
  2265. }
  2266. MODIFY_SERVICE_TTL_CONFIG() {
  2267. selected_services=()
  2268. selected_files=()
  2269. existing_files=()
  2270. non_existing_files=()
  2271. REGISTRY_FILES
  2272. while true; do
  2273. REGISTRY_SER_MENU
  2274. read -e -p "$(INFO "输入序号修改服务对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" ttl_service
  2275. if [[ "$ttl_service" == "0" ]]; then
  2276. WARN "退出修改容器服务缓存配置!"
  2277. SVC_MGMT
  2278. elif [[ "$ttl_service" =~ ^([1-8]+[[:space:]]*)+$ ]]; then
  2279. break
  2280. else
  2281. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2282. fi
  2283. done
  2284. for choice in ${ttl_service}; do
  2285. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2286. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2287. selected_files+=("$file_name")
  2288. if [ -f "${PROXY_DIR}/${file_name}" ]; then
  2289. existing_files+=("$file_name")
  2290. selected_services+=("$service_name")
  2291. else
  2292. non_existing_files+=("$file_name")
  2293. fi
  2294. if ! $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2295. WARN "服务 ${service_name} 未运行。"
  2296. fi
  2297. done
  2298. if [ ${#existing_files[@]} -gt 0 ]; then
  2299. INFO "${GREEN}存在的配置文件:${RESET} ${existing_files[*]}${RESET}"
  2300. fi
  2301. if [ ${#non_existing_files[@]} -gt 0 ]; then
  2302. WARN "${RED}不存在的配置文件:${RESET} ${non_existing_files[*]}"
  2303. fi
  2304. if [ ${#existing_files[@]} -gt 0 ]; then
  2305. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_BLUE}Proxy代理缓存过期时间${RESET} ${MAGENTA}单位:ns、us、ms、s、m、h.默认ns,0不清除缓存${RESET}"
  2306. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2307. while [[ "$modify_cache" != "y" && "$modify_cache" != "n" ]]; do
  2308. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  2309. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2310. done
  2311. if [[ "$modify_cache" == "y" ]]; then
  2312. while true; do
  2313. read -e -p "$(INFO "请输入新的缓存时间值: ")" new_ttl
  2314. for file_url in "${existing_files[@]}"; do
  2315. yml_name=$(basename "$file_url")
  2316. WARN "${YELLOW}正在修改配置文件: ${PROXY_DIR}/${yml_name}${RESET}"
  2317. sed -i "s/ttl: .*/ttl: ${new_ttl}/g" "${PROXY_DIR}/${yml_name}" &>/dev/null
  2318. INFO "${GREEN}配置文件 ${yml_name} 修改完成,代理缓存过期时间已设置为: ${new_ttl}${RESET}"
  2319. done
  2320. break
  2321. done
  2322. fi
  2323. else
  2324. WARN "未选择有效的配置文件进行修改。"
  2325. fi
  2326. }
  2327. ### 启动新容器
  2328. START_NEW_SERVER_DOWN_CONFIG() {
  2329. selected_names=()
  2330. selected_files=()
  2331. selected_containers=()
  2332. REGISTRY_SER_MENU
  2333. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" choices_newser
  2334. while [[ ! "$choices_newser" =~ ^([0-9]+[[:space:]]*)+$ ]]; do
  2335. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2336. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" choices_newser
  2337. done
  2338. if [[ "$choices_newser" == "0" ]]; then
  2339. WARN "退出下载配置! ${LIGHT_YELLOW}没有配置将无法启动服务!!!${RESET}"
  2340. SVC_MGMT
  2341. else
  2342. for choice in ${choices_newser}; do
  2343. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2344. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2345. container_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2346. file_url=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f3-)
  2347. selected_names+=("$file_name")
  2348. selected_containers+=("$container_name")
  2349. selected_files+=("$file_url")
  2350. wget -NP ${PROXY_DIR}/ $file_url &>/dev/null
  2351. else
  2352. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2353. fi
  2354. done
  2355. fi
  2356. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_BLUE}Proxy代理缓存过期时间${RESET} ${MAGENTA}单位:ns、us、ms、s、m、h.默认ns,0不清除缓存${RESET}"
  2357. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2358. while [[ "$modify_cache" != "y" && "$modify_cache" != "n" ]]; do
  2359. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  2360. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2361. done
  2362. if [[ "$modify_cache" == "y" ]]; then
  2363. while true; do
  2364. read -e -p "$(INFO "请输入新的缓存时间值: ")" new_ttl
  2365. for file_url in "${selected_files[@]}"; do
  2366. yml_name=$(basename "$file_url")
  2367. sed -ri "s/ttl: 168h/ttl: ${new_ttl}/g" ${PROXY_DIR}/${yml_name} &>/dev/null
  2368. done
  2369. break
  2370. done
  2371. fi
  2372. }
  2373. START_NEW_DOCKER_SERVICE() {
  2374. if [ -d "${PROXY_DIR}" ]; then
  2375. if [ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]; then
  2376. CONFIG_FILES
  2377. START_NEW_SERVER_DOWN_CONFIG
  2378. PROXY_HTTP
  2379. INFO "正在启动新的容器服务,请稍等..."
  2380. $DOCKER_COMPOSE_CMD -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" up -d "${selected_names[@]}"
  2381. if [ $? -ne 0 ]; then
  2382. WARN "${selected_names[*]} ${LIGHT_YELLOW}服务启动失败${RESET},请排查!"
  2383. else
  2384. INFO "${selected_names[*]} ${LIGHT_GREEN}服务启动完成${RESET}"
  2385. fi
  2386. else
  2387. WARN "${LIGHT_YELLOW}文件${PROXY_DIR}/${DOCKER_COMPOSE_FILE} 不存在,无法启动新的容器!${RESET}"
  2388. fi
  2389. else
  2390. WARN "${LIGHT_YELLOW}目录 ${PROXY_DIR} 不存在,无法启动新的容器!${RESET}"
  2391. fi
  2392. }
  2393. ### 启动新容器 END
  2394. SEPARATOR "服务管理"
  2395. echo -e "1) ${BOLD}${LIGHT_GREEN}重启${RESET}服务"
  2396. echo -e "2) ${BOLD}${LIGHT_CYAN}更新${RESET}服务"
  2397. echo -e "3) ${BOLD}${LIGHT_MAGENTA}查看${RESET}日志"
  2398. echo -e "4) ${BOLD}${LIGHT_BLUE}缓存${RESET}时效"
  2399. echo -e "5) ${BOLD}启动${CYAN}新服务${RESET}"
  2400. echo -e "6) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2401. echo -e "0) ${BOLD}退出脚本${RESET}"
  2402. echo "---------------------------------------------------------------"
  2403. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" ser_choice
  2404. case $ser_choice in
  2405. 1)
  2406. RESTART_SERVICE
  2407. if [ ${#selected_services[@]} -eq 0 ]; then
  2408. ERROR "没有需要重启的服务,请重新选择"
  2409. RESTART_SERVICE
  2410. else
  2411. $DOCKER_COMPOSE_CMD stop ${selected_services[*]}
  2412. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2413. fi
  2414. SVC_MGMT
  2415. ;;
  2416. 2)
  2417. UPDATE_SERVICE
  2418. if [ ${#selected_services[@]} -eq 0 ]; then
  2419. ERROR "没有需要更新的服务,请重新选择"
  2420. UPDATE_SERVICE
  2421. else
  2422. $DOCKER_COMPOSE_CMD pull ${selected_services[*]}
  2423. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2424. fi
  2425. SVC_MGMT
  2426. ;;
  2427. 3)
  2428. CONTAIENR_LOGS
  2429. if [ ${#selected_services[@]} -eq 0 ]; then
  2430. ERROR "没有需要查看的服务,请重新选择"
  2431. CONTAIENR_LOGS
  2432. else
  2433. # 查看最近30条日志
  2434. $DOCKER_COMPOSE_CMD logs --tail=30 ${selected_services[*]}
  2435. fi
  2436. SVC_MGMT
  2437. ;;
  2438. 4)
  2439. MODIFY_SERVICE_TTL_CONFIG
  2440. if [ ${#selected_services[@]} -eq 0 ]; then
  2441. ERROR "修改的服务未运行,请重新选择"
  2442. MODIFY_SERVICE_TTL_CONFIG
  2443. else
  2444. $DOCKER_COMPOSE_CMD restart ${selected_services[*]}
  2445. fi
  2446. SVC_MGMT
  2447. ;;
  2448. 5)
  2449. START_NEW_DOCKER_SERVICE
  2450. SVC_MGMT
  2451. ;;
  2452. 6)
  2453. main_menu
  2454. ;;
  2455. 0)
  2456. exit 1
  2457. ;;
  2458. *)
  2459. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-5${RESET}的选项."
  2460. SVC_MGMT
  2461. ;;
  2462. esac
  2463. }
  2464. function ADD_SYS_CMD() {
  2465. MAX_ATTEMPTS=3
  2466. attempt=0
  2467. success=false
  2468. TARGET_PATH="/usr/bin/hub"
  2469. INSTALL_ENV() {
  2470. while true; do
  2471. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" sys_cmd
  2472. case "$sys_cmd" in
  2473. 1 )
  2474. DOWNLOAD_URL="https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main/install/DockerProxy_Install.sh"
  2475. break;;
  2476. 2 )
  2477. DOWNLOAD_URL="https://cdn.jsdelivr.net/gh/dqzboy/Docker-Proxy/install/DockerProxy_Install.sh"
  2478. break;;
  2479. * )
  2480. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  2481. esac
  2482. done
  2483. }
  2484. INSTALL_OR_UPDATE_CMD() {
  2485. local action=$1
  2486. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  2487. attempt=$((attempt + 1))
  2488. if [[ "$action" == "安装" ]]; then
  2489. if command -v hub &> /dev/null; then
  2490. INFO "系统命令已存在,无需安装。"
  2491. success=true
  2492. break
  2493. fi
  2494. WARN "正在安装脚本中,请稍等..."
  2495. else
  2496. WARN "正在进行脚本更新,请稍等..."
  2497. if [ -f "$TARGET_PATH" ]; then
  2498. rm -f "$TARGET_PATH" &>/dev/null
  2499. fi
  2500. fi
  2501. wget -q -O "$TARGET_PATH" "$DOWNLOAD_URL" &>/dev/null
  2502. if [ $? -eq 0 ]; then
  2503. success=true
  2504. chmod +x "$TARGET_PATH"
  2505. break
  2506. fi
  2507. ERROR "${action}脚本${RED}失败${RESET},正在尝试重新${action} (尝试次数: $attempt)"
  2508. done
  2509. if $success; then
  2510. INFO "${action}脚本${GREEN}成功${RESET},命令行输入 ${LIGHT_GREEN}hub${RESET} 运行"
  2511. else
  2512. ERROR "设置系统命令失败"
  2513. exit 1
  2514. fi
  2515. }
  2516. SEPARATOR "设置脚本为系统命令"
  2517. echo -e "1) ${BOLD}安装${LIGHT_GREEN}系统命令${RESET}"
  2518. echo -e "2) ${BOLD}更新${LIGHT_CYAN}系统命令${RESET}"
  2519. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2520. echo -e "0) ${BOLD}退出脚本${RESET}"
  2521. echo "---------------------------------------------------------------"
  2522. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" cmd_choice
  2523. case $cmd_choice in
  2524. 1)
  2525. INSTALL_ENV
  2526. INSTALL_OR_UPDATE_CMD "安装"
  2527. ;;
  2528. 2)
  2529. INSTALL_ENV
  2530. INSTALL_OR_UPDATE_CMD "更新"
  2531. ;;
  2532. 3)
  2533. main_menu
  2534. ;;
  2535. 0)
  2536. exit 1
  2537. ;;
  2538. *)
  2539. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2540. ADD_SYS_CMD
  2541. ;;
  2542. esac
  2543. }
  2544. function UNI_DOCKER_SERVICE() {
  2545. CHECK_COMPOSE_CMD
  2546. RM_SERVICE() {
  2547. selected_containers=()
  2548. REGISTRY_FILES
  2549. REGISTRY_SER_MENU
  2550. read -e -p "$(INFO "输入序号删除服务和对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" rm_service
  2551. while [[ ! "$rm_service" =~ ^([0-9]+[[:space:]]*)+$ ]]; do
  2552. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2553. read -e -p "$(INFO "输入序号删除服务和对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" rm_service
  2554. done
  2555. if [[ "$rm_service" == "0" ]]; then
  2556. WARN "退出删除容器服务操作!"
  2557. return
  2558. else
  2559. selected_services=()
  2560. for choice in ${rm_service}; do
  2561. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2562. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2563. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2564. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2565. selected_services+=("$service_name")
  2566. else
  2567. WARN "服务 ${LIGHT_MAGENTA}${service_name} 未运行${RESET},但将尝试删除相关文件。"
  2568. fi
  2569. if [ -f "${PROXY_DIR}/${file_name}" ]; then
  2570. rm -f "${PROXY_DIR}/${file_name}"
  2571. INFO "配置文件 ${LIGHT_CYAN}${file_name}${RESET} ${LIGHT_GREEN}已被删除${RESET}"
  2572. else
  2573. WARN "配置文件 ${LIGHT_CYAN}${file_name}${RESET} 不存在,${LIGHT_YELLOW}无需删除${RESET}"
  2574. fi
  2575. else
  2576. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2577. UNI_DOCKER_SERVICE
  2578. return
  2579. fi
  2580. done
  2581. # 一次性删除所有选中的服务
  2582. if [ ${#selected_services[@]} -gt 0 ]; then
  2583. INFO "删除的服务: ${LIGHT_RED}${selected_services[*]}${RESET}"
  2584. $DOCKER_COMPOSE_CMD down ${selected_services[*]}
  2585. fi
  2586. fi
  2587. }
  2588. RM_ALLSERVICE() {
  2589. STOP_REMOVE_CONTAINER
  2590. REMOVE_NONE_TAG
  2591. REMOVE_CMDUI
  2592. docker rmi --force $(docker images -q ${IMAGE_NAME}) &>/dev/null
  2593. docker rmi --force $(docker images -q ${UI_IMAGE_NAME}) &>/dev/null
  2594. if [ -d "${PROXY_DIR}" ]; then
  2595. rm -rf "${PROXY_DIR}" &>/dev/null
  2596. fi
  2597. if [ -f "/usr/bin/hub" ]; then
  2598. rm -f /usr/bin/hub &>/dev/null
  2599. fi
  2600. INFO "${LIGHT_YELLOW}感谢您的使用,Docker-Proxy服务已卸载。欢迎您再次使用!${RESET}"
  2601. SEPARATOR "DONE"
  2602. }
  2603. CONFIREM_ACTION() {
  2604. local action_name=$1
  2605. local action_function=$2
  2606. WARN "${LIGHT_RED}注意:${RESET} ${LIGHT_YELLOW}卸载服务会一同将本地的配置和对应服务删除,请执行删除之前确定是否需要备份本地的配置文件${RESET}"
  2607. while true; do
  2608. read -e -p "$(INFO "本人${LIGHT_RED}已知晓后果,确认${action_name}${RESET}服务? ${PROMPT_YES_NO}")" uniservice
  2609. case "$uniservice" in
  2610. y|Y )
  2611. $action_function
  2612. break;;
  2613. n|N )
  2614. WARN "退出${action_name}服务."
  2615. break;;
  2616. * )
  2617. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  2618. esac
  2619. done
  2620. }
  2621. SEPARATOR "卸载服务"
  2622. echo -e "1) ${BOLD}卸载${LIGHT_YELLOW}所有服务${RESET}"
  2623. echo -e "2) ${BOLD}删除${LIGHT_CYAN}指定服务${RESET}"
  2624. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2625. echo -e "0) ${BOLD}退出脚本${RESET}"
  2626. echo "---------------------------------------------------------------"
  2627. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" rm_choice
  2628. case $rm_choice in
  2629. 1)
  2630. CONFIREM_ACTION "卸载所有" RM_ALLSERVICE
  2631. ;;
  2632. 2)
  2633. CONFIREM_ACTION "删除指定" RM_SERVICE
  2634. UNI_DOCKER_SERVICE
  2635. ;;
  2636. 3)
  2637. main_menu
  2638. ;;
  2639. 0)
  2640. exit 1
  2641. ;;
  2642. *)
  2643. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2644. UNI_DOCKER_SERVICE
  2645. ;;
  2646. esac
  2647. }
  2648. function AUTH_SERVICE_CONFIG() {
  2649. CHECK_COMPOSE_CMD
  2650. CHECK_REG_AUTH() {
  2651. if ! command -v docker &> /dev/null; then
  2652. ERROR "docker 命令未找到,请确保 Docker 已正确安装"
  2653. AUTH_SERVICE_CONFIG
  2654. fi
  2655. # 重置数组
  2656. running_containers=()
  2657. stopped_containers=()
  2658. auth_containers=()
  2659. non_auth_containers=()
  2660. declare -A services
  2661. services=(
  2662. ["reg-docker-hub"]="dockerhub"
  2663. ["reg-gcr"]="gcr"
  2664. ["reg-ghcr"]="ghcr"
  2665. ["reg-quay"]="quay"
  2666. ["reg-k8s-gcr"]="k8sgcr"
  2667. ["reg-k8s"]="k8s"
  2668. ["reg-mcr"]="mcr"
  2669. ["reg-elastic"]="elastic"
  2670. ["reg-nvcr"]="nvcr"
  2671. )
  2672. container_names=$(docker ps --filter "name=reg-" --filter "status=running" --format "{{.Names}}")
  2673. # 检查哪些容器正在运行
  2674. for container_name in "${!services[@]}"; do
  2675. if docker ps --filter "name=$container_name" --filter "status=running" --format "{{.Names}}" | grep -q "$container_name"; then
  2676. running_containers+=("${services[$container_name]}")
  2677. else
  2678. stopped_containers+=("${services[$container_name]}")
  2679. fi
  2680. done
  2681. if [ ${#running_containers[@]} -gt 0 ]; then
  2682. INFO "当前运行的 Docker 容器有: ${LIGHT_CYAN}${running_containers[*]}${RESET}"
  2683. else
  2684. WARN "当前没有运行的 Docker 容器"
  2685. AUTH_SERVICE_CONFIG # 如果没有运行的容器,直接返回
  2686. fi
  2687. auth_containers=()
  2688. non_auth_containers=()
  2689. for container_name in $container_names; do
  2690. specified_name=${services[$container_name]}
  2691. if [ -z "$specified_name" ]; then
  2692. specified_name=$container_name
  2693. fi
  2694. if docker exec $container_name grep -q "auth" /etc/distribution/config.yml; then
  2695. auth_containers+=("$specified_name")
  2696. else
  2697. non_auth_containers+=("$specified_name")
  2698. fi
  2699. done
  2700. if [ ${#auth_containers[@]} -gt 0 ]; then
  2701. INFO "当前运行的 Docker 容器中${LIGHT_GREEN}包含认证${RESET}的容器有: ${LIGHT_CYAN}${auth_containers[*]}${RESET}"
  2702. else
  2703. WARN "当前运行的 Docker 容器中${LIGHT_YELLOW}没有包含认证${RESET}的容器"
  2704. fi
  2705. if [ ${#non_auth_containers[@]} -gt 0 ]; then
  2706. WARN "当前运行的 Docker 容器中${LIGHT_YELLOW}没有包含认证${RESET}的容器有: ${LIGHT_BLUE}${non_auth_containers[*]}${RESET}"
  2707. else
  2708. INFO "当前运行的 Docker 容器中${LIGHT_GREEN}所有容器都包含认证${RESET}"
  2709. fi
  2710. }
  2711. AUTH_MENU() {
  2712. CHECK_REG_AUTH
  2713. selected_files=()
  2714. selected_services=()
  2715. REGISTRY_FILES
  2716. REGISTRY_SER_MENU
  2717. read -e -p "$(INFO "输入序号选择添加认证的服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" auth_service
  2718. while [[ ! "$auth_service" =~ ^([0-9]+[[:space:]]*)+$ ]]; do
  2719. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2720. read -e -p "$(INFO "输入序号选择添加认证的服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" auth_service
  2721. done
  2722. }
  2723. ADD_AUTH_CONFIG() {
  2724. local FILE=$1
  2725. local auth_config="
  2726. auth:
  2727. htpasswd:
  2728. realm: basic-realm
  2729. path: /auth/htpasswd"
  2730. if [ ! -f "$FILE" ]; then
  2731. ERROR "配置文件 ${LIGHT_BLUE}$FILE${RESET} 不存在"
  2732. exit 1
  2733. else
  2734. if ! grep -q "auth:" "$FILE" || ! grep -q "htpasswd:" "$FILE" || ! grep -q "realm: basic-realm" "$FILE" || ! grep -q "path: /auth/htpasswd" "$FILE"; then
  2735. echo -e "$auth_config" | sudo tee -a "$FILE" > /dev/null
  2736. INFO "配置文件 ${LIGHT_BLUE}$FILE${RESET} 添加认证配置成功"
  2737. else
  2738. WARN "配置文件 ${LIGHT_BLUE}$FILE${RESET} 已添加认证配置"
  2739. fi
  2740. fi
  2741. }
  2742. ADD_AUTH_COMPOSE() {
  2743. local SERVICES=$1
  2744. local FILE=${DOCKER_COMPOSE_FILE}
  2745. local HTPASSWD_CONFIG=" - ./${SERVICES}_htpasswd:/auth/htpasswd"
  2746. if [ ! -f "$FILE" ]; then
  2747. ERROR "配置文件 ${LIGHT_BLUE}$FILE${RESET} 不存在"
  2748. exit 1
  2749. fi
  2750. for SERVICE in "${SERVICES[@]}"; do
  2751. if grep -q " $SERVICE:" "$FILE"; then
  2752. if ! grep -A10 " $SERVICE:" "$FILE" | grep -q " - ./${SERVICES}_htpasswd:/auth/htpasswd"; then
  2753. sed -i "/ $SERVICE:/,/volumes:/ {
  2754. /volumes:/a\\
  2755. $HTPASSWD_CONFIG
  2756. }" "$FILE"
  2757. INFO "Htpasswd配置添加到 ${LIGHT_GREEN}$SERVICE${RESET} 服务中"
  2758. else
  2759. WARN "Htpasswd配置已存在 ${LIGHT_YELLOW}$SERVICE${RESET} 服务中"
  2760. fi
  2761. else
  2762. ERROR "服务 $SERVICE 在 $FILE 中不存在"
  2763. fi
  2764. done
  2765. }
  2766. DEL_AUTH_CONFIG() {
  2767. local FILE=$1
  2768. if [ ! -f "$FILE" ]; then
  2769. ERROR "配置文件 $FILE 不存在"
  2770. else
  2771. if grep -q "auth:" "$FILE"; then
  2772. sed -i '/^auth:$/,/^[^[:space:]]/d' "$FILE" >/dev/null
  2773. INFO "配置文件 ${LIGHT_BLUE}$FILE${RESET} 成功移除认证信息"
  2774. else
  2775. WARN "配置文件 ${LIGHT_BLUE}$FILE${RESET} 不存在认证信息"
  2776. fi
  2777. fi
  2778. }
  2779. DEL_AUTH_COMPOSE() {
  2780. local SERVICES=$1
  2781. local FILE=${DOCKER_COMPOSE_FILE}
  2782. if [ ! -f "$FILE" ]; then
  2783. ERROR "$File 不存在"
  2784. exit 1
  2785. fi
  2786. for SERVICE in "${SERVICES[@]}"; do
  2787. if grep -q " $SERVICE:" "$FILE"; then
  2788. sed -i "/ $SERVICE:/,/^[^[:space:]]/ {/^[[:space:]]*- .\/${SERVICES}_htpasswd:\/auth\/htpasswd/d}" "$FILE"
  2789. else
  2790. ERROR "$FILE 中不存在服务 $SERVICE"
  2791. fi
  2792. done
  2793. }
  2794. ENABLE_AUTH() {
  2795. AUTH_MENU
  2796. if [[ "$auth_service" == "0" ]]; then
  2797. WARN "退出添加容器认证操作!"
  2798. return
  2799. else
  2800. for choice in ${auth_service}; do
  2801. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2802. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2803. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2804. selected_files+=("$file_name")
  2805. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2806. selected_services+=("$service_name")
  2807. else
  2808. WARN "服务 ${LIGHT_MAGENTA}${service_name} 未运行${RESET},无法添加认证授权"
  2809. fi
  2810. else
  2811. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2812. AUTH_MENU
  2813. return
  2814. fi
  2815. done
  2816. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_CYAN}配置认证后,执行镜像拉取需先通过 docker login登入后使用.访问UI需输入账号密码${RESET}"
  2817. read -e -p "$(INFO "是否需要配置镜像仓库访问账号和密码? ${PROMPT_YES_NO}")" enable_auth
  2818. while [[ "$enable_auth" != "y" && "$enable_auth" != "n" ]]; do
  2819. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  2820. read -e -p "$(INFO "是否需要配置镜像仓库访问账号和密码? ${PROMPT_YES_NO}")" enable_auth
  2821. done
  2822. if [[ "$enable_auth" == "y" ]]; then
  2823. while true; do
  2824. read -e -p "$(INFO "请输入账号名称: ")" username
  2825. if [[ -z "$username" ]]; then
  2826. ERROR "用户名不能为空。请重新输入"
  2827. else
  2828. break
  2829. fi
  2830. done
  2831. while true; do
  2832. read -e -p "$(INFO "请输入账号密码: ")" password
  2833. if [[ -z "$password" ]]; then
  2834. ERROR "密码不能为空。请重新输入"
  2835. else
  2836. break
  2837. fi
  2838. done
  2839. for file_url in "${selected_files[@]}"; do
  2840. yml_name=$(basename "$file_url")
  2841. ADD_AUTH_CONFIG "${PROXY_DIR}/${yml_name}"
  2842. done
  2843. for server in "${selected_services[@]}"; do
  2844. htpasswd -Bbc ${PROXY_DIR}/${server}_htpasswd "$username" "$password" 2>/dev/null
  2845. ADD_AUTH_COMPOSE "${server}"
  2846. done
  2847. fi
  2848. fi
  2849. }
  2850. DELETE_AUTH() {
  2851. AUTH_MENU
  2852. if [[ "$auth_service" == "0" ]]; then
  2853. WARN "退出移除容器认证操作!"
  2854. return
  2855. else
  2856. for choice in ${auth_service}; do
  2857. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2858. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2859. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2860. selected_files+=("$file_name")
  2861. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2862. selected_services+=("$service_name")
  2863. else
  2864. WARN "服务 ${LIGHT_MAGENTA}${service_name} 未运行${RESET},无法添加认证授权"
  2865. fi
  2866. else
  2867. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2868. AUTH_MENU
  2869. return
  2870. fi
  2871. done
  2872. for file_url in "${selected_files[@]}"; do
  2873. yml_name=$(basename "$file_url")
  2874. DEL_AUTH_CONFIG "${PROXY_DIR}/${yml_name}"
  2875. done
  2876. for server in "${selected_services[@]}"; do
  2877. DEL_AUTH_COMPOSE "${server}"
  2878. rm -f ${PROXY_DIR}/${server}_htpasswd
  2879. done
  2880. fi
  2881. }
  2882. SEPARATOR "认证授权"
  2883. echo -e "1) ${BOLD}${LIGHT_YELLOW}添加${RESET}认证"
  2884. echo -e "2) ${BOLD}${LIGHT_CYAN}删除${RESET}认证"
  2885. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2886. echo -e "0) ${BOLD}退出脚本${RESET}"
  2887. echo "---------------------------------------------------------------"
  2888. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" auth_choice
  2889. case $auth_choice in
  2890. 1)
  2891. ENABLE_AUTH
  2892. if [ ${#selected_services[@]} -eq 0 ]; then
  2893. WARN "退出认证授权,请${LIGHT_CYAN}重新选择${RESET}服务认证的操作"
  2894. AUTH_SERVICE_CONFIG # 没有服务运行调用函数
  2895. else
  2896. $DOCKER_COMPOSE_CMD down ${selected_services[*]}
  2897. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2898. fi
  2899. AUTH_SERVICE_CONFIG
  2900. ;;
  2901. 2)
  2902. DELETE_AUTH
  2903. if [ ${#selected_services[@]} -eq 0 ]; then
  2904. WARN "退出认证授权,请${LIGHT_CYAN}重新选择${RESET}服务认证的操作"
  2905. AUTH_SERVICE_CONFIG # 没有服务运行调用函数
  2906. else
  2907. $DOCKER_COMPOSE_CMD down ${selected_services[*]}
  2908. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2909. fi
  2910. AUTH_SERVICE_CONFIG
  2911. ;;
  2912. 3)
  2913. main_menu
  2914. ;;
  2915. 0)
  2916. exit 1
  2917. ;;
  2918. *)
  2919. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2920. AUTH_SERVICE_CONFIG
  2921. ;;
  2922. esac
  2923. }
  2924. # 本机Docker代理
  2925. function DOCKER_PROXY() {
  2926. SEPARATOR "Docker服务代理"
  2927. echo -e "1) ${BOLD}${LIGHT_GREEN}添加${RESET}本机Docker代理"
  2928. echo -e "2) ${BOLD}${YELLOW}移除${RESET}本机Docker代理"
  2929. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2930. echo -e "0) ${BOLD}退出脚本${RESET}"
  2931. echo "---------------------------------------------------------------"
  2932. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" main_choice
  2933. case $main_choice in
  2934. 1)
  2935. DOCKER_PROXY_HTTP
  2936. ADD_DOCKERD_PROXY
  2937. DOCKER_PROXY
  2938. ;;
  2939. 2)
  2940. DEL_DOCKERD_PROXY
  2941. DOCKER_PROXY
  2942. ;;
  2943. 3)
  2944. main_menu
  2945. ;;
  2946. 0)
  2947. exit 1
  2948. ;;
  2949. *)
  2950. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2951. sleep 2; DOCKER_PROXY
  2952. ;;
  2953. esac
  2954. }
  2955. # IP 黑白名单
  2956. function IP_BLACKWHITE_LIST() {
  2957. if ! command -v iptables &> /dev/null
  2958. then
  2959. WARN "iptables 未安装. 请安装后再运行此脚本."
  2960. exit 1
  2961. fi
  2962. IPTABLES=$(which iptables)
  2963. BLACKLIST_CHAIN="IP_BLACKLIST"
  2964. WHITELIST_CHAIN="IP_WHITELIST"
  2965. WHITELIST_FILE="/etc/firewall/whitelist.txt"
  2966. BLACKLIST_FILE="/etc/firewall/blacklist.txt"
  2967. # 确保文件存在
  2968. mkdir -p /etc/firewall
  2969. touch $WHITELIST_FILE $BLACKLIST_FILE
  2970. get_chain_name() {
  2971. local chain=$1
  2972. case $chain in
  2973. $BLACKLIST_CHAIN) echo "黑名单" ;;
  2974. $WHITELIST_CHAIN) echo "白名单" ;;
  2975. *) echo "未知名单" ;;
  2976. esac
  2977. }
  2978. create_chains() {
  2979. $IPTABLES -N $BLACKLIST_CHAIN 2>/dev/null
  2980. $IPTABLES -N $WHITELIST_CHAIN 2>/dev/null
  2981. }
  2982. check_ip() {
  2983. local ip=$1
  2984. local ipv4_regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
  2985. local ipv6_regex='^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$'
  2986. if [[ $ip =~ $ipv4_regex ]] || [[ $ip =~ $ipv6_regex ]]; then
  2987. return 0
  2988. else
  2989. return 1
  2990. fi
  2991. }
  2992. ip_exists_in_file() {
  2993. local ip=$1
  2994. local file=$2
  2995. grep -q "^$ip$" "$file"
  2996. return $?
  2997. }
  2998. add_ips_to_file() {
  2999. local ips=("$@")
  3000. local file="${ips[-1]}"
  3001. unset 'ips[-1]'
  3002. local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
  3003. local added=()
  3004. local skipped=()
  3005. for ip in "${ips[@]}"; do
  3006. if ! ip_exists_in_file $ip $file; then
  3007. echo $ip >> "$file"
  3008. added+=("$ip")
  3009. else
  3010. skipped+=("$ip")
  3011. fi
  3012. done
  3013. if [ ${#added[@]} -gt 0 ]; then
  3014. INFO "${LIGHT_BLUE}${added[*]}${RESET} ${LIGHT_GREEN}已添加${RESET}到$chain_name"
  3015. fi
  3016. if [ ${#skipped[@]} -gt 0 ]; then
  3017. WARN "${LIGHT_BLUE}${skipped[*]}${RESET} ${LIGHT_YELLOW}已存在${RESET}于$chain_name,跳过添加"
  3018. fi
  3019. }
  3020. remove_ips_from_file() {
  3021. local ips=("$@")
  3022. local file="${ips[-1]}"
  3023. unset 'ips[-1]'
  3024. local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
  3025. local removed=()
  3026. local not_found=()
  3027. for ip in "${ips[@]}"; do
  3028. if ip_exists_in_file $ip $file; then
  3029. sed -i "/^$ip$/d" "$file"
  3030. removed+=("$ip")
  3031. else
  3032. not_found+=("$ip")
  3033. fi
  3034. done
  3035. if [ ${#removed[@]} -gt 0 ]; then
  3036. INFO "${LIGHT_BLUE}${removed[*]}${RESET} ${LIGHT_RED}已从${RESET}$chain_name${LIGHT_RED}移除${RESET}"
  3037. fi
  3038. if [ ${#not_found[@]} -gt 0 ]; then
  3039. WARN "${LIGHT_BLUE}${not_found[*]}${RESET} ${LIGHT_YELLOW}不存在${RESET}于$chain_name,无需移除"
  3040. fi
  3041. }
  3042. list_ips_in_file() {
  3043. local file=$1
  3044. local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
  3045. echo "---------------------------------------------------------------"
  3046. echo "当前${chain_name}中的IP列表:"
  3047. cat "$file"
  3048. }
  3049. apply_ip_list() {
  3050. local chain=$1
  3051. local file=$2
  3052. local action=$3
  3053. # 清空链
  3054. $IPTABLES -F $chain
  3055. # 使用 iptables-restore 批量应用规则
  3056. {
  3057. echo "*filter"
  3058. echo ":$chain - [0:0]"
  3059. while IFS= read -r ip; do
  3060. echo "-A $chain -s $ip -j $action"
  3061. done < "$file"
  3062. echo "COMMIT"
  3063. } | $IPTABLES-restore -n
  3064. }
  3065. ensure_default_deny_for_whitelist() {
  3066. if ! $IPTABLES -C $WHITELIST_CHAIN -j DROP &>/dev/null; then
  3067. $IPTABLES -A $WHITELIST_CHAIN -j DROP
  3068. fi
  3069. }
  3070. whitelist_is_empty() {
  3071. [ ! -s "$WHITELIST_FILE" ]
  3072. }
  3073. apply_whitelist() {
  3074. if whitelist_is_empty; then
  3075. WARN "白名单为空,不应用白名单规则以避免锁定系统。"
  3076. return 1
  3077. fi
  3078. if ! $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
  3079. $IPTABLES -I INPUT 1 -j $WHITELIST_CHAIN
  3080. INFO "已将白名单规则应用到 INPUT 链"
  3081. else
  3082. INFO "白名单规则已经应用到 INPUT 链"
  3083. fi
  3084. apply_ip_list $WHITELIST_CHAIN $WHITELIST_FILE ACCEPT
  3085. ensure_default_deny_for_whitelist
  3086. return 0
  3087. }
  3088. switch_to_whitelist() {
  3089. $IPTABLES -D INPUT -j $BLACKLIST_CHAIN 2>/dev/null
  3090. INFO "${LIGHT_YELLOW}已切换到白名单模式,请注意:请在添加IP后手动应用规则${RESET}"
  3091. }
  3092. switch_to_blacklist() {
  3093. $IPTABLES -D INPUT -j $WHITELIST_CHAIN 2>/dev/null
  3094. $IPTABLES -I INPUT 1 -j $BLACKLIST_CHAIN
  3095. apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
  3096. INFO "${LIGHT_YELLOW}已切换到黑名单模式${RESET}"
  3097. }
  3098. handle_whitelist() {
  3099. create_chains
  3100. local whitelist_mode_active=false
  3101. local whitelist_rules_applied=false
  3102. if $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
  3103. whitelist_mode_active=true
  3104. whitelist_rules_applied=true
  3105. elif $IPTABLES -C INPUT -j $BLACKLIST_CHAIN &>/dev/null; then
  3106. read -e -p "$(WARN "${LIGHT_YELLOW}当前使用黑名单模式${RESET},${LIGHT_CYAN}是否切换到白名单模式?(y/n)${RESET}: ")" switch
  3107. if [[ $switch == "y" ]]; then
  3108. switch_to_whitelist
  3109. whitelist_mode_active=true
  3110. whitelist_rules_applied=false
  3111. else
  3112. WARN "保持在黑名单模式,返回主菜单。"
  3113. return
  3114. fi
  3115. else
  3116. switch_to_whitelist
  3117. whitelist_mode_active=true
  3118. whitelist_rules_applied=false
  3119. fi
  3120. while true; do
  3121. echo "---------------------------------------------------------------"
  3122. echo -e "1) ${BOLD}添加IP到白名单${RESET}"
  3123. echo -e "2) ${BOLD}从白名单移除IP${RESET}"
  3124. echo -e "3) ${BOLD}查看当前白名单${RESET}"
  3125. echo -e "4) ${BOLD}应用白名单规则${RESET}"
  3126. echo -e "5) ${BOLD}返回上一级${RESET}"
  3127. echo "---------------------------------------------------------------"
  3128. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" whitelist_choice
  3129. case $whitelist_choice in
  3130. 1)
  3131. read -e -p "$(INFO "${LIGHT_CYAN}请输入要添加到白名单的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3132. IFS=',' read -ra ip_array <<< "$ips"
  3133. valid_ips=()
  3134. for ip in "${ip_array[@]}"; do
  3135. if check_ip $ip; then
  3136. valid_ips+=("$ip")
  3137. else
  3138. WARN "无效IP: $ip"
  3139. fi
  3140. done
  3141. if [ ${#valid_ips[@]} -gt 0 ]; then
  3142. add_ips_to_file "${valid_ips[@]}" "$WHITELIST_FILE"
  3143. whitelist_rules_applied=false
  3144. fi
  3145. ;;
  3146. 2)
  3147. read -e -p "$(INFO "${LIGHT_CYAN}请输入要从白名单移除的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3148. IFS=',' read -ra ip_array <<< "$ips"
  3149. valid_ips=()
  3150. for ip in "${ip_array[@]}"; do
  3151. if check_ip $ip; then
  3152. valid_ips+=("$ip")
  3153. else
  3154. WARN "无效IP: $ip"
  3155. fi
  3156. done
  3157. if [ ${#valid_ips[@]} -gt 0 ]; then
  3158. remove_ips_from_file "${valid_ips[@]}" "$WHITELIST_FILE"
  3159. whitelist_rules_applied=false
  3160. fi
  3161. ;;
  3162. 3)
  3163. list_ips_in_file $WHITELIST_FILE
  3164. ;;
  3165. 4)
  3166. if apply_whitelist; then
  3167. whitelist_rules_applied=true
  3168. INFO "${LIGHT_GREEN}白名单规则已成功应用${RESET}"
  3169. else
  3170. WARN "${LIGHT_YELLOW}无法应用白名单规则${RESET}"
  3171. fi
  3172. ;;
  3173. 5)
  3174. if ! $whitelist_rules_applied; then
  3175. read -e -p "$(WARN "${LIGHT_YELLOW}白名单规则尚未应用。您确定要退出吗?${RESET} (y/n): ")" confirm
  3176. if [[ $confirm != "y" ]]; then
  3177. continue
  3178. fi
  3179. fi
  3180. return
  3181. ;;
  3182. *)
  3183. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择1-5${RESET}的选项."
  3184. ;;
  3185. esac
  3186. done
  3187. }
  3188. handle_blacklist() {
  3189. create_chains
  3190. local blacklist_mode_active=false
  3191. if $IPTABLES -C INPUT -j $BLACKLIST_CHAIN &>/dev/null; then
  3192. blacklist_mode_active=true
  3193. elif $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
  3194. read -e -p "$(WARN "${LIGHT_YELLOW}当前使用白名单模式${RESET},${LIGHT_CYAN}是否切换到黑名单模式?(y/n)${RESET}: ")" switch
  3195. if [[ $switch == "y" ]]; then
  3196. switch_to_blacklist
  3197. blacklist_mode_active=true
  3198. else
  3199. WARN "保持在白名单模式,返回主菜单。"
  3200. return
  3201. fi
  3202. else
  3203. switch_to_blacklist
  3204. blacklist_mode_active=true
  3205. fi
  3206. while true; do
  3207. echo "---------------------------------------------------------------"
  3208. echo -e "1) ${BOLD}添加IP到黑名单${RESET}"
  3209. echo -e "2) ${BOLD}从黑名单移除IP${RESET}"
  3210. echo -e "3) ${BOLD}查看当前黑名单${RESET}"
  3211. echo -e "4) ${BOLD}返回上一级${RESET}"
  3212. echo "---------------------------------------------------------------"
  3213. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" blacklist_choice
  3214. case $blacklist_choice in
  3215. 1)
  3216. read -e -p "$(INFO "${LIGHT_CYAN}请输入要添加到黑名单的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3217. IFS=',' read -ra ip_array <<< "$ips"
  3218. valid_ips=()
  3219. for ip in "${ip_array[@]}"; do
  3220. if check_ip $ip; then
  3221. valid_ips+=("$ip")
  3222. else
  3223. WARN "无效IP: $ip"
  3224. fi
  3225. done
  3226. if [ ${#valid_ips[@]} -gt 0 ]; then
  3227. add_ips_to_file "${valid_ips[@]}" "$BLACKLIST_FILE"
  3228. apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
  3229. fi
  3230. ;;
  3231. 2)
  3232. read -e -p "$(INFO "${LIGHT_CYAN}请输入要从黑名单移除的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3233. IFS=',' read -ra ip_array <<< "$ips"
  3234. valid_ips=()
  3235. for ip in "${ip_array[@]}"; do
  3236. if check_ip $ip; then
  3237. valid_ips+=("$ip")
  3238. else
  3239. WARN "无效IP: $ip"
  3240. fi
  3241. done
  3242. if [ ${#valid_ips[@]} -gt 0 ]; then
  3243. remove_ips_from_file "${valid_ips[@]}" "$BLACKLIST_FILE"
  3244. apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
  3245. fi
  3246. ;;
  3247. 3)
  3248. list_ips_in_file $BLACKLIST_FILE
  3249. ;;
  3250. 4)
  3251. return
  3252. ;;
  3253. *)
  3254. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择1-4${RESET}的选项."
  3255. ;;
  3256. esac
  3257. done
  3258. }
  3259. while true; do
  3260. SEPARATOR "设置IP黑白名单"
  3261. echo -e "1) ${BOLD}管理${LIGHT_GREEN}白名单${RESET}"
  3262. echo -e "2) ${BOLD}管理${LIGHT_CYAN}黑名单${RESET}"
  3263. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  3264. echo -e "0) ${BOLD}退出脚本${RESET}"
  3265. echo "---------------------------------------------------------------"
  3266. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" ipblack_choice
  3267. case $ipblack_choice in
  3268. 1)
  3269. handle_whitelist
  3270. ;;
  3271. 2)
  3272. handle_blacklist
  3273. ;;
  3274. 3)
  3275. main_menu
  3276. ;;
  3277. 0)
  3278. exit 0
  3279. ;;
  3280. *)
  3281. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  3282. ;;
  3283. esac
  3284. done
  3285. }
  3286. # 其他工具
  3287. function OtherTools() {
  3288. SEPARATOR "其他工具"
  3289. echo -e "1) 设置${BOLD}${YELLOW}系统命令${RESET}"
  3290. echo -e "2) 配置${BOLD}${LIGHT_MAGENTA}IP黑白名单${RESET}"
  3291. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  3292. echo -e "0) ${BOLD}退出脚本${RESET}"
  3293. echo "---------------------------------------------------------------"
  3294. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" main_choice
  3295. case $main_choice in
  3296. 1)
  3297. ADD_SYS_CMD
  3298. ;;
  3299. 2)
  3300. IP_BLACKWHITE_LIST
  3301. ;;
  3302. 3)
  3303. main_menu
  3304. ;;
  3305. 0)
  3306. exit 1
  3307. ;;
  3308. *)
  3309. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  3310. sleep 2; main_menu
  3311. ;;
  3312. esac
  3313. }
  3314. ## 主菜单
  3315. function main_menu() {
  3316. echo -e "╔════════════════════════════════════════════════════╗"
  3317. echo -e "║ ║"
  3318. echo -e "║ ${LIGHT_CYAN}欢迎使用Docker-Proxy${RESET} ║"
  3319. echo -e "║ ║"
  3320. echo -e "║ TG交流群: ${UNDERLINE}https://t.me/Docker_Proxy${RESET} ║"
  3321. echo -e "║ ║"
  3322. echo -e "║ ${LIGHT_BLUE}by dqzboy${RESET} ║"
  3323. echo -e "║ ║"
  3324. echo -e "╚════════════════════════════════════════════════════╝"
  3325. echo
  3326. SEPARATOR "请选择操作"
  3327. echo -e "1) ${BOLD}${LIGHT_GREEN}安装${RESET}服务"
  3328. echo -e "2) ${BOLD}${LIGHT_MAGENTA}组件${RESET}安装"
  3329. echo -e "3) ${BOLD}${LIGHT_YELLOW}管理${RESET}服务"
  3330. echo -e "4) ${BOLD}${LIGHT_CYAN}更新${RESET}配置"
  3331. echo -e "5) ${BOLD}${LIGHT_RED}卸载${RESET}服务"
  3332. echo -e "6) ${BOLD}${LIGHT_BLUE}认证${RESET}授权"
  3333. echo -e "7) 本机${BOLD}${CYAN}Docker代理${RESET}"
  3334. echo -e "8) 其他${BOLD}${YELLOW}工具${RESET}"
  3335. echo -e "0) ${BOLD}退出脚本${RESET}"
  3336. echo "---------------------------------------------------------------"
  3337. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" main_choice
  3338. case $main_choice in
  3339. 1)
  3340. INSTALL_PROXY
  3341. ;;
  3342. 2)
  3343. COMP_INST
  3344. ;;
  3345. 3)
  3346. SVC_MGMT
  3347. ;;
  3348. 4)
  3349. SEPARATOR "更新配置"
  3350. UPDATE_CONFIG
  3351. SEPARATOR "更新完成"
  3352. ;;
  3353. 5)
  3354. UNI_DOCKER_SERVICE
  3355. ;;
  3356. 6)
  3357. AUTH_SERVICE_CONFIG
  3358. ;;
  3359. 7)
  3360. DOCKER_PROXY
  3361. ;;
  3362. 8)
  3363. OtherTools
  3364. ;;
  3365. 0)
  3366. exit 1
  3367. ;;
  3368. *)
  3369. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-8${RESET}的选项."
  3370. sleep 2; main_menu
  3371. ;;
  3372. esac
  3373. }
  3374. main_menu