commit 0b703a77caba0b0de54bddde62ac953006e2022b Author: dqzboy Date: Sat Jun 29 12:04:06 2024 +0800 revert diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..db68ea8 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b8c1251 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,13 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: ['https://github.com/dqzboy/dqzboy/blob/main/.github/FUNDING.md'] diff --git a/.github/ISSUE_TEMPLATE/1.issue.yml b/.github/ISSUE_TEMPLATE/1.issue.yml new file mode 100644 index 0000000..c71cb92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1.issue.yml @@ -0,0 +1,62 @@ +name: 反馈问题 🐛 +description: 项目运行中遇到的Bug或问题。 +title: "🐞 反馈问题:" +labels: ['status: needs check'] +body: + - type: markdown + attributes: + value: | + ### ⚠️ 前置确认 (温馨提示: 未star项目会被自动关闭issue哦!) + 1. 是否国外服务器,并且未被墙(必须) + 2. 是否最新脚本(必须) + 3. 服务器规格是否 >= 1C1G(必须) + - type: checkboxes + attributes: + label: 前置确认 + options: + - label: 我确认使用的是国外未被墙的服务器,使用的是最新脚本,并且服务器规格 >= 1C1G + required: true + - type: checkboxes + attributes: + label: ⚠️ 搜索issues中是否已存在类似问题 + description: > + 请在 [历史issue](https://github.com/dqzboy/Docker-Proxy/issues) 中清空输入框,搜索你的问题 + 或相关日志的关键词来查找是否存在类似问题。 + options: + - label: 我已经搜索过issues和disscussions,没有跟我遇到的问题相关的issue + required: true + - type: markdown + attributes: + value: | + 请在上方的`title`中填写你对你所遇到问题的简略总结,这将帮助其他人更好的找到相似问题,谢谢❤️。 + - type: dropdown + attributes: + label: 操作系统类型? + description: > + 请选择你运行程序的操作系统类型。 + options: + - CentOS 7 + - CentOS 8 + - Redhat + - Ubuntu + - Other (请在问题中说明) + validations: + required: true + - type: textarea + attributes: + label: 复现步骤 🕹 + description: | + **⚠️ 不能复现将会关闭issue.** + - type: textarea + attributes: + label: 问题描述 😯 + description: 详细描述出现的问题,或提供有关截图。 + - type: textarea + attributes: + label: 终端日志 📒 + description: | + 在此处粘贴终端日志 + value: | + ```log + <此处粘贴终端日志> + ``` diff --git a/.github/ISSUE_TEMPLATE/2.feature.yml b/.github/ISSUE_TEMPLATE/2.feature.yml new file mode 100644 index 0000000..7cd457f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2.feature.yml @@ -0,0 +1,30 @@ +name: 功能建议 🚀 +description: 提出你对项目的新想法或建议。 +title: "🚀 功能建议:" +labels: ['status: needs check'] +body: + - type: markdown + attributes: + value: | + 请在上方的`title`中填写简略总结,谢谢❤️。 + ⚠️ 温馨提示: 未`star`项目会被自动关闭issue哦! + - type: checkboxes + attributes: + label: ⚠️ 搜索是否存在类似issue + description: > + 请在 [历史issue](https://github.com/dqzboy/Docker-Proxy/issues) 中清空输入框,搜索关键词查找是否存在相似issue。 + options: + - label: 我已经搜索过issues和disscussions,没有发现相似issue + required: true + - type: textarea + attributes: + label: 总结 + description: 描述feature的功能。 + - type: textarea + attributes: + label: 举例 + description: 提供聊天示例,草图或相关网址。 + - type: textarea + attributes: + label: 动机 + description: 描述你提出该feature的动机,比如没有这项feature对你的使用造成了怎样的影响。 请提供更详细的场景描述,这可能会帮助我们发现并提出更好的解决方案。 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..f7859fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: 浅时光博客 + url: https://www.dqzboy.com/ + about: 更多学习教程,欢迎访问我们的官方网站 diff --git a/.github/close_issue.py b/.github/close_issue.py new file mode 100644 index 0000000..082a9f2 --- /dev/null +++ b/.github/close_issue.py @@ -0,0 +1,104 @@ +import os +import requests + +issue_labels = ['no respect'] +github_repo = 'dqzboy/Docker-Proxy' +github_token = os.getenv("GITHUB_TOKEN") +headers = { + 'Authorization': 'Bearer ' + github_token, + 'Accept': 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28', +} + +def get_stargazers(repo): + page = 1 + _stargazers = {} + while True: + queries = { + 'per_page': 100, + 'page': page, + } + url = 'https://api.github.com/repos/{}/stargazers?'.format(repo) + + resp = requests.get(url, headers=headers, params=queries) + if resp.status_code != 200: + raise Exception('Error get stargazers: ' + resp.text) + + data = resp.json() + if not data: + break + + for stargazer in data: + _stargazers[stargazer['login']] = True + page += 1 + + print('list stargazers done, total: ' + str(len(_stargazers))) + return _stargazers + + +def get_issues(repo): + page = 1 + _issues = [] + while True: + queries = { + 'state': 'open', + 'sort': 'created', + 'direction': 'desc', + 'per_page': 100, + 'page': page, + } + url = 'https://api.github.com/repos/{}/issues?'.format(repo) + + resp = requests.get(url, headers=headers, params=queries) + if resp.status_code != 200: + raise Exception('Error get issues: ' + resp.text) + + data = resp.json() + if not data: + break + + _issues += data + page += 1 + + print('list issues done, total: ' + str(len(_issues))) + return _issues + + +def close_issue(repo, issue_number): + url = 'https://api.github.com/repos/{}/issues/{}'.format(repo, issue_number) + data = { + 'state': 'closed', + 'state_reason': 'not_planned', + 'labels': issue_labels, + } + resp = requests.patch(url, headers=headers, json=data) + if resp.status_code != 200: + raise Exception('Error close issue: ' + resp.text) + + print('issue: {} closed'.format(issue_number)) + + +def lock_issue(repo, issue_number): + url = 'https://api.github.com/repos/{}/issues/{}/lock'.format(repo, issue_number) + data = { + 'lock_reason': 'spam', + } + resp = requests.put(url, headers=headers, json=data) + if resp.status_code != 204: + raise Exception('Error lock issue: ' + resp.text) + + print('issue: {} locked'.format(issue_number)) + + +if '__main__' == __name__: + stargazers = get_stargazers(github_repo) + + issues = get_issues(github_repo) + for issue in issues: + login = issue['user']['login'] + if login not in stargazers: + print('issue: {}, login: {} not in stargazers'.format(issue['number'], login)) + close_issue(github_repo, issue['number']) + lock_issue(github_repo, issue['number']) + + print('done') diff --git a/.github/workflows/CloseIssue.yml b/.github/workflows/CloseIssue.yml new file mode 100644 index 0000000..da77e0e --- /dev/null +++ b/.github/workflows/CloseIssue.yml @@ -0,0 +1,24 @@ +name: CloseIssue + +on: + workflow_dispatch: + issues: + types: [opened] + +jobs: + run-python-script: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Dependencies + run: pip install requests + + - name: Run close_issue.py Script + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python .github/close_issue.py diff --git a/.github/workflows/issue-translator.yml b/.github/workflows/issue-translator.yml new file mode 100644 index 0000000..560f66d --- /dev/null +++ b/.github/workflows/issue-translator.yml @@ -0,0 +1,15 @@ +name: Issue Translator +on: + issue_comment: + types: [created] + issues: + types: [opened] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: usthe/issues-translate-action@v2.7 + with: + IS_MODIFY_TITLE: false + CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82f9275 --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/Koyeb/README.md b/Koyeb/README.md new file mode 100644 index 0000000..ce04fd3 --- /dev/null +++ b/Koyeb/README.md @@ -0,0 +1,157 @@ +
+

+ +
+ 使用 Koyeb 快速部署我们的Docker镜像加速服务. +

