test: flux local cluster setup with infra-devops post

这个提交包含在:
rohow
2026-03-25 12:08:55 +08:00
未验证
父节点 cddcd02d1b
当前提交 eb32e5755d
修改 94 个文件,包含 1567 行新增1023 行删除
+230
查看文件
@@ -0,0 +1,230 @@
# Flux GitOps 迁移指南
补充一份面向本地演练和远端平滑切换的执行清单,见 [TEST_MIGRATION_PLAN.md](TEST_MIGRATION_PLAN.md)。
## 目录结构
```
flux/
├── clusters/
│ └── dev-cm/ # 集群级别编排
│ ├── kustomization.yaml # 资源列表
│ ├── sources.yaml # HelmRepository 源
│ ├── kube-system.yaml # CoreDNS / NodeLocalDNS
│ ├── infra-devops.yaml # cert-manager / reflector / velero
│ ├── infra-data.yaml # CNPG / Valkey
│ ├── infra-monitor.yaml # Loki / Prometheus
│ ├── infra-net.yaml # Nginx / CrowdSec / Tailscale
│ ├── infra-gitops.yaml # Gitea
│ └── apps.yaml # Halo / RustDesk / Fillcode / SinceAI
├── infrastructure/
│ ├── sources/ # 所有 HelmRepository 定义
│ ├── kube-system/ # CoreDNS 自定义 + NodeLocalDNS
│ ├── infra-devops/ # cert-manager, webhook-dnspod, reflector, velero
│ ├── infra-data/ # CNPG operator, Barman, PG集群, Valkey
│ ├── infra-net/ # ingress-nginx, CrowdSec, Tailscale DERP, 证书
│ ├── infra-monitor/ # Loki, Promtail, Prometheus+Grafana
│ └── infra-gitops/ # Gitea, Gitea Actions
└── apps/ # Halo, RustDesk, Whoami, 证书, Ingress
```
## 依赖顺序
```
sources (HelmRepository)
├── kube-system (无依赖)
└── infra-devops (cert-manager → webhook-dnspod → ClusterIssuer, reflector, velero)
├── infra-data (CNPG operator → Barman plugin → PG集群 + ObjectStore, Valkey)
│ │
│ ├── infra-monitor (Loki → Promtail, Prometheus+Grafana→PG)
│ │ │
│ │ ├── infra-net (Nginx, 证书, CrowdSec→Loki+PG, Tailscale)
│ │ │
│ │ └── infra-gitops (Gitea→PG+Valkey, Gitea Actions→Gitea)
│ │
│ └───────┴── apps (Halo→PG, RustDesk, Whoami, 证书, Ingress)
```
## K3s 保留项
以下资源**继续由 K3s HelmChart 管理**,不迁移到 Flux
- `k3s/apps/infra/gitops/namespaces.yaml` — infra-gitops 命名空间
- `k3s/apps/infra/gitops/flux/helmchart.yaml` — flux-operator HelmChart
- `k3s/apps/infra/gitops/flux/flux-instance.yaml` — FluxInstance (含 sync 配置)
- `k3s/apps/infra/gitops/flux/networkpolicy.yaml` — flux-operator NetworkPolicy
- `k3s/apps/infra/gitops/flux/clusterrolebinding.yaml` — flux-web RBAC
## 迁移步骤
### 1. 创建 Git 认证 Secret
Flux 需要 HTTPS 凭据来访问 Gitea 仓库。在集群中创建 Secret:
```bash
kubectl -n infra-gitops create secret generic flux-git-auth \
--from-literal=username=<GITEA_USERNAME> \
--from-literal=password=<GITEA_ACCESS_TOKEN>
```
### 2. 确认仓库 URL
检查 `k3s/apps/infra/gitops/flux/flux-instance.yaml` 中的 `sync.url` 字段,确保指向正确的 deploy 仓库地址。当前设置为:
```yaml
sync:
url: https://git.dev.cm/devcm/deploy.git
```
如果组织名或仓库名不同,请修改。
### 3. 提交并推送 Flux 清单
```bash
git add flux/
git add k3s/apps/infra/gitops/flux/flux-instance.yaml
git commit -m "feat: 迁移到 Flux GitOps 管理"
git push origin main
```
### 4. 应用更新后的 FluxInstance
FluxInstance 的 sync 配置更新后,K3s 会自动检测变更并重新应用。也可以手动触发:
```bash
kubectl apply -f k3s/apps/infra/gitops/flux/flux-instance.yaml
```
这会让 flux-operator 创建:
- `GitRepository/flux` — 监听 deploy 仓库
- `Kustomization/flux` — 应用 `flux/clusters/dev-cm/` 路径下的所有资源
### 5. 等待 Flux 完成同步
```bash
# 查看 GitRepository 状态
kubectl -n infra-gitops get gitrepository flux
# 查看所有 Kustomization 状态
kubectl -n infra-gitops get kustomization
# 查看所有 HelmRelease 状态
kubectl get helmrelease -A
# 实时查看 Flux 事件
kubectl -n infra-gitops get events --sort-by='.lastTimestamp' --watch
```
等待所有 Kustomization 和 HelmRelease 状态变为 `Ready`
### 6. 验证资源被 Flux 接管
对于每个已有的 Helm Release,Flux 会检测到已存在的资源并进行接管(adopt)。验证:
```bash
# 检查所有 HelmRelease 是否就绪
kubectl get helmrelease -A -o wide
# 检查某个具体的 release
kubectl -n infra-devops describe helmrelease cert-manager
```
### 7. 清理旧的 K3s HelmChart 资源
确认 Flux 已成功接管所有资源后,删除旧的 K3s HelmChart CR(不会影响已部署的应用):
```bash
# 列出所有 K3s HelmChart
kubectl get helmchart -A
# 逐个删除(保留 flux-operator
kubectl delete helmchart -n infra-devops cert-manager
kubectl delete helmchart -n infra-devops cert-manager-webhook-dnspod
kubectl delete helmchart -n infra-devops reflector
kubectl delete helmchart -n infra-devops velero
kubectl delete helmchart -n infra-data cloudnative-pg
kubectl delete helmchart -n infra-data cloudnative-pg-plugin-barman
kubectl delete helmchart -n infra-data valkey-cluster-sh
kubectl delete helmchart -n infra-net ingress-nginx
kubectl delete helmchart -n infra-net crowdsec
kubectl delete helmchart -n infra-net tailscale-derp-hk
kubectl delete helmchart -n infra-monitor loki
kubectl delete helmchart -n infra-monitor loki-promtail
kubectl delete helmchart -n infra-monitor prometheus
kubectl delete helmchart -n infra-gitops gitea
kubectl delete helmchart -n infra-gitops gitea-actions
kubectl delete helmchart -n apps fillcode-whoami
kubectl delete helmchart -n apps halo
kubectl delete helmchart -n apps rustdesk
```
> **注意**: K3s HelmChart 使用 `helm.cattle.io/v1` API。删除 HelmChart CR 默认**不会**卸载已部署的 Helm release。Flux 的 HelmRelease 会接管这些 release 的后续管理。
### 8. 清理旧的 K3s 清单文件
确认一切正常后,可以移除 `k3s/apps/` 中已迁移到 Flux 的文件(保留 flux 相关的):
```bash
# 保留以下文件(K3s 继续管理):
# k3s/apps/infra/gitops/namespaces.yaml
# k3s/apps/infra/gitops/flux/
# 其余文件可以删除或归档
```
## 资源映射表
| 原 K3s HelmChart | Flux HelmRelease | 命名空间 |
| ---------------------------- | ---------------------------- | ------------- |
| cert-manager | cert-manager | infra-devops |
| cert-manager-webhook-dnspod | cert-manager-webhook-dnspod | infra-devops |
| reflector | reflector | infra-devops |
| velero | velero | infra-devops |
| cloudnative-pg | cloudnative-pg | infra-data |
| cloudnative-pg-plugin-barman | cloudnative-pg-plugin-barman | infra-data |
| valkey-cluster-sh | valkey-cluster-sh | infra-data |
| ingress-nginx | ingress-nginx | infra-net |
| crowdsec | crowdsec | infra-net |
| tailscale-derp-hk | tailscale-derp-hk | infra-net |
| loki | loki | infra-monitor |
| loki-promtail | loki-promtail | infra-monitor |
| prometheus | prometheus | infra-monitor |
| gitea | gitea | infra-gitops |
| gitea-actions | gitea-actions | infra-gitops |
| fillcode-whoami | fillcode-whoami | apps |
| halo | halo | apps |
| rustdesk | rustdesk | apps |
## HelmRelease 内依赖关系
| HelmRelease | dependsOn |
| ---------------------------- | ------------------------------ |
| cert-manager-webhook-dnspod | cert-manager |
| cloudnative-pg-plugin-barman | cloudnative-pg |
| loki-promtail | loki |
| crowdsec | ingress-nginx, loki (cross-ns) |
| gitea-actions | gitea |
## 注意事项
1. **Helm Release 接管**: Flux 默认会检测与 HelmRelease 同名的已存在 Helm release。如果名称不匹配,需要在 `spec.releaseName` 中指定原始名称。
2. **CRD 管理**: cert-manager 和 kube-prometheus-stack 的 HelmRelease 配置了 `install.crds: CreateReplace``upgrade.crds: CreateReplace` 以确保 CRD 被正确管理。
3. **跨命名空间引用**: 所有 HelmRepository 位于 `infra-gitops` 命名空间。HelmRelease 通过 `sourceRef.namespace: infra-gitops` 跨命名空间引用。FluxInstance 配置为单租户模式 (`multitenant: false`),允许此行为。
4. **kube-system 资源**: `prune: false` 用于 kube-system Kustomization,防止 Flux 意外删除系统资源。
5. **Velero CRD**: Velero HelmRelease 保持 `upgradeCRDs: false`,与原始配置一致。
6. **敏感信息**: 以下 Secret 需要手动维护(不在 Git 中管理):
- `flux-git-auth` (Gitea 访问令牌)
- `dnspod-secret` (DNSPod API 凭据)
- `s3-devcm-hw` (华为云 OBS 凭据)
- `cnpg17-cluster-*-app` (PostgreSQL 密码, 由 CNPG 自动管理)
- `valkey-cluster-sh` (Valkey 密码)
- `gitea-actions` (Gitea Actions runner token)
+14
查看文件
@@ -0,0 +1,14 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: fillcode-com-crt
namespace: apps
spec:
secretName: fillcode-com-crt
issuerRef:
name: dnspod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "fillcode.com"
- "*.fillcode.com"
+14
查看文件
@@ -0,0 +1,14 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: sinceai-com-crt
namespace: apps
spec:
secretName: sinceai-com-crt
issuerRef:
name: dnspod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "sinceai.com"
- "*.sinceai.com"
+57
查看文件
@@ -0,0 +1,57 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: halo
namespace: apps
spec:
interval: 30m
chart:
spec:
chart: halo
version: 1.3.2
sourceRef:
kind: HelmRepository
name: halo
namespace: infra-gitops
interval: 12h
values:
image:
repository: halohub/halo-pro
tag: 2.23.1
service:
type: ClusterIP
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Accept-Encoding "";
subs_filter_types text/html;
subs_filter '<(script|img|link)([^>]*) (src|href)="/' '<$1$2 $3="https://cdn.fillcode.com/dev-cm/' ri;
subs_filter 'url\(\/' 'url(https://cdn.fillcode.com/dev-cm/' ri;
subs_filter '<head>' '<head><script src="/__static/pwa-cdn.js"></script>' ri;
hostname: dev.cm
path: /
pathType: Prefix
podAnnotations:
backup.velero.io/backup-volumes: halo-data
persistence:
annotations:
helm.sh/resource-policy: keep
metrics:
enabled: true
mysql:
enabled: false
postgresql:
enabled: false
externalDatabase:
platform: postgresql
host: cnpg17-cluster-hk-rw.infra-data
port: 5432
user: app
password: from-secret
database: halo
existingSecret: cnpg17-cluster-hk-app
haloUsername: rohow
haloExternalUrl: https://dev.cm
+39
查看文件
@@ -0,0 +1,39 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: rustdesk
namespace: apps
spec:
interval: 30m
chart:
spec:
chart: rustdesk-server
version: 0.0.7
sourceRef:
kind: HelmRepository
name: devcm-repo
namespace: infra-gitops
interval: 12h
values:
rustdeskServer:
encryptedOnly: true
mustLogin: true
server: desk-server.dev.cm
podAnnotations:
backup.velero.io/backup-volumes: data
extraEnvs:
- name: TZ
value: "Asia/Shanghai"
- name: RUSTDESK_API_LANG
value: "zh-CN"
rustdeskApi:
server: desk.dev.cm
ingress:
enabled: true
className: "nginx"
host: desk.dev.cm
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/enable-websocket: "true"
+28
查看文件
@@ -0,0 +1,28 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: fillcode-whoami
namespace: apps
spec:
interval: 30m
chart:
spec:
chart: whoami
version: 5.1.2
sourceRef:
kind: HelmRepository
name: cowboysysop
namespace: infra-gitops
interval: 12h
values:
ingress:
enabled: true
ingressClassName: nginx
tls:
- hosts:
- whoami.fillcode.com
secretName: fillcode-com-crt
hosts:
- host: whoami.fillcode.com
paths:
- /
+22
查看文件
@@ -0,0 +1,22 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: fillcode
namespace: apps
spec:
ingressClassName: nginx
rules:
- host: fillcode.com
http:
paths:
- path: /docs/fillcode
pathType: Prefix
backend:
service:
name: halo
port:
number: 80
tls:
- hosts:
- fillcode.com
secretName: fillcode-com-crt
+30
查看文件
@@ -0,0 +1,30 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: halo-static
namespace: apps
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_cache cache;
proxy_cache_valid 200 302 7d;
proxy_cache_valid 404 10m;
proxy_cache_valid any 1h;
proxy_cache_use_stale error timeout updating http_404 http_500 http_502 http_503 http_504;
proxy_cache_bypass $http_x_purge;
proxy_ignore_headers Cache-Control;
add_header X-Cache-Status $upstream_cache_status;
spec:
ingressClassName: nginx
rules:
- host: dev.cm
http:
paths:
- path: /(.*\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2|ttf|eot)|avatars/[^/]+)$
pathType: ImplementationSpecific
backend:
service:
name: halo
port:
number: 80
+22
查看文件
@@ -0,0 +1,22 @@
# 如果检测到www.dev.cm的请求,则重定向到dev.cm
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: halo-www
namespace: apps
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/(.*)$ https://dev.cm/$1 permanent;
spec:
ingressClassName: nginx
rules:
- host: www.dev.cm
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: halo
port:
number: 80
+26
查看文件
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sinceai-shop
namespace: apps
annotations:
# 302 跳转到https://sinceai.taobao.com/
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/(.*)$ https://sinceai.taobao.com/$1? permanent;
spec:
ingressClassName: nginx
rules:
- host: shop.sinceai.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: halo
port:
number: 80
tls:
- hosts:
- shop.sinceai.com
secretName: sinceai-com-crt
+13
查看文件
@@ -0,0 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- certificate-fillcode-com.yaml
- certificate-sinceai-com.yaml
- helmrelease-halo.yaml
- ingress-fillcode.yaml
- ingress-halo-www.yaml
- ingress-halo-static.yaml
- ingress-sinceai-shop.yaml
- helmrelease-whoami.yaml
- helmrelease-rustdesk.yaml
+4
查看文件
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: apps
+17
查看文件
@@ -0,0 +1,17 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: apps
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/apps
prune: true
dependsOn:
- name: infra-data
- name: infra-net
- name: infra-gitops
+17
查看文件
@@ -0,0 +1,17 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-data
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/infra-data
prune: true
force: true
wait: true
dependsOn:
- name: infra-devops
+35
查看文件
@@ -0,0 +1,35 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-devops
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/infra-devops
prune: true
wait: true
dependsOn:
- name: sources
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-devops-post
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/infra-devops/post
prune: true
force: true
wait: true
dependsOn:
- name: infra-monitor
+17
查看文件
@@ -0,0 +1,17 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-gitops
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/infra-gitops
prune: true
wait: true
dependsOn:
- name: infra-data
- name: infra-monitor
+17
查看文件
@@ -0,0 +1,17 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-monitor
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/infra-monitor
prune: true
force: true
wait: true
dependsOn:
- name: infra-data
+18
查看文件
@@ -0,0 +1,18 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-net
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/infra-net
prune: true
wait: true
dependsOn:
- name: kube-system
- name: infra-devops
- name: infra-monitor
+14
查看文件
@@ -0,0 +1,14 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: kube-system
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/kube-system
prune: false
wait: true
+11
查看文件
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- sources.yaml
- kube-system.yaml
- infra-devops.yaml
- infra-data.yaml
- infra-net.yaml
- infra-monitor.yaml
- infra-gitops.yaml
- apps.yaml
+14
查看文件
@@ -0,0 +1,14 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: sources
namespace: infra-gitops
spec:
interval: 30m
retryInterval: 1m
sourceRef:
kind: GitRepository
name: flux
path: ./flux/infrastructure/sources
prune: true
wait: true
+29
查看文件
@@ -0,0 +1,29 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
patches:
- target:
kind: Kustomization
name: infra-devops
path: patches/infra-devops.yaml
- target:
kind: Kustomization
name: infra-data
path: patches/infra-data.yaml
- target:
kind: Kustomization
name: infra-net
path: patches/infra-net.yaml
- target:
kind: Kustomization
name: infra-monitor
path: patches/infra-monitor.yaml
- target:
kind: Kustomization
name: infra-gitops
path: patches/infra-gitops.yaml
- target:
kind: Kustomization
name: apps
path: patches/apps.yaml
+39
查看文件
@@ -0,0 +1,39 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: apps
spec:
patches:
- target:
kind: HelmRelease
name: halo
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: halo
spec:
values:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
cnpg.io/cluster: cnpg17-cluster-hk
role: primary
topologyKey: kubernetes.io/hostname
namespaceSelector: {}
- target:
kind: HelmRelease
name: rustdesk
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: rustdesk
spec:
values:
nodeSelector:
kubernetes.io/hostname: tcd
@@ -0,0 +1,120 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-data
spec:
patches:
- target:
kind: HelmRelease
name: cloudnative-pg
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cloudnative-pg
spec:
values:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
- target:
kind: HelmRelease
name: cloudnative-pg-plugin-barman
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cloudnative-pg-plugin-barman
spec:
values:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
- target:
kind: Cluster
name: cnpg17-cluster-hk
patch: |
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cnpg17-cluster-hk
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-hk"
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- clawhk
- target:
kind: Cluster
name: cnpg17-cluster-sh
patch: |
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cnpg17-cluster-sh
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- homea
- target:
kind: HelmRelease
name: valkey-cluster-sh
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: valkey-cluster-sh
spec:
values:
valkey:
nodeAffinityPreset:
type: hard
key: topology.kubernetes.io/region
values:
- cn-sh
@@ -0,0 +1,124 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-devops
spec:
patches:
- target:
kind: HelmRelease
name: cert-manager
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
spec:
values:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
webhook:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
cainjector:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
- target:
kind: HelmRelease
name: cert-manager-webhook-dnspod
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager-webhook-dnspod
spec:
values:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
- target:
kind: HelmRelease
name: reflector
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: reflector
spec:
values:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
- target:
kind: HelmRelease
name: velero
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: velero
spec:
values:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- homeb
nodeAgent:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: NotIn
values:
- "true"
- key: svccontroller.k3s.cattle.io/enablelb
operator: NotIn
values:
- "true"
@@ -0,0 +1,51 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-gitops
spec:
patches:
- target:
kind: HelmRelease
name: gitea
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: gitea
spec:
values:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
cnpg.io/cluster: cnpg17-cluster-sh
role: primary
app.kubernetes.io/name: redis
app.kubernetes.io/component: master
topologyKey: kubernetes.io/hostname
namespaceSelector: {}
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- homea
- target:
kind: HelmRelease
name: gitea-actions
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: gitea-actions
spec:
values:
statefulset:
nodeSelector:
dev-cm-runner/enabled: "true"
@@ -0,0 +1,86 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-monitor
spec:
patches:
- target:
kind: HelmRelease
name: loki
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: loki
spec:
values:
lokiCanary:
nodeSelector:
svccontroller.k3s.cattle.io/enablelb: "true"
resultsCache:
nodeSelector:
kubernetes.io/hostname: tce
chunksCache:
nodeSelector:
kubernetes.io/hostname: tce
singleBinary:
nodeSelector:
kubernetes.io/hostname: tce
- target:
kind: HelmRelease
name: loki-promtail
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: loki-promtail
spec:
values:
nodeSelector:
svccontroller.k3s.cattle.io/enablelb: "true"
- target:
kind: HelmRelease
name: prometheus
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: prometheus
spec:
values:
prometheusOperator:
nodeSelector:
kubernetes.io/hostname: hwa
kube-state-metrics:
nodeSelector:
kubernetes.io/hostname: hwa
grafana:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
cnpg.io/cluster: cnpg17-cluster-sh
role: primary
topologyKey: kubernetes.io/hostname
namespaceSelector: {}
persistence:
storageClassName: local-path
prometheus:
prometheusSpec:
nodeSelector:
kubernetes.io/hostname: hwa
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: local-path
alertmanager:
alertmanagerSpec:
nodeSelector:
kubernetes.io/hostname: hwa
storage:
volumeClaimTemplate:
spec:
storageClassName: local-path
@@ -0,0 +1,95 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-net
spec:
patches:
- target:
kind: HelmRelease
name: ingress-nginx
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: ingress-nginx
spec:
values:
controller:
nodeSelector:
svccontroller.k3s.cattle.io/enablelb: "true"
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
dnsPolicy: "None"
dnsConfig:
nameservers:
- "169.254.20.10"
- "10.43.0.10"
maxmindLicenseKey: "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"
defaultBackend:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- "cn-sh"
- "cn-hk"
- target:
kind: HelmRelease
name: crowdsec
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: crowdsec
spec:
values:
agent:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: loki
topologyKey: kubernetes.io/hostname
namespaceSelector: {}
appsec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- cn-hk
lapi:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- cn-hk
- target:
kind: HelmRelease
name: tailscale-derp-hk
patch: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: tailscale-derp-hk
spec:
values:
nodeSelector:
kubernetes.io/hostname: tchk
+4
查看文件
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
+48
查看文件
@@ -0,0 +1,48 @@
apiVersion: fluxcd.controlplane.io/v1
kind: FluxInstance
metadata:
name: flux
namespace: infra-gitops
spec:
distribution:
version: "2.x"
registry: "ghcr.io/fluxcd"
artifact: "oci://ghcr.io/controlplaneio-fluxcd/flux-operator-manifests"
components:
- source-controller
- kustomize-controller
- helm-controller
- notification-controller
cluster:
type: kubernetes
size: small
multitenant: false
networkPolicy: true
domain: "cluster.local"
storage:
class: "local-path"
size: "10Gi"
# Git 仓库同步配置 - 请将 url 替换为实际的 deploy 仓库地址
sync:
kind: GitRepository
url: https://git.dev.cm/devcm/deploy.git
ref: refs/heads/main
path: flux/clusters/dev-cm
pullSecret: flux-git-auth
kustomize:
patches:
- target:
kind: Deployment
patch: |
- op: add
path: /spec/template/spec/affinity
value:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- homea
@@ -0,0 +1,42 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cnpg17-cluster-hk
namespace: infra-data
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:17.4
enableSuperuserAccess: true
enablePDB: false
instances: 1
storage:
size: 10Gi
postgresql:
parameters:
archive_timeout: 30min
env:
- name: AWS_REQUEST_CHECKSUM_CALCULATION
value: when_required
- name: AWS_RESPONSE_CHECKSUM_VALIDATION
value: when_required
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: cnpg17-objectstore-hw
serverName: cnpg17-cluster-hk
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: cnpg17-cluster-hk-backups
namespace: infra-data
spec:
schedule: "0 0 0 * * *"
immediate: true
backupOwnerReference: self
method: plugin
pluginConfiguration:
name: barman-cloud.cloudnative-pg.io
cluster:
name: cnpg17-cluster-hk
@@ -0,0 +1,42 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cnpg17-cluster-sh
namespace: infra-data
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:17.4
enableSuperuserAccess: true
enablePDB: false
instances: 1
storage:
size: 10Gi
postgresql:
parameters:
archive_timeout: 30min
env:
- name: AWS_REQUEST_CHECKSUM_CALCULATION
value: when_required
- name: AWS_RESPONSE_CHECKSUM_VALIDATION
value: when_required
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: cnpg17-objectstore-hw
serverName: cnpg17-cluster-sh
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: cnpg17-cluster-sh-backups
namespace: infra-data
spec:
schedule: "0 0 0 * * *"
immediate: true
backupOwnerReference: self
method: plugin
pluginConfiguration:
name: barman-cloud.cloudnative-pg.io
cluster:
name: cnpg17-cluster-sh
@@ -0,0 +1,20 @@
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: cnpg17-objectstore-hw
namespace: infra-data
spec:
retentionPolicy: "7d"
configuration:
destinationPath: s3://devcm/cnpg/
endpointURL: https://obs.cn-east-3.myhuaweicloud.com
s3Credentials:
accessKeyId:
name: s3-devcm-hw
key: ACCESS_KEY_ID
secretAccessKey:
name: s3-devcm-hw
key: ACCESS_SECRET_KEY
wal:
compression: gzip
maxParallel: 8
@@ -0,0 +1,18 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cloudnative-pg-plugin-barman
namespace: infra-data
spec:
interval: 30m
dependsOn:
- name: cloudnative-pg
chart:
spec:
chart: plugin-barman-cloud
version: 0.5.0
sourceRef:
kind: HelmRepository
name: cloudnative-pg
namespace: infra-gitops
interval: 12h
@@ -0,0 +1,20 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cloudnative-pg
namespace: infra-data
spec:
interval: 30m
chart:
spec:
chart: cloudnative-pg
version: 0.27.1
sourceRef:
kind: HelmRepository
name: cloudnative-pg
namespace: infra-gitops
interval: 12h
install:
crds: CreateReplace
upgrade:
crds: CreateReplace
@@ -0,0 +1,22 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: valkey-cluster-sh
namespace: infra-data
spec:
interval: 30m
chart:
spec:
chart: valkey-cluster
version: 3.0.23
sourceRef:
kind: HelmRepository
name: bitnami
namespace: infra-gitops
interval: 12h
values:
image:
repository: bitnamilegacy/valkey-cluster
cluster:
nodes: 1
replicas: 0
@@ -0,0 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- helmrelease-cloudnative-pg.yaml
- helmrelease-barman-plugin.yaml
- cnpg17-objectstore-hw.yaml
- cnpg17-cluster-hk.yaml
- cnpg17-cluster-sh.yaml
- loadbalancer-hk.yaml
- loadbalancer-sh.yaml
- helmrelease-valkey-cluster.yaml
- reflector-secret-annotations.yaml
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: cnpg17-cluster-hk-lb
namespace: infra-data
spec:
selector:
cnpg.io/cluster: cnpg17-cluster-hk
role: primary
ports:
- protocol: TCP
port: 65432
targetPort: 5432
type: LoadBalancer
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: cnpg17-cluster-sh-lb
namespace: infra-data
spec:
selector:
cnpg.io/cluster: cnpg17-cluster-sh
role: primary
ports:
- protocol: TCP
port: 65431
targetPort: 5432
type: LoadBalancer
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: infra-data
@@ -0,0 +1,41 @@
# 给CNPG和Valkey自动生成的secrets添加Reflector注解
# 通过SSA force合并注解到已有secrets 使其自动复制到消费方命名空间
#
# cnpg17-cluster-hk-app → apps (halo), infra-net (crowdsec)
# cnpg17-cluster-sh-app → infra-gitops (gitea), infra-monitor (grafana)
# valkey-cluster-sh → infra-gitops (gitea)
apiVersion: v1
kind: Secret
metadata:
name: cnpg17-cluster-hk-app
namespace: infra-data
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "apps,infra-net"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "apps,infra-net"
---
apiVersion: v1
kind: Secret
metadata:
name: cnpg17-cluster-sh-app
namespace: infra-data
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "infra-gitops,infra-monitor"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "infra-gitops,infra-monitor"
---
apiVersion: v1
kind: Secret
metadata:
name: valkey-cluster-sh
namespace: infra-data
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "infra-gitops"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "infra-gitops"
@@ -0,0 +1,26 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: dnspod
labels:
app: cert-manager-webhook-dnspod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@dev.cm
privateKeySecretRef:
name: cert-manager-webhook-dnspod-letsencrypt
solvers:
- dns01:
cnameStrategy: Follow
webhook:
groupName: cert.dev.cm
solverName: dnspod
config:
ttl: 600
secretIdRef:
name: dnspod-secret
key: secretId
secretKeyRef:
name: dnspod-secret
key: secretKey
@@ -0,0 +1,29 @@
# 安装后需要将clusterIssuer的cnameStrategy策略设置为Follow
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager-webhook-dnspod
namespace: infra-devops
spec:
interval: 30m
dependsOn:
- name: cert-manager
chart:
spec:
chart: cert-manager-webhook-dnspod
version: 1.4.5
sourceRef:
kind: HelmRepository
name: imroc
namespace: infra-gitops
interval: 12h
values:
image:
tag: "1.5.2"
namespace: infra-devops
certManager:
namespace: infra-devops
groupName: cert.dev.cm
# 此处关闭 选择手动创建 以支持cnameStrategy
clusterIssuer:
enabled: false
@@ -0,0 +1,31 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
namespace: infra-devops
spec:
interval: 30m
chart:
spec:
chart: cert-manager
version: v1.19.3
sourceRef:
kind: HelmRepository
name: jetstack
namespace: infra-gitops
interval: 12h
install:
crds: CreateReplace
upgrade:
crds: CreateReplace
# 首次install时servicemonitor=false(CRD尚不存在)
# infra-monitor层部署后通过SSA patch开启
values:
crds:
enabled: true
keep: true
enableCertificateOwnerRef: true
prometheus:
enabled: true
servicemonitor:
enabled: false
@@ -0,0 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: reflector
namespace: infra-devops
spec:
interval: 30m
chart:
spec:
chart: reflector
version: 9.1.45
sourceRef:
kind: HelmRepository
name: emberstack
namespace: infra-gitops
interval: 12h
values: {}
@@ -0,0 +1,60 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: velero
namespace: infra-devops
spec:
interval: 30m
chart:
spec:
chart: velero
version: 11.3.2
sourceRef:
kind: HelmRepository
name: vmware-tanzu
namespace: infra-gitops
interval: 12h
values:
# 此处暂时切换关闭upgradeCRDs操作 待官方修复后再开启
upgradeCRDs: false
deployNodeAgent: true
snapshotsEnabled: false
configuration:
backupSyncPeriod: 1h0m0s
defaultRepoMaintainFrequency: 3h0m0s
repositoryMaintenanceJob:
repositoryConfigData:
global:
keepLatestMaintenanceJobs: 1
backupStorageLocation:
- name: devcm-hw
default: true
provider: aws
bucket: devcm
prefix: velero
config:
region: cn-east-3
s3ForcePathStyle: false
s3Url: https://obs.cn-east-3.myhuaweicloud.com
checksumAlgorithm: ""
extraEnvVars:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-devcm-hw
key: ACCESS_KEY_ID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-devcm-hw
key: ACCESS_SECRET_KEY
credentials:
useSecret: false
initContainers:
- name: velero-plugin-for-aws
image: velero/velero-plugin-for-aws:v1.13.0
volumeMounts:
- mountPath: /target
name: plugins
nodeAgent:
# 控制面板不启用 lb节点不启用
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- helmrelease-cert-manager.yaml
- helmrelease-cert-manager-webhook-dnspod.yaml
- clusterissuer-dnspod.yaml
- helmrelease-reflector.yaml
- helmrelease-velero.yaml
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: infra-devops
@@ -0,0 +1,17 @@
# 在prometheus-stack部署后 通过SSA patch cert-manager开启ServiceMonitor
# cert-manager初始安装时servicemonitor.enabled=false(CRD尚不存在)
# infra-monitor层部署时CRD已就绪 此patch合并到已有HelmRelease
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
namespace: infra-devops
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
values:
prometheus:
servicemonitor:
enabled: true
interval: 300s
prometheusInstance: kube-prometheus
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- helmrelease-cert-manager-patch.yaml
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-actions-dind-config
namespace: infra-gitops
data:
daemon.json: |-
{
"mtu": 1280
}
@@ -0,0 +1,31 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-custom-templates
namespace: infra-gitops
data:
home.tmpl: |-
{{template "base/head" .}}
<div class="page-content home">
<div class="ui stackable middle very relaxed page grid">
<div class="sixteen wide center aligned centered column">
<div>
<img class="logo" width="220" height="220" src="{{AssetUrlPrefix}}/img/logo.svg"/>
</div>
<div class="hero">
<h1 class="ui icon header title">
{{AppName}}
</h1>
<h2><a href="https://dev.cm">Dev.cm</a> - Git {{ctx.Locale.Tr "repository"}}</h2>
</div>
</div>
</div>
</div>
{{template "base/footer" .}}
extra_links.tmpl: |-
<a class="item" href="https://dev.cm" target="_blank">{{if eq ctx.Locale.Lang "zh-CN"}}博客{{else}}Blog{{end}}</a>
<a class="item extra-links-end" href="https://fillcode.com" target="_blank">Fillcode</a>
<style>
.extra-links-end ~ a { display:none !important; }
</style>
@@ -0,0 +1,47 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: gitea-actions
namespace: infra-gitops
spec:
interval: 30m
dependsOn:
- name: gitea
chart:
spec:
chart: actions
version: 0.0.2
sourceRef:
kind: HelmRepository
name: gitea
namespace: infra-gitops
interval: 12h
values:
enabled: true
statefulset:
actRunner:
config: |
log:
level: info
cache:
enabled: true
container:
require_docker: true
docker_timeout: 300s
# 使用bridge网络模式,解决新建任务临时网络mtu与主机不一致的问题
network: bridge
dind:
# 挂载dind docker配置文件,解决mtu带来的网络问题
extraVolumeMounts:
- name: dind-config-volume
mountPath: /etc/docker/daemon.json
subPath: daemon.json
extraVolumes:
- name: dind-config-volume
configMap:
name: gitea-actions-dind-config
persistence:
size: 10Gi
giteaRootURL: http://gitea-http.infra-gitops.svc.cluster.local:3000
existingSecret: gitea-actions
existingSecretKey: token
@@ -0,0 +1,111 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: gitea
namespace: infra-gitops
spec:
interval: 30m
chart:
spec:
chart: gitea
version: 12.5.0
sourceRef:
kind: HelmRepository
name: gitea
namespace: infra-gitops
interval: 12h
values:
redis-cluster:
enabled: false
postgresql-ha:
enabled: false
image:
tag: 1.25.5
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Accept-Encoding "";
subs_filter_types text/html;
subs_filter '<(script|img|link)([^>]*) (src|href)="/' '<$1$2 $3="https://cdn.fillcode.com/git-dev-cm/' ri;
subs_filter 'url\(\/' 'url(https://cdn.fillcode.com/git-dev-cm/' ri;
subs_filter '<head>' '<head><script src="/__static/pwa-cdn.js"></script>' ri;
hosts:
- host: git.dev.cm
paths:
- path: /
pathType: Prefix
gitea:
podAnnotations:
backup.velero.io/backup-volumes: data
config:
APP_NAME: Git Dev.cm
RUN_MODE: prod
server:
DOMAIN: git.dev.cm
ROOT_URL: https://git.dev.cm/
database:
DB_TYPE: postgres
HOST: cnpg17-cluster-sh-rw.infra-data:5432
NAME: gitea
USER: app
SSL_MODE: disable
session:
PROVIDER: redis
cache:
ADAPTER: redis
queue:
TYPE: redis
repository:
DEFAULT_REPO_UNITS: repo.code,repo.releases,repo.issues,repo.pulls
actions:
ENABLED: true
DEFAULT_ACTIONS_URL: github
service:
DISABLE_REGISTRATION: true
NO_REPLY_ADDRESS: noreply.dev.cm
picture:
GRAVATAR_SOURCE: https://cravatar.cn/avatar/
i18n:
LANGS: zh-CN,en-US
NAMES: 简体中文,English
other:
SHOW_FOOTER_VERSION: false
SHOW_FOOTER_POWERED_BY: false
log:
LEVEL: Info
ui:
THEMES: gitea-auto, gitea-light, gitea-dark, github-auto, github-light, github-dark, github-soft-dark
DEFAULT_THEME: github-auto
additionalConfigFromEnvs:
- name: GITEA__DATABASE__PASSWD
valueFrom:
secretKeyRef:
name: cnpg17-cluster-sh-app
key: password
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: valkey-cluster-sh
key: valkey-password
- name: GITEA__SESSION__PROVIDER_CONFIG
value: "redis://:$(REDIS_PASSWORD)@valkey-cluster-sh-headless.infra-data:6379/0?pool_size=100&idle_timeout=180s"
- name: GITEA__CACHE__HOST
value: "redis://:$(REDIS_PASSWORD)@valkey-cluster-sh-headless.infra-data:6379/0?pool_size=100&idle_timeout=180s"
- name: GITEA__QUEUE__CONN_STR
value: "redis://:$(REDIS_PASSWORD)@valkey-cluster-sh-headless.infra-data:6379/0?pool_size=100&idle_timeout=180s"
valkey-cluster:
enabled: false
extraVolumes:
- name: gitea-custom-templates-volume
configMap:
name: gitea-custom-templates
extraContainerVolumeMounts:
- name: gitea-custom-templates-volume
subPath: home.tmpl
mountPath: /data/gitea/templates/home.tmpl
- name: gitea-custom-templates-volume
subPath: extra_links.tmpl
mountPath: /data/gitea/templates/custom/extra_links.tmpl
@@ -0,0 +1,30 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-static
namespace: infra-gitops
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_cache cache;
proxy_cache_valid 200 302 7d;
proxy_cache_valid 404 10m;
proxy_cache_valid any 1h;
proxy_cache_use_stale error timeout updating http_404 http_500 http_502 http_503 http_504;
proxy_cache_bypass $http_x_purge;
proxy_ignore_headers Cache-Control;
add_header X-Cache-Status $upstream_cache_status;
spec:
ingressClassName: nginx
rules:
- host: git.dev.cm
http:
paths:
- path: /(.*\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2|ttf|eot)|avatars/[^/]+)$
pathType: ImplementationSpecific
backend:
service:
name: gitea-http
port:
number: 3000
@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- helmrelease-gitea.yaml
- helmrelease-gitea-actions.yaml
- configmap-templates.yaml
- configmap-actions-dind.yaml
- ingress-static-gitea.yaml
- loadbalancer-ssh.yaml
- networkpolicy-gitea.yaml
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: gitea-ssh-lb
namespace: infra-gitops
spec:
selector:
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
ports:
- protocol: TCP
port: 22
targetPort: 2222
type: LoadBalancer
@@ -0,0 +1,16 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-gitea
namespace: infra-gitops
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: gitea
ingress:
- {}
egress:
- {}
policyTypes:
- Ingress
- Egress
@@ -0,0 +1,57 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: loki
namespace: infra-monitor
spec:
interval: 30m
chart:
spec:
chart: loki
version: 6.53.0
sourceRef:
kind: HelmRepository
name: grafana
namespace: infra-gitops
interval: 12h
values:
deploymentMode: SingleBinary
gateway:
enabled: false
lokiCanary:
extraArgs:
# 降低测试日志生成条数
- -interval=30s
- -labelname=service_name
- -labelvalue=loki-canary
resultsCache:
allocatedMemory: 1024
chunksCache:
allocatedMemory: 1024
loki:
auth_enabled: false
commonConfig:
replication_factor: 1
limits_config:
reject_old_samples_max_age: 168h
max_query_series: 10000
volume_enabled: true
storage:
type: "filesystem"
schemaConfig:
configs:
- from: "2024-01-01"
store: tsdb
index:
prefix: loki_index_
period: 24h
object_store: filesystem
schema: v13
singleBinary:
replicas: 1
read:
replicas: 0
backend:
replicas: 0
write:
replicas: 0
@@ -0,0 +1,119 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: prometheus
namespace: infra-monitor
spec:
interval: 30m
chart:
spec:
chart: kube-prometheus-stack
version: 81.6.5
sourceRef:
kind: HelmRepository
name: prometheus-community
namespace: infra-gitops
interval: 12h
install:
crds: CreateReplace
upgrade:
crds: CreateReplace
values:
kubeControllerManager:
enabled: false
kubeScheduler:
enabled: false
kubeProxy:
enabled: false
kubeEtcd:
enabled: false
prometheusOperator: {}
kube-state-metrics: {}
grafana:
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Accept-Encoding "";
subs_filter_types text/html;
subs_filter '<(script|img|link)([^>]*) (src|href)="/' '<$1$2 $3="https://cdn.fillcode.com/monitor-dev-cm/' ri;
subs_filter 'url\(\/' 'url(https://cdn.fillcode.com/monitor-dev-cm/' ri;
subs_filter '<head>' '<head><script src="/__static/pwa-cdn.js"></script>' ri;
hosts:
- monitor.dev.cm
paths:
- /
assertNoLeakedSecrets: false
envValueFrom:
GF_DATABASE_PASSWORD:
secretKeyRef:
name: cnpg17-cluster-sh-app
key: password
grafana.ini:
server:
root_url: https://monitor.dev.cm/
public_dashboards:
enabled: false
help:
enabled: false
news:
news_feed_enabled: false
database:
type: postgres
host: cnpg17-cluster-sh-rw.infra-data:5432
name: grafana
user: app
password: $__env{GF_DATABASE_PASSWORD}
persistence:
type: pvc
enabled: true
accessModes:
- ReadWriteOnce
size: 10Gi
prometheus:
prometheusSpec:
storageSpec:
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
routePrefix: /prometheus
serviceMonitorSelectorNilUsesHelmValues: false
podMonitorSelectorNilUsesHelmValues: false
ruleSelectorNilUsesHelmValues: false
scrapeInterval: 1m
ingress:
enabled: false
ingressClassName: nginx
hosts:
- monitor.dev.cm
paths:
- /prometheus
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
routePrefix: /alertmanager
ingress:
enabled: false
ingressClassName: nginx
hosts:
- monitor.dev.cm
paths:
- /alertmanager
@@ -0,0 +1,36 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: loki-promtail
namespace: infra-monitor
spec:
interval: 30m
dependsOn:
- name: loki
chart:
spec:
chart: promtail
sourceRef:
kind: HelmRepository
name: grafana
namespace: infra-gitops
interval: 12h
values:
configmap:
enabled: true
config:
clients:
- url: http://loki.infra-monitor:3100/loki/api/v1/push
tenant_id: 1
snippets:
extraRelabelConfigs:
# 匹配 devcm-log-collecting/enabled 标签 只有为true时才收集日志
- source_labels:
[__meta_kubernetes_pod_label_devcm_log_collecting_enabled]
action: keep
regex: true
# 匹配 devcm-log-collecting/only-errors标签并只保留stderr流
- source_labels:
[__meta_kubernetes_pod_label_devcm_log_collecting_only_errors]
action: drop
regex: stdout
@@ -0,0 +1,30 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grafana-static
namespace: infra-monitor
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_cache cache;
proxy_cache_valid 200 302 7d;
proxy_cache_valid 404 10m;
proxy_cache_valid any 1h;
proxy_cache_use_stale error timeout updating http_404 http_500 http_502 http_503 http_504;
proxy_cache_bypass $http_x_purge;
proxy_ignore_headers Cache-Control;
add_header X-Cache-Status $upstream_cache_status;
spec:
ingressClassName: nginx
rules:
- host: monitor.dev.cm
http:
paths:
- path: /(.*\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2|ttf|eot)|avatars/[^/]+)$
pathType: ImplementationSpecific
backend:
service:
name: prometheus-grafana
port:
number: 80
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- helmrelease-loki.yaml
- helmrelease-promtail.yaml
- helmrelease-prometheus.yaml
- ingress-static-grafana.yaml
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: infra-monitor
@@ -0,0 +1,15 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dev-cm-crt
namespace: infra-net
spec:
secretName: dev-cm-crt
issuerRef:
name: dnspod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "dev.cm"
- "*.dev.cm"
- "*.node.dev.cm"
@@ -0,0 +1,461 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: static
namespace: infra-net
data:
captcha.html: |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width,initial-scale=1,user-scalable=no,viewport-fit=cover" name="viewport">
<title>出于安全原因 请完成验证</title>
<script src="{{captcha_frontend_js}}" async defer></script>
<style>
* {
-webkit-box-sizing: border-box;
box-sizing: border-box
}
body {
padding: 0;
margin: 0
}
#error {
position: relative;
height: 100vh
}
#error .error {
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%)
}
#error .error-bg {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden
}
#error .error-bg > div {
position: absolute;
top: 0;
bottom: 0;
width: 1px;
background-color: #eee
}
#error .error-bg > div:nth-child(1) {
left: 20%
}
#error .error-bg > div:nth-child(2) {
left: 40%
}
#error .error-bg > div:nth-child(3) {
left: 60%
}
#error .error-bg > div:nth-child(4) {
left: 80%
}
#error .error-bg > div:after {
content: '';
position: absolute;
top: 0;
left: -.5px;
-webkit-transform: translateY(-160px);
-ms-transform: translateY(-160px);
transform: translateY(-160px);
height: 160px;
width: 2px;
background-color: #1cfafe
}
@-webkit-keyframes drop {
90% {
height: 20px
}
100% {
height: 160px;
-webkit-transform: translateY(calc(100vh + 160px));
transform: translateY(calc(100vh + 160px))
}
}
@keyframes drop {
90% {
height: 20px
}
100% {
height: 160px;
-webkit-transform: translateY(calc(100vh + 160px));
transform: translateY(calc(100vh + 160px))
}
}
#error .error-bg > div:nth-child(1):after {
-webkit-animation: drop 3s infinite linear;
animation: drop 3s infinite linear;
-webkit-animation-delay: .2s;
animation-delay: .2s
}
#error .error-bg > div:nth-child(2):after {
-webkit-animation: drop 2s infinite linear;
animation: drop 2s infinite linear;
-webkit-animation-delay: .7s;
animation-delay: .7s
}
#error .error-bg > div:nth-child(3):after {
-webkit-animation: drop 3s infinite linear;
animation: drop 3s infinite linear;
-webkit-animation-delay: .9s;
animation-delay: .9s
}
#error .error-bg > div:nth-child(4):after {
-webkit-animation: drop 2s infinite linear;
animation: drop 2s infinite linear;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s
}
.error {
max-width: 520px;
width: 100%;
padding: 20px;
text-align: center
}
.error .error-code {
height: 210px;
line-height: 210px
}
.error .error-code h1 {
font-family: oswald, sans-serif;
font-size: 80px;
font-weight: 700;
margin: 0;
text-shadow: 4px 4px 0 #1cfafe
}
.error h2 {
font-family: oswald, sans-serif;
font-size: 42px;
font-weight: 700;
margin: 0;
text-transform: uppercase;
letter-spacing: 1.6px
}
.error p {
font-family: lato, sans-serif;
color: #000;
font-weight: 400;
margin-top: 20px;
margin-bottom: 25px
}
.error a {
font-family: lato, sans-serif;
padding: 10px 30px;
display: inline-block;
color: #000;
font-weight: 400;
text-transform: uppercase;
-webkit-box-shadow: 0 0 0 2px #000, 2px 2px 0 2px #1cfafe;
box-shadow: 0 0 0 2px #000, 2px 2px 0 2px #1cfafe;
text-decoration: none;
-webkit-transition: .2s all;
transition: .2s all
}
.error a:not(:first-of-type) {
margin-left: 20px
}
.error a:hover {
background-color: #1cfafe;
-webkit-box-shadow: 0 0 0 0 #000, 0 0 0 2px #1cfafe;
box-shadow: 0 0 0 0 #000, 0 0 0 2px #1cfafe
}
.error-social > a {
width: 40px;
height: 40px;
line-height: 40px;
padding: 0;
margin: 0 5px
}
.error-social > a:hover {
background-color: #1cfafe;
-webkit-box-shadow: 0 0 0 0 #000, 0 0 0 2px #1cfafe;
box-shadow: 0 0 0 0 #000, 0 0 0 2px #1cfafe
}
#captcha-form {
position: relative;
width: 300px;
height: 65px;
overflow: hidden;
margin: 0 auto 30px;
background-color: #fff;
-webkit-box-shadow: 0 0 0 2px #000, 2px 2px 0 2px #1cfafe;
box-shadow: 0 0 0 2px #000, 2px 2px 0 2px #1cfafe;
}
.loading {
position: absolute;
top: 0;
left: 0;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 65px;
gap: 10px;
}
.loading:has(+ *) {
display: none;
}
.loading::before {
content: "";
width: 20px;
height: 20px;
border: 2px solid #000;
border-right-color: #1cfafe;
border-radius: 50%;
animation: spin 1s linear infinite;
}
#captcha {
position: relative;
z-index: 2;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media only screen and (max-width: 480px) {
.error .error-code {
height: 122px;
line-height: 122px
}
.error .error-code h1 {
font-size: 60px
}
.error h2 {
font-size: 26px
}
}
</style>
</head>
<body>
<div id="error">
<div class="error-bg">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="error">
<div class="error-code">
<h1>FillCode</h1>
</div>
<h2>请完成验证</h2>
<p>请完成下面验证, 页面将会自动跳转到访问页面。</p>
<form id="captcha-form" method="POST">
<div id="captcha" class="{{captcha_frontend_key}}" data-sitekey="{{captcha_site_key}}"
data-callback="captchaCallback" data-size="flexible"></div>
<div class="loading">验证码加载中, 请稍等...</div>
</form>
<a href="mailto:admin@dev.cm">联系我们</a>
</div>
</div>
<script>
function captchaCallback() {
setTimeout(() => document.querySelector('#captcha-form').submit(), 500)
}
</script>
</body>
</html>
pwa-cdn.js: |
'use strict'
// 配置
const pwaCdnConfig = {
cdnUrl: 'https://cdn.fillcode.com/',
serviceWorkerUrl: '/__static/sw-cdn.js',
staticRegex: /\.(js|css|png|jpg|jpeg|gif|svg|webp|woff|woff2|ttf|ico)$/,
debug: false,
}
/**
* PWA 初始化函数
*/
async function initializePWA() {
// 检查支持
if (!('serviceWorker' in navigator)) return console.log('PWA-CDN: Service Worker not supported')
let registration;
try {
// 注册Service Worker - 使用相对路径
registration = await navigator.serviceWorker.register(pwaCdnConfig.serviceWorkerUrl, {scope: '/'})
console.log('PWA-CDN: Service Worker registered')
} catch (error) {
console.error('PWA-CDN: Failed to register Service Worker:', error)
}
// 发送初始配置
const sendConfig = () => {
registration.active.postMessage({type: 'CONFIG', config: pwaCdnConfig})
}
// 如果注册失败,直接返回错误
if(!registration) return console.error('PWA-CDN: Service Worker registration failed, cannot send config')
// 更新配置函数
window.updatePWACDNConfig = (newConfig) => {
Object.assign(pwaCdnConfig, newConfig)
sendConfig()
}
// 等待Service Worker激活后发送配置
if (registration.active) sendConfig()
// 监听Service Worker更新事件
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'activated') sendConfig()
})
})
}
/**
* 启动 PWA-CDN
* */
initializePWA().catch(console.error)
sw-cdn.js: |
'use strict'
// Service Worker 配置 - 默认值
let config = {
cdnUrl: 'https://cdn.fillcode.com/',
serviceWorkerUrl: '/__static/sw-cdn.js',
staticRegex: /(.*\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2|ttf|eot)|avatars[^/]+)$/,
debug: false,
}
// 监听配置更新消息
self.addEventListener('message', e => {
if (e.data.type !== 'CONFIG') return
config = e.data.config
if (config.debug) console.log('PWA-CDN: Config updated', config)
})
// 拦截网络请求
self.addEventListener('fetch', e => {
const url = new URL(e.request.url)
// 如果请求不是GET方法,直接返回
if (e.request.method !== 'GET') return
// 如果请求的域名不是当前页面的域名
if (url.origin !== self.location.origin) return
// 过滤__static路径下的请求
if (url.pathname.startsWith('/__static/')) return
// 如果请求的路径不匹配静态资源正则表达式,直接返回
if (!config.staticRegex.test(url.pathname)) return
// 判断是否是强制需要同源请求
const requiresSameOrigin = ['worker', 'sharedworker', 'serviceworker'].includes(e.request.destination)
// 如果是强制需要同源请求的资源类型,直接返回
if (requiresSameOrigin) return
// 开始处理静态资源请求
e.respondWith(handleStaticResource(e.request, url))
})
// 处理静态资源请求
async function handleStaticResource(request, url) {
// 生成CDN子路径
const hostname = self.location.hostname
const cdnPath = hostname.replace(/\./g, '-')
const targetUrl = config.cdnUrl + cdnPath + url.pathname + url.search
if (config.debug) console.log('PWA-CDN:', url.href, '->', targetUrl)
try {
// 创建新请求
const newRequest = new Request(targetUrl, {
...request,
mode: 'cors',
redirect: 'error',
})
// 请求目标域名,浏览器会自动处理缓存
const response = await fetch(newRequest)
// 检查响应状态
if (!response.ok) throw new Error('PWA-CDN: Non-2xx response detected')
return response
} catch (error) {
if (config.debug) console.warn('PWA-CDN: Fallback to original request for', url.href, error)
// 失败时回退到原始请求
return fetch(request)
}
}
// Service Worker 生命周期
self.addEventListener('install', () => {
if (config.debug) console.log('PWA-CDN: Service Worker installing')
self.skipWaiting().catch(console.error)
})
self.addEventListener('activate', () => {
if (config.debug) console.log('PWA-CDN: Service Worker activated')
self.clients.claim().catch(console.error)
})
@@ -0,0 +1,217 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: crowdsec
namespace: infra-net
spec:
interval: 30m
dependsOn:
- name: ingress-nginx
- name: loki
namespace: infra-monitor
chart:
spec:
chart: crowdsec
version: 0.22.0
sourceRef:
kind: HelmRepository
name: crowdsec
namespace: infra-gitops
interval: 12h
values:
container_runtime: containerd
image:
tag: v1.7.6
agent:
isDeployment: true
additionalAcquisition:
- source: loki
log_level: info
url: http://loki.infra-monitor:3100/
limit: 1000
query: |
{job="infra-net/ingress-nginx"}
labels:
type: nginx
env:
- name: COLLECTIONS
value: "crowdsecurity/base-http-scenarios crowdsecurity/http-dos"
- name: SCENARIOS
value: "crowdsecurity/nginx-req-limit-exceeded"
persistentVolume:
config:
enabled: false
appsec:
enabled: false
acquisitions:
- source: appsec
listen_addr: "0.0.0.0:7422"
path: /
appsec_config: crowdsecurity/crs-vpatch
labels:
type: appsec
configs:
mycustom-appsec-config.yaml: |
name: crowdsecurity/crs-vpatch
default_remediation: ban
#log_level: debug
outofband_rules:
- crowdsecurity/crs
inband_rules:
- crowdsecurity/base-config
- crowdsecurity/vpatch-*
env:
- name: COLLECTIONS
value: "crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-crs"
lapi:
resources:
requests:
cpu: 150m
memory: 100Mi
persistentVolume:
config:
enabled: false
data:
enabled: false
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: cnpg17-cluster-hk-app
key: password
config:
# api config.yaml配置
config.yaml.local: |
db_config:
type: postgresql
host: cnpg17-cluster-hk-rw.infra-data
port: 5432
db_name: crowdsec
user: app
password: ${DB_PASSWORD}
sslmode: require
api:
server:
auto_registration:
enabled: true
token: "${REGISTRATION_TOKEN}"
allowed_ranges:
- "127.0.0.1/32"
- "192.168.0.0/16"
- "172.16.0.0/12"
- "10.0.0.0/8"
# api profiles.yaml配置
profiles.yaml: |
name: captcha_remediation
filters:
# 规则过滤条件 1.范围为Ip 2.触发场景为http或nginx 3.24小时内决策次数小于等于3
- Alert.Remediation == true && Alert.GetScope() == "Ip" &&
(Alert.GetScenario() contains "http" || Alert.GetScenario() contains "nginx") &&
GetDecisionsSinceCount(Alert.GetValue(), "24h") <= 3
decisions:
- type: captcha
duration: 4h
on_success: break
---
name: default_ip_remediation
filters:
- Alert.Remediation == true && Alert.GetScope() == "Ip"
decisions:
- type: ban
duration: 4h
on_success: break
---
name: default_range_remediation
filters:
- Alert.Remediation == true && Alert.GetScope() == "Range"
decisions:
- type: ban
duration: 4h
on_success: break
# agent parsers 配置
parsers:
s01-parse:
# 新增nginx json日志解析
nginx-logs.yaml: |
filter: "evt.Parsed.program startsWith 'nginx'"
onsuccess: next_stage
name: crowdsecurity/nginx-logs
description: "Parse nginx access and error logs"
pattern_syntax:
NGCUSTOMURIPATH: "(?:/[A-Za-z0-9$.+!*'\\(\\)\\{\\},~:;=@\\#%&_\\-]*)+"
NGCUSTOMURIPATHPARAM: '%{NGCUSTOMURIPATH}(?:%{URIPARAM})?'
nodes:
# nginx access logs
- filter: TrimSpace(evt.Parsed.message) startsWith "{" && UnmarshalJSON(evt.Parsed.message, evt.Unmarshaled, "nginx") in ["", nil]
statics:
- meta: service
value: http
- meta: log_type
value: http_access-log
- target: evt.StrTime
expression: evt.Unmarshaled.nginx.time_local
- meta: source_ip
expression: evt.Unmarshaled.nginx.remote_addr
- meta: http_status
expression: evt.Unmarshaled.nginx.status
- meta: http_path
expression: evt.Unmarshaled.nginx.request_uri
- meta: http_verb
expression: evt.Unmarshaled.nginx.request_method
- meta: http_user_agent
expression: evt.Unmarshaled.nginx.http_user_agent
- meta: target_fqdn
expression: evt.Unmarshaled.nginx.server_name
# nginx error logs
- grok:
pattern: '(%{IPORHOST:target_fqdn} )?%{NGINXERRTIME:time} \[%{LOGLEVEL:loglevel}\] %{NONNEGINT:pid}#%{NONNEGINT:tid}: (\*%{NONNEGINT:cid} )?%{GREEDYDATA:message}, client: %{IPORHOST:remote_addr}, server: %{DATA:target_fqdn}, request: "%{WORD:verb} ([^/]+)?%{NGCUSTOMURIPATHPARAM:request}( HTTP/%{NUMBER:http_version})?", host: "%{IPORHOST}(:%{NONNEGINT})?"'
apply_on: message
statics:
- meta: service
value: http
- meta: log_type
value: http_error-log
- target: evt.StrTime
expression: evt.Parsed.time
- meta: source_ip
expression: evt.Parsed.remote_addr
- meta: http_status
expression: evt.Parsed.status
- meta: http_path
expression: evt.Parsed.request
- meta: http_verb
expression: evt.Parsed.verb
- meta: http_user_agent
expression: evt.Parsed.http_user_agent
- meta: target_fqdn
expression: evt.Parsed.target_fqdn
pattern_syntax:
NO_DOUBLE_QUOTE: '[^"]+'
onsuccess: next_stage
nodes:
- filter: "evt.Parsed.message contains 'was not found in'"
pattern_syntax:
USER_NOT_FOUND: 'user "%{NO_DOUBLE_QUOTE:username}" was not found in "%{NO_DOUBLE_QUOTE}"'
grok:
pattern: '%{USER_NOT_FOUND}'
apply_on: message
statics:
- meta: sub_type
value: "auth_fail"
- meta: username
expression: evt.Parsed.username
- filter: "evt.Parsed.message contains 'password mismatch'"
pattern_syntax:
PASSWORD_MISMATCH: 'user "%{NO_DOUBLE_QUOTE:username}": password mismatch'
grok:
pattern: '%{PASSWORD_MISMATCH}'
apply_on: message
statics:
- meta: sub_type
value: "auth_fail"
- meta: username
expression: evt.Parsed.username
- filter: "evt.Parsed.message contains 'limiting requests, excess'"
statics:
- meta: sub_type
value: "req_limit_exceeded"
@@ -0,0 +1,195 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: ingress-nginx
namespace: infra-net
spec:
interval: 30m
chart:
spec:
chart: ingress-nginx
version: 4.13.2
sourceRef:
kind: HelmRepository
name: ingress-nginx
namespace: infra-gitops
interval: 12h
values:
fullnameOverride: ingress-nginx
controller:
image:
registry: docker.io
image: crowdsecurity/controller
tag: v1.13.2
digest: sha256:4575be24781cad35f8e58437db6a3f492df2a3167fed2b6759a6ff0dc3488d56
labels:
devcm-log-collecting/enabled: "true"
kind: DaemonSet
hostNetwork: true
hostPort:
enabled: true
service:
enabled: false
publishService:
enabled: false
# 禁用默认的注解验证以防止冲突
enableAnnotationValidations: false
config:
use-forwarded-headers: "true"
enable-real-ip: "true"
forwarded-for-header: "X-Dev-Cm-Real-IP"
proxy-real-ip-cidr: "0.0.0.0/0"
allow-snippet-annotations: "true"
annotations-risk-level: Critical
# 启用http2
use-http2: "true"
# http to https重定向
ssl-redirect: "true"
# 自定义错误页面
custom-http-errors: "403,404,502,503"
# 全局限速配置
limit-req-status-code: "429"
limit-conn-status-code: "429"
http-snippet: |
# lua插件配置
lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
# 缓存配置
proxy_cache_path /tmp/nginx-cache levels=1:2 keys_zone=cache:2m max_size=100m inactive=7d use_temp_path=off;
proxy_cache_key $uri$is_args$args;
proxy_cache_lock on;
proxy_cache_use_stale updating;
# 全局限速配置
limit_req_zone $binary_remote_addr zone=global_limit:20m rate=20r/s;
limit_req zone=global_limit burst=50 nodelay;
server-snippet: |
# dns配置 配置在http块下会出现重复配置 所以配置在server块下
resolver 169.254.20.10 10.43.0.10 ipv6=off;
# 代理全局静态资源 可提供serviceWorker的支持
location ^~ /__static/ {
proxy_pass http://ingress-nginx-defaultbackend.infra-net.svc.cluster.local/static/;
proxy_set_header Host $host;
add_header Service-Worker-Allowed "/";
}
# 启用geoip2模块
use-geoip: "false"
use-geoip2: "true"
# 日志配置
log-format-escape-json: "true"
log-format-upstream: '{
"msec": "$msec",
"connection": "$connection",
"connection_requests": "$connection_requests",
"pid": "$pid",
"request_id": "$request_id",
"request_length": "$request_length",
"remote_addr": "$remote_addr",
"remote_user": "$remote_user",
"remote_port": "$remote_port",
"time_local": "$time_local",
"time_iso8601": "$time_iso8601",
"request": "$request",
"request_uri": "$request_uri",
"args": "$args",
"status": "$status",
"body_bytes_sent": "$body_bytes_sent",
"bytes_sent": "$bytes_sent",
"http_referer": "$http_referer",
"http_user_agent": "$http_user_agent",
"http_x_forwarded_for": "$http_x_forwarded_for",
"http_host": "$http_host",
"http_upgrade": "$http_upgrade",
"server_name": "$server_name",
"request_time": "$request_time",
"upstream": "$upstream_addr",
"upstream_connect_time": "$upstream_connect_time",
"upstream_header_time": "$upstream_header_time",
"upstream_response_time": "$upstream_response_time",
"upstream_response_length": "$upstream_response_length",
"upstream_cache_status": "$upstream_cache_status",
"ssl_protocol": "$ssl_protocol",
"ssl_cipher": "$ssl_cipher",
"scheme": "$scheme",
"request_method": "$request_method",
"server_protocol": "$server_protocol",
"pipe": "$pipe",
"gzip_ratio": "$gzip_ratio",
"http_cf_ray": "$http_cf_ray",
"geoip_country_code": "$geoip2_city_country_code",
"geoip_city": "$geoip2_city",
"geoip_org": "$geoip2_org",
"geoip_longitude": "$geoip2_longitude",
"geoip_latitude": "$geoip2_latitude",
"level": "info"
}'
# crowdsec插件配置
plugins: "crowdsec"
lua-shared-dicts: "crowdsec_cache: 50m"
# 启用geoip2模块
maxmindLicenseKey: ""
extraArgs:
default-ssl-certificate: "infra-net/dev-cm-crt"
# crowdsec插件配置
extraInitContainers:
- name: init-clone-crowdsec-bouncer
image: crowdsecurity/lua-bouncer-plugin:v1.1.2
imagePullPolicy: IfNotPresent
env:
- name: SHELL
value: "/bin/sh"
- name: API_URL
value: "http://crowdsec-service.infra-net.svc.cluster.local:8080"
- name: API_KEY
value: "ImxBThnyiNm224V5DHYPY63KPAcyJ+WF0rm18Gr4M80"
- name: BOUNCER_CONFIG
value: "/crowdsec/crowdsec-bouncer.conf"
- name: MODE
value: "live"
- name: CACHE_EXPIRATION
value: "3"
- name: UPDATE_FREQUENCY
value: "10"
- name: REQUEST_TIMEOUT
value: "1000"
- name: CAPTCHA_PROVIDER
value: "turnstile"
- name: SITE_KEY
value: "0x4AAAAAAAxJ2RPNWzn2LCc-"
- name: SECRET_KEY
value: "0x4AAAAAAAxJ2dwFOaNg5ae3c6wYTmWH0bU"
- name: CAPTCHA_TEMPLATE_PATH
value: /etc/nginx/static/captcha.html
command: ['/bin/sh', '-c']
args: ['sh /docker_start.sh; mkdir -p /lua_plugins/crowdsec/; cp -R /crowdsec/* /lua_plugins/crowdsec/']
volumeMounts:
- name: crowdsec-bouncer-plugin
mountPath: /lua_plugins
extraVolumes:
- name: crowdsec-bouncer-plugin
emptyDir: {}
- name: static
configMap:
name: static
extraVolumeMounts:
- name: crowdsec-bouncer-plugin
mountPath: /etc/nginx/lua/plugins/crowdsec
subPath: crowdsec
- name: static
mountPath: /etc/nginx/static
defaultBackend:
enabled: true
image:
registry: docker.io
image: devcm/default-backend
tag: v0.2.0
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 3
targetCPUUtilizationPercentage: 80
extraVolumes:
- name: static
configMap:
name: static
extraVolumeMounts:
- name: static
mountPath: /app/static
@@ -0,0 +1,39 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: tailscale-derp-hk
namespace: infra-net
spec:
interval: 30m
chart:
spec:
chart: tailscale-derp
version: 0.0.9
sourceRef:
kind: HelmRepository
name: devcm-repo
namespace: infra-gitops
interval: 12h
values:
image:
tag: v1.94.1
hostNetwork: true
extraVolumes:
- name: cert-volume
secret:
secretName: dev-cm-crt
items:
- key: tls.key
path: tchk.node.dev.cm.key
- key: tls.crt
path: tchk.node.dev.cm.crt
extraVolumeMounts:
- name: cert-volume
mountPath: /certs
derp:
hostname: "tchk.node.dev.cm"
verify_clients: true
http_port: -1
https_port: 30443
stun_port: 33478
certdir: /certs
@@ -0,0 +1,78 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cdn
namespace: infra-net
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: "/$3"
# 重定向配置
nginx.ingress.kubernetes.io/proxy-redirect-from: "/"
nginx.ingress.kubernetes.io/proxy-redirect-to: "/$1/"
# 添加允许跨域请求
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://dev.cm, https://*.dev.cm, https://fillcode.cm, https://*.fillcode.cm"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
# cookie配置
nginx.ingress.kubernetes.io/proxy-cookie-domain: "~^(.+)$ cdn.fillcode.com"
nginx.ingress.kubernetes.io/proxy-cookie-path: "/ /$1"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_cookie_flags ~ SameSite=None Secure;
spec:
ingressClassName: nginx
rules:
- host: cdn.fillcode.com
http:
paths:
- path: /(dev-cm)(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: cdn-halo
port:
number: 80
- path: /(git-dev-cm)(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: cdn-gitea-http
port:
number: 3000
- path: /(monitor-dev-cm)(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: cdn-prometheus-grafana
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
name: cdn-halo
namespace: infra-net
spec:
type: ExternalName
externalName: halo.apps.svc.cluster.local
---
apiVersion: v1
kind: Service
metadata:
name: cdn-gitea-http
namespace: infra-net
spec:
type: ExternalName
externalName: gitea-http.infra-gitops.svc.cluster.local
---
apiVersion: v1
kind: Service
metadata:
name: cdn-prometheus-grafana
namespace: infra-net
spec:
type: ExternalName
externalName: prometheus-grafana.infra-monitor.svc.cluster.local
@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- helmrelease-ingress-nginx.yaml
- configmap-static.yaml
- certificate-dev-cm.yaml
- ingress-cdn.yaml
- helmrelease-crowdsec.yaml
- helmrelease-tailscale-derp.yaml
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: infra-net
@@ -0,0 +1,14 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns-custom
namespace: kube-system
data:
local.override: |
# 腾讯云内网DNS会将HINFO解析请求返回本机 造成循环 此处直接屏蔽处理
template ANY HINFO . {
rcode NXDOMAIN
}
local.server: |
#
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- configmap-coredns.yaml
- nodelocaldns.yaml
@@ -0,0 +1,204 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: node-local-dns
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: v1
kind: Service
metadata:
name: kube-dns-upstream
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/name: "KubeDNSUpstream"
spec:
ports:
- name: dns
port: 53
protocol: UDP
targetPort: 53
- name: dns-tcp
port: 53
protocol: TCP
targetPort: 53
selector:
k8s-app: kube-dns
---
apiVersion: v1
kind: ConfigMap
metadata:
name: node-local-dns
namespace: kube-system
labels:
addonmanager.kubernetes.io/mode: Reconcile
data:
Corefile: |
# 腾讯云内网DNS会将HINFO解析请求返回本机 造成循环 此处直接屏蔽处理
(disableHINFO) {
template ANY HINFO . {
rcode NXDOMAIN
}
}
cluster.local:53 {
errors
cache {
success 9984 30
denial 9984 5
}
reload
loop
bind 169.254.20.10 10.43.0.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
health 169.254.20.10:8080
import disableHINFO
}
in-addr.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10 10.43.0.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
import disableHINFO
}
ip6.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10 10.43.0.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
import disableHINFO
}
.:53 {
errors
cache 30
reload
loop
bind 169.254.20.10 10.43.0.10
forward . __PILLAR__UPSTREAM__SERVERS__
prometheus :9253
import disableHINFO
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-local-dns
namespace: kube-system
labels:
k8s-app: node-local-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 10%
selector:
matchLabels:
k8s-app: node-local-dns
template:
metadata:
labels:
k8s-app: node-local-dns
annotations:
prometheus.io/port: "9253"
prometheus.io/scrape: "true"
spec:
priorityClassName: system-node-critical
serviceAccountName: node-local-dns
hostNetwork: true
dnsPolicy: Default # Don't use cluster DNS.
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
- effect: "NoExecute"
operator: "Exists"
- effect: "NoSchedule"
operator: "Exists"
containers:
- name: node-cache
image: registry.k8s.io/dns/k8s-dns-node-cache:1.26.7
resources:
requests:
cpu: 25m
memory: 5Mi
args: [ "-localip", "169.254.20.10,10.43.0.10", "-conf", "/etc/Corefile", "-upstreamsvc", "kube-dns-upstream" ]
securityContext:
capabilities:
add:
- NET_ADMIN
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9253
name: metrics
protocol: TCP
livenessProbe:
httpGet:
host: 169.254.20.10
path: /health
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
volumeMounts:
- mountPath: /run/xtables.lock
name: xtables-lock
readOnly: false
- name: config-volume
mountPath: /etc/coredns
- name: kube-dns-config
mountPath: /etc/kube-dns
volumes:
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
- name: kube-dns-config
configMap:
name: kube-dns
optional: true
- name: config-volume
configMap:
name: node-local-dns
items:
- key: Corefile
path: Corefile.base
---
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/port: "9253"
prometheus.io/scrape: "true"
labels:
k8s-app: node-local-dns
name: node-local-dns
namespace: kube-system
spec:
clusterIP: None
ports:
- name: metrics
port: 9253
targetPort: 9253
selector:
k8s-app: node-local-dns
@@ -0,0 +1,141 @@
# cert-manager
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: jetstack
namespace: infra-gitops
spec:
interval: 24h
url: https://charts.jetstack.io
---
# cert-manager-webhook-dnspod (OCI)
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: imroc
namespace: infra-gitops
spec:
interval: 24h
type: oci
url: oci://registry-1.docker.io/imroc
---
# reflector
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: emberstack
namespace: infra-gitops
spec:
interval: 24h
url: https://emberstack.github.io/helm-charts
---
# velero
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: vmware-tanzu
namespace: infra-gitops
spec:
interval: 24h
url: https://vmware-tanzu.github.io/helm-charts
---
# cloudnative-pg, plugin-barman-cloud
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: cloudnative-pg
namespace: infra-gitops
spec:
interval: 24h
url: https://cloudnative-pg.github.io/charts
---
# valkey-cluster (OCI)
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: bitnami
namespace: infra-gitops
spec:
interval: 24h
type: oci
url: oci://registry-1.docker.io/bitnamicharts
---
# ingress-nginx
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: ingress-nginx
namespace: infra-gitops
spec:
interval: 24h
url: https://kubernetes.github.io/ingress-nginx
---
# crowdsec
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: crowdsec
namespace: infra-gitops
spec:
interval: 24h
url: https://crowdsecurity.github.io/helm-charts
---
# tailscale-derp, rustdesk-server
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: devcm-repo
namespace: infra-gitops
spec:
interval: 24h
url: https://devcm-repo.github.io/helm-charts
---
# loki, promtail
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: grafana
namespace: infra-gitops
spec:
interval: 24h
url: https://grafana.github.io/helm-charts
---
# kube-prometheus-stack
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: prometheus-community
namespace: infra-gitops
spec:
interval: 24h
url: https://prometheus-community.github.io/helm-charts
---
# gitea, gitea-actions
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: gitea
namespace: infra-gitops
spec:
interval: 24h
url: https://dl.gitea.com/charts
---
# whoami
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: cowboysysop
namespace: infra-gitops
spec:
interval: 24h
url: https://cowboysysop.github.io/charts/
---
# halo
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: halo
namespace: infra-gitops
spec:
interval: 24h
url: https://halo-sigs.github.io/charts/
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- helm-repositories.yaml