update front data & pack it to image
All checks were successful
Build NGINX on Ubuntu / build-and-deploy (push) Successful in 59s
All checks were successful
Build NGINX on Ubuntu / build-and-deploy (push) Successful in 59s
This commit is contained in:
parent
30ae89715c
commit
b9cb643c3e
@ -1,121 +0,0 @@
|
|||||||
# NGINX CI/CD 配置说明
|
|
||||||
|
|
||||||
本目录包含了为 NGINX 项目定制的 Git Action 工作流配置文件。
|
|
||||||
|
|
||||||
## 工作流文件说明
|
|
||||||
|
|
||||||
### 1. `build-ubuntu.yaml` - 主要构建流程
|
|
||||||
这是主要的构建和部署流水线,适用于生产环境:
|
|
||||||
|
|
||||||
- **触发条件**: 代码推送和 Pull Request
|
|
||||||
- **功能**:
|
|
||||||
- 在 Ubuntu 22.04 上编译 NGINX
|
|
||||||
- 包含完整的模块配置(SSL、流处理、图像处理等)
|
|
||||||
- 创建 Docker 镜像并推送到 Harbor 仓库
|
|
||||||
- 进行基本的功能测试
|
|
||||||
- 上传构建产物
|
|
||||||
|
|
||||||
### 2. `build-multi-platform.yaml` - 多平台构建
|
|
||||||
用于发布版本的完整构建流程:
|
|
||||||
|
|
||||||
- **触发条件**: 标签推送、工作流手动触发
|
|
||||||
- **功能**:
|
|
||||||
- 多 Ubuntu 版本支持(20.04、22.04)
|
|
||||||
- 配置验证和编译测试
|
|
||||||
- 安全漏洞扫描
|
|
||||||
- 完整的 Docker 镜像构建和发布
|
|
||||||
|
|
||||||
### 3. `build-dev.yaml` - 开发测试流程
|
|
||||||
用于日常开发的快速验证:
|
|
||||||
|
|
||||||
- **触发条件**: develop 分支和 feature 分支推送
|
|
||||||
- **功能**:
|
|
||||||
- 快速构建(最小配置)
|
|
||||||
- 代码质量检查
|
|
||||||
- 多编译器兼容性测试(GCC、Clang)
|
|
||||||
- 构建缓存优化
|
|
||||||
|
|
||||||
## 配置要点
|
|
||||||
|
|
||||||
### 依赖库安装
|
|
||||||
根据 NGINX 官方文档,安装了以下依赖:
|
|
||||||
- `libpcre3-dev` - 正则表达式支持
|
|
||||||
- `zlib1g-dev` - 压缩支持
|
|
||||||
- `libssl-dev` - SSL/TLS 支持
|
|
||||||
- `libxslt1-dev` - XSLT 模块
|
|
||||||
- `libgd-dev` - 图像处理模块
|
|
||||||
- `libgeoip-dev` - GeoIP 模块
|
|
||||||
|
|
||||||
### 编译配置
|
|
||||||
使用 `./auto/configure` 脚本进行配置,主要特性:
|
|
||||||
- HTTP/2 支持
|
|
||||||
- SSL/TLS 加密
|
|
||||||
- 流处理模块
|
|
||||||
- 图像过滤器
|
|
||||||
- 地理位置模块
|
|
||||||
- 负载均衡功能
|
|
||||||
|
|
||||||
### Docker 镜像
|
|
||||||
- 基于 Ubuntu 22.04
|
|
||||||
- 运行时优化(仅包含必要的运行时库)
|
|
||||||
- 健康检查配置
|
|
||||||
- 非 root 用户运行
|
|
||||||
|
|
||||||
## 环境变量配置
|
|
||||||
|
|
||||||
需要在仓库设置中配置以下 Secrets:
|
|
||||||
|
|
||||||
```
|
|
||||||
HARBOR_REGISTRY # Harbor 仓库地址
|
|
||||||
HARBOR_USERNAME # Harbor 用户名
|
|
||||||
HARBOR_PASSWORD # Harbor 密码
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
### 开发流程
|
|
||||||
1. 在 `develop` 或 `feature/*` 分支上工作
|
|
||||||
2. 推送代码会触发 `build-dev.yaml`,进行快速验证
|
|
||||||
3. 创建 Pull Request 到 `main` 分支
|
|
||||||
4. 会触发完整的构建测试
|
|
||||||
|
|
||||||
### 发布流程
|
|
||||||
1. 合并到 `main` 分支后,创建版本标签
|
|
||||||
2. 推送标签会触发 `build-multi-platform.yaml`
|
|
||||||
3. 执行完整的多平台构建和安全扫描
|
|
||||||
4. 自动构建并推送 Docker 镜像
|
|
||||||
|
|
||||||
### 手动触发
|
|
||||||
可以在 Actions 页面手动触发 `build-multi-platform.yaml` 工作流。
|
|
||||||
|
|
||||||
## 构建产物
|
|
||||||
|
|
||||||
- **二进制文件**: 上传到 GitHub Actions Artifacts
|
|
||||||
- **Docker 镜像**: 推送到配置的 Harbor 仓库
|
|
||||||
- **版本标记**: 支持语义化版本标签
|
|
||||||
|
|
||||||
## 故障排除
|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
1. **依赖安装失败**: 检查 Ubuntu 版本和包名称
|
|
||||||
2. **编译错误**: 查看具体的编译器错误信息
|
|
||||||
3. **Docker 推送失败**: 检查 Harbor 凭据配置
|
|
||||||
4. **测试失败**: 检查 NGINX 配置文件语法
|
|
||||||
|
|
||||||
### 调试建议
|
|
||||||
- 查看 Actions 日志中的详细输出
|
|
||||||
- 本地使用相同的命令进行测试
|
|
||||||
- 检查依赖库版本兼容性
|
|
||||||
|
|
||||||
## 性能优化
|
|
||||||
|
|
||||||
- 使用 `make -j$(nproc)` 进行并行编译
|
|
||||||
- 配置构建缓存减少重复下载
|
|
||||||
- 分阶段构建减少单次运行时间
|
|
||||||
|
|
||||||
## 安全考虑
|
|
||||||
|
|
||||||
- 定期更新基础镜像
|
|
||||||
- 运行 Trivy 安全扫描
|
|
||||||
- 使用非 root 用户运行容器
|
|
||||||
- 及时更新依赖库版本
|
|
@ -112,6 +112,20 @@ jobs:
|
|||||||
sudo cp -r /usr/local/nginx ./nginx-install
|
sudo cp -r /usr/local/nginx ./nginx-install
|
||||||
sudo chown -R $(whoami):$(whoami) ./nginx-install
|
sudo chown -R $(whoami):$(whoami) ./nginx-install
|
||||||
|
|
||||||
|
# 检查并复制前端文件
|
||||||
|
echo "检查 app 目录..."
|
||||||
|
if [ -d "./app" ]; then
|
||||||
|
echo "发现前端应用目录,准备复制到 Nginx HTML 目录..."
|
||||||
|
mkdir -p ./nginx-install/html
|
||||||
|
cp -r ./app/* ./nginx-install/html/
|
||||||
|
echo "前端文件已复制到 Nginx HTML 目录"
|
||||||
|
ls -la ./nginx-install/html/
|
||||||
|
else
|
||||||
|
echo "未找到 app 目录,将使用默认 HTML 内容"
|
||||||
|
mkdir -p ./nginx-install/html
|
||||||
|
echo "<h1>Nginx Default Page</h1><p>Replace this with your application.</p>" > ./nginx-install/html/index.html
|
||||||
|
fi
|
||||||
|
|
||||||
- name: 创建 Dockerfile
|
- name: 创建 Dockerfile
|
||||||
run: |
|
run: |
|
||||||
cat > Dockerfile << 'EOF'
|
cat > Dockerfile << 'EOF'
|
||||||
|
125
app/404.html
Normal file
125
app/404.html
Normal file
File diff suppressed because one or more lines are too long
BIN
app/build-your-Quartz-og-image.webp
Normal file
BIN
app/build-your-Quartz-og-image.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
147
app/build-your-Quartz.html
Normal file
147
app/build-your-Quartz.html
Normal file
File diff suppressed because one or more lines are too long
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
app/index-og-image.webp
Normal file
BIN
app/index-og-image.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
1
app/index.css
Normal file
1
app/index.css
Normal file
File diff suppressed because one or more lines are too long
136
app/index.html
Normal file
136
app/index.html
Normal file
File diff suppressed because one or more lines are too long
22
app/index.xml
Normal file
22
app/index.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<rss version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title>Quartz 4</title>
|
||||||
|
<link>https://quartz.jzhao.xyz</link>
|
||||||
|
<description>Last 10 notes on Quartz 4</description>
|
||||||
|
<generator>Quartz -- quartz.jzhao.xyz</generator>
|
||||||
|
<item>
|
||||||
|
<title>build-your-Quartz</title>
|
||||||
|
<link>https://quartz.jzhao.xyz/build-your-Quartz</link>
|
||||||
|
<guid>https://quartz.jzhao.xyz/build-your-Quartz</guid>
|
||||||
|
<description>在您初始化 Quartz 之后,我们可以来看看它在本地构建出来的样子: npx quartz build --serve 这将在您的计算机上启动一个本地 Web 服务器来运行 Quartz,打开浏览器并访问 http://localhost:8080/ 进行查看。 其他参数选项 要获得完整的帮助选项,您可以运行 npx quartz build --help.</description>
|
||||||
|
<pubDate>Tue, 10 Jun 2025 02:33:41 GMT</pubDate>
|
||||||
|
</item><item>
|
||||||
|
<title>Welcome to Quartz</title>
|
||||||
|
<link>https://quartz.jzhao.xyz/</link>
|
||||||
|
<guid>https://quartz.jzhao.xyz/</guid>
|
||||||
|
<description>This is a blank Quartz installation. See the documentation for how to get started.</description>
|
||||||
|
<pubDate>Wed, 23 Aug 2023 19:09:04 GMT</pubDate>
|
||||||
|
</item>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
1097
app/postscript.js
Normal file
1097
app/postscript.js
Normal file
File diff suppressed because one or more lines are too long
1
app/prescript.js
Normal file
1
app/prescript.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
(function(){var d=window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark",a=localStorage.getItem("theme")??d;document.documentElement.setAttribute("saved-theme",a);var n=e=>{let m=new CustomEvent("themechange",{detail:{theme:e}});document.dispatchEvent(m)};document.addEventListener("nav",()=>{let e=()=>{let t=document.documentElement.getAttribute("saved-theme")==="dark"?"light":"dark";document.documentElement.setAttribute("saved-theme",t),localStorage.setItem("theme",t),n(t)},m=t=>{let o=t.matches?"dark":"light";document.documentElement.setAttribute("saved-theme",o),localStorage.setItem("theme",o),n(o)};for(let t of document.getElementsByClassName("darkmode"))t.addEventListener("click",e),window.addCleanup(()=>t.removeEventListener("click",e));let c=window.matchMedia("(prefers-color-scheme: dark)");c.addEventListener("change",m),window.addCleanup(()=>c.removeEventListener("change",m))})})(),function(){var d=!1,a=n=>{let e=new CustomEvent("readermodechange",{detail:{mode:n}});document.dispatchEvent(e)};document.addEventListener("nav",()=>{let n=()=>{d=!d;let e=d?"on":"off";document.documentElement.setAttribute("reader-mode",e),a(e)};for(let e of document.getElementsByClassName("readermode"))e.addEventListener("click",n),window.addCleanup(()=>e.removeEventListener("click",n));document.documentElement.setAttribute("reader-mode",d?"on":"off")})}();
|
7
app/sitemap.xml
Normal file
7
app/sitemap.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url>
|
||||||
|
<loc>https://quartz.jzhao.xyz/build-your-Quartz</loc>
|
||||||
|
<lastmod>2025-06-10T02:33:41.400Z</lastmod>
|
||||||
|
</url><url>
|
||||||
|
<loc>https://quartz.jzhao.xyz/</loc>
|
||||||
|
<lastmod>2023-08-23T19:09:04.000Z</lastmod>
|
||||||
|
</url></urlset>
|
1
app/static/contentIndex.json
Normal file
1
app/static/contentIndex.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"build-your-Quartz":{"slug":"build-your-Quartz","filePath":"build-your-Quartz.md","title":"build-your-Quartz","links":[],"tags":[],"content":"在您初始化 Quartz 之后,我们可以来看看它在本地构建出来的样子:\nnpx quartz build --serve\n\n这将在您的计算机上启动一个本地 Web 服务器来运行 Quartz,打开浏览器并访问 http://localhost:8080/ 进行查看。\n其他参数选项\n要获得完整的帮助选项,您可以运行 npx quartz build --help.\n其中大多数都有合理的默认值,但如果您需要自定义设置,则可以覆盖它们:\n-d 或 --directory: 内容文件夹,一般即 content\n-v 或 --verbose: 输出额外的日志信息\n-o 或 --output: 输出文件夹,一般即 public\n--serve: 在本地运行一个支持热重载的服务器来预览您的 Quartz\n--port: 本地服务器运行的端口\n--concurrency: 解析文档内容所使用的线程数"},"index":{"slug":"index","filePath":"index.md","title":"Welcome to Quartz","links":[],"tags":[],"content":"This is a blank Quartz installation.\nSee the documentation for how to get started."}}
|
99
app/static/giscus/dark.css
Normal file
99
app/static/giscus/dark.css
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*! MIT License
|
||||||
|
* Copyright (c) 2018 GitHub Inc.
|
||||||
|
* https://github.com/primer/primitives/blob/main/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
main {
|
||||||
|
--color-prettylights-syntax-comment: #8b949e;
|
||||||
|
--color-prettylights-syntax-constant: #79c0ff;
|
||||||
|
--color-prettylights-syntax-entity: #d2a8ff;
|
||||||
|
--color-prettylights-syntax-storage-modifier-import: #c9d1d9;
|
||||||
|
--color-prettylights-syntax-entity-tag: #7ee787;
|
||||||
|
--color-prettylights-syntax-keyword: #ff7b72;
|
||||||
|
--color-prettylights-syntax-string: #a5d6ff;
|
||||||
|
--color-prettylights-syntax-variable: #ffa657;
|
||||||
|
--color-prettylights-syntax-brackethighlighter-unmatched: #f85149;
|
||||||
|
--color-prettylights-syntax-invalid-illegal-text: #f0f6fc;
|
||||||
|
--color-prettylights-syntax-invalid-illegal-bg: #8e1519;
|
||||||
|
--color-prettylights-syntax-carriage-return-text: #f0f6fc;
|
||||||
|
--color-prettylights-syntax-carriage-return-bg: #b62324;
|
||||||
|
--color-prettylights-syntax-string-regexp: #7ee787;
|
||||||
|
--color-prettylights-syntax-markup-list: #f2cc60;
|
||||||
|
--color-prettylights-syntax-markup-heading: #1f6feb;
|
||||||
|
--color-prettylights-syntax-markup-italic: #c9d1d9;
|
||||||
|
--color-prettylights-syntax-markup-bold: #c9d1d9;
|
||||||
|
--color-prettylights-syntax-markup-deleted-text: #ffdcd7;
|
||||||
|
--color-prettylights-syntax-markup-deleted-bg: #67060c;
|
||||||
|
--color-prettylights-syntax-markup-inserted-text: #aff5b4;
|
||||||
|
--color-prettylights-syntax-markup-inserted-bg: #033a16;
|
||||||
|
--color-prettylights-syntax-markup-changed-text: #ffdfb6;
|
||||||
|
--color-prettylights-syntax-markup-changed-bg: #5a1e02;
|
||||||
|
--color-prettylights-syntax-markup-ignored-text: #c9d1d9;
|
||||||
|
--color-prettylights-syntax-markup-ignored-bg: #1158c7;
|
||||||
|
--color-prettylights-syntax-meta-diff-range: #d2a8ff;
|
||||||
|
--color-prettylights-syntax-brackethighlighter-angle: #8b949e;
|
||||||
|
--color-prettylights-syntax-sublimelinter-gutter-mark: #484f58;
|
||||||
|
--color-prettylights-syntax-constant-other-reference-link: #a5d6ff;
|
||||||
|
--color-btn-text: #d4d4d4; /* --darkgray */
|
||||||
|
--color-btn-bg: #161618; /* --light */
|
||||||
|
--color-btn-border: rgb(240, 246, 252 / 10%); /* --dark */
|
||||||
|
--color-btn-shadow: 0 0 transparent;
|
||||||
|
--color-btn-inset-shadow: 0 0 transparent;
|
||||||
|
--color-btn-hover-bg: #30363d;
|
||||||
|
--color-btn-hover-border: #8b949e;
|
||||||
|
--color-btn-active-bg: hsl(212deg 12% 18% / 100%);
|
||||||
|
--color-btn-active-border: #6e7681;
|
||||||
|
--color-btn-selected-bg: #161b22;
|
||||||
|
--color-btn-primary-text: #fff;
|
||||||
|
--color-btn-primary-bg: #84a59d; /* --tertiary */
|
||||||
|
--color-btn-primary-border: rgb(240, 246, 252 / 10%); /* --dark */
|
||||||
|
--color-btn-primary-shadow: 0 0 transparent;
|
||||||
|
--color-btn-primary-inset-shadow: 0 0 transparent;
|
||||||
|
--color-btn-primary-hover-bg: #7b97aa; /* --secondary */
|
||||||
|
--color-btn-primary-hover-border: rgb(240, 246, 252 / 10%); /* --dark */
|
||||||
|
--color-btn-primary-selected-bg: #7b97aa; /* --secondary */
|
||||||
|
--color-btn-primary-selected-shadow: 0 0 transparent;
|
||||||
|
--color-btn-primary-disabled-text: rgba(33, 32, 32, 0.5);
|
||||||
|
--color-btn-primary-disabled-bg: rgb(35 134 54 / 60%);
|
||||||
|
--color-btn-primary-disabled-border: rgb(240 246 252 / 10%);
|
||||||
|
--color-action-list-item-default-hover-bg: rgb(177 186 196 / 12%);
|
||||||
|
--color-segmented-control-bg: rgb(110 118 129 / 10%);
|
||||||
|
--color-segmented-control-button-bg: #0d1117;
|
||||||
|
--color-segmented-control-button-selected-border: #6e7681;
|
||||||
|
--color-fg-default: #ebebec; /* --dark */
|
||||||
|
--color-fg-muted: #d4d4d4; /* --darkgray */
|
||||||
|
--color-fg-subtle: #d4d4d4; /* --darkgray */
|
||||||
|
--color-canvas-default: #0d1117;
|
||||||
|
--color-canvas-overlay: #161b22;
|
||||||
|
--color-canvas-inset: #010409;
|
||||||
|
--color-canvas-subtle: #161b22;
|
||||||
|
--color-border-default: #30363d;
|
||||||
|
--color-border-muted: #21262d;
|
||||||
|
--color-neutral-muted: rgb(110 118 129 / 40%);
|
||||||
|
--color-accent-fg: #2f81f7;
|
||||||
|
--color-accent-emphasis: #1f6feb;
|
||||||
|
--color-accent-muted: rgb(56 139 253 / 40%);
|
||||||
|
--color-accent-subtle: rgb(56 139 253 / 10%);
|
||||||
|
--color-success-fg: #3fb950;
|
||||||
|
--color-attention-fg: #d29922;
|
||||||
|
--color-attention-muted: rgb(187 128 9 / 40%);
|
||||||
|
--color-attention-subtle: rgb(187 128 9 / 15%);
|
||||||
|
--color-danger-fg: #f85149;
|
||||||
|
--color-danger-muted: rgb(248 81 73 / 40%);
|
||||||
|
--color-danger-subtle: rgb(248 81 73 / 10%);
|
||||||
|
--color-primer-shadow-inset: 0 0 transparent;
|
||||||
|
--color-scale-gray-7: #21262d;
|
||||||
|
--color-scale-blue-8: #0c2d6b;
|
||||||
|
|
||||||
|
/*! Extensions from @primer/css/alerts/flash.scss */
|
||||||
|
--color-social-reaction-bg-hover: var(--color-scale-gray-7);
|
||||||
|
--color-social-reaction-bg-reacted-hover: var(--color-scale-blue-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
main .pagination-loader-container {
|
||||||
|
background-image: url("https://github.com/images/modules/pulls/progressive-disclosure-line-dark.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
main .gsc-loading-image {
|
||||||
|
background-image: url("https://github.githubassets.com/images/mona-loading-dark.gif");
|
||||||
|
}
|
99
app/static/giscus/light.css
Normal file
99
app/static/giscus/light.css
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*! MIT License
|
||||||
|
* Copyright (c) 2018 GitHub Inc.
|
||||||
|
* https://github.com/primer/primitives/blob/main/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
main {
|
||||||
|
--color-prettylights-syntax-comment: #6e7781;
|
||||||
|
--color-prettylights-syntax-constant: #0550ae;
|
||||||
|
--color-prettylights-syntax-entity: #8250df;
|
||||||
|
--color-prettylights-syntax-storage-modifier-import: #24292f;
|
||||||
|
--color-prettylights-syntax-entity-tag: #116329;
|
||||||
|
--color-prettylights-syntax-keyword: #cf222e;
|
||||||
|
--color-prettylights-syntax-string: #0a3069;
|
||||||
|
--color-prettylights-syntax-variable: #953800;
|
||||||
|
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
|
||||||
|
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
|
||||||
|
--color-prettylights-syntax-invalid-illegal-bg: #82071e;
|
||||||
|
--color-prettylights-syntax-carriage-return-text: #f6f8fa;
|
||||||
|
--color-prettylights-syntax-carriage-return-bg: #cf222e;
|
||||||
|
--color-prettylights-syntax-string-regexp: #116329;
|
||||||
|
--color-prettylights-syntax-markup-list: #3b2300;
|
||||||
|
--color-prettylights-syntax-markup-heading: #0550ae;
|
||||||
|
--color-prettylights-syntax-markup-italic: #24292f;
|
||||||
|
--color-prettylights-syntax-markup-bold: #24292f;
|
||||||
|
--color-prettylights-syntax-markup-deleted-text: #82071e;
|
||||||
|
--color-prettylights-syntax-markup-deleted-bg: #ffebe9;
|
||||||
|
--color-prettylights-syntax-markup-inserted-text: #116329;
|
||||||
|
--color-prettylights-syntax-markup-inserted-bg: #dafbe1;
|
||||||
|
--color-prettylights-syntax-markup-changed-text: #953800;
|
||||||
|
--color-prettylights-syntax-markup-changed-bg: #ffd8b5;
|
||||||
|
--color-prettylights-syntax-markup-ignored-text: #eaeef2;
|
||||||
|
--color-prettylights-syntax-markup-ignored-bg: #0550ae;
|
||||||
|
--color-prettylights-syntax-meta-diff-range: #8250df;
|
||||||
|
--color-prettylights-syntax-brackethighlighter-angle: #57606a;
|
||||||
|
--color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f;
|
||||||
|
--color-prettylights-syntax-constant-other-reference-link: #0a3069;
|
||||||
|
--color-btn-text: #4e4e4e; /* --darkgray */
|
||||||
|
--color-btn-bg: #faf8f8; /* --light */
|
||||||
|
--color-btn-border: rgb(43, 43, 43 / 15%); /* --dark */
|
||||||
|
--color-btn-shadow: 0 1px 0 rgb(31 35 40 / 4%);
|
||||||
|
--color-btn-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 25%);
|
||||||
|
--color-btn-hover-bg: #f3f4f6;
|
||||||
|
--color-btn-hover-border: rgb(43, 43, 43 / 15%); /* --dark */
|
||||||
|
--color-btn-active-bg: hsl(220deg 14% 93% / 100%);
|
||||||
|
--color-btn-active-border: rgb(31 35 40 / 15%);
|
||||||
|
--color-btn-selected-bg: hsl(220deg 14% 94% / 100%);
|
||||||
|
--color-btn-primary-text: #fff;
|
||||||
|
--color-btn-primary-bg: #84a59d; /* --tertiary */
|
||||||
|
--color-btn-primary-border: rgb(43, 43, 43 / 15%); /* --dark */
|
||||||
|
--color-btn-primary-shadow: 0 1px 0 rgb(31 35 40 / 10%);
|
||||||
|
--color-btn-primary-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 3%);
|
||||||
|
--color-btn-primary-hover-bg: #284b63; /* --secondary */
|
||||||
|
--color-btn-primary-hover-border: rgb(43, 43, 43 / 15%); /* --dark */
|
||||||
|
--color-btn-primary-selected-bg: #284b63; /* --secondary */
|
||||||
|
--color-btn-primary-selected-shadow: inset 0 1px 0 rgb(0 45 17 / 20%);
|
||||||
|
--color-btn-primary-disabled-text: rgb(255 255 255 / 80%);
|
||||||
|
--color-btn-primary-disabled-bg: #94d3a2;
|
||||||
|
--color-btn-primary-disabled-border: rgb(31 35 40 / 15%);
|
||||||
|
--color-action-list-item-default-hover-bg: rgb(208 215 222 / 32%);
|
||||||
|
--color-segmented-control-bg: #eaeef2;
|
||||||
|
--color-segmented-control-button-bg: #fff;
|
||||||
|
--color-segmented-control-button-selected-border: #8c959f;
|
||||||
|
--color-fg-default: #2b2b2b; /* --dark */
|
||||||
|
--color-fg-muted: #4e4e4e; /* --darkgray */
|
||||||
|
--color-fg-subtle: #4e4e4e; /* --darkgray */
|
||||||
|
--color-canvas-default: #fff;
|
||||||
|
--color-canvas-overlay: #fff;
|
||||||
|
--color-canvas-inset: #f6f8fa;
|
||||||
|
--color-canvas-subtle: #f6f8fa;
|
||||||
|
--color-border-default: #d0d7de;
|
||||||
|
--color-border-muted: hsl(210deg 18% 87% / 100%);
|
||||||
|
--color-neutral-muted: rgb(175 184 193 / 20%);
|
||||||
|
--color-accent-fg: #0969da;
|
||||||
|
--color-accent-emphasis: #0969da;
|
||||||
|
--color-accent-muted: rgb(84 174 255 / 40%);
|
||||||
|
--color-accent-subtle: #ddf4ff;
|
||||||
|
--color-success-fg: #1a7f37;
|
||||||
|
--color-attention-fg: #9a6700;
|
||||||
|
--color-attention-muted: rgb(212 167 44 / 40%);
|
||||||
|
--color-attention-subtle: #fff8c5;
|
||||||
|
--color-danger-fg: #d1242f;
|
||||||
|
--color-danger-muted: rgb(255 129 130 / 40%);
|
||||||
|
--color-danger-subtle: #ffebe9;
|
||||||
|
--color-primer-shadow-inset: inset 0 1px 0 rgb(208 215 222 / 20%);
|
||||||
|
--color-scale-gray-1: #eaeef2;
|
||||||
|
--color-scale-blue-1: #b6e3ff;
|
||||||
|
|
||||||
|
/*! Extensions from @primer/css/alerts/flash.scss */
|
||||||
|
--color-social-reaction-bg-hover: var(--color-scale-gray-1);
|
||||||
|
--color-social-reaction-bg-reacted-hover: var(--color-scale-blue-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
main .pagination-loader-container {
|
||||||
|
background-image: url("https://github.com/images/modules/pulls/progressive-disclosure-line.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
main .gsc-loading-image {
|
||||||
|
background-image: url("https://github.githubassets.com/images/mona-loading-default.gif");
|
||||||
|
}
|
BIN
app/static/icon.png
Normal file
BIN
app/static/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
app/static/og-image.png
Normal file
BIN
app/static/og-image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
125
app/tags/index.html
Normal file
125
app/tags/index.html
Normal file
File diff suppressed because one or more lines are too long
308
k8s/README.md
308
k8s/README.md
@ -1,308 +0,0 @@
|
|||||||
# Kubernetes 部署指南
|
|
||||||
|
|
||||||
本指南详细说明了如何将构建好的 NGINX Docker 镜像从私有 Harbor 仓库部署到 Kubernetes 集群。
|
|
||||||
|
|
||||||
## 📋 目录结构
|
|
||||||
|
|
||||||
```
|
|
||||||
k8s/
|
|
||||||
├── deploy.sh # Linux/macOS 自动部署脚本
|
|
||||||
├── deploy.bat # Windows 自动部署脚本
|
|
||||||
├── nginx-deployment.yaml # Kubernetes 部署配置
|
|
||||||
├── .env.template # 环境变量模板
|
|
||||||
└── README.md # 本文档
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
|
||||||
|
|
||||||
### 方法一:使用自动部署脚本(推荐)
|
|
||||||
|
|
||||||
1. **设置环境变量**
|
|
||||||
```bash
|
|
||||||
# Linux/macOS
|
|
||||||
export HARBOR_REGISTRY=harbor.example.com
|
|
||||||
export HARBOR_USERNAME=your-username
|
|
||||||
export HARBOR_PASSWORD=your-password
|
|
||||||
export NGINX_IMAGE_TAG=latest # 或使用 ${GITHUB_SHA}
|
|
||||||
```
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
REM Windows
|
|
||||||
set HARBOR_REGISTRY=harbor.example.com
|
|
||||||
set HARBOR_USERNAME=your-username
|
|
||||||
set HARBOR_PASSWORD=your-password
|
|
||||||
set NGINX_IMAGE_TAG=latest
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **运行部署脚本**
|
|
||||||
```bash
|
|
||||||
# Linux/macOS
|
|
||||||
chmod +x deploy.sh
|
|
||||||
./deploy.sh
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
deploy.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法二:使用环境变量文件
|
|
||||||
|
|
||||||
1. **创建环境变量文件**
|
|
||||||
```bash
|
|
||||||
cp .env.template .env
|
|
||||||
# 编辑 .env 文件,填入实际的配置值
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **运行部署脚本**
|
|
||||||
```bash
|
|
||||||
# 脚本会自动加载 .env 文件
|
|
||||||
./deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法三:手动部署
|
|
||||||
|
|
||||||
1. **创建 Harbor 仓库访问凭据**
|
|
||||||
```bash
|
|
||||||
kubectl create secret docker-registry harbor-registry-secret \
|
|
||||||
--docker-server=harbor.example.com \
|
|
||||||
--docker-username=your-username \
|
|
||||||
--docker-password=your-password \
|
|
||||||
--namespace=default
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **更新部署文件中的镜像标签**
|
|
||||||
```bash
|
|
||||||
# 编辑 nginx-deployment.yaml,替换镜像标签
|
|
||||||
# 将 harbor.example.com/test/nginx:latest 替换为实际的镜像地址
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **应用 Kubernetes 配置**
|
|
||||||
```bash
|
|
||||||
kubectl apply -f nginx-deployment.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **检查部署状态**
|
|
||||||
```bash
|
|
||||||
kubectl get pods -l app=nginx
|
|
||||||
kubectl get services -l app=nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 配置说明
|
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
|
|
||||||
| 变量名 | 描述 | 必需 | 默认值 |
|
|
||||||
|--------|------|------|--------|
|
|
||||||
| `HARBOR_REGISTRY` | Harbor 仓库地址 | 是 | - |
|
|
||||||
| `HARBOR_USERNAME` | Harbor 用户名 | 是 | - |
|
|
||||||
| `HARBOR_PASSWORD` | Harbor 密码 | 是 | - |
|
|
||||||
| `NGINX_IMAGE_TAG` | NGINX 镜像标签 | 是 | - |
|
|
||||||
| `NAMESPACE` | Kubernetes 命名空间 | 否 | `default` |
|
|
||||||
| `DEPLOYMENT_FILE` | 部署配置文件路径 | 否 | `./nginx-deployment.yaml` |
|
|
||||||
|
|
||||||
### Kubernetes 资源
|
|
||||||
|
|
||||||
部署文件包含以下 Kubernetes 资源:
|
|
||||||
|
|
||||||
1. **ConfigMap** (`nginx-config`)
|
|
||||||
- 包含 NGINX 配置文件
|
|
||||||
- 自定义日志格式和访问控制
|
|
||||||
|
|
||||||
2. **Deployment** (`nginx-deployment`)
|
|
||||||
- 3 个副本的 NGINX Pod
|
|
||||||
- 从私有 Harbor 仓库拉取镜像
|
|
||||||
- 包含健康检查和资源限制
|
|
||||||
|
|
||||||
3. **Service** (`nginx-service`)
|
|
||||||
- NodePort 类型(端口 30080)
|
|
||||||
- 可以改为 LoadBalancer 或 ClusterIP
|
|
||||||
|
|
||||||
4. **HPA** (`nginx-hpa`)
|
|
||||||
- 水平自动伸缩
|
|
||||||
- 基于 CPU 使用率(目标 70%)
|
|
||||||
- 副本数范围:3-10
|
|
||||||
|
|
||||||
5. **PodDisruptionBudget** (`nginx-pdb`)
|
|
||||||
- 确保更新期间的可用性
|
|
||||||
- 最小可用副本数:2
|
|
||||||
|
|
||||||
## 🔍 验证部署
|
|
||||||
|
|
||||||
### 检查 Pod 状态
|
|
||||||
```bash
|
|
||||||
kubectl get pods -l app=nginx -o wide
|
|
||||||
```
|
|
||||||
|
|
||||||
### 检查服务状态
|
|
||||||
```bash
|
|
||||||
kubectl get services -l app=nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
### 查看日志
|
|
||||||
```bash
|
|
||||||
# 查看特定 Pod 的日志
|
|
||||||
kubectl logs -l app=nginx -f
|
|
||||||
|
|
||||||
# 查看所有 NGINX Pod 的日志
|
|
||||||
kubectl logs -l app=nginx --all-containers=true -f
|
|
||||||
```
|
|
||||||
|
|
||||||
### 访问应用
|
|
||||||
|
|
||||||
根据服务类型不同,访问方式如下:
|
|
||||||
|
|
||||||
1. **NodePort**(默认)
|
|
||||||
```bash
|
|
||||||
# 获取节点 IP 和端口
|
|
||||||
kubectl get nodes -o wide
|
|
||||||
kubectl get service nginx-service
|
|
||||||
# 访问 http://<node-ip>:30080
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **LoadBalancer**
|
|
||||||
```bash
|
|
||||||
# 等待外部 IP 分配
|
|
||||||
kubectl get service nginx-service -w
|
|
||||||
# 访问 http://<external-ip>
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **ClusterIP**
|
|
||||||
```bash
|
|
||||||
# 使用端口转发进行测试
|
|
||||||
kubectl port-forward service/nginx-service 8080:80
|
|
||||||
# 访问 http://localhost:8080
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 故障排除
|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
|
|
||||||
1. **镜像拉取失败**
|
|
||||||
```bash
|
|
||||||
# 检查 Secret 是否正确创建
|
|
||||||
kubectl get secret harbor-registry-secret -o yaml
|
|
||||||
|
|
||||||
# 检查镜像地址是否正确
|
|
||||||
kubectl describe pod <pod-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Pod 启动失败**
|
|
||||||
```bash
|
|
||||||
# 查看 Pod 详细信息
|
|
||||||
kubectl describe pod <pod-name>
|
|
||||||
|
|
||||||
# 查看 Pod 日志
|
|
||||||
kubectl logs <pod-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **服务无法访问**
|
|
||||||
```bash
|
|
||||||
# 检查服务端点
|
|
||||||
kubectl get endpoints nginx-service
|
|
||||||
|
|
||||||
# 检查网络策略(如果启用)
|
|
||||||
kubectl get networkpolicy
|
|
||||||
```
|
|
||||||
|
|
||||||
### 日志查看
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 查看部署事件
|
|
||||||
kubectl get events --sort-by=.metadata.creationTimestamp
|
|
||||||
|
|
||||||
# 查看特定资源的事件
|
|
||||||
kubectl describe deployment nginx-deployment
|
|
||||||
kubectl describe service nginx-service
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 更新部署
|
|
||||||
|
|
||||||
### 更新镜像版本
|
|
||||||
|
|
||||||
1. **使用脚本更新**
|
|
||||||
```bash
|
|
||||||
export NGINX_IMAGE_TAG=new-version
|
|
||||||
./deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **手动更新**
|
|
||||||
```bash
|
|
||||||
kubectl set image deployment/nginx-deployment \
|
|
||||||
nginx=harbor.example.com/test/nginx:new-version
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **滚动更新策略**
|
|
||||||
```bash
|
|
||||||
# 查看滚动更新状态
|
|
||||||
kubectl rollout status deployment/nginx-deployment
|
|
||||||
|
|
||||||
# 回滚到上一个版本
|
|
||||||
kubectl rollout undo deployment/nginx-deployment
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🗑️ 清理资源
|
|
||||||
|
|
||||||
### 删除部署
|
|
||||||
```bash
|
|
||||||
kubectl delete -f nginx-deployment.yaml
|
|
||||||
kubectl delete secret harbor-registry-secret
|
|
||||||
```
|
|
||||||
|
|
||||||
### 删除命名空间(如果使用专用命名空间)
|
|
||||||
```bash
|
|
||||||
kubectl delete namespace <namespace-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔐 安全注意事项
|
|
||||||
|
|
||||||
1. **敏感信息管理**
|
|
||||||
- 不要将 Harbor 凭据提交到代码仓库
|
|
||||||
- 使用 Kubernetes Secrets 存储敏感信息
|
|
||||||
- 考虑使用外部密钥管理系统
|
|
||||||
|
|
||||||
2. **网络安全**
|
|
||||||
- 配置网络策略限制 Pod 间通信
|
|
||||||
- 使用 HTTPS 和 TLS 证书
|
|
||||||
- 配置防火墙规则
|
|
||||||
|
|
||||||
3. **镜像安全**
|
|
||||||
- 定期扫描镜像漏洞
|
|
||||||
- 使用最小权限运行容器
|
|
||||||
- 启用镜像签名验证
|
|
||||||
|
|
||||||
## 📚 参考资料
|
|
||||||
|
|
||||||
- [Kubernetes 官方文档](https://kubernetes.io/docs/)
|
|
||||||
- [Harbor 官方文档](https://goharbor.io/docs/)
|
|
||||||
- [NGINX 官方文档](https://nginx.org/en/docs/)
|
|
||||||
- [Docker 私有仓库配置](https://docs.docker.com/registry/deploying/)
|
|
||||||
|
|
||||||
## 💡 提示
|
|
||||||
|
|
||||||
1. **性能优化**
|
|
||||||
- 根据实际负载调整副本数和资源限制
|
|
||||||
- 配置 NGINX 缓存策略
|
|
||||||
- 使用持久化存储保存日志
|
|
||||||
|
|
||||||
2. **监控配置**
|
|
||||||
- 集成 Prometheus 监控
|
|
||||||
- 配置 Grafana 仪表板
|
|
||||||
- 设置告警规则
|
|
||||||
|
|
||||||
3. **自动化**
|
|
||||||
- 集成到 CI/CD 流水线
|
|
||||||
- 使用 Helm 管理复杂部署
|
|
||||||
- 配置自动化测试
|
|
||||||
|
|
||||||
## `${{ github.sha }}` 变量说明
|
|
||||||
|
|
||||||
`${{ github.sha }}` 是 GitHub Actions 中的一个内置环境变量,代表:
|
|
||||||
|
|
||||||
- **含义**: 当前提交的完整 SHA-1 哈希值(40 字符)
|
|
||||||
- **格式**: 例如 `a1b2c3d4e5f6789012345678901234567890abcd`
|
|
||||||
- **用途**: 作为 Docker 镜像的唯一标签,确保每次构建的镜像都有唯一标识
|
|
||||||
- **优势**:
|
|
||||||
- 可追溯性:能够准确对应到具体的代码提交
|
|
||||||
- 唯一性:避免镜像标签冲突
|
|
||||||
- 版本控制:便于回滚和版本管理
|
|
||||||
|
|
||||||
在 CI/CD 中使用 `${{ github.sha }}` 作为镜像标签是最佳实践,可以实现精确的版本控制和部署追踪。
|
|
@ -230,51 +230,6 @@ get_access_info() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
# 处理HTML_DIR变量
|
|
||||||
process_html_dir() {
|
|
||||||
print_info "处理HTML目录变量..."
|
|
||||||
|
|
||||||
# 如果HTML_DIR变量不存在,设置默认值
|
|
||||||
if [[ -z "${HTML_DIR}" ]]; then
|
|
||||||
export HTML_DIR="/mnt/nginx-html"
|
|
||||||
print_warning "HTML_DIR环境变量未设置,使用默认值: $HTML_DIR"
|
|
||||||
else
|
|
||||||
print_info "使用HTML目录: $HTML_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 检查PV配置文件是否存在
|
|
||||||
local pv_file="./nginx-pv.yaml"
|
|
||||||
if [[ -f "$pv_file" ]]; then
|
|
||||||
print_info "更新持久卷配置中的HTML目录路径..."
|
|
||||||
|
|
||||||
# 备份原文件
|
|
||||||
cp "$pv_file" "${pv_file}.bak"
|
|
||||||
|
|
||||||
# 替换变量
|
|
||||||
sed -i.tmp "s|\"\${{ vars.HTML_DIR }}\"|\"${HTML_DIR}\"|g" "$pv_file"
|
|
||||||
|
|
||||||
# 清理临时文件
|
|
||||||
rm -f "${pv_file}.tmp"
|
|
||||||
|
|
||||||
print_success "持久卷配置已更新,使用HTML目录: $HTML_DIR"
|
|
||||||
else
|
|
||||||
print_warning "持久卷配置文件不存在: $pv_file"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# 应用持久卷配置
|
|
||||||
apply_pv_config() {
|
|
||||||
print_info "应用持久卷配置..."
|
|
||||||
|
|
||||||
local pv_file="./nginx-pv.yaml"
|
|
||||||
if [[ -f "$pv_file" ]]; then
|
|
||||||
kubectl apply -f "$pv_file"
|
|
||||||
print_success "持久卷配置应用成功"
|
|
||||||
else
|
|
||||||
print_warning "持久卷配置文件不存在: $pv_file,跳过应用"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# 主函数
|
# 主函数
|
||||||
main() {
|
main() {
|
||||||
print_info "开始 NGINX Kubernetes 自动部署..."
|
print_info "开始 NGINX Kubernetes 自动部署..."
|
||||||
@ -290,10 +245,6 @@ main() {
|
|||||||
create_namespace "$namespace"
|
create_namespace "$namespace"
|
||||||
create_harbor_secret "$namespace"
|
create_harbor_secret "$namespace"
|
||||||
|
|
||||||
# 处理HTML_DIR变量并应用持久卷配置
|
|
||||||
process_html_dir
|
|
||||||
apply_pv_config
|
|
||||||
|
|
||||||
update_deployment_image "$deployment_file" "$image_tag"
|
update_deployment_image "$deployment_file" "$image_tag"
|
||||||
apply_k8s_config "$deployment_file"
|
apply_k8s_config "$deployment_file"
|
||||||
wait_for_deployment "$namespace"
|
wait_for_deployment "$namespace"
|
||||||
|
@ -50,15 +50,30 @@ data:
|
|||||||
listen 8080; # 修改为非特权端口
|
listen 8080; # 修改为非特权端口
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
# 添加重写规则 - 如果请求不带扩展名且不存在对应目录,尝试添加.html后缀
|
# 为SPA应用添加特殊处理
|
||||||
location / {
|
location / {
|
||||||
root /usr/local/nginx/html;
|
root /usr/local/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
|
|
||||||
# 首先尝试完全匹配,然后尝试添加.html扩展名,最后回退到index
|
# 支持HTML扩展名省略和SPA路由
|
||||||
try_files $uri $uri.html $uri/ /index.html;
|
try_files $uri $uri.html $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 静态资源处理
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
root /usr/local/nginx/html;
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public, max-age=2592000";
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API代理配置 (如果需要)
|
||||||
|
# location /api/ {
|
||||||
|
# proxy_pass http://backend-service:8080/;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# }
|
||||||
|
|
||||||
# 健康检查端点
|
# 健康检查端点
|
||||||
location /health {
|
location /health {
|
||||||
return 200 'ok';
|
return 200 'ok';
|
||||||
@ -222,7 +237,11 @@ spec:
|
|||||||
echo "警告: HTML目录不可读";
|
echo "警告: HTML目录不可读";
|
||||||
chmod -R 755 /usr/local/nginx/html;
|
chmod -R 755 /usr/local/nginx/html;
|
||||||
fi;
|
fi;
|
||||||
if [ ! -r /usr/local/nginx/html/index.html ] && [ ! -r /usr/local/nginx/html/index.htm ]; then
|
|
||||||
|
# 保留已存在的前端文件,不覆盖
|
||||||
|
if [ -f /usr/local/nginx/html/index.html ]; then
|
||||||
|
echo "找到现有index.html文件,将保留这些文件";
|
||||||
|
else
|
||||||
echo "警告: 没有找到index文件,创建默认页面";
|
echo "警告: 没有找到index文件,创建默认页面";
|
||||||
cat > /usr/local/nginx/html/index.html << 'EOF'
|
cat > /usr/local/nginx/html/index.html << 'EOF'
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -232,13 +251,11 @@ spec:
|
|||||||
</body></html>
|
</body></html>
|
||||||
EOF
|
EOF
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
echo "设置目录权限...";
|
echo "设置目录权限...";
|
||||||
chown -R 65534:65534 /usr/local/nginx/html || true;
|
chown -R 65534:65534 /usr/local/nginx/html || true;
|
||||||
chmod -R 755 /usr/local/nginx/html || true;
|
chmod -R 755 /usr/local/nginx/html || true;
|
||||||
echo "HTML目录权限设置完成";
|
echo "HTML目录权限设置完成";
|
||||||
volumeMounts:
|
|
||||||
- name: nginx-html-content
|
|
||||||
mountPath: /usr/local/nginx/html
|
|
||||||
|
|
||||||
containers:
|
containers:
|
||||||
- name: nginx
|
- name: nginx
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
# 持久卷和持久卷声明定义
|
|
||||||
# 用于存储HTML静态文件
|
|
||||||
|
|
||||||
# 1. 持久卷 - 基于主机路径
|
|
||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolume
|
|
||||||
metadata:
|
|
||||||
name: nginx-html-pv
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
type: local
|
|
||||||
spec:
|
|
||||||
storageClassName: manual
|
|
||||||
capacity:
|
|
||||||
storage: 1Gi
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteMany
|
|
||||||
hostPath:
|
|
||||||
path: "${{ vars.HTML_DIR }}"
|
|
||||||
persistentVolumeReclaimPolicy: Retain
|
|
||||||
|
|
||||||
---
|
|
||||||
# 2. 持久卷声明
|
|
||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: nginx-html-pvc
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
storageClassName: manual
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteMany
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 1Gi
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx
|
|
||||||
type: local
|
|
@ -1,257 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# NGINX Kubernetes 快速启动脚本
|
|
||||||
# 用于快速设置和部署 NGINX 到 Kubernetes
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# 颜色输出
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
BLUE='\033[0;34m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
print_banner() {
|
|
||||||
echo -e "${BLUE}"
|
|
||||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
|
||||||
echo "║ NGINX Kubernetes 部署工具 ║"
|
|
||||||
echo "║ 快速启动和配置向导 ║"
|
|
||||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
|
||||||
echo -e "${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_info() {
|
|
||||||
echo -e "${BLUE}[INFO]${NC} $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_success() {
|
|
||||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_warning() {
|
|
||||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_error() {
|
|
||||||
echo -e "${RED}[ERROR]${NC} $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 交互式配置收集
|
|
||||||
collect_config() {
|
|
||||||
print_info "开始收集配置信息..."
|
|
||||||
echo
|
|
||||||
|
|
||||||
# Harbor 配置
|
|
||||||
read -p "$(echo -e ${BLUE}请输入 Harbor 仓库地址${NC} (例: harbor.example.com): " HARBOR_REGISTRY
|
|
||||||
read -p "$(echo -e ${BLUE}请输入 Harbor 用户名${NC}: " HARBOR_USERNAME
|
|
||||||
read -s -p "$(echo -e ${BLUE}请输入 Harbor 密码${NC}: " HARBOR_PASSWORD
|
|
||||||
echo
|
|
||||||
|
|
||||||
# 镜像配置
|
|
||||||
read -p "$(echo -e ${BLUE}请输入镜像标签${NC} (默认: latest): " NGINX_IMAGE_TAG
|
|
||||||
NGINX_IMAGE_TAG=${NGINX_IMAGE_TAG:-latest}
|
|
||||||
|
|
||||||
# Kubernetes 配置
|
|
||||||
read -p "$(echo -e ${BLUE}请输入 Kubernetes 命名空间${NC} (默认: default): " NAMESPACE
|
|
||||||
NAMESPACE=${NAMESPACE:-default}
|
|
||||||
|
|
||||||
echo
|
|
||||||
print_success "配置收集完成"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 验证配置
|
|
||||||
validate_config() {
|
|
||||||
print_info "验证配置..."
|
|
||||||
|
|
||||||
if [[ -z "$HARBOR_REGISTRY" ]]; then
|
|
||||||
print_error "Harbor 仓库地址不能为空"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$HARBOR_USERNAME" ]]; then
|
|
||||||
print_error "Harbor 用户名不能为空"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$HARBOR_PASSWORD" ]]; then
|
|
||||||
print_error "Harbor 密码不能为空"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_success "配置验证通过"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 保存配置到环境文件
|
|
||||||
save_config() {
|
|
||||||
print_info "保存配置到 .env 文件..."
|
|
||||||
|
|
||||||
cat > .env << EOF
|
|
||||||
# NGINX Kubernetes 部署配置
|
|
||||||
# 由快速启动脚本生成于 $(date)
|
|
||||||
|
|
||||||
# Harbor 仓库配置
|
|
||||||
HARBOR_REGISTRY=$HARBOR_REGISTRY
|
|
||||||
HARBOR_USERNAME=$HARBOR_USERNAME
|
|
||||||
HARBOR_PASSWORD=$HARBOR_PASSWORD
|
|
||||||
|
|
||||||
# 镜像配置
|
|
||||||
NGINX_IMAGE_TAG=$NGINX_IMAGE_TAG
|
|
||||||
|
|
||||||
# Kubernetes 配置
|
|
||||||
NAMESPACE=$NAMESPACE
|
|
||||||
DEPLOYMENT_FILE=./nginx-deployment.yaml
|
|
||||||
EOF
|
|
||||||
|
|
||||||
print_success "配置已保存到 .env 文件"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 显示配置摘要
|
|
||||||
show_config_summary() {
|
|
||||||
echo
|
|
||||||
print_info "配置摘要:"
|
|
||||||
echo " Harbor 仓库: $HARBOR_REGISTRY"
|
|
||||||
echo " Harbor 用户: $HARBOR_USERNAME"
|
|
||||||
echo " 镜像标签: $NGINX_IMAGE_TAG"
|
|
||||||
echo " 命名空间: $NAMESPACE"
|
|
||||||
echo " 完整镜像地址: $HARBOR_REGISTRY/test/nginx:$NGINX_IMAGE_TAG"
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
# 检查先决条件
|
|
||||||
check_prerequisites() {
|
|
||||||
print_info "检查先决条件..."
|
|
||||||
|
|
||||||
local missing_tools=()
|
|
||||||
|
|
||||||
# 检查 kubectl
|
|
||||||
if ! command -v kubectl &> /dev/null; then
|
|
||||||
missing_tools+=("kubectl")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 检查 docker (可选)
|
|
||||||
if ! command -v docker &> /dev/null; then
|
|
||||||
print_warning "Docker 未安装 (可选)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
||||||
print_error "缺少必要工具: ${missing_tools[*]}"
|
|
||||||
echo "请安装缺少的工具后重试"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 检查 kubectl 连接
|
|
||||||
if ! kubectl cluster-info &> /dev/null; then
|
|
||||||
print_error "无法连接到 Kubernetes 集群"
|
|
||||||
echo "请确保 kubectl 已正确配置并能访问集群"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_success "先决条件检查通过"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 测试 Harbor 连接
|
|
||||||
test_harbor_connection() {
|
|
||||||
print_info "测试 Harbor 连接..."
|
|
||||||
|
|
||||||
if command -v docker &> /dev/null; then
|
|
||||||
if echo "$HARBOR_PASSWORD" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USERNAME" --password-stdin &> /dev/null; then
|
|
||||||
print_success "Harbor 连接测试通过"
|
|
||||||
docker logout "$HARBOR_REGISTRY" &> /dev/null
|
|
||||||
else
|
|
||||||
print_warning "Harbor 连接测试失败,请检查凭据"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
print_warning "Docker 未安装,跳过 Harbor 连接测试"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# 运行部署
|
|
||||||
run_deployment() {
|
|
||||||
print_info "开始部署..."
|
|
||||||
|
|
||||||
# 导出环境变量
|
|
||||||
export HARBOR_REGISTRY
|
|
||||||
export HARBOR_USERNAME
|
|
||||||
export HARBOR_PASSWORD
|
|
||||||
export NGINX_IMAGE_TAG
|
|
||||||
export NAMESPACE
|
|
||||||
|
|
||||||
# 运行部署脚本
|
|
||||||
if [[ -f "deploy.sh" ]]; then
|
|
||||||
chmod +x deploy.sh
|
|
||||||
./deploy.sh
|
|
||||||
else
|
|
||||||
print_error "部署脚本 deploy.sh 不存在"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# 提供后续操作建议
|
|
||||||
show_next_steps() {
|
|
||||||
echo
|
|
||||||
print_success "🎉 部署完成!"
|
|
||||||
echo
|
|
||||||
print_info "后续操作建议:"
|
|
||||||
echo " 1. 查看部署状态: make status"
|
|
||||||
echo " 2. 查看日志: make logs"
|
|
||||||
echo " 3. 设置端口转发: make port-forward"
|
|
||||||
echo " 4. 扩缩容: make scale REPLICAS=5"
|
|
||||||
echo " 5. 更新镜像: make update NGINX_IMAGE_TAG=new-version"
|
|
||||||
echo " 6. 清理部署: make clean"
|
|
||||||
echo
|
|
||||||
print_info "配置文件已保存到 .env,下次可以直接运行 ./deploy.sh"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 主函数
|
|
||||||
main() {
|
|
||||||
print_banner
|
|
||||||
|
|
||||||
# 检查是否已有配置文件
|
|
||||||
if [[ -f ".env" ]]; then
|
|
||||||
read -p "$(echo -e ${YELLOW}发现已存在配置文件 .env,是否重新配置?${NC} (y/N): " RECONFIGURE
|
|
||||||
if [[ "$RECONFIGURE" =~ ^[Yy]$ ]]; then
|
|
||||||
collect_config
|
|
||||||
else
|
|
||||||
print_info "使用现有配置文件..."
|
|
||||||
source .env
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
collect_config
|
|
||||||
fi
|
|
||||||
|
|
||||||
validate_config || exit 1
|
|
||||||
show_config_summary
|
|
||||||
|
|
||||||
# 询问是否继续
|
|
||||||
read -p "$(echo -e ${YELLOW}是否继续部署?${NC} (Y/n): " CONTINUE
|
|
||||||
if [[ "$CONTINUE" =~ ^[Nn]$ ]]; then
|
|
||||||
print_info "部署已取消"
|
|
||||||
save_config
|
|
||||||
echo "配置已保存,可以稍后运行 ./deploy.sh 进行部署"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
check_prerequisites || exit 1
|
|
||||||
test_harbor_connection
|
|
||||||
save_config
|
|
||||||
run_deployment
|
|
||||||
show_next_steps
|
|
||||||
}
|
|
||||||
|
|
||||||
# 清理函数
|
|
||||||
cleanup() {
|
|
||||||
# 恢复终端状态
|
|
||||||
stty echo 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# 设置清理陷阱
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
# 处理中断信号
|
|
||||||
trap 'print_warning "操作被中断"; exit 130' INT
|
|
||||||
|
|
||||||
# 如果直接运行此脚本
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
main "$@"
|
|
||||||
fi
|
|
Loading…
x
Reference in New Issue
Block a user