Merge branch 'main' of github.com:BrunoGaoSZ/ljwx-health
Merging two diverged development lines: - Local (Gitea): Gitea Actions CI/CD, test suite, tenant optimization - GitHub: Harbor registry, ArgoCD, K8s configurations Resolved conflicts: - .trigger-test: Merged timestamps from both branches 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
client/data/mysql/mysql.sock
|
||||
@@ -0,0 +1,21 @@
|
||||
# 本地 Docker Registry 配置(用于 CI/CD)
|
||||
# 此文件配置使用本地 Registry 进行镜像构建和部署
|
||||
|
||||
# Registry 配置(使用宿主机 IP)
|
||||
REGISTRY=173.212.254.252:5000
|
||||
HARBOR_HOST=173.212.254.252:5000
|
||||
HARBOR_PROJECT=ljwx-health
|
||||
|
||||
# 版本配置
|
||||
LJWX_VERSION=2.0.4
|
||||
|
||||
# 镜像版本(与 LJWX_VERSION 保持一致)
|
||||
LJWX_MYSQL_VERSION=2.0.4
|
||||
LJWX_REDIS_VERSION=2.0.4
|
||||
LJWX_BOOT_VERSION=2.0.4
|
||||
LJWX_BIGSCREEN_VERSION=2.0.4
|
||||
LJWX_ADMIN_VERSION=2.0.4
|
||||
|
||||
# Registry 凭据(用于本地开发)
|
||||
REGISTRY_USERNAME=admin
|
||||
REGISTRY_PASSWORD=admin123
|
||||
@@ -0,0 +1,440 @@
|
||||
# GitHub Actions CI/CD 配置指南
|
||||
|
||||
本文档说明如何配置 GitHub Actions 实现从构建、推送到自动部署 k3s 的完整 CI/CD 流程。
|
||||
|
||||
## 架构概述
|
||||
|
||||
```
|
||||
GitHub Actions Workflow
|
||||
├── 1. Build & Push (ubuntu-latest)
|
||||
│ ├── 构建 Docker 镜像(多架构支持)
|
||||
│ └── 推送到 Harbor 仓库
|
||||
└── 2. Deploy to K3s (self-hosted runner)
|
||||
├── 创建 namespace 和 secrets
|
||||
├── 更新镜像标签
|
||||
├── 部署 ljwx-boot
|
||||
├── 部署 ljwx-bigscreen
|
||||
└── 验证部署状态
|
||||
```
|
||||
|
||||
## 前置条件
|
||||
|
||||
### 1. Harbor 仓库配置
|
||||
|
||||
确保您的 Harbor 仓库已正确配置:
|
||||
|
||||
- **Registry 地址**: `harbor.omniverseai.net`
|
||||
- **项目名称**: `ljwx-health`
|
||||
- **访问凭据**: `admin/admin123`(生产环境请修改)
|
||||
|
||||
### 2. K3s 集群配置
|
||||
|
||||
确保 k3s 集群正常运行,并且 GitHub Actions runner 可以访问:
|
||||
|
||||
```bash
|
||||
# 验证 k3s 状态
|
||||
kubectl cluster-info
|
||||
kubectl get nodes
|
||||
|
||||
# 验证 namespace
|
||||
kubectl get ns ljwx-health
|
||||
# 如果不存在,workflow 会自动创建
|
||||
```
|
||||
|
||||
### 3. GitHub Actions Self-Hosted Runner
|
||||
|
||||
Runner 必须安装在 k3s 集群内部或可以访问 k3s 的环境中。
|
||||
|
||||
**验证 Runner 配置**:
|
||||
|
||||
```bash
|
||||
# 检查 kubectl 配置
|
||||
kubectl version --client
|
||||
kubectl cluster-info
|
||||
|
||||
# 检查 kubeconfig
|
||||
echo $KUBECONFIG
|
||||
# 或者检查默认配置
|
||||
cat ~/.kube/config
|
||||
```
|
||||
|
||||
## GitHub Secrets 配置
|
||||
|
||||
在 GitHub 仓库中配置以下 Secrets(Settings → Secrets and variables → Actions):
|
||||
|
||||
### 必需的 Secrets
|
||||
|
||||
| Secret 名称 | 说明 | 示例值 |
|
||||
|------------|------|--------|
|
||||
| `HARBOR_HOST` | Harbor 仓库地址 | `harbor.omniverseai.net` |
|
||||
| `HARBOR_USERNAME` | Harbor 用户名 | `admin` |
|
||||
| `HARBOR_PASSWORD` | Harbor 密码 | `admin123` |
|
||||
|
||||
### 可选的 Secrets(使用默认值)
|
||||
|
||||
| Secret 名称 | 说明 | 默认值 |
|
||||
|------------|------|--------|
|
||||
| `MYSQL_USERNAME` | MySQL 用户名 | `root` |
|
||||
| `MYSQL_PASSWORD` | MySQL 密码 | `123456` |
|
||||
| `REDIS_PASSWORD` | Redis 密码 | `123456` |
|
||||
| `JWT_SECRET` | JWT 密钥 | `ljwx-default-jwt-secret-change-me` |
|
||||
|
||||
**配置步骤**:
|
||||
|
||||
1. 进入 GitHub 仓库页面
|
||||
2. 点击 `Settings` → `Secrets and variables` → `Actions`
|
||||
3. 点击 `New repository secret`
|
||||
4. 添加上述 Secrets
|
||||
|
||||
## Workflow 配置
|
||||
|
||||
### 触发条件
|
||||
|
||||
Workflow 在以下情况下自动触发:
|
||||
|
||||
1. **推送到 main/develop 分支** - 完整的构建、推送和部署
|
||||
2. **创建版本标签 (v*)** - 构建特定版本
|
||||
3. **Pull Request** - 仅构建和推送,不部署
|
||||
4. **手动触发** - 通过 GitHub UI 手动运行
|
||||
|
||||
### 部署条件
|
||||
|
||||
部署到 k3s 仅在以下情况执行:
|
||||
|
||||
- ✅ 构建和推送成功
|
||||
- ✅ 分支为 `main` 或 `develop`
|
||||
- ✅ Runner 为 `self-hosted`
|
||||
|
||||
### 镜像版本策略
|
||||
|
||||
1. **从 .env 文件读取** - 使用 `LJWX_VERSION` 变量
|
||||
2. **从 Git 标签读取** - 推送 `v*` 标签时使用标签名
|
||||
3. **手动指定** - 通过 workflow_dispatch 输入
|
||||
4. **默认值** - `latest`
|
||||
|
||||
## 部署流程详解
|
||||
|
||||
### 1. 构建和推送镜像
|
||||
|
||||
```yaml
|
||||
# 支持的组件
|
||||
- ljwx-boot # Spring Boot 后端
|
||||
- ljwx-admin # Vue3 前端
|
||||
- ljwx-bigscreen # Flask 数据大屏
|
||||
- ljwx-mysql # MySQL 数据库
|
||||
- ljwx-redis # Redis 缓存
|
||||
```
|
||||
|
||||
**多架构支持**:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
|
||||
### 2. 部署到 K3s
|
||||
|
||||
**部署步骤**:
|
||||
|
||||
1. **创建 namespace**
|
||||
```bash
|
||||
kubectl create namespace ljwx-health
|
||||
```
|
||||
|
||||
2. **创建 Harbor 镜像拉取密钥**
|
||||
```bash
|
||||
kubectl create secret docker-registry harbor-secret \
|
||||
--docker-server=harbor.omniverseai.net \
|
||||
--docker-username=admin \
|
||||
--docker-password=admin123 \
|
||||
--namespace=ljwx-health
|
||||
```
|
||||
|
||||
3. **更新镜像标签**
|
||||
- 自动替换 deployment 文件中的镜像版本
|
||||
- 修正 namespace 为 `ljwx-health`
|
||||
|
||||
4. **部署 ljwx-boot**
|
||||
- 应用 ConfigMap(数据库、Redis 配置)
|
||||
- 创建 Secret(密码、JWT 密钥)
|
||||
- 部署 Service 和 Deployment
|
||||
- 等待 Pod 就绪(最多 5 分钟)
|
||||
|
||||
5. **部署 ljwx-bigscreen**
|
||||
- 应用 ConfigMap
|
||||
- 部署 Service 和 Deployment
|
||||
- 等待 Pod 就绪(最多 5 分钟)
|
||||
|
||||
6. **验证部署**
|
||||
- 检查 Pod 状态
|
||||
- 检查 Service 状态
|
||||
- 输出部署摘要到 GitHub Actions Summary
|
||||
|
||||
## 手动触发部署
|
||||
|
||||
### 通过 GitHub UI
|
||||
|
||||
1. 进入仓库的 `Actions` 标签页
|
||||
2. 选择 `Build and Push Docker Images` workflow
|
||||
3. 点击 `Run workflow`
|
||||
4. 选择参数:
|
||||
- **Branch**: 选择分支(main/develop)
|
||||
- **Component**: 选择要构建的组件(all 或特定组件)
|
||||
- **Version**: 可选,指定版本标签
|
||||
|
||||
### 通过命令行(使用 GitHub CLI)
|
||||
|
||||
```bash
|
||||
# 安装 GitHub CLI
|
||||
brew install gh # macOS
|
||||
# 或访问 https://cli.github.com/
|
||||
|
||||
# 触发 workflow
|
||||
gh workflow run build-and-push.yml \
|
||||
--ref main \
|
||||
-f component=all \
|
||||
-f version=v2.0.4
|
||||
```
|
||||
|
||||
## 验证部署
|
||||
|
||||
### 检查 Workflow 状态
|
||||
|
||||
在 GitHub Actions 页面查看:
|
||||
|
||||
1. ✅ Build and Push - 所有组件构建成功
|
||||
2. ✅ Deploy to K3s - 部署完成
|
||||
3. ✅ Summary - 汇总报告
|
||||
|
||||
### 检查 K3s 部署
|
||||
|
||||
```bash
|
||||
# 查看 namespace
|
||||
kubectl get ns ljwx-health
|
||||
|
||||
# 查看所有资源
|
||||
kubectl get all -n ljwx-health
|
||||
|
||||
# 查看 Pods 状态
|
||||
kubectl get pods -n ljwx-health -o wide
|
||||
|
||||
# 查看 Services
|
||||
kubectl get svc -n ljwx-health
|
||||
|
||||
# 查看 Deployments
|
||||
kubectl get deployments -n ljwx-health
|
||||
|
||||
# 查看最近的事件
|
||||
kubectl get events -n ljwx-health --sort-by='.lastTimestamp' | tail -20
|
||||
|
||||
# 查看 Pod 日志
|
||||
kubectl logs -f deployment/ljwx-boot -n ljwx-health
|
||||
kubectl logs -f deployment/ljwx-bigscreen -n ljwx-health
|
||||
```
|
||||
|
||||
### 检查应用健康状态
|
||||
|
||||
```bash
|
||||
# ljwx-boot 健康检查
|
||||
kubectl exec -n ljwx-health deployment/ljwx-boot -- curl -s http://localhost:9998/actuator/health
|
||||
|
||||
# ljwx-bigscreen 健康检查
|
||||
kubectl exec -n ljwx-health deployment/ljwx-bigscreen -- curl -s http://localhost:5001/api/health
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. 构建失败
|
||||
|
||||
**常见原因**:
|
||||
- Harbor 凭据错误
|
||||
- Dockerfile 路径错误
|
||||
- 构建上下文问题
|
||||
|
||||
**解决方法**:
|
||||
```bash
|
||||
# 检查 Secrets 配置
|
||||
# 查看 workflow 日志中的详细错误信息
|
||||
# 本地测试构建
|
||||
docker build -f ljwx-boot/ljwx-boot-admin/Dockerfile.prod .
|
||||
```
|
||||
|
||||
### 2. 推送到 Harbor 失败
|
||||
|
||||
**常见原因**:
|
||||
- Harbor 凭据错误
|
||||
- 网络连接问题
|
||||
- Harbor 项目不存在
|
||||
|
||||
**解决方法**:
|
||||
```bash
|
||||
# 测试 Harbor 登录
|
||||
docker login harbor.omniverseai.net -u admin -p admin123
|
||||
|
||||
# 检查项目是否存在
|
||||
# 访问 https://harbor.omniverseai.net/harbor/projects
|
||||
```
|
||||
|
||||
### 3. 部署到 K3s 失败
|
||||
|
||||
**常见原因**:
|
||||
- kubectl 未配置或无权限
|
||||
- namespace 不存在
|
||||
- Secret 配置错误
|
||||
- 镜像拉取失败
|
||||
|
||||
**解决方法**:
|
||||
```bash
|
||||
# 检查 kubectl 配置
|
||||
kubectl config current-context
|
||||
kubectl auth can-i create deployments -n ljwx-health
|
||||
|
||||
# 检查 Harbor Secret
|
||||
kubectl get secret harbor-secret -n ljwx-health -o yaml
|
||||
|
||||
# 检查镜像是否可以拉取
|
||||
kubectl run test-pod --image=harbor.omniverseai.net/ljwx-health/ljwx-boot:latest \
|
||||
--image-pull-policy=Always \
|
||||
--dry-run=client -n ljwx-health
|
||||
|
||||
# 查看 Pod 拉取镜像失败的详细信息
|
||||
kubectl describe pod <pod-name> -n ljwx-health
|
||||
```
|
||||
|
||||
### 4. Pod 启动失败
|
||||
|
||||
**常见原因**:
|
||||
- ConfigMap/Secret 配置错误
|
||||
- 数据库连接失败
|
||||
- 资源不足
|
||||
|
||||
**解决方法**:
|
||||
```bash
|
||||
# 查看 Pod 详细信息
|
||||
kubectl describe pod <pod-name> -n ljwx-health
|
||||
|
||||
# 查看 Pod 日志
|
||||
kubectl logs <pod-name> -n ljwx-health --tail=100
|
||||
|
||||
# 查看所有容器日志(包括 init 容器)
|
||||
kubectl logs <pod-name> -n ljwx-health --all-containers=true
|
||||
|
||||
# 检查节点资源
|
||||
kubectl top nodes
|
||||
kubectl describe node <node-name>
|
||||
```
|
||||
|
||||
### 5. 数据库连接失败
|
||||
|
||||
**检查配置**:
|
||||
```bash
|
||||
# 查看 ConfigMap
|
||||
kubectl get configmap ljwx-boot-config -n ljwx-health -o yaml
|
||||
|
||||
# 查看 Secret(base64 解码)
|
||||
kubectl get secret ljwx-boot-secret -n ljwx-health -o jsonpath='{.data.database\.password}' | base64 -d
|
||||
|
||||
# 测试数据库连接
|
||||
kubectl run mysql-test --image=mysql:8.0 --rm -it --restart=Never -n ljwx-health -- \
|
||||
mysql -h mysql-service.ljwx-health.svc.cluster.local -u root -p123456 -e "SELECT 1"
|
||||
```
|
||||
|
||||
## 回滚部署
|
||||
|
||||
如果部署出现问题,可以快速回滚:
|
||||
|
||||
```bash
|
||||
# 查看部署历史
|
||||
kubectl rollout history deployment/ljwx-boot -n ljwx-health
|
||||
|
||||
# 回滚到上一个版本
|
||||
kubectl rollout undo deployment/ljwx-boot -n ljwx-health
|
||||
|
||||
# 回滚到特定版本
|
||||
kubectl rollout undo deployment/ljwx-boot -n ljwx-health --to-revision=2
|
||||
|
||||
# 查看回滚状态
|
||||
kubectl rollout status deployment/ljwx-boot -n ljwx-health
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 加速镜像拉取
|
||||
|
||||
```bash
|
||||
# 在 k3s 节点上预拉取镜像
|
||||
docker pull harbor.omniverseai.net/ljwx-health/ljwx-boot:latest
|
||||
docker pull harbor.omniverseai.net/ljwx-health/ljwx-bigscreen:latest
|
||||
```
|
||||
|
||||
### 2. 优化 Workflow 缓存
|
||||
|
||||
Workflow 已配置 GitHub Actions 缓存:
|
||||
|
||||
```yaml
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
```
|
||||
|
||||
### 3. 并行构建
|
||||
|
||||
可以同时构建多个组件,利用 matrix 策略加速构建。
|
||||
|
||||
## 安全建议
|
||||
|
||||
### 1. 生产环境配置
|
||||
|
||||
- ❌ 不要使用默认密码
|
||||
- ✅ 为 MySQL、Redis 设置强密码
|
||||
- ✅ 定期轮换 JWT 密钥
|
||||
- ✅ 限制 Harbor 用户权限(使用专用的 CI/CD 账户)
|
||||
|
||||
### 2. Secret 管理
|
||||
|
||||
- ✅ 使用 GitHub Secrets 存储敏感信息
|
||||
- ✅ 不要在代码中硬编码密码
|
||||
- ✅ 定期审计 Secrets 访问日志
|
||||
|
||||
### 3. 镜像安全
|
||||
|
||||
- ✅ 启用 Harbor 镜像扫描
|
||||
- ✅ 使用非 root 用户运行容器
|
||||
- ✅ 定期更新基础镜像
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 查看实时日志
|
||||
|
||||
```bash
|
||||
# 实时查看 ljwx-boot 日志
|
||||
kubectl logs -f deployment/ljwx-boot -n ljwx-health
|
||||
|
||||
# 查看最近 100 行日志
|
||||
kubectl logs deployment/ljwx-boot -n ljwx-health --tail=100
|
||||
|
||||
# 查看前一个容器的日志(崩溃后)
|
||||
kubectl logs <pod-name> -n ljwx-health --previous
|
||||
```
|
||||
|
||||
### 查看 Metrics
|
||||
|
||||
```bash
|
||||
# 查看 Pod 资源使用
|
||||
kubectl top pods -n ljwx-health
|
||||
|
||||
# 查看节点资源使用
|
||||
kubectl top nodes
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [K8s 部署指南](../ljwx-boot/k8s/README.md)
|
||||
- [Docker 构建指南](../DOCKER_README.md)
|
||||
- [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- [K3s 官方文档](https://docs.k3s.io/)
|
||||
|
||||
## 联系支持
|
||||
|
||||
如遇到问题,请:
|
||||
|
||||
1. 查看 GitHub Actions 日志
|
||||
2. 查看 K8s Events 和 Pod 日志
|
||||
3. 参考本文档的故障排查章节
|
||||
4. 提交 Issue 到项目仓库
|
||||
@@ -0,0 +1,302 @@
|
||||
# 本地 Docker Registry + GitHub Actions Self-Hosted Runner 完整配置指南
|
||||
|
||||
本文档记录了如何配置本地 Docker Registry 并与 K3s 中的 GitHub Actions Self-Hosted Runner 集成。
|
||||
|
||||
## 架构概览
|
||||
|
||||
```
|
||||
GitHub Push → Self-Hosted Runner (K3s Pod)
|
||||
↓
|
||||
Docker Build (DinD)
|
||||
↓
|
||||
Push to 173.212.254.252:5000
|
||||
↓
|
||||
Deploy to K3s (ljwx-health namespace)
|
||||
```
|
||||
|
||||
## 关键组件
|
||||
|
||||
### 1. 本地 Docker Registry
|
||||
|
||||
**部署位置**: 宿主机
|
||||
**地址**: `173.212.254.252:5000`
|
||||
**Web UI**: `http://localhost:8888`
|
||||
**凭据**: `admin/admin123`
|
||||
|
||||
**配置文件**:
|
||||
- `harbor/docker-compose.yml` - Registry 服务定义
|
||||
- `harbor/setup.sh` - 部署脚本
|
||||
|
||||
**启动**:
|
||||
```bash
|
||||
cd /root/codes/ljwx-health/harbor
|
||||
./setup.sh
|
||||
```
|
||||
|
||||
**验证**:
|
||||
```bash
|
||||
curl -u admin:admin123 http://localhost:5000/v2/_catalog
|
||||
docker login 173.212.254.252:5000 -u admin -p admin123
|
||||
```
|
||||
|
||||
### 2. GitHub Actions Runner (K3s)
|
||||
|
||||
**Namespace**: `github-runner`
|
||||
**类型**: RunnerDeployment (summerwind/actions-runner-controller)
|
||||
**组织**: `BrunoGaoSZ`
|
||||
**副本数**: 1
|
||||
|
||||
**关键配置**:
|
||||
- **Docker-in-Docker (DinD)**: 每个 runner pod 包含两个容器 (`runner` + `docker`)
|
||||
- **Docker Daemon 配置**: 通过 ConfigMap 持久化
|
||||
- **资源限制**: 2 CPU, 4Gi Memory
|
||||
|
||||
### 3. 配置持久化
|
||||
|
||||
#### ConfigMap: docker-daemon-config
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: docker-daemon-config
|
||||
namespace: github-runner
|
||||
data:
|
||||
daemon.json: |
|
||||
{
|
||||
"insecure-registries": ["173.212.254.252:5000", "localhost:5000"]
|
||||
}
|
||||
```
|
||||
|
||||
**作用**:
|
||||
- 允许 Runner 的 DinD 容器访问 HTTP Registry(无 TLS)
|
||||
- 配置会自动挂载到每个新 runner pod
|
||||
- Pod 重建后配置依然生效
|
||||
|
||||
#### RunnerDeployment 配置
|
||||
|
||||
```yaml
|
||||
apiVersion: actions.summerwind.dev/v1alpha1
|
||||
kind: RunnerDeployment
|
||||
metadata:
|
||||
name: brunogao-runner
|
||||
namespace: github-runner
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
dockerEnabled: true
|
||||
organization: BrunoGaoSZ
|
||||
labels: ["k3s", "self-hosted", "linux", "x64"]
|
||||
|
||||
# 挂载 Docker daemon 配置到 DinD 容器
|
||||
dockerVolumeMounts:
|
||||
- mountPath: /etc/docker/daemon.json
|
||||
name: docker-daemon-config
|
||||
subPath: daemon.json
|
||||
|
||||
volumes:
|
||||
- name: docker-daemon-config
|
||||
configMap:
|
||||
name: docker-daemon-config
|
||||
```
|
||||
|
||||
## 配置步骤总结
|
||||
|
||||
### 步骤 1: 部署本地 Registry
|
||||
|
||||
```bash
|
||||
cd /root/codes/ljwx-health/harbor
|
||||
./setup.sh
|
||||
```
|
||||
|
||||
### 步骤 2: 配置宿主机 Docker
|
||||
|
||||
```bash
|
||||
# 允许不安全的 Registry
|
||||
cat > /etc/docker/daemon.json <<EOF
|
||||
{
|
||||
"insecure-registries": ["173.212.254.252:5000", "localhost:5000"]
|
||||
}
|
||||
EOF
|
||||
|
||||
systemctl restart docker
|
||||
```
|
||||
|
||||
### 步骤 3: 配置 K3s
|
||||
|
||||
```bash
|
||||
# 配置 K3s Registry
|
||||
mkdir -p /etc/rancher/k3s
|
||||
cat > /etc/rancher/k3s/registries.yaml <<EOF
|
||||
mirrors:
|
||||
"173.212.254.252:5000":
|
||||
endpoint:
|
||||
- "http://173.212.254.252:5000"
|
||||
|
||||
configs:
|
||||
"173.212.254.252:5000":
|
||||
auth:
|
||||
username: admin
|
||||
password: admin123
|
||||
tls:
|
||||
insecure_skip_verify: true
|
||||
EOF
|
||||
|
||||
systemctl restart k3s
|
||||
```
|
||||
|
||||
### 步骤 4: 创建 Docker Daemon ConfigMap
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: docker-daemon-config
|
||||
namespace: github-runner
|
||||
data:
|
||||
daemon.json: |
|
||||
{
|
||||
"insecure-registries": ["173.212.254.252:5000", "localhost:5000"]
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
### 步骤 5: 更新 RunnerDeployment
|
||||
|
||||
```bash
|
||||
kubectl apply -f /tmp/runner-deployment-updated.yaml
|
||||
```
|
||||
|
||||
### 步骤 6: 验证配置
|
||||
|
||||
```bash
|
||||
# 等待新 runner pod 启动
|
||||
kubectl get pods -n github-runner -w
|
||||
|
||||
# 验证 Docker daemon 配置
|
||||
NEW_POD=$(kubectl get pods -n github-runner -o name | grep runner | tail -1 | sed 's|pod/||')
|
||||
kubectl exec -n github-runner $NEW_POD -c docker -- cat /etc/docker/daemon.json
|
||||
|
||||
# 测试登录
|
||||
kubectl exec -n github-runner $NEW_POD -c runner -- \
|
||||
sh -c 'echo "admin123" | docker login 173.212.254.252:5000 -u admin --password-stdin'
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题 1: Pod 无法访问 localhost:5000
|
||||
|
||||
**原因**: 在 Pod 内部,localhost 指向 Pod 自己,而不是宿主机。
|
||||
|
||||
**解决**: 使用宿主机 IP 地址 `173.212.254.252:5000`
|
||||
|
||||
### 问题 2: HTTPS 错误
|
||||
|
||||
```
|
||||
Error: http: server gave HTTP response to HTTPS client
|
||||
```
|
||||
|
||||
**原因**: Docker 默认尝试使用 HTTPS 连接 Registry。
|
||||
|
||||
**解决**: 配置 `insecure-registries` 允许 HTTP。
|
||||
|
||||
### 问题 3: Runner Pod 重建后配置丢失
|
||||
|
||||
**原因**: DinD 容器的配置未持久化。
|
||||
|
||||
**解决**:
|
||||
1. 创建 ConfigMap 包含 daemon.json
|
||||
2. 在 RunnerDeployment 中使用 `dockerVolumeMounts` 挂载配置
|
||||
3. 每次 pod 重建时自动应用配置
|
||||
|
||||
### 问题 4: 认证失败
|
||||
|
||||
```
|
||||
Error: unauthorized: authentication required
|
||||
```
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 在 K3s 中创建镜像拉取密钥
|
||||
kubectl create secret docker-registry harbor-secret \
|
||||
--docker-server=173.212.254.252:5000 \
|
||||
--docker-username=admin \
|
||||
--docker-password=admin123 \
|
||||
--namespace=ljwx-health
|
||||
```
|
||||
|
||||
## 监控和维护
|
||||
|
||||
### 查看 Registry 镜像
|
||||
|
||||
```bash
|
||||
# 命令行
|
||||
curl -u admin:admin123 http://173.212.254.252:5000/v2/_catalog
|
||||
|
||||
# Web UI
|
||||
open http://localhost:8888
|
||||
|
||||
# 使用脚本
|
||||
./check-registry.sh
|
||||
```
|
||||
|
||||
### 查看 Runner 状态
|
||||
|
||||
```bash
|
||||
# Runner Deployment
|
||||
kubectl get runnerdeployment -n github-runner
|
||||
|
||||
# Runner Pods
|
||||
kubectl get pods -n github-runner
|
||||
|
||||
# Runner 日志
|
||||
kubectl logs -n github-runner -l app.kubernetes.io/component=runner -c runner --tail=50 -f
|
||||
```
|
||||
|
||||
### 实时监控 CI/CD
|
||||
|
||||
```bash
|
||||
./watch-cicd.sh
|
||||
```
|
||||
|
||||
## 文件清单
|
||||
|
||||
| 文件路径 | 说明 |
|
||||
|---------|------|
|
||||
| `harbor/docker-compose.yml` | Registry 服务定义 |
|
||||
| `harbor/setup.sh` | Registry 部署脚本 |
|
||||
| `.env.local-registry` | Registry 配置变量 |
|
||||
| `.github/workflows/build-and-push.yml` | CI/CD workflow |
|
||||
| `/etc/docker/daemon.json` | 宿主机 Docker 配置 |
|
||||
| `/etc/rancher/k3s/registries.yaml` | K3s Registry 配置 |
|
||||
| `docker-daemon-config` ConfigMap | Runner DinD 配置 |
|
||||
| `brunogao-runner` RunnerDeployment | Runner 部署配置 |
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
### 生产环境建议
|
||||
|
||||
1. **使用 TLS**: 配置 HTTPS Registry
|
||||
2. **强密码**: 更改默认的 admin/admin123
|
||||
3. **网络隔离**: 限制 Registry 访问范围
|
||||
4. **定期备份**: Registry 数据目录 `harbor/data/registry`
|
||||
|
||||
### 当前配置(开发环境)
|
||||
|
||||
- ⚠️ HTTP Registry(无加密)
|
||||
- ⚠️ 默认密码
|
||||
- ✅ 基本认证
|
||||
- ✅ 配置持久化
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Docker Registry Documentation](https://docs.docker.com/registry/)
|
||||
- [Actions Runner Controller](https://github.com/actions/actions-runner-controller)
|
||||
- [K3s Private Registry Configuration](https://docs.k3s.io/installation/private-registry)
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-12-16
|
||||
**维护者**: Claude Code with BrunoGaoSZ
|
||||
@@ -0,0 +1,75 @@
|
||||
apiVersion: actions.summerwind.dev/v1alpha1
|
||||
kind: RunnerDeployment
|
||||
metadata:
|
||||
name: brunogao-runner
|
||||
namespace: github-runner
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
serviceAccountName: github-runner-sa
|
||||
dockerEnabled: true
|
||||
|
||||
# 初始化容器:安装 kubectl
|
||||
initContainers:
|
||||
- name: install-kubectl
|
||||
image: alpine:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
apk add --no-cache curl
|
||||
cd /custom-bin
|
||||
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
||||
chmod +x kubectl
|
||||
echo "kubectl installed successfully"
|
||||
ls -lh /custom-bin/kubectl
|
||||
volumeMounts:
|
||||
- name: custom-bin
|
||||
mountPath: /custom-bin
|
||||
|
||||
# Runner 容器的环境变量
|
||||
env:
|
||||
- name: DISABLE_RUNNER_UPDATE
|
||||
value: "true"
|
||||
- name: PATH
|
||||
value: "/custom-bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
labels:
|
||||
- k3s
|
||||
- self-hosted
|
||||
- linux
|
||||
- x64
|
||||
|
||||
organization: BrunoGaoSZ
|
||||
|
||||
resources:
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 2Gi
|
||||
|
||||
# Docker daemon 配置挂载
|
||||
dockerVolumeMounts:
|
||||
- mountPath: /etc/docker/daemon.json
|
||||
name: docker-daemon-config
|
||||
subPath: daemon.json
|
||||
|
||||
# Runner 容器的挂载
|
||||
volumeMounts:
|
||||
- mountPath: /runner/_work
|
||||
name: work
|
||||
- mountPath: /custom-bin
|
||||
name: custom-bin
|
||||
|
||||
# 卷定义
|
||||
volumes:
|
||||
- name: work
|
||||
emptyDir: {}
|
||||
- name: docker-daemon-config
|
||||
configMap:
|
||||
name: docker-daemon-config
|
||||
- name: custom-bin
|
||||
emptyDir: {}
|
||||
@@ -0,0 +1,51 @@
|
||||
# ServiceAccount for runner
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: github-runner-sa
|
||||
namespace: github-runner
|
||||
---
|
||||
# ClusterRole with necessary permissions
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: github-runner-role
|
||||
rules:
|
||||
# Deployment permissions
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["deployments", "replicasets"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
# Pod permissions
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
# Service permissions
|
||||
- apiGroups: [""]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
# ConfigMap and Secret permissions
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps", "secrets"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
# Namespace permissions - 添加 update 和 patch
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces"]
|
||||
verbs: ["get", "list", "create", "update", "patch"]
|
||||
# Rollout status
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["deployments/status"]
|
||||
verbs: ["get", "watch"]
|
||||
---
|
||||
# ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: github-runner-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: github-runner-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: github-runner-sa
|
||||
namespace: github-runner
|
||||
@@ -40,13 +40,19 @@ jobs:
|
||||
- name: Load .env configuration
|
||||
id: config
|
||||
run: |
|
||||
if [ -f .env ]; then
|
||||
source .env
|
||||
# 优先使用本地 Registry 配置
|
||||
if [ -f .env.local-registry ]; then
|
||||
source .env.local-registry
|
||||
echo "registry=${REGISTRY}" >> $GITHUB_OUTPUT
|
||||
echo "harbor_host=${HARBOR_HOST}" >> $GITHUB_OUTPUT
|
||||
echo "harbor_project=${HARBOR_PROJECT}" >> $GITHUB_OUTPUT
|
||||
elif [ -f .env ]; then
|
||||
source .env
|
||||
echo "registry=${REGISTRY:-173.212.254.252:5000}" >> $GITHUB_OUTPUT
|
||||
echo "harbor_host=${HARBOR_HOST:-173.212.254.252:5000}" >> $GITHUB_OUTPUT
|
||||
echo "harbor_project=${HARBOR_PROJECT:-ljwx-health}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "registry=harbor.omniverseai.net/health" >> $GITHUB_OUTPUT
|
||||
echo "registry=173.212.254.252:5000" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Determine version
|
||||
@@ -80,7 +86,7 @@ jobs:
|
||||
build-and-push:
|
||||
name: Build and Push ${{ matrix.component }}
|
||||
needs: prepare
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, Linux, X64, k3s]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -89,20 +95,79 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2 # 获取最近两次提交以检测变化
|
||||
|
||||
- name: Detect changes for ${{ matrix.component }}
|
||||
id: changes
|
||||
run: |
|
||||
COMPONENT="${{ matrix.component }}"
|
||||
|
||||
# 手动触发或标签推送时,强制构建所有组件
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
echo "should_build=true" >> $GITHUB_OUTPUT
|
||||
echo "reason=Manual trigger or tag push" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 定义每个组件相关的文件路径
|
||||
case "$COMPONENT" in
|
||||
ljwx-boot)
|
||||
PATHS="ljwx-boot/ docker/mysql/Dockerfile docker/redis/Dockerfile"
|
||||
;;
|
||||
ljwx-admin)
|
||||
PATHS="ljwx-admin/"
|
||||
;;
|
||||
ljwx-bigscreen)
|
||||
PATHS="ljwx-bigscreen/"
|
||||
;;
|
||||
ljwx-mysql)
|
||||
PATHS="docker/mysql/"
|
||||
;;
|
||||
ljwx-redis)
|
||||
PATHS="docker/redis/"
|
||||
;;
|
||||
*)
|
||||
PATHS="."
|
||||
;;
|
||||
esac
|
||||
|
||||
# 检测文件变化
|
||||
CHANGED=false
|
||||
for path in $PATHS; do
|
||||
if git diff --name-only HEAD~1 HEAD | grep -q "^$path"; then
|
||||
CHANGED=true
|
||||
echo "✅ Detected changes in: $path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$CHANGED" = "true" ]; then
|
||||
echo "should_build=true" >> $GITHUB_OUTPUT
|
||||
echo "reason=Code changes detected" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_build=false" >> $GITHUB_OUTPUT
|
||||
echo "reason=No code changes" >> $GITHUB_OUTPUT
|
||||
echo "⏭️ No changes detected for $COMPONENT, skipping build"
|
||||
fi
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: steps.changes.outputs.should_build == 'true'
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64
|
||||
config-inline: |
|
||||
[registry."173.212.254.252:5000"]
|
||||
http = true
|
||||
insecure = true
|
||||
|
||||
- name: Log in to Harbor
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ secrets.HARBOR_HOST || 'harbor.omniverseai.net' }}
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||||
- name: Log in to Local Registry
|
||||
if: steps.changes.outputs.should_build == 'true'
|
||||
run: |
|
||||
echo "admin123" | docker login 173.212.254.252:5000 -u admin --password-stdin
|
||||
|
||||
- name: Prepare build context
|
||||
if: steps.changes.outputs.should_build == 'true'
|
||||
id: context
|
||||
run: |
|
||||
COMPONENT="${{ matrix.component }}"
|
||||
@@ -127,7 +192,7 @@ jobs:
|
||||
CONTEXT="ljwx-bigscreen/bigscreen"
|
||||
;;
|
||||
ljwx-admin)
|
||||
DOCKERFILE="ljwx-admin/Dockerfile"
|
||||
DOCKERFILE="ljwx-admin/Dockerfile.prod"
|
||||
CONTEXT="ljwx-admin"
|
||||
;;
|
||||
*)
|
||||
@@ -138,10 +203,11 @@ jobs:
|
||||
|
||||
echo "dockerfile=${DOCKERFILE}" >> $GITHUB_OUTPUT
|
||||
echo "context=${CONTEXT}" >> $GITHUB_OUTPUT
|
||||
echo "image_name=${REGISTRY}/${COMPONENT}" >> $GITHUB_OUTPUT
|
||||
echo "image_name=${REGISTRY}/ljwx-health/${COMPONENT}" >> $GITHUB_OUTPUT
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Extract metadata
|
||||
if: steps.changes.outputs.should_build == 'true'
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
@@ -152,11 +218,12 @@ jobs:
|
||||
type=sha,prefix={{branch}}-
|
||||
|
||||
- name: Build and push Docker image
|
||||
if: steps.changes.outputs.should_build == 'true'
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ${{ steps.context.outputs.context }}
|
||||
file: ${{ steps.context.outputs.dockerfile }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
@@ -166,13 +233,139 @@ jobs:
|
||||
VERSION=${{ steps.context.outputs.version }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
network: host
|
||||
|
||||
- name: Image digest
|
||||
run: echo "Image pushed successfully"
|
||||
- name: Build summary
|
||||
run: |
|
||||
if [ "${{ steps.changes.outputs.should_build }}" = "true" ]; then
|
||||
echo "✅ ${{ matrix.component }} - Built and pushed successfully"
|
||||
echo "📦 Reason: ${{ steps.changes.outputs.reason }}"
|
||||
else
|
||||
echo "⏭️ ${{ matrix.component }} - Skipped (no changes)"
|
||||
echo "📦 Reason: ${{ steps.changes.outputs.reason }}"
|
||||
fi
|
||||
|
||||
deploy-to-k3s:
|
||||
name: Deploy to K3s
|
||||
needs: [prepare, build-and-push]
|
||||
runs-on: self-hosted
|
||||
# 暂时禁用自动部署 - 等本地测试完成后再启用
|
||||
if: false
|
||||
# if: success() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
|
||||
env:
|
||||
PATH: /custom-bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up kubectl context
|
||||
run: |
|
||||
# Verify kubectl is available
|
||||
kubectl version --client
|
||||
|
||||
# Verify cluster connection
|
||||
kubectl cluster-info
|
||||
|
||||
- name: Create namespace if not exists
|
||||
run: |
|
||||
kubectl create namespace ljwx-health --dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
- name: Create Local Registry image pull secret
|
||||
run: |
|
||||
kubectl create secret docker-registry harbor-secret \
|
||||
--docker-server=173.212.254.252:5000 \
|
||||
--docker-username=admin \
|
||||
--docker-password=admin123 \
|
||||
--namespace=ljwx-health \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
- name: Update image tags in deployments
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
REGISTRY: ${{ needs.prepare.outputs.registry }}
|
||||
run: |
|
||||
# Update ljwx-boot deployment image tag
|
||||
if [ -f ljwx-boot/k8s/deployment.yml ]; then
|
||||
sed -i "s|image:.*ljwx-boot:.*|image: ${REGISTRY}/ljwx-boot:${VERSION}|g" ljwx-boot/k8s/deployment.yml
|
||||
fi
|
||||
|
||||
# Update ljwx-bigscreen deployment image tag
|
||||
if [ -f ljwx-bigscreen/k8s/prod/deployment.yaml ]; then
|
||||
# Fix namespace to ljwx-health
|
||||
sed -i 's|namespace: ljwx-system|namespace: ljwx-health|g' ljwx-bigscreen/k8s/prod/deployment.yaml
|
||||
# Update image reference
|
||||
sed -i "s|\${REGISTRY}/\${IMAGE_NAME}:\${IMAGE_TAG}|${REGISTRY}/ljwx-bigscreen:${VERSION}|g" ljwx-bigscreen/k8s/prod/deployment.yaml
|
||||
fi
|
||||
|
||||
- name: Deploy ljwx-boot
|
||||
env:
|
||||
DB_USERNAME: ${{ secrets.MYSQL_USERNAME || 'root' }}
|
||||
DB_PASSWORD: ${{ secrets.MYSQL_PASSWORD || '123456' }}
|
||||
REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD || '123456' }}
|
||||
JWT_SECRET: ${{ secrets.JWT_SECRET || 'ljwx-default-jwt-secret-change-me' }}
|
||||
run: |
|
||||
# Apply ConfigMap first
|
||||
kubectl apply -f ljwx-boot/k8s/configmap.yml -n ljwx-health || true
|
||||
|
||||
# Create secret from template
|
||||
if [ -f ljwx-boot/k8s/secret.yml.template ]; then
|
||||
sed "s|<BASE64_ENCODED_DB_USERNAME>|$(echo -n "${DB_USERNAME}" | base64)|g" ljwx-boot/k8s/secret.yml.template | \
|
||||
sed "s|<BASE64_ENCODED_DB_PASSWORD>|$(echo -n "${DB_PASSWORD}" | base64)|g" | \
|
||||
sed "s|<BASE64_ENCODED_REDIS_PASSWORD>|$(echo -n "${REDIS_PASSWORD}" | base64)|g" | \
|
||||
sed "s|<BASE64_ENCODED_JWT_SECRET>|$(echo -n "${JWT_SECRET}" | base64)|g" | \
|
||||
kubectl apply -f - -n ljwx-health
|
||||
fi
|
||||
|
||||
# Apply Service
|
||||
kubectl apply -f ljwx-boot/k8s/service.yml -n ljwx-health || true
|
||||
|
||||
# Apply Deployment
|
||||
kubectl apply -f ljwx-boot/k8s/deployment.yml -n ljwx-health
|
||||
|
||||
# Wait for rollout
|
||||
kubectl rollout status deployment/ljwx-boot -n ljwx-health --timeout=5m
|
||||
|
||||
- name: Deploy ljwx-bigscreen
|
||||
run: |
|
||||
# Apply ConfigMap
|
||||
kubectl apply -f ljwx-bigscreen/k8s/base/configmap.yaml -n ljwx-health || true
|
||||
|
||||
# Apply Service
|
||||
kubectl apply -f ljwx-bigscreen/k8s/prod/service.yaml -n ljwx-health || true
|
||||
|
||||
# Apply Deployment
|
||||
kubectl apply -f ljwx-bigscreen/k8s/prod/deployment.yaml -n ljwx-health
|
||||
|
||||
# Wait for rollout
|
||||
kubectl rollout status deployment/ljwx-bigscreen -n ljwx-health --timeout=5m
|
||||
|
||||
- name: Verify deployment
|
||||
run: |
|
||||
echo "## Deployment Status" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# Get pod status
|
||||
kubectl get pods -n ljwx-health -o wide >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# Get service status
|
||||
echo "### Services" >> $GITHUB_STEP_SUMMARY
|
||||
kubectl get svc -n ljwx-health >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# Check deployment health
|
||||
BOOT_READY=$(kubectl get deployment ljwx-boot -n ljwx-health -o jsonpath='{.status.readyReplicas}')
|
||||
BOOT_DESIRED=$(kubectl get deployment ljwx-boot -n ljwx-health -o jsonpath='{.status.replicas}')
|
||||
|
||||
if [ "$BOOT_READY" == "$BOOT_DESIRED" ]; then
|
||||
echo "✅ ljwx-boot: $BOOT_READY/$BOOT_DESIRED replicas ready" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "⚠️ ljwx-boot: $BOOT_READY/$BOOT_DESIRED replicas ready" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
summary:
|
||||
name: Build Summary
|
||||
needs: [prepare, build-and-push]
|
||||
needs: [prepare, build-and-push, deploy-to-k3s]
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
steps:
|
||||
@@ -190,3 +383,11 @@ jobs:
|
||||
else
|
||||
echo "❌ Some builds failed. Check the logs above." >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [ "${{ needs.deploy-to-k3s.result }}" == "success" ]; then
|
||||
echo "✅ Deployment to K3s successful!" >> $GITHUB_STEP_SUMMARY
|
||||
elif [ "${{ needs.deploy-to-k3s.result }}" == "skipped" ]; then
|
||||
echo "⏭️ Deployment skipped (not main/develop branch)" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "❌ Deployment to K3s failed. Check the logs above." >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
name: Build -> Push Harbor -> Update Deploy Repo
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ljwx-health-dev
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build_push_and_bump_deploy:
|
||||
runs-on: [self-hosted, linux, x64]
|
||||
|
||||
env:
|
||||
IMAGE: harbor.eu.lingjingwanxiang.cn:8080/ljwx/ljwx-health
|
||||
DEPLOY_REPO: BrunoGaoSZ/ljwx-deploy
|
||||
DEPLOY_BRANCH: main
|
||||
DEPLOY_FILE: apps/nginx/overlays/dev/kustomization.yaml
|
||||
|
||||
steps:
|
||||
- name: Checkout app repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Compute tag (dev-${sha7})
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SHA7="${GITHUB_SHA:0:7}"
|
||||
echo "tag=dev-${SHA7}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Docker login to Harbor
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "${{ secrets.HARBOR_PASSWORD }}" | docker login harbor.eu.lingjingwanxiang.cn:8080 \
|
||||
-u "${{ secrets.HARBOR_USERNAME }}" --password-stdin
|
||||
|
||||
- name: Build & push image
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker build -t "${IMAGE}:${{ steps.meta.outputs.tag }}" .
|
||||
docker push "${IMAGE}:${{ steps.meta.outputs.tag }}"
|
||||
|
||||
- name: Checkout deploy repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: BrunoGaoSZ/ljwx-deploy
|
||||
token: ${{ secrets.DEPLOY_REPO_TOKEN }}
|
||||
path: deploy
|
||||
ref: main
|
||||
|
||||
- name: Update newTag and push
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd deploy
|
||||
|
||||
perl -0777 -i -pe "s/(\\bnewTag:\\s*).*/\$1${{ steps.meta.outputs.tag }}/m" \
|
||||
apps/nginx/overlays/dev/kustomization.yaml
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
git add apps/nginx/overlays/dev/kustomization.yaml
|
||||
git commit -m "deploy(dev): bump ljwx-health to ${{ steps.meta.outputs.tag }}" || exit 0
|
||||
git push origin main
|
||||
+2
-1
@@ -199,4 +199,5 @@ performance-test/results/*.jtl
|
||||
# ================================
|
||||
# 网络和其他文件
|
||||
# ================================
|
||||
.nfs*
|
||||
.nfs*
|
||||
harbor/data/
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Tue Dec 16 15:31:18 CET 2025
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
This file is created to trigger the ci-cd.yml workflow after fixing the YAML 'on:' keyword issue.
|
||||
|
||||
Tue Dec 16 08:13:12 CET 2025
|
||||
Tue Dec 16 12:36:42 CST 2025
|
||||
Tue Dec 16 12:41:44 CST 2025
|
||||
Tue Dec 16 13:10:39 CST 2025
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels: { app: nginx }
|
||||
template:
|
||||
metadata:
|
||||
labels: { app: nginx }
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.27
|
||||
ports:
|
||||
- containerPort: 80
|
||||
@@ -0,0 +1,3 @@
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
@@ -0,0 +1,5 @@
|
||||
resources:
|
||||
- ../../base
|
||||
images:
|
||||
- name: nginx
|
||||
newTag: "1.27"
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cluster-bootstrap
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/BrunoGaoSZ/ljwx-health.git
|
||||
targetRevision: main
|
||||
path: cluster
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: argocd
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: nginx-dev
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/BrunoGaoSZ/ljwx-health.git
|
||||
targetRevision: main
|
||||
path: apps/nginx/overlays/dev
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: dev
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "========================================="
|
||||
echo "📦 本地 Registry 镜像检查"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
echo "🔍 Registry 容器状态:"
|
||||
docker ps | grep -E "NAME|registry" | grep -v grep
|
||||
echo ""
|
||||
|
||||
echo "📋 Registry 中的所有仓库:"
|
||||
curl -s -u admin:admin123 http://localhost:5000/v2/_catalog | jq '.'
|
||||
echo ""
|
||||
|
||||
echo "🏷️ ljwx-health 项目的镜像:"
|
||||
REPOS=$(curl -s -u admin:admin123 http://localhost:5000/v2/_catalog | jq -r '.repositories[]' 2>/dev/null)
|
||||
|
||||
if [ -z "$REPOS" ]; then
|
||||
echo "暂无镜像(CI/CD 构建中...)"
|
||||
else
|
||||
for repo in $REPOS; do
|
||||
if [[ $repo == ljwx-health/* ]]; then
|
||||
echo ""
|
||||
echo "📦 $repo:"
|
||||
TAGS=$(curl -s -u admin:admin123 "http://localhost:5000/v2/$repo/tags/list" | jq -r '.tags[]?' 2>/dev/null)
|
||||
if [ -z "$TAGS" ]; then
|
||||
echo " └─ 暂无标签"
|
||||
else
|
||||
for tag in $TAGS; do
|
||||
echo " └─ $tag"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "💡 实用命令"
|
||||
echo "========================================="
|
||||
echo "访问 Web UI: http://localhost:8888"
|
||||
echo "重新运行检查: ./check-registry.sh"
|
||||
echo "查看 K3s 部署: ./monitor-deployment.sh"
|
||||
echo ""
|
||||
@@ -1 +0,0 @@
|
||||
/var/run/mysqld/mysqld.sock
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: default
|
||||
namespace: dev
|
||||
imagePullSecrets:
|
||||
- name: regcred
|
||||
@@ -0,0 +1,4 @@
|
||||
resources:
|
||||
- namespace-dev.yaml
|
||||
- regcred.yaml
|
||||
- default-sa.yaml
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: dev
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IuZXUubGluZ2ppbmd3YW54aWFuZy5jbjo4MDgwIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IkhhcmJvcjEyMzQ1IiwiYXV0aCI6IllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSJ9fX0=
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: regcred
|
||||
namespace: dev
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
@@ -0,0 +1 @@
|
||||
Tue Dec 16 09:18:06 CET 2025
|
||||
@@ -0,0 +1,2 @@
|
||||
admin:$2y$05$d3UA3lnupxLKfSoVhqHoG.QQriPbPTkdrCKJbVxmxvtXXCGDhwcaW
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
container_name: local-harbor-registry
|
||||
restart: always
|
||||
ports:
|
||||
- "5000:5000"
|
||||
environment:
|
||||
REGISTRY_AUTH: htpasswd
|
||||
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
|
||||
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
|
||||
REGISTRY_STORAGE_DELETE_ENABLED: "true"
|
||||
volumes:
|
||||
- ./data/registry:/var/lib/registry
|
||||
- ./auth:/auth
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
registry-ui:
|
||||
image: joxit/docker-registry-ui:latest
|
||||
container_name: local-harbor-ui
|
||||
restart: always
|
||||
ports:
|
||||
- "8888:80"
|
||||
environment:
|
||||
- SINGLE_REGISTRY=true
|
||||
- REGISTRY_TITLE=LJWX Health Registry
|
||||
- DELETE_IMAGES=true
|
||||
- SHOW_CONTENT_DIGEST=true
|
||||
- NGINX_PROXY_PASS_URL=http://registry:5000
|
||||
- SHOW_CATALOG_NB_TAGS=true
|
||||
- CATALOG_MIN_BRANCHES=1
|
||||
- CATALOG_MAX_BRANCHES=1
|
||||
- TAGLIST_PAGE_SIZE=100
|
||||
- REGISTRY_SECURED=false
|
||||
- CATALOG_ELEMENTS_LIMIT=1000
|
||||
networks:
|
||||
- harbor
|
||||
depends_on:
|
||||
- registry
|
||||
|
||||
networks:
|
||||
harbor:
|
||||
driver: bridge
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "========================================="
|
||||
echo "🚀 本地 Docker Registry 部署脚本"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
HARBOR_DIR="/root/codes/ljwx-health/harbor"
|
||||
cd "$HARBOR_DIR"
|
||||
|
||||
# 创建必要的目录
|
||||
echo "📁 创建数据目录..."
|
||||
mkdir -p data/registry
|
||||
mkdir -p auth
|
||||
|
||||
# 生成 htpasswd 文件(admin/admin123)
|
||||
echo "🔐 创建认证文件..."
|
||||
if command -v htpasswd &> /dev/null; then
|
||||
htpasswd -Bbn admin admin123 > auth/htpasswd
|
||||
else
|
||||
# 如果没有 htpasswd 命令,使用 docker 生成
|
||||
docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin admin123 > auth/htpasswd
|
||||
fi
|
||||
|
||||
echo "✅ 认证文件已创建"
|
||||
cat auth/htpasswd
|
||||
echo ""
|
||||
|
||||
# 停止并删除旧容器
|
||||
echo "🧹 清理旧容器..."
|
||||
docker compose down -v 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "🐳 启动 Docker Registry..."
|
||||
docker compose up -d
|
||||
|
||||
echo ""
|
||||
echo "⏳ 等待 Registry 启动 (10秒)..."
|
||||
sleep 10
|
||||
|
||||
# 测试连接
|
||||
echo ""
|
||||
echo "🔍 测试 Registry 连接..."
|
||||
if curl -s -f http://localhost:5000/v2/ > /dev/null; then
|
||||
echo "✅ Registry API 可访问"
|
||||
else
|
||||
echo "⚠️ Registry API 尚未就绪,请稍等片刻"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "✅ Docker Registry 部署完成!"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo "📦 Registry 信息:"
|
||||
echo " - Registry API: http://localhost:5000"
|
||||
echo " - Web UI: http://localhost:8888"
|
||||
echo " - 用户名: admin"
|
||||
echo " - 密码: admin123"
|
||||
echo ""
|
||||
echo "🔧 Docker 登录:"
|
||||
echo " docker login localhost:5000 -u admin -p admin123"
|
||||
echo ""
|
||||
echo "📝 推送镜像示例:"
|
||||
echo " docker tag myimage:latest localhost:5000/ljwx-health/myimage:latest"
|
||||
echo " docker push localhost:5000/ljwx-health/myimage:latest"
|
||||
echo ""
|
||||
echo "🌐 查看所有仓库:"
|
||||
echo " curl -u admin:admin123 http://localhost:5000/v2/_catalog"
|
||||
echo ""
|
||||
@@ -1,23 +1,15 @@
|
||||
# 多阶段构建:第一阶段 - 前端构建环境
|
||||
FROM harbor.omniverseai.net/proxy-dockerhub/node:18-alpine AS builder
|
||||
# 多阶段构建:第一阶段 - 前端构建环境
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 设置阿里云镜像加速环境变量
|
||||
ENV SASS_BINARY_SITE=https://npmmirror.com/mirrors/node-sass/ \
|
||||
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ \
|
||||
PUPPETEER_DOWNLOAD_HOST=https://npmmirror.com/mirrors \
|
||||
CHROMEDRIVER_CDNURL=https://npmmirror.com/mirrors/chromedriver \
|
||||
OPERADRIVER_CDNURL=https://npmmirror.com/mirrors/operadriver \
|
||||
PHANTOMJS_CDNURL=https://npmmirror.com/mirrors/phantomjs \
|
||||
SELENIUM_CDNURL=https://npmmirror.com/mirrors/selenium \
|
||||
SQLITE3_BINARY_SITE=https://npmmirror.com/mirrors
|
||||
|
||||
# 安装 pnpm 并设置阿里云 npm 镜像
|
||||
RUN npm config set registry https://registry.npmmirror.com && \
|
||||
# 安装 pnpm 并配置超时重试(使用官方 registry)
|
||||
RUN npm config set fetch-timeout 600000 && \
|
||||
npm config set fetch-retries 5 && \
|
||||
npm install -g pnpm && \
|
||||
pnpm config set registry https://registry.npmmirror.com
|
||||
pnpm config set network-timeout 600000 && \
|
||||
pnpm config set fetch-retries 5
|
||||
|
||||
# 复制 package 相关文件(利用Docker层缓存)
|
||||
COPY package*.json pnpm-*.yaml ./
|
||||
@@ -47,7 +39,7 @@ ENV VITE_SERVICE_EXPIRED_TOKEN_CODES=40101
|
||||
RUN pnpm run build
|
||||
|
||||
# 多阶段构建:第二阶段 - 生产运行环境
|
||||
FROM harbor.omniverseai.net/proxy-dockerhub/nginx:alpine
|
||||
FROM nginx:alpine
|
||||
|
||||
# 设置北京时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
@@ -55,8 +47,6 @@ RUN apk add --no-cache tzdata && \
|
||||
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
|
||||
echo $TZ > /etc/timezone
|
||||
|
||||
RUN apk add --no-cache findutils # 添加find命令支持
|
||||
|
||||
# 从构建阶段复制构建结果
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
|
||||
@@ -7,8 +7,13 @@
|
||||
# 4. 分层构建:系统依赖 + Python 依赖 + 应用代码
|
||||
# ============================================
|
||||
|
||||
# 动态镜像源配置
|
||||
# 默认使用 Docker Hub 官方源(本机/GitHub Actions)
|
||||
# 开发服务器可通过 --build-arg REGISTRY_PREFIX=harbor.omniverseai.net/proxy-dockerhub/ 使用 Harbor 代理
|
||||
ARG REGISTRY_PREFIX=""
|
||||
|
||||
# ====== 构建阶段 ======
|
||||
FROM harbor.omniverseai.net/proxy-dockerhub/python:3.12-slim AS builder
|
||||
FROM ${REGISTRY_PREFIX}python:3.12-slim AS builder
|
||||
|
||||
# 安装编译工具和运行时依赖
|
||||
RUN apt-get update --fix-missing && \
|
||||
@@ -37,7 +42,9 @@ RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install --user --no-cache-dir -r requirements-docker.txt
|
||||
|
||||
# ====== 运行阶段(最小化镜像)======
|
||||
FROM harbor.omniverseai.net/proxy-dockerhub/python:3.12-slim
|
||||
# 复用 ARG 以在运行阶段使用相同的镜像源
|
||||
ARG REGISTRY_PREFIX=""
|
||||
FROM ${REGISTRY_PREFIX}python:3.12-slim
|
||||
|
||||
# 安装运行时依赖
|
||||
RUN apt-get update --fix-missing && \
|
||||
|
||||
@@ -2,9 +2,9 @@ apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ljwx-config
|
||||
namespace: ljwx-system
|
||||
namespace: ljwx-health
|
||||
data:
|
||||
redis.host: "redis-service.ljwx-system.svc.cluster.local"
|
||||
redis.host: "redis-service.ljwx-health.svc.cluster.local"
|
||||
redis.port: "6379"
|
||||
app.log.level: "INFO"
|
||||
app.debug: "false"
|
||||
@@ -14,10 +14,10 @@ apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ljwx-db-secret
|
||||
namespace: ljwx-system
|
||||
namespace: ljwx-health
|
||||
type: Opaque
|
||||
data:
|
||||
host: bXlzcWwtc2VydmljZS5sand4LXN5c3RlbS5zdmMuY2x1c3Rlci5sb2NhbA== # mysql-service.ljwx-system.svc.cluster.local
|
||||
username: bGp3eA== # ljwx
|
||||
password: bGp3eDEyMw== # ljwx123
|
||||
database: bGp3eA== # ljwx
|
||||
host: bXlzcWwtc2VydmljZS5sand4LWhlYWx0aC5zdmMuY2x1c3Rlci5sb2NhbA== # mysql-service.ljwx-health.svc.cluster.local
|
||||
username: cm9vdA== # root
|
||||
password: MTIzNDU2 # 123456
|
||||
database: dGVzdA== # test
|
||||
@@ -2,7 +2,7 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ljwx-bigscreen
|
||||
namespace: ljwx-system
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: ljwx-bigscreen
|
||||
env: prod
|
||||
@@ -41,7 +41,7 @@ spec:
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- name: ljwx-bigscreen
|
||||
image: ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}
|
||||
image: 173.212.254.252:5000/ljwx-health/ljwx-bigscreen:latest
|
||||
ports:
|
||||
- containerPort: 5001
|
||||
name: http
|
||||
@@ -63,6 +63,10 @@ spec:
|
||||
secretKeyRef:
|
||||
name: ljwx-db-secret
|
||||
key: password
|
||||
- name: MYSQL_DATABASE
|
||||
value: "test"
|
||||
- name: APP_PORT
|
||||
value: "5001"
|
||||
- name: REDIS_HOST
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -80,24 +84,21 @@ spec:
|
||||
memory: "1Gi"
|
||||
cpu: "1000m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/health
|
||||
tcpSocket:
|
||||
port: 5001
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/ready
|
||||
tcpSocket:
|
||||
port: 5001
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
startupProbe: # 启动探针,给应用更多启动时间
|
||||
httpGet:
|
||||
path: /api/health
|
||||
tcpSocket:
|
||||
port: 5001
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
@@ -108,7 +109,7 @@ apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: ljwx-bigscreen-hpa
|
||||
namespace: ljwx-system
|
||||
namespace: ljwx-health
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
|
||||
@@ -2,7 +2,7 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ljwx-bigscreen-service
|
||||
namespace: ljwx-system
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: ljwx-bigscreen
|
||||
env: prod
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
app: ljwx-boot
|
||||
data:
|
||||
# 数据库配置
|
||||
database.url: "jdbc:mysql://mysql-service.ljwx-health.svc.cluster.local:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false"
|
||||
database.url: "jdbc:mysql://mysql-service.ljwx-health.svc.cluster.local:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true"
|
||||
database.driver: "com.mysql.cj.jdbc.Driver"
|
||||
|
||||
# Redis配置
|
||||
@@ -30,6 +30,7 @@ data:
|
||||
name: ljwx-boot
|
||||
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
minimum-idle: 10
|
||||
@@ -39,6 +40,9 @@ data:
|
||||
max-lifetime: 1800000
|
||||
|
||||
redis:
|
||||
# Redis Service DNS 名称(K8s 集群内部)
|
||||
host: redis-service.ljwx-health.svc.cluster.local
|
||||
port: 6379
|
||||
database: 1
|
||||
timeout: 10000
|
||||
lettuce:
|
||||
|
||||
@@ -46,7 +46,7 @@ spec:
|
||||
|
||||
containers:
|
||||
- name: ljwx-boot
|
||||
image: harbor.omniverseai.net/ljwx-health/ljwx-boot:latest
|
||||
image: 173.212.254.252:5000/ljwx-health/ljwx-boot:latest
|
||||
imagePullPolicy: Always
|
||||
|
||||
ports:
|
||||
@@ -80,18 +80,18 @@ spec:
|
||||
name: ljwx-boot-secret
|
||||
key: database.password
|
||||
|
||||
# Redis配置
|
||||
# Redis配置 - 直接指定值,覆盖配置文件
|
||||
- name: SPRING_DATA_REDIS_HOST
|
||||
value: "redis-service.ljwx-health.svc.cluster.local"
|
||||
|
||||
- name: SPRING_DATA_REDIS_PORT
|
||||
value: "6379"
|
||||
|
||||
- name: SPRING_REDIS_HOST
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: ljwx-boot-config
|
||||
key: redis.host
|
||||
value: "redis-service.ljwx-health.svc.cluster.local"
|
||||
|
||||
- name: SPRING_REDIS_PORT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: ljwx-boot-config
|
||||
key: redis.port
|
||||
value: "6379"
|
||||
|
||||
- name: SPRING_REDIS_PASSWORD
|
||||
valueFrom:
|
||||
@@ -102,9 +102,25 @@ spec:
|
||||
- name: SPRING_REDIS_DATABASE
|
||||
value: "1"
|
||||
|
||||
# Redis URL 连接配置(application-common.yml 使用)
|
||||
- name: REDIS_HOST
|
||||
value: "redis-service.ljwx-health.svc.cluster.local"
|
||||
|
||||
- name: REDIS_PORT
|
||||
value: "6379"
|
||||
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ljwx-boot-secret
|
||||
key: redis.password
|
||||
|
||||
- name: REDIS_DB
|
||||
value: "1"
|
||||
|
||||
# JVM参数
|
||||
- name: JAVA_OPTS
|
||||
value: "-Xms1g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof"
|
||||
value: "-Xms1g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -Dspring.data.redis.host=redis-service.ljwx-health.svc.cluster.local -Dspring.data.redis.port=6379 -Dspring.redis.host=redis-service.ljwx-health.svc.cluster.local -Dspring.redis.port=6379"
|
||||
|
||||
# 资源限制
|
||||
resources:
|
||||
@@ -147,7 +163,7 @@ spec:
|
||||
# 挂载卷
|
||||
volumeMounts:
|
||||
- name: logs
|
||||
mountPath: /app/logs
|
||||
mountPath: /app/ljwx-boot-logs
|
||||
- name: config
|
||||
mountPath: /app/config
|
||||
readOnly: true
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mysql
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: mysql
|
||||
component: database
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mysql
|
||||
strategy:
|
||||
type: Recreate # MySQL 使用 Recreate 策略,避免多实例同时访问数据
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mysql
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: harbor-secret
|
||||
containers:
|
||||
- name: mysql
|
||||
image: 173.212.254.252:5000/ljwx-health/ljwx-mysql:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: mysql
|
||||
containerPort: 3306
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ljwx-boot-secret
|
||||
key: database.password
|
||||
- name: MYSQL_DATABASE
|
||||
value: "test"
|
||||
- name: TZ
|
||||
value: "Asia/Shanghai"
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: "1Gi"
|
||||
limits:
|
||||
cpu: "2000m"
|
||||
memory: "2Gi"
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- mysqladmin
|
||||
- ping
|
||||
- -h
|
||||
- localhost
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- mysqladmin
|
||||
- ping
|
||||
- -h
|
||||
- localhost
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
volumeMounts:
|
||||
- name: mysql-data
|
||||
mountPath: /var/lib/mysql
|
||||
- name: mysql-config
|
||||
mountPath: /etc/mysql/conf.d
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: mysql-data
|
||||
persistentVolumeClaim:
|
||||
claimName: mysql-pvc
|
||||
- name: mysql-config
|
||||
configMap:
|
||||
name: mysql-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: mysql-config
|
||||
namespace: ljwx-health
|
||||
data:
|
||||
custom.cnf: |
|
||||
[mysqld]
|
||||
character-set-server=utf8mb4
|
||||
collation-server=utf8mb4_unicode_ci
|
||||
default-time-zone='+08:00'
|
||||
max_connections=200
|
||||
innodb_buffer_pool_size=1G
|
||||
innodb_log_file_size=256M
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mysql-pvc
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: mysql
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
storageClassName: local-path # k3s 默认使用 local-path
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mysql-service
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: mysql
|
||||
component: database
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: mysql
|
||||
ports:
|
||||
- name: mysql
|
||||
port: 3306
|
||||
targetPort: 3306
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,109 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: redis
|
||||
component: cache
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
strategy:
|
||||
type: Recreate # Redis 使用 Recreate 策略
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: harbor-secret
|
||||
containers:
|
||||
- name: redis
|
||||
image: 173.212.254.252:5000/ljwx-health/ljwx-redis:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: redis
|
||||
containerPort: 6379
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Asia/Shanghai"
|
||||
command:
|
||||
- redis-server
|
||||
- /usr/local/etc/redis/redis.conf
|
||||
- --requirepass
|
||||
- $(REDIS_PASSWORD)
|
||||
env:
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ljwx-boot-secret
|
||||
key: redis.password
|
||||
resources:
|
||||
requests:
|
||||
cpu: "200m"
|
||||
memory: "512Mi"
|
||||
limits:
|
||||
cpu: "1000m"
|
||||
memory: "1Gi"
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
- name: redis-config
|
||||
mountPath: /usr/local/etc/redis
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: redis-data
|
||||
persistentVolumeClaim:
|
||||
claimName: redis-pvc
|
||||
- name: redis-config
|
||||
configMap:
|
||||
name: redis-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: redis-config
|
||||
namespace: ljwx-health
|
||||
data:
|
||||
redis.conf: |
|
||||
bind 0.0.0.0
|
||||
port 6379
|
||||
protected-mode yes
|
||||
timeout 0
|
||||
tcp-keepalive 300
|
||||
databases 16
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
stop-writes-on-bgsave-error yes
|
||||
rdbcompression yes
|
||||
rdbchecksum yes
|
||||
dbfilename dump.rdb
|
||||
dir /data
|
||||
maxmemory 512mb
|
||||
maxmemory-policy allkeys-lru
|
||||
appendonly yes
|
||||
appendfilename "appendonly.aof"
|
||||
appendfsync everysec
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: redis-pvc
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
storageClassName: local-path # k3s 默认使用 local-path
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-service
|
||||
namespace: ljwx-health
|
||||
labels:
|
||||
app: redis
|
||||
component: cache
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: redis
|
||||
ports:
|
||||
- name: redis
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
protocol: TCP
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
# 监控 ljwx-health 部署状态
|
||||
|
||||
echo "========================================="
|
||||
echo "📊 LJWX Health 部署状态监控"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# 设置颜色
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 检查 namespace
|
||||
echo -e "${YELLOW}[1/5] 检查 Namespace...${NC}"
|
||||
kubectl get ns ljwx-health -o wide
|
||||
echo ""
|
||||
|
||||
# 检查 Secrets
|
||||
echo -e "${YELLOW}[2/5] 检查 Secrets...${NC}"
|
||||
kubectl get secrets -n ljwx-health | grep -E "NAME|harbor-secret|ljwx-boot-secret"
|
||||
echo ""
|
||||
|
||||
# 检查 Deployments
|
||||
echo -e "${YELLOW}[3/5] 检查 Deployments...${NC}"
|
||||
kubectl get deployments -n ljwx-health -o wide
|
||||
echo ""
|
||||
|
||||
# 检查 Pods
|
||||
echo -e "${YELLOW}[4/5] 检查 Pods...${NC}"
|
||||
kubectl get pods -n ljwx-health -o wide
|
||||
echo ""
|
||||
|
||||
# 检查最近的 Events
|
||||
echo -e "${YELLOW}[5/5] 最近的 Events (最后 10 条)...${NC}"
|
||||
kubectl get events -n ljwx-health --sort-by='.lastTimestamp' | tail -10
|
||||
echo ""
|
||||
|
||||
# 健康状态摘要
|
||||
echo "========================================="
|
||||
echo "📈 健康状态摘要"
|
||||
echo "========================================="
|
||||
|
||||
TOTAL_PODS=$(kubectl get pods -n ljwx-health --no-headers 2>/dev/null | wc -l | tr -d ' ')
|
||||
RUNNING_PODS=$(kubectl get pods -n ljwx-health --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l | tr -d ' ')
|
||||
READY_PODS=$(kubectl get pods -n ljwx-health -o json 2>/dev/null | jq '[.items[] | select(.status.conditions[] | select(.type=="Ready" and .status=="True"))] | length' 2>/dev/null || echo "0")
|
||||
|
||||
echo "总 Pods: $TOTAL_PODS"
|
||||
echo "运行中: $RUNNING_PODS"
|
||||
echo "就绪: $READY_PODS"
|
||||
|
||||
if [ "$READY_PODS" = "$TOTAL_PODS" ] && [ "$TOTAL_PODS" -gt 0 ]; then
|
||||
echo -e "${GREEN}✅ 所有 Pods 已就绪!${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 部分 Pods 未就绪,请检查详细信息${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "💡 实用命令"
|
||||
echo "========================================="
|
||||
echo "查看 ljwx-boot 日志: kubectl logs -f deployment/ljwx-boot -n ljwx-health"
|
||||
echo "查看 ljwx-bigscreen 日志: kubectl logs -f deployment/ljwx-bigscreen -n ljwx-health"
|
||||
echo "查看所有资源: kubectl get all -n ljwx-health"
|
||||
echo "重新运行此脚本: ./monitor-deployment.sh"
|
||||
echo ""
|
||||
Executable
+189
@@ -0,0 +1,189 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "========================================="
|
||||
echo "🧪 K3s 本地部署测试脚本"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
NAMESPACE="ljwx-health"
|
||||
REGISTRY="173.212.254.252:5000"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
function log_info() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
function log_warn() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
function log_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
# 步骤 1: 验证 YAML 文件语法
|
||||
echo "========================================="
|
||||
echo "📝 步骤 1: 验证 K8s YAML 文件语法"
|
||||
echo "========================================="
|
||||
|
||||
YAML_FILES=(
|
||||
"ljwx-boot/k8s/configmap.yml"
|
||||
"ljwx-boot/k8s/secret.yml.template"
|
||||
"ljwx-boot/k8s/service.yml"
|
||||
"ljwx-boot/k8s/deployment.yml"
|
||||
"ljwx-bigscreen/k8s/base/configmap.yaml"
|
||||
"ljwx-bigscreen/k8s/prod/service.yaml"
|
||||
"ljwx-bigscreen/k8s/prod/deployment.yaml"
|
||||
)
|
||||
|
||||
for file in "${YAML_FILES[@]}"; do
|
||||
if [ -f "$file" ]; then
|
||||
echo "检查: $file"
|
||||
if kubectl apply --dry-run=client -f "$file" &>/dev/null; then
|
||||
log_info "$file - 语法正确"
|
||||
else
|
||||
log_error "$file - 语法错误,请检查!"
|
||||
kubectl apply --dry-run=client -f "$file"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_warn "$file - 文件不存在"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# 步骤 2: 创建 namespace
|
||||
echo "========================================="
|
||||
echo "📦 步骤 2: 创建 Namespace"
|
||||
echo "========================================="
|
||||
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
|
||||
log_info "Namespace $NAMESPACE 已创建"
|
||||
echo ""
|
||||
|
||||
# 步骤 3: 创建镜像拉取密钥
|
||||
echo "========================================="
|
||||
echo "🔐 步骤 3: 创建镜像拉取密钥"
|
||||
echo "========================================="
|
||||
kubectl create secret docker-registry harbor-secret \
|
||||
--docker-server=$REGISTRY \
|
||||
--docker-username=admin \
|
||||
--docker-password=admin123 \
|
||||
--namespace=$NAMESPACE \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
log_info "镜像拉取密钥已创建"
|
||||
echo ""
|
||||
|
||||
# 步骤 4: 部署 ljwx-boot
|
||||
echo "========================================="
|
||||
echo "🚀 步骤 4: 部署 ljwx-boot"
|
||||
echo "========================================="
|
||||
|
||||
# 4.1 ConfigMap
|
||||
echo "4.1 部署 ConfigMap..."
|
||||
kubectl apply -f ljwx-boot/k8s/configmap.yml -n $NAMESPACE
|
||||
log_info "ConfigMap 已创建"
|
||||
|
||||
# 4.2 Secret (从模板创建)
|
||||
echo "4.2 部署 Secret..."
|
||||
if [ -f ljwx-boot/k8s/secret.yml.template ]; then
|
||||
DB_USERNAME="${DB_USERNAME:-root}"
|
||||
DB_PASSWORD="${DB_PASSWORD:-123456}"
|
||||
REDIS_PASSWORD="${REDIS_PASSWORD:-123456}"
|
||||
JWT_SECRET="${JWT_SECRET:-ljwx-default-jwt-secret-change-me}"
|
||||
|
||||
sed "s|<BASE64_ENCODED_DB_USERNAME>|$(echo -n "$DB_USERNAME" | base64)|g" ljwx-boot/k8s/secret.yml.template | \
|
||||
sed "s|<BASE64_ENCODED_DB_PASSWORD>|$(echo -n "$DB_PASSWORD" | base64)|g" | \
|
||||
sed "s|<BASE64_ENCODED_REDIS_PASSWORD>|$(echo -n "$REDIS_PASSWORD" | base64)|g" | \
|
||||
sed "s|<BASE64_ENCODED_JWT_SECRET>|$(echo -n "$JWT_SECRET" | base64)|g" | \
|
||||
kubectl apply -f - -n $NAMESPACE
|
||||
log_info "Secret 已创建"
|
||||
else
|
||||
log_warn "Secret 模板文件不存在,跳过"
|
||||
fi
|
||||
|
||||
# 4.3 Service
|
||||
echo "4.3 部署 Service..."
|
||||
kubectl apply -f ljwx-boot/k8s/service.yml -n $NAMESPACE
|
||||
log_info "Service 已创建"
|
||||
|
||||
# 4.4 Deployment
|
||||
echo "4.4 部署 Deployment..."
|
||||
kubectl apply -f ljwx-boot/k8s/deployment.yml -n $NAMESPACE
|
||||
log_info "Deployment 已创建"
|
||||
|
||||
# 4.5 等待就绪
|
||||
echo "4.5 等待 ljwx-boot 就绪..."
|
||||
kubectl rollout status deployment/ljwx-boot -n $NAMESPACE --timeout=5m || {
|
||||
log_error "ljwx-boot 部署超时"
|
||||
kubectl get pods -n $NAMESPACE
|
||||
exit 1
|
||||
}
|
||||
log_info "ljwx-boot 部署成功!"
|
||||
|
||||
echo ""
|
||||
|
||||
# 步骤 5: 部署 ljwx-bigscreen
|
||||
echo "========================================="
|
||||
echo "🚀 步骤 5: 部署 ljwx-bigscreen"
|
||||
echo "========================================="
|
||||
|
||||
# 5.1 ConfigMap
|
||||
echo "5.1 部署 ConfigMap..."
|
||||
if [ -f ljwx-bigscreen/k8s/base/configmap.yaml ]; then
|
||||
kubectl apply -f ljwx-bigscreen/k8s/base/configmap.yaml -n $NAMESPACE
|
||||
log_info "ConfigMap 已创建"
|
||||
fi
|
||||
|
||||
# 5.2 Service
|
||||
echo "5.2 部署 Service..."
|
||||
if [ -f ljwx-bigscreen/k8s/prod/service.yaml ]; then
|
||||
kubectl apply -f ljwx-bigscreen/k8s/prod/service.yaml -n $NAMESPACE
|
||||
log_info "Service 已创建"
|
||||
fi
|
||||
|
||||
# 5.3 Deployment
|
||||
echo "5.3 部署 Deployment..."
|
||||
if [ -f ljwx-bigscreen/k8s/prod/deployment.yaml ]; then
|
||||
kubectl apply -f ljwx-bigscreen/k8s/prod/deployment.yaml -n $NAMESPACE
|
||||
log_info "Deployment 已创建"
|
||||
|
||||
# 5.4 等待就绪
|
||||
echo "5.4 等待 ljwx-bigscreen 就绪..."
|
||||
kubectl rollout status deployment/ljwx-bigscreen -n $NAMESPACE --timeout=5m || {
|
||||
log_error "ljwx-bigscreen 部署超时"
|
||||
kubectl get pods -n $NAMESPACE
|
||||
exit 1
|
||||
}
|
||||
log_info "ljwx-bigscreen 部署成功!"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 步骤 6: 验证部署
|
||||
echo "========================================="
|
||||
echo "✅ 步骤 6: 验证部署状态"
|
||||
echo "========================================="
|
||||
|
||||
echo ""
|
||||
echo "📊 Pods 状态:"
|
||||
kubectl get pods -n $NAMESPACE -o wide
|
||||
|
||||
echo ""
|
||||
echo "🌐 Services 状态:"
|
||||
kubectl get svc -n $NAMESPACE
|
||||
|
||||
echo ""
|
||||
echo "📦 Deployments 状态:"
|
||||
kubectl get deployments -n $NAMESPACE
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "🎉 部署测试完成!"
|
||||
echo "========================================="
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "========================================="
|
||||
echo "🔍 实时监控 CI/CD 执行 (每 10 秒刷新)"
|
||||
echo "========================================="
|
||||
echo "按 Ctrl+C 停止监控"
|
||||
echo ""
|
||||
sleep 2
|
||||
|
||||
while true; do
|
||||
clear
|
||||
echo "========================================="
|
||||
echo "🚀 CI/CD 执行状态监控"
|
||||
echo "========================================="
|
||||
date "+%Y-%m-%d %H:%M:%S"
|
||||
echo ""
|
||||
|
||||
echo "📦 GitHub Actions Runner:"
|
||||
kubectl get pods -n github-runner -o wide | grep -E "NAME|runner"
|
||||
echo ""
|
||||
|
||||
echo "🔨 当前正在执行的任务:"
|
||||
RUNNER_POD=$(kubectl get pods -n github-runner -o name | grep runner | head -1 | cut -d'/' -f2)
|
||||
if [ -n "$RUNNER_POD" ]; then
|
||||
kubectl logs -n github-runner "$RUNNER_POD" -c runner --tail=5 2>&1 | grep -E "Running job|Finished|Starting" || echo " 等待任务分配..."
|
||||
else
|
||||
echo " 无 runner pod 运行"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "🐳 Registry 镜像数量:"
|
||||
REPO_COUNT=$(curl -s -u admin:admin123 http://localhost:5000/v2/_catalog 2>/dev/null | jq -r '.repositories | length' 2>/dev/null || echo "0")
|
||||
echo " 已推送镜像仓库数: $REPO_COUNT"
|
||||
|
||||
if [ "$REPO_COUNT" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "📋 Registry 中的镜像:"
|
||||
curl -s -u admin:admin123 http://localhost:5000/v2/_catalog 2>/dev/null | jq -r '.repositories[]' | while read repo; do
|
||||
TAGS=$(curl -s -u admin:admin123 "http://localhost:5000/v2/$repo/tags/list" 2>/dev/null | jq -r '.tags[]?' | head -3 | tr '\n' ', ' | sed 's/,$//')
|
||||
echo " └─ $repo: $TAGS"
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "📊 K3s 部署状态 (ljwx-health namespace):"
|
||||
kubectl get deployments -n ljwx-health 2>/dev/null | grep -E "NAME|ljwx" || echo " 部署尚未更新"
|
||||
echo ""
|
||||
|
||||
echo "========================================="
|
||||
echo "⏰ 每 10 秒自动刷新 | 按 Ctrl+C 退出"
|
||||
echo "========================================="
|
||||
|
||||
sleep 10
|
||||
done
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
# 实时监控 ljwx-health 部署变化
|
||||
|
||||
echo "========================================="
|
||||
echo "🔍 实时监控 ljwx-health 部署 (每 5 秒刷新)"
|
||||
echo "========================================="
|
||||
echo "按 Ctrl+C 停止监控"
|
||||
echo ""
|
||||
sleep 2
|
||||
|
||||
# 使用 watch 命令实时监控
|
||||
watch -n 5 -c '
|
||||
echo "📊 Deployments:"
|
||||
kubectl get deployments -n ljwx-health -o wide
|
||||
echo ""
|
||||
echo "🐳 Pods:"
|
||||
kubectl get pods -n ljwx-health -o wide
|
||||
echo ""
|
||||
echo "🔑 Secrets:"
|
||||
kubectl get secrets -n ljwx-health | grep -E "NAME|harbor|ljwx"
|
||||
echo ""
|
||||
echo "⏰ 更新时间: $(date +"%Y-%m-%d %H:%M:%S")"
|
||||
'
|
||||
Reference in New Issue
Block a user