From 5c7293be88cb8f33320a07719e0e2e60bb27dba5 Mon Sep 17 00:00:00 2001 From: huangzhiqiang Date: Sat, 7 Jun 2025 17:40:01 +0800 Subject: [PATCH] add action for k8s deploy --- .gitea/workflows/README.md | 121 ++++++++++++ .gitea/workflows/build-ubuntu.yaml | 39 ++++ k8s/.env.template | 17 ++ k8s/Makefile | 152 ++++++++++++++ k8s/README.md | 308 +++++++++++++++++++++++++++++ k8s/deploy.bat | 295 +++++++++++++++++++++++++++ k8s/deploy.sh | 263 ++++++++++++++++++++++++ k8s/nginx-deployment.yaml | 308 +++++++++++++++++++++++++++++ k8s/quickstart.sh | 257 ++++++++++++++++++++++++ 9 files changed, 1760 insertions(+) create mode 100644 .gitea/workflows/README.md create mode 100644 k8s/.env.template create mode 100644 k8s/Makefile create mode 100644 k8s/README.md create mode 100644 k8s/deploy.bat create mode 100644 k8s/deploy.sh create mode 100644 k8s/nginx-deployment.yaml create mode 100644 k8s/quickstart.sh diff --git a/.gitea/workflows/README.md b/.gitea/workflows/README.md new file mode 100644 index 0000000..60dd24f --- /dev/null +++ b/.gitea/workflows/README.md @@ -0,0 +1,121 @@ +# 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 用户运行容器 +- 及时更新依赖库版本 diff --git a/.gitea/workflows/build-ubuntu.yaml b/.gitea/workflows/build-ubuntu.yaml index 0051a69..d4d2448 100644 --- a/.gitea/workflows/build-ubuntu.yaml +++ b/.gitea/workflows/build-ubuntu.yaml @@ -174,3 +174,42 @@ jobs: docker rmi ${{ secrets.HARBOR_REGISTRY }}/test/nginx:${{ github.sha }} || true docker rmi ${{ secrets.HARBOR_REGISTRY }}/test/nginx:latest || true + - name: 部署到 Kubernetes (可选) + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + run: | + echo "开始部署到 Kubernetes..." + + # 检查是否配置了 Kubernetes 部署 + if [[ -n "${{ secrets.KUBE_CONFIG }}" ]]; then + # 安装 kubectl + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x kubectl + sudo mv kubectl /usr/local/bin/ + + # 配置 kubectl + mkdir -p ~/.kube + echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + # 验证 kubectl 连接 + kubectl cluster-info --short || (echo "Kubernetes 连接失败" && exit 1) + + # 设置环境变量 + export HARBOR_REGISTRY="${{ secrets.HARBOR_REGISTRY }}" + export HARBOR_USERNAME="${{ secrets.HARBOR_USERNAME }}" + export HARBOR_PASSWORD="${{ secrets.HARBOR_PASSWORD }}" + export NGINX_IMAGE_TAG="${{ github.sha }}" + export NAMESPACE="${{ secrets.K8S_NAMESPACE || 'default' }}" + + # 进入 k8s 目录 + cd k8s + + # 运行部署脚本 + chmod +x deploy.sh + ./deploy.sh + + echo "Kubernetes 部署完成" + else + echo "跳过 Kubernetes 部署 - 未配置 KUBE_CONFIG" + fi + diff --git a/k8s/.env.template b/k8s/.env.template new file mode 100644 index 0000000..01f067a --- /dev/null +++ b/k8s/.env.template @@ -0,0 +1,17 @@ +# 环境变量配置文件模板 +# 复制此文件为 .env 并填入实际值 + +# Harbor 仓库配置 +HARBOR_REGISTRY=harbor.example.com +HARBOR_USERNAME=your-username +HARBOR_PASSWORD=your-password + +# 镜像配置 +NGINX_IMAGE_TAG=latest + +# Kubernetes 配置 +NAMESPACE=default +DEPLOYMENT_FILE=./nginx-deployment.yaml + +# 可选配置 +# KUBECONFIG=/path/to/kubeconfig # 如果不使用默认的 kubectl 配置 diff --git a/k8s/Makefile b/k8s/Makefile new file mode 100644 index 0000000..18aca04 --- /dev/null +++ b/k8s/Makefile @@ -0,0 +1,152 @@ +# NGINX Kubernetes 部署 Makefile +# 简化部署操作和管理 + +# 默认配置 +HARBOR_REGISTRY ?= harbor.example.com +HARBOR_USERNAME ?= your-username +HARBOR_PASSWORD ?= your-password +NGINX_IMAGE_TAG ?= latest +NAMESPACE ?= default +DEPLOYMENT_FILE ?= ./nginx-deployment.yaml + +# 颜色输出 +RED := \033[0;31m +GREEN := \033[0;32m +YELLOW := \033[1;33m +BLUE := \033[0;34m +NC := \033[0m # No Color + +.PHONY: help deploy clean status logs port-forward scale update rollback check-env install-deps + +# 默认目标 +help: ## 显示帮助信息 + @echo "$(BLUE)NGINX Kubernetes 部署工具$(NC)" + @echo "" + @echo "$(YELLOW)可用命令:$(NC)" + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(GREEN)%-15s$(NC) %s\n", $$1, $$2}' $(MAKEFILE_LIST) + @echo "" + @echo "$(YELLOW)环境变量:$(NC)" + @echo " HARBOR_REGISTRY Harbor 仓库地址 (当前: $(HARBOR_REGISTRY))" + @echo " HARBOR_USERNAME Harbor 用户名 (当前: $(HARBOR_USERNAME))" + @echo " HARBOR_PASSWORD Harbor 密码 (已设置: $(if $(HARBOR_PASSWORD),是,否))" + @echo " NGINX_IMAGE_TAG 镜像标签 (当前: $(NGINX_IMAGE_TAG))" + @echo " NAMESPACE 命名空间 (当前: $(NAMESPACE))" + +check-env: ## 检查环境变量 + @echo "$(BLUE)[INFO]$(NC) 检查必要的环境变量..." + @if [ -z "$(HARBOR_REGISTRY)" ]; then echo "$(RED)[ERROR]$(NC) HARBOR_REGISTRY 未设置"; exit 1; fi + @if [ -z "$(HARBOR_USERNAME)" ]; then echo "$(RED)[ERROR]$(NC) HARBOR_USERNAME 未设置"; exit 1; fi + @if [ -z "$(HARBOR_PASSWORD)" ]; then echo "$(RED)[ERROR]$(NC) HARBOR_PASSWORD 未设置"; exit 1; fi + @if [ -z "$(NGINX_IMAGE_TAG)" ]; then echo "$(RED)[ERROR]$(NC) NGINX_IMAGE_TAG 未设置"; exit 1; fi + @echo "$(GREEN)[SUCCESS]$(NC) 环境变量检查通过" + +install-deps: ## 安装必要的依赖工具 + @echo "$(BLUE)[INFO]$(NC) 检查并安装必要的工具..." + @which kubectl > /dev/null || (echo "$(RED)[ERROR]$(NC) kubectl 未安装" && exit 1) + @echo "$(GREEN)[SUCCESS]$(NC) 所有必要工具已安装" + +deploy: check-env install-deps ## 部署 NGINX 到 Kubernetes + @echo "$(BLUE)[INFO]$(NC) 开始部署 NGINX 到 Kubernetes..." + @cd k8s && chmod +x deploy.sh && \ + HARBOR_REGISTRY=$(HARBOR_REGISTRY) \ + HARBOR_USERNAME=$(HARBOR_USERNAME) \ + HARBOR_PASSWORD=$(HARBOR_PASSWORD) \ + NGINX_IMAGE_TAG=$(NGINX_IMAGE_TAG) \ + NAMESPACE=$(NAMESPACE) \ + ./deploy.sh + +status: ## 查看部署状态 + @echo "$(BLUE)[INFO]$(NC) 查看 NGINX 部署状态..." + @echo "" + @echo "$(YELLOW)=== Pods ===$(NC)" + @kubectl get pods -l app=nginx -n $(NAMESPACE) -o wide || true + @echo "" + @echo "$(YELLOW)=== Services ===$(NC)" + @kubectl get services -l app=nginx -n $(NAMESPACE) || true + @echo "" + @echo "$(YELLOW)=== Deployments ===$(NC)" + @kubectl get deployments -l app=nginx -n $(NAMESPACE) || true + @echo "" + @echo "$(YELLOW)=== HPA ===$(NC)" + @kubectl get hpa -l app=nginx -n $(NAMESPACE) 2>/dev/null || echo "HPA 未启用" + +logs: ## 查看 NGINX Pod 日志 + @echo "$(BLUE)[INFO]$(NC) 查看 NGINX Pod 日志..." + @kubectl logs -l app=nginx -n $(NAMESPACE) -f --all-containers=true + +port-forward: ## 设置端口转发以便本地访问 + @echo "$(BLUE)[INFO]$(NC) 设置端口转发 localhost:8080 -> nginx-service:80" + @echo "$(YELLOW)访问 http://localhost:8080 来测试 NGINX$(NC)" + @kubectl port-forward service/nginx-service 8080:80 -n $(NAMESPACE) + +scale: ## 扩缩容 NGINX 部署 (用法: make scale REPLICAS=5) + @if [ -z "$(REPLICAS)" ]; then echo "$(RED)[ERROR]$(NC) 请指定副本数: make scale REPLICAS=5"; exit 1; fi + @echo "$(BLUE)[INFO]$(NC) 扩缩容 NGINX 到 $(REPLICAS) 个副本..." + @kubectl scale deployment nginx-deployment --replicas=$(REPLICAS) -n $(NAMESPACE) + @kubectl rollout status deployment/nginx-deployment -n $(NAMESPACE) + +update: check-env ## 更新 NGINX 镜像版本 + @echo "$(BLUE)[INFO]$(NC) 更新 NGINX 镜像到 $(NGINX_IMAGE_TAG)..." + @kubectl set image deployment/nginx-deployment nginx=$(HARBOR_REGISTRY)/test/nginx:$(NGINX_IMAGE_TAG) -n $(NAMESPACE) + @kubectl rollout status deployment/nginx-deployment -n $(NAMESPACE) + @echo "$(GREEN)[SUCCESS]$(NC) 镜像更新完成" + +rollback: ## 回滚到上一个版本 + @echo "$(BLUE)[INFO]$(NC) 回滚 NGINX 部署到上一个版本..." + @kubectl rollout undo deployment/nginx-deployment -n $(NAMESPACE) + @kubectl rollout status deployment/nginx-deployment -n $(NAMESPACE) + @echo "$(GREEN)[SUCCESS]$(NC) 回滚完成" + +restart: ## 重启 NGINX 部署 + @echo "$(BLUE)[INFO]$(NC) 重启 NGINX 部署..." + @kubectl rollout restart deployment/nginx-deployment -n $(NAMESPACE) + @kubectl rollout status deployment/nginx-deployment -n $(NAMESPACE) + @echo "$(GREEN)[SUCCESS]$(NC) 重启完成" + +clean: ## 清理 NGINX 部署 + @echo "$(BLUE)[INFO]$(NC) 清理 NGINX 部署..." + @kubectl delete -f k8s/nginx-deployment.yaml -n $(NAMESPACE) --ignore-not-found=true + @kubectl delete secret harbor-registry-secret -n $(NAMESPACE) --ignore-not-found=true + @echo "$(GREEN)[SUCCESS]$(NC) 清理完成" + +config: ## 显示当前配置 + @echo "$(BLUE)[INFO]$(NC) 当前配置:" + @echo " Harbor 仓库: $(HARBOR_REGISTRY)" + @echo " Harbor 用户: $(HARBOR_USERNAME)" + @echo " 镜像标签: $(NGINX_IMAGE_TAG)" + @echo " 命名空间: $(NAMESPACE)" + @echo " 部署文件: $(DEPLOYMENT_FILE)" + +test: ## 测试 NGINX 服务连接 + @echo "$(BLUE)[INFO]$(NC) 测试 NGINX 服务连接..." + @POD_NAME=$$(kubectl get pods -l app=nginx -n $(NAMESPACE) -o jsonpath='{.items[0].metadata.name}'); \ + if [ -n "$$POD_NAME" ]; then \ + echo "测试 Pod: $$POD_NAME"; \ + kubectl exec $$POD_NAME -n $(NAMESPACE) -- curl -s -o /dev/null -w "HTTP状态码: %{http_code}\n" http://localhost/; \ + else \ + echo "$(RED)[ERROR]$(NC) 未找到运行中的 NGINX Pod"; \ + fi + +debug: ## 调试部署问题 + @echo "$(BLUE)[INFO]$(NC) 调试 NGINX 部署..." + @echo "" + @echo "$(YELLOW)=== 检查 Secrets ===$(NC)" + @kubectl get secret harbor-registry-secret -n $(NAMESPACE) -o yaml 2>/dev/null || echo "Secret 不存在" + @echo "" + @echo "$(YELLOW)=== 检查事件 ===$(NC)" + @kubectl get events --sort-by=.metadata.creationTimestamp -n $(NAMESPACE) | grep nginx | tail -10 + @echo "" + @echo "$(YELLOW)=== Pod 详细信息 ===$(NC)" + @POD_NAME=$$(kubectl get pods -l app=nginx -n $(NAMESPACE) -o jsonpath='{.items[0].metadata.name}' 2>/dev/null); \ + if [ -n "$$POD_NAME" ]; then \ + kubectl describe pod $$POD_NAME -n $(NAMESPACE); \ + else \ + echo "未找到 NGINX Pod"; \ + fi + +# 为方便使用,创建一些简短的别名 +s: status ## 别名: status +l: logs ## 别名: logs +d: deploy ## 别名: deploy +c: clean ## 别名: clean +u: update ## 别名: update diff --git a/k8s/README.md b/k8s/README.md new file mode 100644 index 0000000..c5eda52 --- /dev/null +++ b/k8s/README.md @@ -0,0 +1,308 @@ +# 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://:30080 + ``` + +2. **LoadBalancer** + ```bash + # 等待外部 IP 分配 + kubectl get service nginx-service -w + # 访问 http:// + ``` + +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 + ``` + +2. **Pod 启动失败** + ```bash + # 查看 Pod 详细信息 + kubectl describe pod + + # 查看 Pod 日志 + kubectl logs + ``` + +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 +``` + +## 🔐 安全注意事项 + +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 }}` 作为镜像标签是最佳实践,可以实现精确的版本控制和部署追踪。 diff --git a/k8s/deploy.bat b/k8s/deploy.bat new file mode 100644 index 0000000..49b5b84 --- /dev/null +++ b/k8s/deploy.bat @@ -0,0 +1,295 @@ +@echo off +REM Kubernetes 自动部署脚本 (Windows 版本) +REM 用于从私有 Harbor 仓库拉取 NGINX 镜像并部署到 K8s 集群 + +setlocal EnableDelayedExpansion + +REM 设置颜色代码(Windows 10/11 支持 ANSI 转义序列) +set "RED=[91m" +set "GREEN=[92m" +set "YELLOW=[93m" +set "BLUE=[94m" +set "NC=[0m" + +REM 打印带颜色的信息 +:print_info +echo %BLUE%[INFO]%NC% %~1 +goto :eof + +:print_success +echo %GREEN%[SUCCESS]%NC% %~1 +goto :eof + +:print_warning +echo %YELLOW%[WARNING]%NC% %~1 +goto :eof + +:print_error +echo %RED%[ERROR]%NC% %~1 +goto :eof + +REM 检查必要的环境变量 +:check_env_vars +call :print_info "检查环境变量..." + +set "missing_vars=" +if "%HARBOR_REGISTRY%"=="" set "missing_vars=%missing_vars% HARBOR_REGISTRY" +if "%HARBOR_USERNAME%"=="" set "missing_vars=%missing_vars% HARBOR_USERNAME" +if "%HARBOR_PASSWORD%"=="" set "missing_vars=%missing_vars% HARBOR_PASSWORD" +if "%NGINX_IMAGE_TAG%"=="" set "missing_vars=%missing_vars% NGINX_IMAGE_TAG" + +if not "%missing_vars%"=="" ( + call :print_error "缺少必要的环境变量: %missing_vars%" + echo. + echo 请设置以下环境变量: + echo set HARBOR_REGISTRY=^<你的Harbor仓库地址^> + echo set HARBOR_USERNAME=^ + echo set HARBOR_PASSWORD=^ + echo set NGINX_IMAGE_TAG=^<镜像标签,如: %%GITHUB_SHA%% 或 latest^> + echo. + echo 或者创建 .env 文件包含这些变量 + exit /b 1 +) + +call :print_success "环境变量检查通过" +goto :eof + +REM 检查 kubectl 连接 +:check_kubectl +call :print_info "检查 kubectl 连接..." + +kubectl version --client >nul 2>&1 +if errorlevel 1 ( + call :print_error "kubectl 未安装或不在 PATH 中" + echo 请从 https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/ 安装 kubectl + exit /b 1 +) + +kubectl cluster-info >nul 2>&1 +if errorlevel 1 ( + call :print_error "无法连接到 Kubernetes 集群" + echo 请确保: + echo 1. kubectl 已正确配置 + echo 2. 能够访问 Kubernetes 集群 + echo 3. 当前用户有适当的权限 + exit /b 1 +) + +call :print_success "kubectl 连接正常" +kubectl cluster-info --short +goto :eof + +REM 创建命名空间(如果不存在) +:create_namespace +set "namespace=%~1" +if "%namespace%"=="" set "namespace=default" + +call :print_info "检查命名空间: %namespace%" + +kubectl get namespace %namespace% >nul 2>&1 +if errorlevel 1 ( + call :print_info "创建命名空间: %namespace%" + kubectl create namespace %namespace% + if errorlevel 1 ( + call :print_error "创建命名空间失败" + exit /b 1 + ) + call :print_success "命名空间 '%namespace%' 创建成功" +) else ( + call :print_success "命名空间 '%namespace%' 已存在" +) +goto :eof + +REM 创建或更新 Harbor 仓库访问凭据 +:create_harbor_secret +set "namespace=%~1" +if "%namespace%"=="" set "namespace=default" + +call :print_info "创建/更新 Harbor 仓库访问凭据..." + +REM 删除已存在的 secret(如果存在) +kubectl delete secret harbor-registry-secret -n %namespace% --ignore-not-found=true >nul 2>&1 + +REM 创建新的 secret +kubectl create secret docker-registry harbor-registry-secret --docker-server=%HARBOR_REGISTRY% --docker-username=%HARBOR_USERNAME% --docker-password=%HARBOR_PASSWORD% --namespace=%namespace% +if errorlevel 1 ( + call :print_error "创建 Harbor 仓库访问凭据失败" + exit /b 1 +) + +call :print_success "Harbor 仓库访问凭据创建成功" +goto :eof + +REM 更新部署文件中的镜像标签 +:update_deployment_image +set "deployment_file=%~1" +set "image_tag=%~2" + +call :print_info "更新部署文件中的镜像标签: %image_tag%" + +set "full_image=%HARBOR_REGISTRY%/test/nginx:%image_tag%" + +REM 备份原文件 +copy "%deployment_file%" "%deployment_file%.bak" >nul + +REM 使用 PowerShell 替换镜像标签 +powershell -Command "(Get-Content '%deployment_file%') -replace '%HARBOR_REGISTRY%/test/nginx:[^\s]*', '%full_image%' | Set-Content '%deployment_file%'" +if errorlevel 1 ( + call :print_error "更新镜像标签失败" + exit /b 1 +) + +call :print_success "镜像标签更新为: %full_image%" +goto :eof + +REM 应用 Kubernetes 配置 +:apply_k8s_config +set "deployment_file=%~1" +call :print_info "应用 Kubernetes 配置..." + +if not exist "%deployment_file%" ( + call :print_error "部署文件不存在: %deployment_file%" + exit /b 1 +) + +kubectl apply -f "%deployment_file%" +if errorlevel 1 ( + call :print_error "应用 Kubernetes 配置失败" + exit /b 1 +) + +call :print_success "Kubernetes 配置应用成功" +goto :eof + +REM 等待部署就绪 +:wait_for_deployment +set "deployment_name=nginx-deployment" +set "namespace=%~1" +set "timeout=%~2" +if "%namespace%"=="" set "namespace=default" +if "%timeout%"=="" set "timeout=300" + +call :print_info "等待部署就绪..." + +kubectl wait --for=condition=available deployment/%deployment_name% --namespace=%namespace% --timeout=%timeout%s +if errorlevel 1 ( + call :print_error "部署超时,请检查部署状态" + kubectl describe deployment %deployment_name% -n %namespace% + exit /b 1 +) + +call :print_success "部署已就绪" +goto :eof + +REM 显示部署状态 +:show_deployment_status +set "namespace=%~1" +if "%namespace%"=="" set "namespace=default" + +call :print_info "部署状态:" + +echo. +echo === Pods === +kubectl get pods -l app=nginx -n %namespace% -o wide + +echo. +echo === Services === +kubectl get services -l app=nginx -n %namespace% + +echo. +echo === Deployments === +kubectl get deployments -l app=nginx -n %namespace% + +echo. +echo === HPA === +kubectl get hpa -l app=nginx -n %namespace% 2>nul || echo HPA 未启用 + +echo. +echo === Events === +kubectl get events --sort-by=.metadata.creationTimestamp -n %namespace% | findstr /C:"nginx" +goto :eof + +REM 获取访问信息 +:get_access_info +set "namespace=%~1" +if "%namespace%"=="" set "namespace=default" + +call :print_info "获取访问信息..." + +for /f "tokens=*" %%i in ('kubectl get service nginx-service -n %namespace% -o jsonpath^="{.spec.type}"') do set "service_type=%%i" + +if "%service_type%"=="NodePort" ( + for /f "tokens=*" %%i in ('kubectl get service nginx-service -n %namespace% -o jsonpath^="{.spec.ports[0].nodePort}"') do set "node_port=%%i" + for /f "tokens=*" %%i in ('kubectl get nodes -o jsonpath^="{.items[0].status.addresses[?(@.type==\"InternalIP\")].address}"') do set "node_ip=%%i" + call :print_success "NodePort 访问地址: http://!node_ip!:!node_port!" +) else if "%service_type%"=="LoadBalancer" ( + call :print_info "等待 LoadBalancer 外部 IP..." + for /f "tokens=*" %%i in ('kubectl get service nginx-service -n %namespace% -o jsonpath^="{.status.loadBalancer.ingress[0].ip}" 2^>nul') do set "external_ip=%%i" + if not "!external_ip!"=="" ( + call :print_success "LoadBalancer 访问地址: http://!external_ip!" + ) else ( + call :print_warning "LoadBalancer 外部 IP 仍在分配中" + ) +) else if "%service_type%"=="ClusterIP" ( + for /f "tokens=*" %%i in ('kubectl get service nginx-service -n %namespace% -o jsonpath^="{.spec.clusterIP}"') do set "cluster_ip=%%i" + call :print_success "ClusterIP 访问地址: http://!cluster_ip!" + call :print_info "注意: ClusterIP 只能在集群内部访问" +) +goto :eof + +REM 清理函数 +:cleanup +call :print_info "执行清理操作..." +if exist ".\nginx-deployment.yaml.bak" ( + move ".\nginx-deployment.yaml.bak" ".\nginx-deployment.yaml" >nul +) +goto :eof + +REM 主函数 +:main +call :print_info "开始 NGINX Kubernetes 自动部署..." + +REM 设置默认值 +if "%NAMESPACE%"=="" set "NAMESPACE=default" +if "%DEPLOYMENT_FILE%"=="" set "DEPLOYMENT_FILE=.\nginx-deployment.yaml" +if "%NGINX_IMAGE_TAG%"=="" set "NGINX_IMAGE_TAG=latest" + +REM 检查是否有 .env 文件 +if exist ".env" ( + call :print_info "加载 .env 文件..." + for /f "usebackq tokens=1,2 delims==" %%a in (".env") do ( + set "%%a=%%b" + ) +) + +REM 执行部署步骤 +call :check_env_vars +if errorlevel 1 exit /b 1 + +call :check_kubectl +if errorlevel 1 exit /b 1 + +call :create_namespace "%NAMESPACE%" +if errorlevel 1 exit /b 1 + +call :create_harbor_secret "%NAMESPACE%" +if errorlevel 1 exit /b 1 + +call :update_deployment_image "%DEPLOYMENT_FILE%" "%NGINX_IMAGE_TAG%" +if errorlevel 1 exit /b 1 + +call :apply_k8s_config "%DEPLOYMENT_FILE%" +if errorlevel 1 exit /b 1 + +call :wait_for_deployment "%NAMESPACE%" +if errorlevel 1 exit /b 1 + +call :show_deployment_status "%NAMESPACE%" +call :get_access_info "%NAMESPACE%" + +call :print_success "🎉 NGINX 部署完成!" +goto :eof + +REM 如果直接运行此脚本,执行主函数 +call :main +call :cleanup diff --git a/k8s/deploy.sh b/k8s/deploy.sh new file mode 100644 index 0000000..8fb0fa9 --- /dev/null +++ b/k8s/deploy.sh @@ -0,0 +1,263 @@ +#!/bin/bash + +# Kubernetes 自动部署脚本 +# 用于从私有 Harbor 仓库拉取 NGINX 镜像并部署到 K8s 集群 + +set -e + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 打印带颜色的信息 +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" +} + +# 检查必要的环境变量 +check_env_vars() { + print_info "检查环境变量..." + + required_vars=("HARBOR_REGISTRY" "HARBOR_USERNAME" "HARBOR_PASSWORD" "NGINX_IMAGE_TAG") + missing_vars=() + + for var in "${required_vars[@]}"; do + if [[ -z "${!var}" ]]; then + missing_vars+=("$var") + fi + done + + if [[ ${#missing_vars[@]} -gt 0 ]]; then + print_error "缺少必要的环境变量:" + for var in "${missing_vars[@]}"; do + echo " - $var" + done + print_info "请设置以下环境变量:" + echo " export HARBOR_REGISTRY=<你的Harbor仓库地址>" + echo " export HARBOR_USERNAME=" + echo " export HARBOR_PASSWORD=" + echo " export NGINX_IMAGE_TAG=<镜像标签,如: \${GITHUB_SHA} 或 latest>" + exit 1 + fi + + print_success "环境变量检查通过" +} + +# 检查 kubectl 连接 +check_kubectl() { + print_info "检查 kubectl 连接..." + + if ! command -v kubectl &> /dev/null; then + print_error "kubectl 未安装或不在 PATH 中" + exit 1 + fi + + if ! kubectl cluster-info &> /dev/null; then + print_error "无法连接到 Kubernetes 集群" + print_info "请确保:" + echo " 1. kubectl 已正确配置" + echo " 2. 能够访问 Kubernetes 集群" + echo " 3. 当前用户有适当的权限" + exit 1 + fi + + print_success "kubectl 连接正常" + kubectl cluster-info --short +} + +# 创建命名空间(如果不存在) +create_namespace() { + local namespace=${1:-default} + print_info "检查命名空间: $namespace" + + if kubectl get namespace "$namespace" &> /dev/null; then + print_success "命名空间 '$namespace' 已存在" + else + print_info "创建命名空间: $namespace" + kubectl create namespace "$namespace" + print_success "命名空间 '$namespace' 创建成功" + fi +} + +# 创建或更新 Harbor 仓库访问凭据 +create_harbor_secret() { + local namespace=${1:-default} + print_info "创建/更新 Harbor 仓库访问凭据..." + + # 删除已存在的 secret(如果存在) + kubectl delete secret harbor-registry-secret -n "$namespace" --ignore-not-found=true + + # 创建新的 secret + kubectl create secret docker-registry harbor-registry-secret \ + --docker-server="$HARBOR_REGISTRY" \ + --docker-username="$HARBOR_USERNAME" \ + --docker-password="$HARBOR_PASSWORD" \ + --namespace="$namespace" + + print_success "Harbor 仓库访问凭据创建成功" +} + +# 更新部署文件中的镜像标签 +update_deployment_image() { + local deployment_file="$1" + local image_tag="$2" + + print_info "更新部署文件中的镜像标签: $image_tag" + + # 使用 sed 替换镜像标签 + local full_image="${HARBOR_REGISTRY}/test/nginx:${image_tag}" + + # 备份原文件 + cp "$deployment_file" "${deployment_file}.bak" + + # 替换镜像标签 (假设镜像行包含 harbor-registry/test/nginx) + sed -i.tmp "s|${HARBOR_REGISTRY}/test/nginx:[^[:space:]]*|${full_image}|g" "$deployment_file" + + print_success "镜像标签更新为: $full_image" +} + +# 应用 Kubernetes 配置 +apply_k8s_config() { + local deployment_file="$1" + print_info "应用 Kubernetes 配置..." + + if [[ ! -f "$deployment_file" ]]; then + print_error "部署文件不存在: $deployment_file" + exit 1 + fi + + kubectl apply -f "$deployment_file" + print_success "Kubernetes 配置应用成功" +} + +# 等待部署就绪 +wait_for_deployment() { + local deployment_name="nginx-deployment" + local namespace=${1:-default} + local timeout=${2:-300} + + print_info "等待部署就绪..." + + if kubectl wait --for=condition=available deployment/"$deployment_name" \ + --namespace="$namespace" --timeout="${timeout}s"; then + print_success "部署已就绪" + else + print_error "部署超时,请检查部署状态" + kubectl describe deployment "$deployment_name" -n "$namespace" + exit 1 + fi +} + +# 显示部署状态 +show_deployment_status() { + local namespace=${1:-default} + print_info "部署状态:" + + echo + echo "=== Pods ===" + kubectl get pods -l app=nginx -n "$namespace" -o wide + + echo + echo "=== Services ===" + kubectl get services -l app=nginx -n "$namespace" + + echo + echo "=== Deployments ===" + kubectl get deployments -l app=nginx -n "$namespace" + + echo + echo "=== HPA ===" + kubectl get hpa -l app=nginx -n "$namespace" 2>/dev/null || echo "HPA 未启用" + + echo + echo "=== Events ===" + kubectl get events --sort-by=.metadata.creationTimestamp -n "$namespace" | tail -10 +} + +# 获取访问信息 +get_access_info() { + local namespace=${1:-default} + print_info "获取访问信息..." + + local service_type=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.spec.type}') + + case "$service_type" in + "NodePort") + local node_port=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.spec.ports[0].nodePort}') + local node_ip=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}') + if [[ -z "$node_ip" ]]; then + node_ip=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}') + fi + print_success "NodePort 访问地址: http://${node_ip}:${node_port}" + ;; + "LoadBalancer") + print_info "等待 LoadBalancer 外部 IP..." + local external_ip=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + if [[ -n "$external_ip" ]]; then + print_success "LoadBalancer 访问地址: http://${external_ip}" + else + print_warning "LoadBalancer 外部 IP 仍在分配中" + fi + ;; + "ClusterIP") + local cluster_ip=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.spec.clusterIP}') + print_success "ClusterIP 访问地址: http://${cluster_ip}" + print_info "注意: ClusterIP 只能在集群内部访问" + ;; + esac +} + +# 主函数 +main() { + print_info "开始 NGINX Kubernetes 自动部署..." + + # 设置默认值 + local namespace=${NAMESPACE:-default} + local deployment_file=${DEPLOYMENT_FILE:-./nginx-deployment.yaml} + local image_tag=${NGINX_IMAGE_TAG:-latest} + + # 执行部署步骤 + check_env_vars + check_kubectl + create_namespace "$namespace" + create_harbor_secret "$namespace" + update_deployment_image "$deployment_file" "$image_tag" + apply_k8s_config "$deployment_file" + wait_for_deployment "$namespace" + show_deployment_status "$namespace" + get_access_info "$namespace" + + print_success "🎉 NGINX 部署完成!" +} + +# 清理函数 +cleanup() { + print_info "执行清理操作..." + # 恢复备份文件 + if [[ -f "./nginx-deployment.yaml.bak" ]]; then + mv "./nginx-deployment.yaml.bak" "./nginx-deployment.yaml" + fi +} + +# 设置清理陷阱 +trap cleanup EXIT + +# 如果直接运行此脚本 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/k8s/nginx-deployment.yaml b/k8s/nginx-deployment.yaml new file mode 100644 index 0000000..42b944b --- /dev/null +++ b/k8s/nginx-deployment.yaml @@ -0,0 +1,308 @@ +# Kubernetes 部署配置文件 +# 用于从私有 Harbor 仓库拉取 NGINX 镜像并部署 +# +# 使用方法: +# 1. 设置环境变量: +# export HARBOR_REGISTRY=<你的Harbor仓库地址> +# export HARBOR_USERNAME= +# export HARBOR_PASSWORD= +# export NGINX_IMAGE_TAG=<镜像标签> +# +# 2. 运行部署脚本: +# ./deploy.sh +# +# 或者手动执行: +# 1. kubectl create secret docker-registry harbor-registry-secret \ +# --docker-server=$HARBOR_REGISTRY \ +# --docker-username=$HARBOR_USERNAME \ +# --docker-password=$HARBOR_PASSWORD +# 2. kubectl apply -f nginx-deployment.yaml + +--- +# 1. 私有仓库访问凭据 Secret (通过脚本自动创建) +# 如果需要手动创建,请使用以下命令: +# kubectl create secret docker-registry harbor-registry-secret \ +# --docker-server= \ +# --docker-username= \ +# --docker-password= + +--- +# 1. ConfigMap - NGINX 配置 +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-config + namespace: default +data: + nginx.conf: | + user nginx; + worker_processes auto; + error_log /var/log/nginx/error.log warn; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + } + + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + # 基本安全头 + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Gzip 压缩 + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html index.htm; + + # 健康检查端点 + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + + # 状态监控端点 + location /nginx_status { + stub_status on; + access_log off; + allow 127.0.0.1; + allow 10.0.0.0/8; + allow 172.16.0.0/12; + allow 192.168.0.0/16; + deny all; + } + + location / { + try_files $uri $uri/ =404; + } + + # 错误页面 + error_page 404 /404.html; + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + } + } + +--- +# 3. Deployment - NGINX 应用部署 +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + namespace: default + labels: + app: nginx + version: v1 +spec: + replicas: 3 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + version: v1 + spec: + # 使用私有仓库凭据 + imagePullSecrets: + - name: harbor-registry-secret + + # 安全上下文 + securityContext: + runAsNonRoot: true + runAsUser: 65534 + fsGroup: 65534 + + containers: + - name: nginx + # 使用私有仓库中的镜像(需要根据实际情况修改) + image: ${HARBOR_REGISTRY}/test/nginx:latest + imagePullPolicy: Always + + ports: + - name: http + containerPort: 80 + protocol: TCP + + # 环境变量 + env: + - name: TZ + value: "Asia/Shanghai" + + # 资源限制 + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "128Mi" + cpu: "200m" + + # 健康检查 + livenessProbe: + httpGet: + path: /health + port: 80 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + + readinessProbe: + httpGet: + path: /health + port: 80 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + + # 启动探针 + startupProbe: + httpGet: + path: /health + port: 80 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 5 + + # 挂载配置文件 + volumeMounts: + - name: nginx-config-volume + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + readOnly: true + - name: nginx-cache + mountPath: /var/cache/nginx + - name: nginx-run + mountPath: /var/run + + volumes: + - name: nginx-config-volume + configMap: + name: nginx-config + defaultMode: 0644 + - name: nginx-cache + emptyDir: {} + - name: nginx-run + emptyDir: {} + + # 节点选择器(可选) + nodeSelector: + kubernetes.io/os: linux + + # 容忍度(可选) + tolerations: + - key: "node.kubernetes.io/not-ready" + operator: "Exists" + effect: "NoExecute" + tolerationSeconds: 300 + - key: "node.kubernetes.io/unreachable" + operator: "Exists" + effect: "NoExecute" + tolerationSeconds: 300 + +--- +# 4. Service - 服务暴露 +apiVersion: v1 +kind: Service +metadata: + name: nginx-service + namespace: default + labels: + app: nginx +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: 80 + protocol: TCP + selector: + app: nginx + +--- +# 5. HorizontalPodAutoscaler - 自动扩缩容 +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: nginx-hpa + namespace: default +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: nginx-deployment + minReplicas: 2 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 50 + periodSeconds: 60 + scaleUp: + stabilizationWindowSeconds: 60 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + +--- +# 6. PodDisruptionBudget - Pod 中断预算 +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: nginx-pdb + namespace: default +spec: + minAvailable: 1 + selector: + matchLabels: + app: nginx diff --git a/k8s/quickstart.sh b/k8s/quickstart.sh new file mode 100644 index 0000000..165bf80 --- /dev/null +++ b/k8s/quickstart.sh @@ -0,0 +1,257 @@ +#!/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