+ + +--- + +[Telegram Group](https://t.me/+ghs_XDp1vwxkMGU9) + +--- + + +## 📦 部署 +> 以下步骤需要有Koyeb账号,没有账号的可以先注册 + +**1. 登入 [Koyeb](https://app.koyeb.com/auth/signup/)** + + + + + +
+ +**2. 创建我们的服务** + + + + + +
+ +**3. 选择以docker容器的方式部署,输入下面任一镜像地址** + +| 镜像 | 平台 | +|-------|---------------| +| dqzboy/mirror-hub:latest | docker hub +| dqzboy/mirror-gcr:latest | Google Container Registry +| dqzboy/mirror-ghcr:latest | GitHub Container Registry +| dqzboy/mirror-k8sgcr:latest | Kubernetes Container Registry +| dqzboy/mirror-k8sreg:latest | Kubernetes's container image registry +| dqzboy/mirror-quay:latest | Quay Container Registry +| dqzboy/mirror-mcr:latest | Microsoft Container +| dqzboy/mirror-elastic:latest | Elastic Stack + + + + + +
+ + + + + +
+ + +**4. 实例类型选择免费即可** + + + + + +
+ +**5. 暴露端口改为5000,自定义服务名称,然后直接创建即可** + + + + +
+ +**6. 等待服务运行完成之后,使用分配的外网域名即可愉快的使用了** + + + + +
+ + + + +
+ + +## ✨ 使用 + +**1. 改Docker的daemon.json配置,配置你Koyeb服务地址。修改后重启docker** +```shell +~]# vim /etc/docker/daemon.json +{ + "registry-mirrors": [ "https://your_koyeb_url" ], + "log-opts": { + "max-size": "100m", + "max-file": "5" + } +} +``` +**2. 使用Koyeb服务地址替换官方的 Registry 地址拉取镜像** +```shell +# docker hub Registry +## 源:redis:latest +## 替换 +docker pull your_koyeb_url/library/redis:latest +``` + +> **说明**:如果上面配置了docker的daemon.json,那么拉取镜像的时候就不需要在镜像前面加Render_URL了。【只针对Docker生效】 + + +**3. 前缀替换的 Registry 的参考** + +| 源站 | 替换为 | 平台 | +|-------|---------------|----------| +| docker.io | your_koyeb_url | docker hub +| gcr.io | your_koyeb_url | Google Container Registry +| ghcr.io | your_koyeb_url | GitHub Container Registry +| k8s.gcr.io | your_koyeb_url | Kubernetes Container Registry +| quay.io | your_koyeb_url | Quay Container Registry + +--- + +## ✨ 将镜像上传到自己的Docker Hub仓库 + +#### 步骤 1: 登录到 Docker Hub +- 打开终端输入以下命令并按提示输入你的 Docker Hub 用户名和密码: + +```shell +docker login +``` + +#### 步骤 2: 拉取镜像 +- 使用 docker pull 命令拉取上面的镜像,这里以 dqzboy/mirror-hub:latest 举例: + +```shell +docker pull dqzboy/mirror-hub:latest +``` + +#### 步骤 3: 标记镜像 +- 给拉下来的镜像打一个新标签,使其指向你的 Docker Hub 用户名。 +- 假设你的 Docker Hub 用户名是 yourusername,你可以使用以下命令: + +```shell +docker tag dqzboy/mirror-hub:latest yourusername/mirror-hub:latest +``` + +#### 步骤 4: 上传镜像 +- 使用 docker push 命令上传标记的镜像到你的 Docker Hub 仓库: + +```shell +docker push yourusername/mirror-hub:latest +``` + +#### 步骤 5: 验证上传 +- 上传完成后,你可以登录到 Docker Hub 网站,查看你的仓库中是否已经存在刚刚上传的镜像。 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..58952d3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 dqzboy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..78c83ff --- /dev/null +++ b/README.md @@ -0,0 +1,218 @@ +
+

+ +
+ 自建Docker镜像加速服务,基于官方 registry 一键部署Docker、K8s、Quay、Ghcr、Mcr、elastic等镜像加速\管理服务. +

+
+ +
+ +[![Auth](https://img.shields.io/badge/Auth-dqzboy-ff69b4)](https://github.com/dqzboy) +[![GitHub contributors](https://img.shields.io/github/contributors/dqzboy/Docker-Proxy)](https://github.com/dqzboy/Docker-Proxy/graphs/contributors) +[![GitHub Issues](https://img.shields.io/github/issues/dqzboy/Docker-Proxy.svg)](https://github.com/dqzboy/Docker-Proxy/issues) +[![GitHub Pull Requests](https://img.shields.io/github/stars/dqzboy/Docker-Proxy)](https://github.com/dqzboy/Docker-Proxy) +[![HitCount](https://views.whatilearened.today/views/github/dqzboy/Docker-Proxy.svg)](https://github.com/dqzboy/Docker-Proxy) +[![GitHub license](https://img.shields.io/github/license/dqzboy/Docker-Proxy)](https://github.com/dqzboy/Docker-Proxy/blob/main/LICENSE) + +
+ +--- + +[Docker Proxy—技术交流群](https://t.me/+ghs_XDp1vwxkMGU9) + +--- + +## 📝 准备工作 +⚠️ **重要**:一台国外的服务器,并且未被墙。一个域名,无需国内备案,便宜的就行!一键部署时选择安装Caddy可自动实现HTTPS。如果部署的是Nginx服务,那么你需要申请一个免费的SSL证书或通过[Acme.sh自动生成和续订Lets Encrypt免费SSL证书](https://www.dqzboy.com/16437.html)还可以把域名托管到[Cloudflare 开启免费SSL证书](https://www.cloudflare.com/zh-cn/application-services/products/ssl/) + + +> 如果没有域名,只有公网IP,那么你可以尝试通过 **[zerossl](https://zerossl.com)** 给IP申请SSL证书 +> +> 如果你只有一台服务器,不想搞域名也不想配置TLS,那么你可以配置Docker的配置文件daemon.json,指定insecure-registries配置你的镜像加速地址 +> +> **如果你是在国内的服务器部署,那么你可以在执行一键部署时配置代理,同时会帮你解决国内无法安装Docker的问题** + + +🚀 如果你身边没有上面提到的这些东西,那么你也可以部署到Render,详细操作查看下面教程 + +## 📦 部署 +#### 通过项目脚本部署 +```shell +# CentOS +yum -y install wget curl +# ubuntu +apt -y install wget curl + +bash -c "$(curl -fsSL https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main/install/DockerProxy_Install.sh)" +``` + +#### 使用 Render 部署 +
+部署到 Render +
+ +[使用Render快速部署](Render/README.md) + +
+ +#### 使用 Koyeb 部署 +
+部署到 Koyeb +
+ +[使用Koyeb快速部署](Koyeb/README.md) + +
+ +#### Docker Compose 部署 +
+手动部署容器 +
+ +**1.** 下载[config](https://github.com/dqzboy/Docker-Proxy/tree/main/config)目录下对应的`yml`文件到你本地机器上 + +**2.** 下载[docker-compose.yaml](https://github.com/dqzboy/Docker-Proxy/blob/main/docker-compose.yaml)文件到你本地机器上,并且与配置文件同级目录下 + +**3.** 执行 `docker compose` 命令启动容器服务 +```shell +docker compose up -d + +# 查看容器日志 +docker logs -f [容器ID或名称] +``` + +**4.** 如果你对Nginx或Caddy不熟悉,那么你可以使用你熟悉的服务进行代理。也可以直接通过IP+端口的方式访问 + +
+ + +## 🔨 功能 +- 一键部署Docker镜像代理服务的功能,支持基于官方Docker Registry的镜像代理. +- 支持多个镜像仓库的代理,包括Docker Hub、GitHub Container Registry(ghcr.io)、Quay Container Registry(quay.io)、Kubernetes Container Registry(k8s.gcr.io)、Microsoft Container(mcr.microsoft.com)、Elastic Stack(docker.elastic.co) +- 自动检查并安装所需的依赖软件,如Docker、Nginx\Caddy等,并确保系统环境满足运行要求 +- 根据你所选择部署的服务,自动渲染对应的Nginx或Caddy服务配置 +- 自动清理注册表上传目录中的那些不再被任何镜像或清单引用的文件 +- 提供了重启服务、更新服务、更新配置和卸载服务的功能,方便用户进行日常管理和维护 +- 支持用户在部署时选择是否提供身份验证 +- 支持配置代理(HTTP_PROXY),仅支持http +- 解决国内环境无法安装Docker服务的难题 +- 支持主流Linux发行版操作系统,例如Centos、Ubuntu、Rocky、Debian、Rhel等 +- 支持主流ARCH架构下部署,包括linux/amd64、linux/arm64 + +## ✨ 教程 +### 配置Nginx反向代理 +**注意**: 如果你选择部署的是Nginx,那么代理程序部署完成之后,需自行配置 Nginx
+ +**1.下载仓库下的nginx配置文件 [registry-proxy.conf](https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main/nginx/registry-proxy.conf) 到你的nginx服务下,并修改配置里的域名和证书部分**
+**2.在你的DNS服务提供商将相应的访问域名解析到部署docker proxy服务的机器IP上**
+**3.修改Docker的daemon.json配置,配置你自建的Registry地址。修改后重启docker** +```shell +~]# vim /etc/docker/daemon.json +{ + "registry-mirrors": [ "https://hub.your_domain_name" ], + "log-opts": { + "max-size": "100m", + "max-file": "5" + } +} +``` + +> **说明:** 配置了daemon.json之后,现在拉取镜像无需指定你的加速地址,直接执行docker pull 拉取你需要的镜像即可。下面的步骤是你在没有配置daemon.json的时候,拉取镜像需要加上你的加速地址才可以正常拉取。 + +--- + +**1. 使用自建的 Registry 地址替换官方的 Registry 地址拉取镜像** +```shell +# docker hub Registry +## 源:nginx:latest +## 替换 +docker pull hub.your_domain_name/library/nginx:latest + +# Google Registry +## 源:gcr.io/google-containers/pause:3.1 +## 替换: +docker pull gcr.your_domain_name/google-containers/pause:3.1 +``` + +**2. 前缀替换的 Registry 的参考** + +| 源站 | 替换为 | 平台 | +|-------|---------------|----------| +| docker.io | hub.your_domain_name | docker hub +| gcr.io | gcr.your_domain_name | Google Container Registry +| ghcr.io | ghcr.your_domain_name | GitHub Container Registry +| k8s.gcr.io | k8s-gcr.your_domain_name | Kubernetes Container Registry +| registry.k8s.io | k8s.your_domain_name | Kubernetes's container image registry +| quay.io | quay.your_domain_name | Quay Container Registry +| mcr.microsoft.com | mcr.your_domain_name | Microsoft Container Registry +| docker.elastic.co | elastic.your_domain_name | Elastic Stack + +--- + +**关于使用镜像加速拉取docker hub公共空间下的镜像时如何不添加library的方案** + +- 此方案来自交流群里大佬提供,通过nginx实现并实测 +```shell +location ^~ / { + if ($request_uri ~ ^/v2/([^/]+)/(manifests|blobs)/(.*)$) { + # 重写路径并添加 library/ + rewrite ^/v2/(.*)$ /v2/library/$1 break; + } + + proxy_pass http://127.0.0.1:51000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_http_version 1.1; + add_header X-Cache $upstream_cache_status; +} +``` + +> 详细教程:[自建Docker镜像加速服务:加速与优化镜像管理](https://www.dqzboy.com/8709.html) + +## 📚 展示 +
+ + + + + + + + + +
系统环境检查服务部署安装
+ +## 💻 UI +![docker-proxy](https://github.com/dqzboy/Docker-Proxy/assets/42825450/5194cfc0-1108-4c99-bf87-31e90b9154a1) + + +## 🫶 赞助 +如果你觉得这个项目对你有帮助,请给我点个Star。并且情况允许的话,可以给我一点点支持,总之非常感谢支持😊 + + + + + + + + + + +
Alipay WeChat Pay
+ +## 😺 其他 + +开源不易,若你参考此项目或基于此项目修改可否麻烦在你的项目文档中标识此项目?谢谢你! + + +## ❤ 鸣谢 +感谢以下项目的开源的付出: + +[CNCF Distribution](https://distribution.github.io/distribution/) + +[docker-registry-browser](https://github.com/klausmeyer/docker-registry-browser) diff --git a/Render/README.md b/Render/README.md new file mode 100644 index 0000000..258ffc9 --- /dev/null +++ b/Render/README.md @@ -0,0 +1,179 @@ +
+

+ +
+ 使用 Render 快速部署我们的Docker镜像加速服务. +

+ + +--- + +[Telegram Group](https://t.me/+ghs_XDp1vwxkMGU9) + +--- + + +## 📦 部署 +**1. 登入 [Render](https://dashboard.render.com)** + +**2. 创建我们的服务** + + + + +
+ + + + + +
+ +**3. 选择以docker容器的方式部署,输入下面任一镜像地址** + +> **⚠️ 特别说明:目前作者账号已被Render特殊对待了,建议大家把下面的镜像下载到自己本地,然后上传到自己的Docker hub仓库。下面的镜像地址也会随时被Render限制使用(具体操作可以看下面教程)** + +| 镜像 | 平台 | +|-------|---------------| +| dqzboy01/mirror-hub:latest | docker hub +| dqzboy01/mirror-gcr:latest | Google Container Registry +| dqzboy01/mirror-ghcr:latest | GitHub Container Registry +| dqzboy01/mirror-k8sgcr:latest | Kubernetes Container Registry +| dqzboy01/mirror-k8sreg:latest | Kubernetes's container image registry +| dqzboy01/mirror-quay:latest | Quay Container Registry +| dqzboy01/mirror-elastic:latest | Microsoft Container Registry +| dqzboy01/mirror-mcr:latest | Elastic Stack + + + + + +
+ + + + + +
+ +**4. 实例类型选择免费即可(免费实例需要保活,可使用 [uptime-kuma](https://uptime.kuma.pet/) 或 [D监控](https://www.dnspod.cn/Products/Monitor) 实现)** + + + + + +
+ +**5. 环境变量不用添加,直接选择创建即可** + + + + +
+ +**6. 等待服务运行完成之后,使用分配的外网域名即可愉快的使用了** + + + + +
+ +## ✨ 使用 + +**1. 改Docker的daemon.json配置,配置你Render服务地址。修改后重启docker** +```shell +~]# vim /etc/docker/daemon.json +{ + "registry-mirrors": [ "https://your_render_url" ], + "log-opts": { + "max-size": "100m", + "max-file": "5" + } +} +``` +**2. 使用Render服务地址替换官方的 Registry 地址拉取镜像** +```shell +# docker hub Registry +## 源:redis:latest +## 替换 +docker pull your_render_url/library/redis:latest +``` + +> **说明**:如果上面配置了docker的daemon.json,那么拉取镜像的时候就不需要在镜像前面加Render_URL了。【只针对Docker生效】 + +**3. 拉取速度测试,效果还是可以的,主要是免费** +![image](https://github.com/dqzboy/Blog-Image/assets/42825450/06ad14d4-cb0f-4924-ab41-5c3f001261a2) + +**4. 前缀替换的 Registry 的参考** + +| 源站 | 替换为 | 平台 | +|-------|---------------|----------| +| docker.io | your_render_url | docker hub +| gcr.io | your_render_url | Google Container Registry +| ghcr.io | your_render_url | GitHub Container Registry +| k8s.gcr.io | your_render_url | Kubernetes Container Registry +| quay.io | your_render_url | Quay Container Registry +| mcr.microsoft.com | mcr.your_domain_name | Microsoft Container Registry +| docker.elastic.co | elastic.your_domain_name | Elastic Stack + + +--- + +## ✨ 将镜像上传到自己的Docker Hub仓库 + +#### 镜像下载地址 +| 镜像 | 平台 | +|-------|---------------| +| dqzboy/mirror-hub:latest | docker hub +| dqzboy/mirror-gcr:latest | Google Container Registry +| dqzboy/mirror-ghcr:latest | GitHub Container Registry +| dqzboy/mirror-k8sgcr:latest | Kubernetes Container Registry +| dqzboy/mirror-k8sreg:latest | Kubernetes's container image registry +| dqzboy/mirror-quay:latest | Quay Container Registry +| dqzboy/mirror-mcr:latest | Microsoft Container +| dqzboy/mirror-elastic:latest | Elastic Stack + +#### 步骤 1: 登录到 Docker Hub +- 打开终端输入以下命令并按提示输入你的 Docker Hub 用户名和密码: + +```shell +docker login +``` + +#### 步骤 2: 拉取镜像 +- 使用 docker pull 命令拉取上面的镜像,这里以 dqzboy/mirror-hub:latest 举例: + +```shell +docker pull dqzboy/mirror-hub:latest +``` + +#### 步骤 3: 标记镜像 +- 给拉下来的镜像打一个新标签,使其指向你的 Docker Hub 用户名。 +- 假设你的 Docker Hub 用户名是 yourusername,你可以使用以下命令: + +```shell +docker tag dqzboy/mirror-hub:latest yourusername/mirror-hub:latest +``` + +#### 步骤 4: 上传镜像 +- 使用 docker push 命令上传标记的镜像到你的 Docker Hub 仓库: + +```shell +docker push yourusername/mirror-hub:latest +``` + +#### 步骤 5: 验证上传 +- 上传完成后,你可以登录到 Docker Hub 网站,查看你的仓库中是否已经存在刚刚上传的镜像。 + +--- + +## ⚠️ 注意 +**1.** 免费实例如果15分钟内未收到入站流量,Render会关闭实例的网络服务。Render 会在下次收到处理请求时重新启动该服务。 + +**2.** Render每月为每个用户和团队提供 750 小时的免费实例时间: + - 免费网络服务在运行期间会消耗这些时间(停止服务不要消耗免费实例 + - 小时数)。 + - 如果您在某个月内用完了所有免费实例小时数,Render将暂停您的所有免费网络服务,直到下个月开始。 + - 每个月开始时,您的免费实例小时数将重置为 750 小时(剩余小时数不会结转)。 + +**3.** 最好自己个人使用或者小团队使用,如果你的服务使用人多了,Render照样会把你的服务给删除掉,并且没有任何提醒! \ No newline at end of file diff --git a/caddy/Caddyfile b/caddy/Caddyfile new file mode 100644 index 0000000..f385503 --- /dev/null +++ b/caddy/Caddyfile @@ -0,0 +1,83 @@ +ui.your_domain_name { + reverse_proxy localhost:50000 { + header_up Host {host} + header_up Origin {scheme}://{host} + header_up X-Forwarded-For {remote_addr} + header_up X-Forwarded-Proto {scheme} + header_up X-Forwarded-Ssl on + header_up X-Forwarded-Port {server_port} + header_up X-Forwarded-Host {host} + } +} + +hub.your_domain_name { + reverse_proxy localhost:51000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +ghcr.your_domain_name { + reverse_proxy localhost:52000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +gcr.your_domain_name { + reverse_proxy localhost:53000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +k8s-gcr.your_domain_name { + reverse_proxy localhost:54000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +k8s.your_domain_name { + reverse_proxy localhost:55000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +quay.your_domain_name { + reverse_proxy localhost:56000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +mcr.your_domain_name { + reverse_proxy localhost:57000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} + +elastic.your_domain_name { + reverse_proxy localhost:58000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +} \ No newline at end of file diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..11ac579 --- /dev/null +++ b/config/README.md @@ -0,0 +1,7 @@ +
+

+ +
+ Docker、K8s、Quay、Ghcr镜像加速服务配置文件. +

+ \ No newline at end of file diff --git a/config/registry-elastic.yml b/config/registry-elastic.yml new file mode 100644 index 0000000..8bec1d4 --- /dev/null +++ b/config/registry-elastic.yml @@ -0,0 +1,41 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://docker.elastic.co + username: + password: diff --git a/config/registry-gcr.yml b/config/registry-gcr.yml new file mode 100644 index 0000000..989c173 --- /dev/null +++ b/config/registry-gcr.yml @@ -0,0 +1,42 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://gcr.io + username: + password: + ttl: \ No newline at end of file diff --git a/config/registry-ghcr.yml b/config/registry-ghcr.yml new file mode 100644 index 0000000..7d3b86e --- /dev/null +++ b/config/registry-ghcr.yml @@ -0,0 +1,42 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://ghcr.io + username: + password: + ttl: \ No newline at end of file diff --git a/config/registry-hub.yml b/config/registry-hub.yml new file mode 100644 index 0000000..bf54658 --- /dev/null +++ b/config/registry-hub.yml @@ -0,0 +1,42 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://registry-1.docker.io + username: + password: + ttl: \ No newline at end of file diff --git a/config/registry-k8s.yml b/config/registry-k8s.yml new file mode 100644 index 0000000..c3c42c2 --- /dev/null +++ b/config/registry-k8s.yml @@ -0,0 +1,42 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://registry.k8s.io + username: + password: + ttl: \ No newline at end of file diff --git a/config/registry-k8sgcr.yml b/config/registry-k8sgcr.yml new file mode 100644 index 0000000..2f67748 --- /dev/null +++ b/config/registry-k8sgcr.yml @@ -0,0 +1,42 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://k8s.gcr.io + username: + password: + ttl: \ No newline at end of file diff --git a/config/registry-mcr.yml b/config/registry-mcr.yml new file mode 100644 index 0000000..2a0b180 --- /dev/null +++ b/config/registry-mcr.yml @@ -0,0 +1,41 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://mcr.microsoft.com + username: + password: diff --git a/config/registry-quay.yml b/config/registry-quay.yml new file mode 100644 index 0000000..424bc2d --- /dev/null +++ b/config/registry-quay.yml @@ -0,0 +1,42 @@ +version: 0.1 +log: + fields: + service: registry +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true + cache: + blobdescriptor: inmemory + blobdescriptorsize: 10000 + maintenance: + uploadpurging: + enabled: true + age: 168h + interval: 24h + dryrun: false + readonly: + enabled: false +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + Access-Control-Allow-Origin: ['*'] + Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] + Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] + Access-Control-Max-Age: [1728000] + Access-Control-Allow-Credentials: [true] + Access-Control-Expose-Headers: ['Docker-Content-Digest'] + +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +proxy: + remoteurl: https://quay.io + username: + password: + ttl: \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..5006b5c --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,158 @@ +services: + ## docker hub + dockerhub: + container_name: reg-docker-hub + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-hub.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 51000:5000 + networks: + - registry-net + + + ## ghcr.io + ghcr: + container_name: reg-ghcr + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-ghcr.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 52000:5000 + networks: + - registry-net + + ## gcr.io + gcr: + container_name: reg-gcr + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-gcr.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 53000:5000 + networks: + - registry-net + + ## k8s.gcr.io + k8sgcr: + container_name: reg-k8s-gcr + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-k8sgcr.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 54000:5000 + networks: + - registry-net + + ## registry.k8s.io + k8s: + container_name: reg-k8s + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-k8s.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 55000:5000 + networks: + - registry-net + + ## quay.io + quay: + container_name: reg-quay + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-quay.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 56000:5000 + networks: + - registry-net + + ## mcr.microsoft.com + mcr: + container_name: reg-mcr + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-mcr.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 57000:5000 + networks: + - registry-net + + ## docker.elastic.co + elastic: + container_name: reg-elastic + image: registry:latest + restart: always + #environment: + #- http=http://host:port + #- https=http://host:port + volumes: + - ./registry/data:/var/lib/registry + - ./registry-elastic.yml:/etc/docker/registry/config.yml + #- ./htpasswd:/auth/htpasswd + ports: + - 58000:5000 + networks: + - registry-net + + + ## UI + registry-ui: + container_name: registry-ui + image: dqzboy/docker-registry-ui:latest + environment: + - DOCKER_REGISTRY_URL=http://reg-docker-hub:5000 + # [必须]使用 openssl rand -hex 16 生成唯一值 + - SECRET_KEY_BASE=9f18244a1e1179fa5aa4a06a335d01b2 + # 启用Image TAG 的删除按钮 + - ENABLE_DELETE_IMAGES=true + - NO_SSL_VERIFICATION=true + restart: always + ports: + - 50000:8080 + networks: + - registry-net + +networks: + registry-net: diff --git a/install/DockerProxy_Install.sh b/install/DockerProxy_Install.sh new file mode 100644 index 0000000..c73a256 --- /dev/null +++ b/install/DockerProxy_Install.sh @@ -0,0 +1,1709 @@ +#!/usr/bin/env bash +#=============================================================================== +# +# FILE: DockerProxy_Install.sh +# +# USAGE: ./DockerProxy_Install.sh +# +# DESCRIPTION: 自建Docker镜像加速服务,基于官方 registry 一键部署Docker、K8s、Quay、Ghcr镜像加速\管理服务.支持部署到Render. +# +# ORGANIZATION: DingQz dqzboy.com 浅时光博客 +#=============================================================================== + +echo +cat << EOF + + ██████╗ ██████╗ ██████╗██╗ ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗██╗ ██╗ + ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗ ██╔══██╗██╔══██╗██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝ + ██║ ██║██║ ██║██║ █████╔╝ █████╗ ██████╔╝ ██████╔╝██████╔╝██║ ██║ ╚███╔╝ ╚████╔╝ + ██║ ██║██║ ██║██║ ██╔═██╗ ██╔══╝ ██╔══██╗ ██╔═══╝ ██╔══██╗██║ ██║ ██╔██╗ ╚██╔╝ + ██████╔╝╚██████╔╝╚██████╗██║ ██╗███████╗██║ ██║ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗ ██║ + ╚═════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ + + 博客: dqzboy.com 浅时光博客 + 项目地址: https://github.com/dqzboy/Docker-Proxy + +EOF + +echo "----------------------------------------------------------------------------------------------------------" +echo -e "\033[32m机场推荐\033[0m(\033[34m按量不限时,解锁ChatGPT\033[0m):\033[34;4mhttps://mojie.mx/#/register?code=CG6h8Irm\033[0m" +echo "----------------------------------------------------------------------------------------------------------" +echo +echo + +GREEN="\033[0;32m" +RED="\033[31m" +YELLOW="\033[33m" +RESET="\033[0m" + +INFO="[${GREEN}INFO${RESET}]" +ERROR="[${RED}ERROR${RESET}]" +WARN="[${YELLOW}WARN${RESET}]" +function INFO() { + echo -e "${INFO} ${1}" +} +function ERROR() { + echo -e "${ERROR} ${1}" +} +function WARN() { + echo -e "${WARN} ${1}" +} + + +PROXY_DIR="/data/registry-proxy" +mkdir -p ${PROXY_DIR} +cd "${PROXY_DIR}" + +GITRAW="https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main" + +IMAGE_NAME="registry" +UI_IMAGE_NAME="dqzboy/docker-registry-ui" +DOCKER_COMPOSE_FILE="docker-compose.yaml" + +attempts=0 +maxAttempts=3 + + +function CHECK_OS() { +INFO "======================= 检查环境 =======================" +# OS version +OSVER=$(cat /etc/os-release | grep -o '[0-9]' | head -n 1) + +if [ -f /etc/os-release ]; then + . /etc/os-release +else + echo "无法确定发行版" + exit 1 +fi + +case "$ID" in + "centos") + repo_type="centos" + ;; + "debian") + repo_type="debian" + ;; + "rhel") + repo_type="rhel" + ;; + "ubuntu") + repo_type="ubuntu" + ;; + "opencloudos") + repo_type="centos" + ;; + "rocky") + repo_type="centos" + ;; + *) + WARN "此脚本目前不支持您的系统: $ID" + exit 1 + ;; +esac + +INFO "System release:: $NAME" +INFO "System version: $VERSION" +INFO "System ID: $ID" +INFO "System ID Like: $ID_LIKE" +} + +function CHECK_PACKAGE_MANAGER() { + if command -v dnf &> /dev/null; then + package_manager="dnf" + elif command -v yum &> /dev/null; then + package_manager="yum" + elif command -v apt-get &> /dev/null; then + package_manager="apt-get" + elif command -v apt &> /dev/null; then + package_manager="apt" + else + ERROR "不受支持的软件包管理器." + exit 1 + fi +} + +function CHECK_PKG_MANAGER() { + if command -v rpm &> /dev/null; then + pkg_manager="rpm" + elif command -v dpkg &> /dev/null; then + pkg_manager="dpkg" + elif command -v apt &> /dev/null; then + pkg_manager="apt" + else + ERROR "无法确定包管理系统." + exit 1 + fi +} + +function CHECKMEM() { +memory_usage=$(free | awk '/^Mem:/ {printf "%.2f", $3/$2 * 100}') +memory_usage=${memory_usage%.*} + +if [[ $memory_usage -gt 90 ]]; then # 判断是否超过 90% + read -e -p "$(WARN '内存占用率高于 70%($memory_usage%). 是否继续安装?: ')" continu + if [ "$continu" == "n" ] || [ "$continu" == "N" ]; then + exit 1 + fi +else + INFO "内存资源充足。请继续.($memory_usage%)" +fi +} + +function CHECKFIRE() { +systemctl stop firewalld &> /dev/null +systemctl disable firewalld &> /dev/null +systemctl stop iptables &> /dev/null +systemctl disable iptables &> /dev/null +ufw disable &> /dev/null +INFO "防火墙已被禁用." + +if [[ "$repo_type" == "centos" || "$repo_type" == "rhel" ]]; then + if sestatus | grep "SELinux status" | grep -q "enabled"; then + WARN "SELinux 已启用。禁用 SELinux..." + setenforce 0 + sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config + INFO "SELinux 已被禁用." + else + INFO "SELinux 已被禁用." + fi +fi +} + + +function CHECKBBR() { +kernel_version=$(uname -r | awk -F "-" '{print $1}') + +read -e -p "$(WARN '是否开启BBR,优化网络带宽提高网络性能? [y/n]: ')" choice_bbr +case $choice_bbr in + y | Y) + version_compare=$(echo "${kernel_version} 4.9" | awk '{if ($1 >= $2) print "yes"; else print "no"}') + if [ "$version_compare" != "yes" ]; then + WARN "你的内核版本小于4.9,无法启动BBR,需要你手动升级内核" + exit 0 + fi + sysctl net.ipv4.tcp_available_congestion_control | grep -q "bbr" + if [ $? -eq 0 ]; then + INFO "你的服务器已经启动BBR" + else + INFO "开启BBR中..." + + modprobe tcp_bbr + if [ $? -eq 0 ]; then + INFO "BBR模块添加成功." + else + ERROR "BBR模块添加失败,请执行 sysctl -p 检查." + exit 1 + fi + + if [ ! -d /etc/modules-load.d/ ]; then + mkdir -p /etc/modules-load.d/ + fi + + if [ ! -f /etc/modules-load.d/tcp_bbr.conf ]; then + touch /etc/modules-load.d/tcp_bbr.conf + fi + + if ! grep -q "tcp_bbr" /etc/modules-load.d/tcp_bbr.conf ; then + echo 'tcp_bbr' >> /etc/modules-load.d/tcp_bbr.conf + fi + + for setting in "net.core.default_qdisc=fq" "net.ipv4.tcp_congestion_control=bbr"; do + if ! grep -q "$setting" /etc/sysctl.conf; then + echo "$setting" >> /etc/sysctl.conf + fi + done + + sysctl -p &> /dev/null + if [ $? -ne 0 ]; then + ERROR "应用sysctl设置过程中发生了一个错误,请执行 sysctl -p 检查." + exit 2 + fi + + lsmod | grep tcp_bbr + if [ $? -eq 0 ]; then + INFO "BBR已经成功开启。" + else + ERROR "BBR开启失败,请执行 sysctl -p 检查." + exit 3 + fi + + WARN "如果BBR开启后未生效,请执行 reboot 重启服务器使其BBR模块生效" + fi + ;; + n | N) + INFO "不开启BBR" + ;; + *) + ERROR "输入错误!请输入 y 或 n" + ;; +esac +} + + +function INSTALL_PACKAGE(){ +INFO "======================= 安装依赖 =======================" +INFO "检查依赖安装情况,请稍等 ..." +TIMEOUT=300 +PACKAGES_APT=( + lsof jq wget apache2-utils tar +) +PACKAGES_YUM=( + epel-release lsof jq wget yum-utils httpd-tools tar +) + +if [ "$package_manager" = "dnf" ] || [ "$package_manager" = "yum" ]; then + for package in "${PACKAGES_YUM[@]}"; do + if $pkg_manager -q "$package" &>/dev/null; then + INFO "已经安装 $package ..." + else + INFO "正在安装 $package ..." + + start_time=$(date +%s) + + $package_manager -y install "$package" --skip-broken > /dev/null 2>&1 & + install_pid=$! + + while [[ $(($(date +%s) - $start_time)) -lt $TIMEOUT ]] && kill -0 $install_pid &>/dev/null; do + sleep 1 + done + + if kill -0 $install_pid &>/dev/null; then + WARN "$package 的安装时间超过 $TIMEOUT 秒。是否继续? (y/n)" + read -r continue_install + if [ "$continue_install" != "y" ]; then + ERROR "$package 的安装超时。退出脚本。" + exit 1 + else + continue + fi + fi + + wait $install_pid + if [ $? -ne 0 ]; then + ERROR "$package 安装失败。请检查系统安装源,然后再次运行此脚本!请尝试手动执行安装:$package_manager -y install $package" + exit 1 + fi + fi + done +elif [ "$package_manager" = "apt-get" ] || [ "$package_manager" = "apt" ];then + dpkg --configure -a &>/dev/null + $package_manager update &>/dev/null + for package in "${PACKAGES_APT[@]}"; do + if $pkg_manager -s "$package" &>/dev/null; then + INFO "已经安装 $package ..." + else + INFO "正在安装 $package ..." + $package_manager install -y $package > /dev/null 2>&1 + if [ $? -ne 0 ]; then + ERROR "安装 $package 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装:$package_manager -y install $package" + exit 1 + fi + fi + done +else + WARN "无法确定包管理系统." + exit 1 +fi +} + + +function INSTALL_CADDY() { +INFO "====================== 安装Caddy ======================" +start_caddy() { +systemctl enable caddy.service &>/dev/null +systemctl restart caddy.service + +status=$(systemctl is-active caddy) + +if [ "$status" = "active" ]; then + INFO "Caddy 服务运行正常,请继续..." +else + ERROR "Caddy 服务未运行,会导致服务无法正常安装运行,请检查后再次执行脚本!" + ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------" + journalctl -u caddy.service --no-pager + ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------" + exit 1 +fi +} + +check_caddy() { +if pgrep "caddy" > /dev/null; then + INFO "Caddy 已在运行." +else + WARN "Caddy 未运行。尝试启动 Caddy..." + start_attempts=3 + + for ((i=1; i<=$start_attempts; i++)); do + start_caddy + if pgrep "caddy" > /dev/null; then + INFO "Caddy 已成功启动." + break + else + if [ $i -eq $start_attempts ]; then + ERROR "Caddy 在尝试 $start_attempts 后无法启动。请检查配置" + exit 1 + else + WARN "在 $i 时间内启动 Caddy 失败。重试..." + fi + fi + done +fi +} + +if [ "$package_manager" = "dnf" ]; then + if which caddy &>/dev/null; then + INFO "Caddy 已经安装." + else + INFO "正在安装Caddy程序,请稍候..." + + $package_manager -y install 'dnf-command(copr)' &>/dev/null + $package_manager -y copr enable @caddy/caddy &>/dev/null + while [ $attempts -lt $maxAttempts ]; do + $package_manager -y install caddy &>/dev/null + + if [ $? -ne 0 ]; then + ((attempts++)) + WARN "正在尝试安装Caddy >>> (Attempt: $attempts)" + + if [ $attempts -eq $maxAttempts ]; then + ERROR "Caddy installation failed. Please try installing manually." + echo "命令: $package_manager -y install 'dnf-command(copr)' && $package_manager -y copr enable @caddy/caddy && $package_manager -y install caddy" + exit 1 + fi + else + INFO "已安装 Caddy." + break + fi + done + fi + check_caddy + +elif [ "$package_manager" = "yum" ]; then + if which caddy &>/dev/null; then + INFO "Caddy 已经安装." + else + INFO "正在安装Caddy程序,请稍候..." + + $package_manager -y install yum-plugin-copr &>/dev/null + $package_manager -y copr enable @caddy/caddy &>/dev/null + while [ $attempts -lt $maxAttempts ]; do + $package_manager -y install caddy &>/dev/null + if [ $? -ne 0 ]; then + ((attempts++)) + WARN "正在尝试安装Caddy >>> (Attempt: $attempts)" + + if [ $attempts -eq $maxAttempts ]; then + ERROR "Caddy installation failed. Please try installing manually." + echo "命令: $package_manager -y install 'dnf-command(copr)' && $package_manager -y copr enable @caddy/caddy && $package_manager -y install caddy" + exit 1 + fi + else + INFO "已安装 Caddy." + break + fi + done + fi + + check_caddy + +elif [ "$package_manager" = "apt" ] || [ "$package_manager" = "apt-get" ];then + dpkg --configure -a &>/dev/null + $package_manager update &>/dev/null + if $pkg_manager -s "caddy" &>/dev/null; then + INFO "Caddy 已安装,跳过..." + else + INFO "安装 Caddy 请稍等 ..." + $package_manager install -y debian-keyring debian-archive-keyring apt-transport-https &>/dev/null + 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 + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list &>/dev/null + $package_manager update &>/dev/null + $package_manager install -y caddy &>/dev/null + if [ $? -ne 0 ]; then + ERROR "安装 Caddy 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装:$package_manager -y install caddy" + exit 1 + fi + fi + + check_caddy +else + WARN "无法确定包管理系统." + exit 1 +fi + + +INFO "====================== 配置Caddy ======================" +while true; do + INFO ">>> 域名解析主机记录(即域名前缀):ui、hub、gcr、ghcr、k8sgcr、k8s、quay、mcr、elastic <<<" + WARN ">>> 只需选择你部署的服务进行解析即可,无需将上面提示中所有的主机记录进行解析 <<<" + read -e -p "$(WARN '是否配置Caddy,实现自动HTTPS? 执行前需提前在DNS服务商选择部署的服务进行解析主机记录[y/n]: ')" caddy_conf + case "$caddy_conf" in + y|Y ) + read -e -p "$(INFO '请输入你的域名[例: baidu.com],不可为空: ')" caddy_domain + + read -e -p "$(INFO '请输入要配置的主机记录,用逗号分隔[例: hub,mcr]: ')" selected_records + IFS=',' read -r -a records_array <<< "$selected_records" + + declare -A record_templates + record_templates[ui]="ui.$caddy_domain { + reverse_proxy localhost:50000 { + header_up Host {host} + header_up Origin {scheme}://{host} + header_up X-Forwarded-For {remote_addr} + header_up X-Forwarded-Proto {scheme} + header_up X-Forwarded-Ssl on + header_up X-Forwarded-Port {server_port} + header_up X-Forwarded-Host {host} + } +}" + record_templates[hub]="hub.$caddy_domain { + reverse_proxy localhost:51000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[ghcr]="ghcr.$caddy_domain { + reverse_proxy localhost:52000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[gcr]="gcr.$caddy_domain { + reverse_proxy localhost:53000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[k8sgcr]="k8sgcr.$caddy_domain { + reverse_proxy localhost:54000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[k8s]="k8s.$caddy_domain { + reverse_proxy localhost:55000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[quay]="quay.$caddy_domain { + reverse_proxy localhost:56000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[mcr]="mcr.$caddy_domain { + reverse_proxy localhost:57000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + record_templates[elastic]="elastic.$caddy_domain { + reverse_proxy localhost:58000 { + header_up Host {host} + header_up X-Real-IP {remote_addr} + header_up X-Forwarded-For {remote_addr} + header_up X-Nginx-Proxy true + } +}" + > /etc/caddy/Caddyfile + for record in "${records_array[@]}"; do + if [[ -n "${record_templates[$record]}" ]]; then + echo "${record_templates[$record]}" >> /etc/caddy/Caddyfile + fi + done + + start_attempts=3 + for ((i=1; i<=$start_attempts; i++)); do + start_caddy + if pgrep "caddy" > /dev/null; then + INFO "重新载入配置成功. Caddy服务启动完成" + break + else + if [ $i -eq $start_attempts ]; then + ERROR "Caddy 在尝试 $start_attempts 后无法启动。请检查配置" + exit 1 + else + WARN "第 $i 次启动 Caddy 失败。重试..." + fi + fi + done + break;; + n|N ) + WARN "退出配置 Caddy 操作。" + break;; + * ) + INFO "请输入 'y' 表示是,或者 'n' 表示否。";; + esac +done +} + + +function INSTALL_NGINX() { +INFO "====================== 安装Nginx ======================" +start_nginx() { +systemctl enable nginx &>/dev/null +systemctl restart nginx + +status=$(systemctl is-active nginx) + +if [ "$status" = "active" ]; then + INFO "Nginx 服务运行正常,请继续..." +else + ERROR "Nginx 服务未运行,会导致服务无法正常安装运行,请检查后再次执行脚本!" + ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------" + journalctl -u nginx.service --no-pager + ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------" + exit 1 +fi +} + +check_nginx() { +if pgrep "nginx" > /dev/null; then + INFO "Nginx 已在运行." +else + WARN "Nginx 未运行。尝试启动 Nginx..." + start_attempts=3 + + for ((i=1; i<=$start_attempts; i++)); do + start_nginx + if pgrep "nginx" > /dev/null; then + INFO "Nginx 已成功启动." + break + else + if [ $i -eq $start_attempts ]; then + ERROR "Nginx 在尝试 $start_attempts 次后无法启动。请检查配置" + exit 1 + else + WARN "第 $i 次启动 Nginx 失败。重试..." + fi + fi + done +fi +} + +if [ "$package_manager" = "dnf" ] || [ "$package_manager" = "yum" ]; then + if which nginx &>/dev/null; then + INFO "Nginx 已经安装." + else + INFO "正在安装Nginx程序,请稍候..." + NGINX="nginx-1.24.0-1.el${OSVER}.ngx.x86_64.rpm" + + rm -f ${NGINX} + wget http://nginx.org/packages/centos/${OSVER}/x86_64/RPMS/${NGINX} &>/dev/null + while [ $attempts -lt $maxAttempts ]; do + $package_manager -y install ${NGINX} &>/dev/null + + if [ $? -ne 0 ]; then + ((attempts++)) + WARN "正在尝试安装Nginx >>> (Attempt: $attempts)" + + if [ $attempts -eq $maxAttempts ]; then + ERROR "Nginx installation failed. Please try installing manually." + rm -f ${NGINX} + echo "命令: wget http://nginx.org/packages/centos/${OSVER}/x86_64/RPMS/${NGINX} && $package_manager -y install ${NGINX}" + exit 1 + fi + else + INFO "已安装 Nginx." + rm -f ${NGINX} + break + fi + done + fi + + check_nginx + +elif [ "$package_manager" = "apt-get" ] || [ "$package_manager" = "apt" ];then + dpkg --configure -a &>/dev/null + $package_manager update &>/dev/null + if $pkg_manager -s "nginx" &>/dev/null; then + INFO "nginx 已安装,跳过..." + else + INFO "安装 nginx 请稍等 ..." + $package_manager install -y nginx > /dev/null 2>&1 + if [ $? -ne 0 ]; then + ERROR "安装 nginx 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装:$package_manager -y install nginx" + exit 1 + fi + fi + + check_nginx +else + WARN "无法确定包管理系统." + exit 1 +fi + + +INFO "====================== 配置Nginx ======================" +while true; do + WARN "自行安装的 Nginx 请勿执行此操作,以防覆盖原有配置" + INFO ">>> 域名解析主机记录(即域名前缀):ui、hub、gcr、ghcr、k8sgcr、k8s、quay、mcr、elastic <<<" + WARN ">>> 只需选择你部署的服务进行解析即可,无需将上面提示中所有的主机记录进行解析 <<<" + read -e -p "$(WARN '是否配置 Nginx ?配置完成后需在DNS服务商对部署的服务进行解析主机记录[y/n]: ')" nginx_conf + case "$nginx_conf" in + y|Y ) + read -e -p "$(INFO '请输入你的域名[例: baidu.com],不可为空: ')" nginx_domain + + read -e -p "$(INFO '请输入要配置的主机记录,用逗号分隔[例: hub,mcr]: ')" selected_records + IFS=',' read -r -a records_array <<< "$selected_records" + + declare -A record_templates + record_templates[ui]="server { + listen 80; + #listen 443 ssl; + server_name ui.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:50000; + proxy_set_header Host \$host; + proxy_set_header Origin \$scheme://\$host; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header X-Forwarded-Ssl on; + proxy_set_header X-Forwarded-Port \$server_port; + proxy_set_header X-Forwarded-Host \$host; + } +}" + record_templates[hub]="server { + listen 80; + #listen 443 ssl; + server_name hub.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:51000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[ghcr]="server { + listen 80; + #listen 443 ssl; + server_name ghcr.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:52000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[gcr]="server { + listen 80; + #listen 443 ssl; + server_name gcr.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:53000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[k8sgcr]="server { + listen 80; + #listen 443 ssl; + server_name k8sgcr.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:54000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[k8s]="server { + listen 80; + #listen 443 ssl; + server_name k8s.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:55000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[quay]="server { + listen 80; + #listen 443 ssl; + server_name quay.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:56000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[mcr]="server { + listen 80; + #listen 443 ssl; + server_name mcr.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:57000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + record_templates[elastic]="server { + listen 80; + #listen 443 ssl; + server_name elastic.$nginx_domain; + #ssl_certificate /path/to/your_domain_name.crt; + #ssl_certificate_key /path/to/your_domain_name.key; + #ssl_session_timeout 1d; + #ssl_session_cache shared:SSL:50m; + #ssl_session_tickets off; + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + #ssl_prefer_server_ciphers on; + #ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + location / { + proxy_pass http://localhost:58000; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +}" + > /etc/nginx/conf.d/docker-proxy.conf + for record in "${records_array[@]}"; do + if [[ -n "${record_templates[$record]}" ]]; then + echo "${record_templates[$record]}" >> /etc/nginx/conf.d/docker-proxy.conf + fi + done + + start_attempts=3 + for ((i=1; i<=$start_attempts; i++)); do + start_nginx + if pgrep "nginx" > /dev/null; then + INFO "重新载入配置成功. Nginx服务启动完成" + break + else + if [ $i -eq $start_attempts ]; then + ERROR "Nginx 在尝试 $start_attempts 后无法启动。请检查配置" + exit 1 + else + WARN "第 $i 次启动 Nginx 失败。重试..." + fi + fi + done + break;; + n|N ) + WARN "退出配置 Nginx 操作。" + break;; + * ) + INFO "请输入 'y' 表示是,或者 'n' 表示否。";; + esac +done +} + + +function CHECK_DOCKER() { +status=$(systemctl is-active docker) + +if [ "$status" = "active" ]; then + INFO "Docker 服务运行正常,请继续..." +else + ERROR "Docker 服务未运行,会导致服务无法正常安装运行,请检查后再次执行脚本!" + ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------" + journalctl -u docker.service --no-pager + ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------" + exit 1 +fi +} + + +function INSTALL_DOCKER() { +repo_file="docker-ce.repo" +url="https://download.docker.com/linux/$repo_type" +MAX_ATTEMPTS=3 +attempt=0 +success=false + +if [ "$repo_type" = "centos" ] || [ "$repo_type" = "rhel" ]; then + if ! command -v docker &> /dev/null;then + while [[ $attempt -lt $MAX_ATTEMPTS ]]; do + attempt=$((attempt + 1)) + WARN "Docker 未安装,正在进行安装..." + yum-config-manager --add-repo $url/$repo_file &>/dev/null + $package_manager -y install docker-ce &>/dev/null + if [ $? -eq 0 ]; then + success=true + break + fi + ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)" + done + + if $success; then + INFO "Docker 安装成功,版本为:$(docker --version)" + systemctl restart docker &>/dev/null + CHECK_DOCKER + systemctl enable docker &>/dev/null + else + ERROR "Docker 安装失败,请尝试手动安装" + exit 1 + fi + else + INFO "Docker 已安装,安装版本为:$(docker --version)" + systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN" + fi +elif [ "$repo_type" == "ubuntu" ]; then + if ! command -v docker &> /dev/null;then + while [[ $attempt -lt $MAX_ATTEMPTS ]]; do + attempt=$((attempt + 1)) + WARN "Docker 未安装,正在进行安装..." + curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null + add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null + $package_manager -y install docker-ce docker-ce-cli containerd.io &>/dev/null + if [ $? -eq 0 ]; then + success=true + break + fi + ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)" + done + + if $success; then + INFO "Docker 安装成功,版本为:$(docker --version)" + systemctl restart docker &>/dev/null + CHECK_DOCKER + systemctl enable docker &>/dev/null + else + ERROR "Docker 安装失败,请尝试手动安装" + exit 1 + fi + else + INFO "Docker 已安装,安装版本为:$(docker --version)" + systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN" + fi +elif [ "$repo_type" == "debian" ]; then + if ! command -v docker &> /dev/null;then + while [[ $attempt -lt $MAX_ATTEMPTS ]]; do + attempt=$((attempt + 1)) + + WARN "Docker 未安装,正在进行安装..." + curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null + add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null + $package_manager -y install docker-ce docker-ce-cli containerd.io &>/dev/null + if [ $? -eq 0 ]; then + success=true + break + fi + ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)" + done + + if $success; then + INFO "Docker 安装成功,版本为:$(docker --version)" + systemctl restart docker &>/dev/null + CHECK_DOCKER + systemctl enable docker &>/dev/null + else + ERROR "Docker 安装失败,请尝试手动安装" + exit 1 + fi + else + INFO "Docker 已安装,安装版本为:$(docker --version)" + systemctl restart docker &>/dev/null + CHECK_DOCKER + fi +else + ERROR "不支持的操作系统." + exit 1 +fi +} + + +function INSTALL_COMPOSE() { +INFO "================== 安装Docker Compose ==================" + +TAG=`curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r '.tag_name'` +url="https://github.com/docker/compose/releases/download/$TAG/docker-compose-$(uname -s)-$(uname -m)" +MAX_ATTEMPTS=3 +attempt=0 +success=false +save_path="/usr/local/bin" + +chmod +x $save_path/docker-compose &>/dev/null +if ! command -v docker-compose &> /dev/null || [ -z "$(docker-compose --version)" ]; then + WARN "Docker Compose 未安装或安装不完整,正在进行安装..." + while [ $attempt -lt $MAX_ATTEMPTS ]; do + attempt=$((attempt + 1)) + wget --continue -q $url -O $save_path/docker-compose + if [ $? -eq 0 ]; then + chmod +x $save_path/docker-compose + version_check=$(docker-compose --version) + if [ -n "$version_check" ]; then + success=true + chmod +x $save_path/docker-compose + break + else + WARN "Docker Compose 下载的文件不完整,正在尝试重新下载 (尝试次数: $attempt)" + rm -f $save_path/docker-compose + fi + fi + + ERROR "Docker Compose 下载失败,正在尝试重新下载 (尝试次数: $attempt)" + done + + if $success; then + INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)" + else + ERROR "Docker Compose 下载失败,请尝试手动安装docker-compose" + exit 1 + fi +else + chmod +x $save_path/docker-compose + INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)" +fi +} + +function INSTALL_DOCKER_CN() { +MAX_ATTEMPTS=3 +attempt=0 +success=false +cpu_arch=$(uname -m) +save_path="/opt/docker_tgz" +mkdir -p $save_path +docker_ver="docker-26.1.4.tgz" + +case $cpu_arch in + "arm64") + url="https://gitlab.com/dqzboy/docker/-/raw/main/stable/aarch64/$docker_ver" + ;; + "aarch64") + url="https://gitlab.com/dqzboy/docker/-/raw/main/stable/aarch64/$docker_ver" + ;; + "x86_64") + url="https://gitlab.com/dqzboy/docker/-/raw/main/stable/x86_64/$docker_ver" + ;; + *) + ERROR "不支持的CPU架构: $cpu_arch" + exit 1 + ;; +esac + + +if ! command -v docker &> /dev/null; then + while [ $attempt -lt $MAX_ATTEMPTS ]; do + attempt=$((attempt + 1)) + WARN "Docker 未安装,正在进行安装..." + wget -P "$save_path" "$url" &>/dev/null + if [ $? -eq 0 ]; then + success=true + break + fi + ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)" + done + + if $success; then + tar -xzf $save_path/$docker_ver -C $save_path + \cp $save_path/docker/* /usr/bin/ &>/dev/null + rm -rf $save_path + INFO "Docker 安装成功,版本为:$(docker --version)" + + cat > /usr/lib/systemd/system/docker.service </dev/null + CHECK_DOCKER + systemctl enable docker &>/dev/null + else + ERROR "Docker 安装失败,请尝试手动安装" + exit 1 + fi +else + INFO "Docker 已安装,安装版本为:$(docker --version)" + systemctl restart docker &>/dev/null + CHECK_DOCKER +fi +} + + +function INSTALL_COMPOSE_CN() { +INFO "================== 安装Docker Compose ==================" +MAX_ATTEMPTS=3 +attempt=0 +cpu_arch=$(uname -m) +success=false +save_path="/usr/local/bin" + +case $cpu_arch in + "arm64") + url="https://gitlab.com/dqzboy/docker/-/raw/main/stable/aarch64/docker-compose-linux-aarch64" + ;; + "aarch64") + url="https://gitlab.com/dqzboy/docker/-/raw/main/stable/aarch64/docker-compose-linux-aarch64" + ;; + "x86_64") + url="https://gitlab.com/dqzboy/docker/-/raw/main/stable/x86_64/docker-compose-linux-x86_64" + ;; + *) + ERROR "不支持的CPU架构: $cpu_arch" + exit 1 + ;; +esac + + +chmod +x $save_path/docker-compose &>/dev/null +if ! command -v docker-compose &> /dev/null || [ -z "$(docker-compose --version)" ]; then + WARN "Docker Compose 未安装或安装不完整,正在进行安装..." + while [ $attempt -lt $MAX_ATTEMPTS ]; do + attempt=$((attempt + 1)) + wget --continue -q $url -O $save_path/docker-compose + if [ $? -eq 0 ]; then + chmod +x $save_path/docker-compose + version_check=$(docker-compose --version) + if [ -n "$version_check" ]; then + success=true + chmod +x $save_path/docker-compose + break + else + WARN "Docker Compose 下载的文件不完整,正在尝试重新下载 (尝试次数: $attempt)" + rm -f $save_path/docker-compose + fi + fi + + ERROR "Docker Compose 下载失败,正在尝试重新下载 (尝试次数: $attempt)" + done + + if $success; then + INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)" + else + ERROR "Docker Compose 下载失败,请尝试手动安装docker-compose" + exit 1 + fi +else + chmod +x $save_path/docker-compose + INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)" +fi +} + + +function append_auth_config() { + local file=$1 + local auth_config=" + +auth: + htpasswd: + realm: basic-realm + path: /auth/htpasswd" + + echo -e "$auth_config" | sudo tee -a "$file" > /dev/null + + sed -ri "s@#- ./htpasswd:/auth/htpasswd@- ./htpasswd:/auth/htpasswd@g" ${PROXY_DIR}/docker-compose.yaml &>/dev/null +} + +function update_docker_registry_url() { + local container_name=$1 + sed -ri "s@- DOCKER_REGISTRY_URL=http://reg-docker-hub:5000@- DOCKER_REGISTRY_URL=http://${container_name}:5000@g" ${PROXY_DIR}/docker-compose.yaml +} + +function DOWN_CONFIG() { + files=( + "dockerhub reg-docker-hub ${GITRAW}/config/registry-hub.yml" + "gcr reg-gcr ${GITRAW}/config/registry-gcr.yml" + "ghcr reg-ghcr ${GITRAW}/config/registry-ghcr.yml" + "quay reg-quay ${GITRAW}/config/registry-quay.yml" + "k8sgcr reg-k8s-gcr ${GITRAW}/config/registry-k8sgcr.yml" + "k8s reg-k8s ${GITRAW}/config/registry-k8s.yml" + "mcr reg-mcr ${GITRAW}/config/registry-mcr.yml" + "elastic reg-elastic ${GITRAW}/config/registry-elastic.yml" + ) + + selected_names=() + selected_files=() + selected_containers=() + + echo -e "${YELLOW}-------------------------------------------------${RESET}" + echo -e "${GREEN}1) ${RESET}docker hub" + echo -e "${GREEN}2) ${RESET}gcr" + echo -e "${GREEN}3) ${RESET}ghcr" + echo -e "${GREEN}4) ${RESET}quay" + echo -e "${GREEN}5) ${RESET}k8s-gcr" + echo -e "${GREEN}6) ${RESET}k8s" + echo -e "${GREEN}7) ${RESET}mcr" + echo -e "${GREEN}8) ${RESET}elastic" + echo -e "${GREEN}9) ${RESET}all" + echo -e "${GREEN}0) ${RESET}exit" + echo -e "${YELLOW}-------------------------------------------------${RESET}" + + read -e -p "$(INFO '输入序号下载对应配置文件,空格分隔多个选项. all下载所有: ')" choices_reg + + if [[ "$choices_reg" == "9" ]]; then + for file in "${files[@]}"; do + file_name=$(echo "$file" | cut -d' ' -f1) + container_name=$(echo "$file" | cut -d' ' -f2) + file_url=$(echo "$file" | cut -d' ' -f3-) + selected_names+=("$file_name") + selected_containers+=("$container_name") + selected_files+=("$file_url") + wget -NP ${PROXY_DIR}/ $file_url &>/dev/null + done + selected_all=true + elif [[ "$choices_reg" == "0" ]]; then + WARN "退出下载配置! 首次安装如果没有配置无法启动服务,只能启动UI服务" + return + else + for choice in ${choices_reg}; do + if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then + file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1) + container_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2) + file_url=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f3-) + selected_names+=("$file_name") + selected_containers+=("$container_name") + selected_files+=("$file_url") + wget -NP ${PROXY_DIR}/ $file_url &>/dev/null + else + ERROR "无效的选择: $choice" + exit 1 + fi + done + + selected_all=false + + + if [[ "$user_choice" != "4" ]]; then + first_selected_container=${selected_containers[0]} + update_docker_registry_url "$first_selected_container" + fi + fi + + read -e -p "$(echo -e ${INFO} ${GREEN}"是否需要配置镜像仓库访问账号和密码? (y/n): "${RESET})" config_auth + if [[ "$config_auth" == "y" ]]; then + while true; do + read -e -p "$(echo -e ${INFO} ${GREEN}"请输入账号名称: "${RESET})" username + if [[ -z "$username" ]]; then + ERROR "用户名不能为空。请重新输入" + else + break + fi + done + + while true; do + read -e -p "$(echo -e ${INFO} ${GREEN}"请输入账号密码: "${RESET})" password + if [[ -z "$password" ]]; then + ERROR "密码不能为空。请重新输入" + else + break + fi + done + + htpasswd -Bbn "$username" "$password" > ${PROXY_DIR}/htpasswd + + for file_url in "${selected_files[@]}"; do + yml_name=$(basename "$file_url") + append_auth_config "${PROXY_DIR}/${yml_name}" + done + fi +} + + +function PROXY_HTTP() { +read -e -p "$(echo -e ${INFO} ${GREEN}"是否添加代理? (y/n): "${RESET})" modify_config +case $modify_config in + [Yy]* ) + read -e -p "$(INFO "输入代理地址 (e.g. host:port): ")" url + while [[ -z "$url" ]]; do + WARN "代理地址不能为空,请重新输入。" + read -e -p "$(INFO "输入代理地址 (e.g. host:port): ")" url + done + sed -i "s@#environment:@environment:@g" ${PROXY_DIR}/docker-compose.yaml + sed -i "s@#- http=http://host:port@- http_proxy=http://${url}@g" ${PROXY_DIR}/docker-compose.yaml + sed -i "s@#- https=http://host:port@- https_proxy=http://${url}@g" ${PROXY_DIR}/docker-compose.yaml + + INFO "你配置代理地址为: http://${url}." + ;; + [Nn]* ) + WARN "跳过代理配置" + ;; + * ) + ERROR "无效的输入。跳过配置修改" + ;; +esac +} + + +function ADD_PROXY() { +mkdir -p /etc/systemd/system/docker.service.d + + +if [ ! -f /etc/systemd/system/docker.service.d/http-proxy.conf ]; then + cat > /etc/systemd/system/docker.service.d/http-proxy.conf </dev/null + CHECK_DOCKER +else + if ! grep -q "HTTP_PROXY=http://$url" /etc/systemd/system/docker.service.d/http-proxy.conf || ! grep -q "HTTPS_PROXY=http://$url" /etc/systemd/system/docker.service.d/http-proxy.conf; then + cat >> /etc/systemd/system/docker.service.d/http-proxy.conf </dev/null + CHECK_DOCKER + else + INFO "======================================================= " + fi +fi +} + + +function START_CONTAINER() { + if [ "$modify_config" = "y" ] || [ "$modify_config" = "Y" ]; then + ADD_PROXY + else + INFO "拉取服务镜像并启动服务中,请稍等..." + fi + + if [ "$selected_all" = true ]; then + docker-compose up -d --force-recreate + else + docker-compose up -d "${selected_names[@]}" registry-ui + fi +} + +function RESTART_CONTAINER() { + if [ "$selected_all" = true ]; then + docker-compose restart + else + docker-compose restart "${selected_names[@]}" + fi +} + +function INSTALL_DOCKER_PROXY() { +INFO "======================= 开始安装 =======================" +wget -P ${PROXY_DIR}/ ${GITRAW}/docker-compose.yaml &>/dev/null +DOWN_CONFIG +PROXY_HTTP +START_CONTAINER +} + + +function STOP_REMOVE_CONTAINER() { + if [[ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then + INFO "停止和移除所有容器" + docker-compose -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" down --remove-orphans + else + WARN "容器未运行,无需删除" + exit 1 + fi +} + + +function UPDATE_CONFIG() { +while true; do + read -e -p "$(WARN '是否更新配置,更新前请确保您已备份现有配置,此操作不可逆? [y/n]: ')" update_conf + case "$update_conf" in + y|Y ) + DOWN_CONFIG + RESTART_CONTAINER + break;; + n|N ) + WARN "退出配置更新操作。" + break;; + * ) + INFO "请输入 'y' 表示是,或者 'n' 表示否。";; + esac +done +} + +function REMOVE_NONE_TAG() { + docker images | grep "^${IMAGE_NAME}.*" | awk '{print $3}' | xargs -r docker rmi + images=$(docker images ${IMAGE_NAME} --format '{{.Repository}}:{{.Tag}}') + latest=$(echo "$images" | sort -V | tail -n1) + for image in $images + do + if [ "$image" != "$latest" ];then + docker rmi $image + fi + done +} + + +function PACKAGE() { +while true; do + read -e -p "$(INFO '是否执行软件包安装? [y/n]: ')" choice_package + case "$choice_package" in + y|Y ) + INSTALL_PACKAGE + break;; + n|N ) + WARN "跳过软件包安装步骤。" + break;; + * ) + INFO "请输入 'y' 表示是,或者 'n' 表示否。";; + esac +done +} + + +function INSTALL_WEB() { +while true; do + read -e -p "$(INFO "是否安装WEB服务?(用来通过域名方式访问加速服务) [y/n]: ")" choice_service + if [[ "$choice_service" =~ ^[YyNn]$ ]]; then + if [[ "$choice_service" == "Y" || "$choice_service" == "y" ]]; then + while true; do + read -e -p "$(INFO "选择安装的WEB服务。安装Caddy可自动开启HTTPS [Nginx/Caddy]: ")" web_service + if [[ "$web_service" =~ ^(nginx|Nginx|caddy|Caddy)$ ]]; then + if [[ "$web_service" == "nginx" || "$web_service" == "Nginx" ]]; then + INSTALL_NGINX + break + elif [[ "$web_service" == "caddy" || "$web_service" == "Caddy" ]]; then + INSTALL_CADDY + break + fi + else + WARN "请输入'nginx' 或者 'caddy'" + fi + done + break + else + WARN "跳过WEB服务的安装。" + break + fi + else + INFO "请输入 'y' 表示是,或者 'n' 表示否。" + fi +done +} + + + +function UPDATE_SERVICE() { + services=( + "dockerhub" + "gcr" + "ghcr" + "quay" + "k8sgcr" + "k8s" + ) + + selected_services=() + + WARN "更新服务请在docker compose文件存储目录下执行脚本.默认存储路径: ${PROXY_DIR}" + echo -e "${YELLOW}-------------------------------------------------${RESET}" + echo -e "${GREEN}1) ${RESET}docker hub" + echo -e "${GREEN}2) ${RESET}gcr" + echo -e "${GREEN}3) ${RESET}ghcr" + echo -e "${GREEN}4) ${RESET}quay" + echo -e "${GREEN}5) ${RESET}k8s-gcr" + echo -e "${GREEN}6) ${RESET}k8s" + echo -e "${GREEN}7) ${RESET}mcr" + echo -e "${GREEN}8) ${RESET}elastic" + echo -e "${GREEN}9) ${RESET}all" + echo -e "${GREEN}0) ${RESET}exit" + echo -e "${YELLOW}-------------------------------------------------${RESET}" + + read -e -p "$(INFO '输入序号选择对应服务,空格分隔多个选项. all选择所有: ')" choices_service + + if [[ "$choices_service" == "9" ]]; then + for service_name in "${services[@]}"; do + if docker-compose ps --services | grep -q "^${service_name}$"; then + selected_services+=("$service_name") + else + WARN "服务 ${service_name}未运行,跳过更新。" + fi + done + INFO "更新的服务: ${selected_services[*]}" + elif [[ "$choices_service" == "0" ]]; then + WARN "退出更新服务!" + exit 1 + else + for choice in ${choices_service}; do + if [[ $choice =~ ^[0-9]+$ ]] && ((choice >0 && choice <= ${#services[@]})); then + service_name="${services[$((choice -1))]}" + if docker-compose ps --services | grep -q "^${service_name}$"; then + selected_services+=("$service_name") + INFO "更新的服务: ${selected_services[*]}" + else + WARN "服务 ${service_name} 未运行,跳过更新。" + + fi + else + ERROR "无效的选择: $choice" + exit 3 + fi + done + fi +} + + +function PROMPT(){ +PUBLIC_IP=$(curl -s https://ifconfig.me) +ALL_IPS=$(hostname -I) +INTERNAL_IP=$(echo "$ALL_IPS" | awk '$1!="127.0.0.1" && $1!="::1" && $1!="docker0" {print $1}') + +echo +INFO "=================感谢您的耐心等待,安装已经完成==================" +INFO +INFO "请用浏览器访问 UI 面板: " +INFO "公网访问地址: http://$PUBLIC_IP:50000" +INFO "内网访问地址: http://$INTERNAL_IP:50000" +INFO +INFO "服务安装路径: ${PROXY_DIR}" +INFO +INFO "作者博客: https://dqzboy.com" +INFO "技术交流: https://t.me/dqzboyblog" +INFO "代码仓库: https://github.com/dqzboy/Docker-Proxy" +INFO +INFO "如果使用的是云服务器,且配置了域名与证书,请至安全组开放80、443端口;否则开放对应服务的监听端口" +INFO +INFO "================================================================" +} + + +function main() { +INFO "====================== 请选择操作 ======================" +echo "1) 新装服务" +echo "2) 重启服务" +echo "3) 更新服务" +echo "4) 更新配置" +echo "5) 卸载服务" +read -e -p "$(INFO '输入对应数字并按 Enter 键: ')" user_choice +case $user_choice in + 1) + CHECK_OS + CHECK_PACKAGE_MANAGER + CHECK_PKG_MANAGER + CHECKMEM + CHECKFIRE + CHECKBBR + PACKAGE + INSTALL_WEB + + while true; do + INFO "====================== 安装Docker ======================" + read -e -p "$(INFO '安装环境确认.[国外输1;大陆输2]: ')" deploy_docker + case "$deploy_docker" in + 1 ) + INSTALL_DOCKER + INSTALL_COMPOSE + break;; + 2 ) + INSTALL_DOCKER_CN + INSTALL_COMPOSE_CN + break;; + * ) + INFO "请输入 '1' 表示国外,或者 '2' 表示大陆。";; + esac + done + + INSTALL_DOCKER_PROXY + PROMPT + ;; + 2) + INFO "======================= 重启服务 =======================" + docker-compose restart + INFO "======================= 重启完成 =======================" + ;; + 3) + INFO "======================= 更新服务 =======================" + UPDATE_SERVICE + if [ ${#selected_services[@]} -eq 0 ]; then + WARN "没有需要更新的服务。" + else + docker-compose pull ${selected_services[*]} + docker-compose up -d --force-recreate ${selected_services[*]} + fi + INFO "======================= 更新完成 =======================" + ;; + 4) + INFO "======================= 更新配置 =======================" + UPDATE_CONFIG + INFO "======================= 更新完成 =======================" + ;; + 5) + INFO "======================= 卸载服务 =======================" + WARN "注意: 卸载服务会一同将项目本地的镜像缓存删除,请执行卸载之前确定是否需要备份本地的镜像缓存文件" + while true; do + read -e -p "$(INFO '本人已知晓后果,确认卸载服务? [y/n]: ')" uninstall + case "$uninstall" in + y|Y ) + STOP_REMOVE_CONTAINER + REMOVE_NONE_TAG + docker rmi --force $(docker images -q ${IMAGE_NAME}) &>/dev/null + docker rmi --force $(docker images -q ${UI_IMAGE_NAME}) &>/dev/null + rm -rf ${PROXY_DIR} &>/dev/null + INFO "服务已经卸载,感谢你的使用!" + INFO "========================================================" + break;; + n|N ) + WARN "退出卸载服务." + break;; + * ) + INFO "请输入 'y' 表示是,或者 'n' 表示否。";; + esac + done + ;; + *) + WARN "输入了无效的选择。请重新运行脚本并选择1-4的选项。" + ;; +esac +} +main \ No newline at end of file diff --git a/nginx/registry-proxy.conf b/nginx/registry-proxy.conf new file mode 100644 index 0000000..8a90e65 --- /dev/null +++ b/nginx/registry-proxy.conf @@ -0,0 +1,312 @@ +## registry-ui +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name ui.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:50000; + proxy_set_header Host $host; + proxy_set_header Origin $scheme://$host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Ssl on; # Optional + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Host $host; + } +} + +## docker hub +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name hub.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:51000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + +## GitHub Container Registry (ghcr.io) +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name ghcr.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:52000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + +## Google Container Registry (gcr.io) +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name gcr.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:53000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + +## Kubernetes Container Registry (k8s.gcr.io) +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name k8s-gcr.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:54000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + + +## Kubernetes's container image registry (registry.k8s.io) +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name k8s.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:55000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + +## Quay Container Registry (quay.io) +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name quay.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:56000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + + +## Microsoft Container (mcr.microsoft.com) +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name mcr.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:57000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} + + +## docker.elastic.co +server { + listen 80; + listen 443 ssl; + + ## 填写绑定证书的域名 + server_name elastic.your_domain_name; + ## 证书文件名称(填写你证书存放的路径和名称) + ssl_certificate your_domain_name.crt; + ## 私钥文件名称(填写你证书存放的路径和名称) + ssl_certificate_key your_domain_name.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + ssl_buffer_size 8k; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + + location / { + proxy_pass http://localhost:58000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_buffering off; + proxy_redirect off; + } +} \ No newline at end of file