chore(gitops): sync workspace state
This commit is contained in:
parent
5224b82b7d
commit
e4815a8c97
106
README.md
106
README.md
@ -1,100 +1,18 @@
|
|||||||
# ansible-playbook
|
# Cloud-Neutral Toolkit GitOps
|
||||||
|
|
||||||
This repository contains a collection of Ansible playbooks and roles for various infrastructure setups and service management tasks.
|
This repository is the GitOps declaration layer for the Cloud-Neutral Toolkit.
|
||||||
|
|
||||||
For a quick overview of the directory layout see [docs/repo-structure.md](docs/repo-structure.md).
|
## Scope
|
||||||
Additional documentation is stored under the `docs/` folder.
|
|
||||||
|
|
||||||
## Playbook 角色说明
|
- Store declarative Kubernetes resources, Flux Kustomizations, and non-sensitive multi-environment values.
|
||||||
|
- Keep application charts and Helm templates in the dedicated chart repository.
|
||||||
|
- Keep imperative automation such as Ansible playbooks and inventories out of this repository.
|
||||||
|
|
||||||
1. playbooks/roles/docker:适用于简单的、单机环境的部署,主要使用 Docker 和 Docker Compose 进行容器化管理。
|
## Layout
|
||||||
2. playbooks/roles/charts:面向大规模的 Kubernetes 集群,使用 Helm 和标准化 Chart 部署模式进行高可用和可扩展的管理。
|
|
||||||
3. playbooks/roles/vhosts:传统的非容器化部署方式,通常涉及手动配置服务器和虚拟主机,适用于不使用容器的应用场景。
|
|
||||||
|
|
||||||
|
- `infra/`: platform, infrastructure, and shared service declarations
|
||||||
|
- `apps/`: application release declarations
|
||||||
|
- `clusters/`: cluster-level overlays and entrypoints
|
||||||
|
- `docs/`: repository conventions and operational documentation
|
||||||
|
|
||||||
## Role Summary
|
For a quick structure overview, see [docs/repo-structure.md](docs/repo-structure.md).
|
||||||
|
|
||||||
| Role Name | Description | Docker | Charts | VHosts | CICD | Validate | Last Update |
|
|
||||||
|-------------------------|-------------------------------------------------------|--------|--------|--------|--------|--------|------------|
|
|
||||||
| `common` | 通用角色,包含一些常用的功能,如日志记录、监控等。 | | | ✔ | | yes | 2025-02-14 |
|
|
||||||
| `keycloak` | 用于管理身份认证和授权服务。 | ✔ | | | github | yes | 2024-11-10 |
|
|
||||||
| `harbor` | 容器镜像仓库角色,用于存储和管理容器镜像。 | ✔ | | | github | yes | 2024-11-14 |
|
|
||||||
| `app` | 参考模板。 | | | | | | |
|
|
||||||
| `nginx` | 用于设置 Nginx | | ✔ | ✔ | | | |
|
|
||||||
| `grafana` | 用于设置 Grafana | | ✔ | ✔ | | | |
|
|
||||||
| `grafana-loki` | 用于设置 Grafana-loki | | ✔ | ✔ | | | |
|
|
||||||
| `Grafana-tempo` | 用于设置 Grafana-tempo | | ✔ | ✔ | | | |
|
|
||||||
| `prometheus` | 用于设置 Prometheus | | ✔ | ✔ | | | |
|
|
||||||
| `prometheus-transfer` | 用于 Prometheus 数据传输设置。 | | | ✔ | | | |
|
|
||||||
| `vector` | 用于配置日志收集代理。 | | | ✔ | | | |
|
|
||||||
| `node-exporter` | 用于导出系统和硬件的监控数据。 | | ✔ | | | | |
|
|
||||||
| `observability-agent` | 用于管理 Observability 代理。 | | ✔ | ✔ | | | |
|
|
||||||
| `observability-server` | 用于设置 Observability 服务端。 | | ✔ | ✔ | | | |
|
|
||||||
| `wireguard-client` | 用于设置 WireGuard 客户端。 | | | ✔ | | | |
|
|
||||||
| `wireguard-gateway` | 用于设置 WireGuard 网关。 | | | ✔ | | | |
|
|
||||||
| `vault` | 用于管理敏感数据和密钥。 | | | ✔ | | | |
|
|
||||||
| `postgresql` | PostgreSQL 数据库角色,用于提供 PostgreSQL 数据库服务。 | | ✔ | | | | |
|
|
||||||
| `redis` | Redis 数据库角色,用于提供 Redis 数据库服务。 | | ✔ | | | | |
|
|
||||||
| `chartmuseum` | 图表仓库角色,用于存储和管理 Kubernetes 图表。 | | ✔ | | | | |
|
|
||||||
| `gitlab` | 代码仓库角色,用于存储和管理代码。 | | ✔ | | | | |
|
|
||||||
| `mysql` | MySQL 数据库角色,用于提供 MySQL 数据库服务。 | | ✔ | | | | |
|
|
||||||
| `argo-server` | 用于设置和管理 Argo Server。 | | ✔ | | | | |
|
|
||||||
| `deepflow` | 用于流量监控与网络性能分析的 DeepFlow 服务。 | | ✔ | | | | |
|
|
||||||
| `jenkins` | Jenkins 自动化构建工具角色,用于 CI/CD 管道。 | | ✔ | | | | |
|
|
||||||
| `chaos-mesh` | 用于 Chaos Engineering 测试的 Chaos Mesh 角色。 | | ✔ | | | | |
|
|
||||||
| `flagger-loadtester` | 用于负载测试的 Flagger Loadtester 角色。 | | ✔ | | | | |
|
|
||||||
| `splunk-otel-collector` | 用于配置 Splunk OpenTelemetry Collector。 | | ✔ | | | | |
|
|
||||||
| `openldap` | 用于设置和管理 OpenLDAP 身份认证服务。 | | ✔ | | | | |
|
|
||||||
| `alerting` | 用于设置和管理警报系统。 | | | ✔ | | | |
|
|
||||||
| `k3s` | 用于创建 Kubernetes 集群。 | | | ✔ | | | |
|
|
||||||
| `k3s-reset` | 用于重置 Kubernetes 集群。 | | | ✔ | | | |
|
|
||||||
| `k3s-addon` | 用于安装 Kubernetes 集群插件。 | | | ✔ | | | |
|
|
||||||
| `secret-manger` | 密钥管理角色,用于管理密钥。 | | | ✔ | | | |
|
|
||||||
| `cert-manager` | 证书管理角色,用于管理证书。 | | | ✔ | | | |
|
|
||||||
| `ssh-trust` | 配置 ops 主机与节点的 SSH 互信。 | | | ✔ | | | |
|
|
||||||
|
|
||||||
表格说明
|
|
||||||
- Docker:是否属于 Docker 角色。
|
|
||||||
- Charts:是否属于 Helm Chart 角色。
|
|
||||||
- VHosts:是否属于虚拟主机管理相关角色。
|
|
||||||
- CICD:是否启用 CICD 管道,标明是否集成了自动化流程。
|
|
||||||
- Validate:是否经过验证测试。
|
|
||||||
- Last Update:最后更新时间。
|
|
||||||
|
|
||||||
## Usage Examples
|
|
||||||
|
|
||||||
- Linux OS Setup
|
|
||||||
|
|
||||||
ansible-playbook -i inventory/hosts/all playbooks/common -D -C
|
|
||||||
ansible-playbook -i inventory/hosts/all playbooks/common -D
|
|
||||||
|
|
||||||
- Gather Network Information
|
|
||||||
|
|
||||||
ansible-playbook -i inventory gather_network_info.yml -e target_group=master
|
|
||||||
|
|
||||||
- Display network information on all nodes
|
|
||||||
|
|
||||||
ansible -i inventory all -m script -a 'roles/network_info/tasks/files/display_network_info.sh'
|
|
||||||
|
|
||||||
- Deploy Keycloak Server
|
|
||||||
|
|
||||||
ansible-playbook -i inventory/hosts/core playbooks/keycloak_server -D
|
|
||||||
|
|
||||||
- Set up WireGuard Gateway
|
|
||||||
|
|
||||||
ansible-playbook -i inventory/hosts/vpn playbooks/wireguard_gateway.yaml -D
|
|
||||||
|
|
||||||
- Set up Grafana Alloy
|
|
||||||
|
|
||||||
ansible-playbook -i inventory/k3s-cluster playbooks/init_grafana_alloy -D -C -l cn-k3s-server.svc.plus -e @playbooks/roles/alloy/files/loki_journal_sources_k3s_server.yml -e "ansible_become_pass='xxxx'"
|
|
||||||
|
|
||||||
|
|
||||||
- Setup VPN gateway
|
|
||||||
|
|
||||||
ansible-playbook -i inventory/hosts/all playbooks/common -l gateway -D
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- [docs/gpu-k8s-role.md](docs/gpu-k8s-role.md) - How to run the GPU-enabled Kubernetes role.
|
|
||||||
- [docs/repo-structure.md](docs/repo-structure.md) - Overview of repository layout.
|
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
只加密 private_key 字段
|
|
||||||
1. 原始 vpn-keys.yaml
|
|
||||||
yaml
|
|
||||||
keys:
|
|
||||||
- name: master-1
|
|
||||||
private_key: <master_private_key>
|
|
||||||
public_key: <master_public_key>
|
|
||||||
2. 使用 ansible-vault encrypt_string 加密 private_key
|
|
||||||
|
|
||||||
- ansible-vault encrypt_string 'private-key-xxxx' --name 'private_key'
|
|
||||||
- ansible-vault encrypt_string 'public_key-xxxx' --name 'public_key'
|
|
||||||
|
|
||||||
示例输出(加密后是 YAML 结构):
|
|
||||||
|
|
||||||
yaml
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
62326432376162336462343864333933356363373235623262306463326432363737623732613763
|
|
||||||
3962613662616565393463343030653733623066626137610a313465323462623261303031323337
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
keys:
|
|
||||||
- name: cn-hub
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
33643635306332303761356562383035353333373234393132313162613834323963313635326562
|
|
||||||
3932356235303234356561623762393862666438386565310a376235306238343139386532336162
|
|
||||||
65623164666665353435653432396530303634666438656566656466643866366139613961363631
|
|
||||||
6363306631393038320a613163313338313237383837303966356333303737643331616433396430
|
|
||||||
33316331333766613438356462313130326433363961316162313761616561616466363939613033
|
|
||||||
3837623938376434656434386135333739613939653133373733
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
38336537383061383333643431643261343739323864316235303366623930633366336139386636
|
|
||||||
6162336232336533636134353863386233303631626363360a376533336664636661373933623230
|
|
||||||
34333765346661383335663034393561646436333135613838373438396336633061396533613061
|
|
||||||
3031326364353036630a373862396266653961346334663139626633313362656131663163383563
|
|
||||||
34376231306239636536313830333962323934343035333263643234363363396164626366353061
|
|
||||||
3833613132373666303563623863373735396566666239316536
|
|
||||||
|
|
||||||
- name: global-hub
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
63343838666530633031313536616535313936373634396165376132333661616534663937626632
|
|
||||||
3530646463663462383130323930356239636438643035380a343433303064383531663332303839
|
|
||||||
32613733323263623836346266383363336361323036383536313031386435386534646661616463
|
|
||||||
6631346431316334620a643831313033326261333365623037306565663131373664343930623665
|
|
||||||
31346564363635323765336465646466663631376538626237386165326464326632323438663038
|
|
||||||
3937363832363731353834633663646538666232336239353936
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
34666430316566393939656436323231623935316331373264383830653934323261656136373666
|
|
||||||
3630356330396362323763383832376538633163636331650a376339326661363431353532303831
|
|
||||||
37336134303235633334643036326564313163626433613261333062336238316333363165386263
|
|
||||||
3666386330343261340a333662636630356635373938623335656462633039353565383133613935
|
|
||||||
35643661363334313733346430633432353736343463613264393433623135613833376435333661
|
|
||||||
3462643164356563346166656237613334616130386532393565
|
|
||||||
|
|
||||||
- name: deepflow-demo
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
36316136663466336564383766626434626338356130626537663163373530326332366335306136
|
|
||||||
3266383533373032623366396139653063626338646237310a353439346238653832646437313663
|
|
||||||
62623239623761326436613833313739386662356263353338666461363438613766663962386162
|
|
||||||
3539343836623936370a313439316335346235306633333333643738333461323963313038313161
|
|
||||||
62376566626335306335623134346361326364346433626234383162616636326265356364313938
|
|
||||||
6534613330643764613733333266313365633635663138636633
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
32326461646138373831356335656664643737313032656134663138323439313164353766363134
|
|
||||||
6232303034663064303235303363663661326433313536660a666133616438316436306463303163
|
|
||||||
64646530633639616266396563383362306235313662373565323963633039653931376431303565
|
|
||||||
6136396164346563660a643235646232353061323463396539383266333133343532396139373035
|
|
||||||
39653262653638363930383861353262303030373332313538383362393633663562303566373737
|
|
||||||
3062336434313031613534393033616330333363613863613464
|
|
||||||
|
|
||||||
- name: icp-aliyun
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
34383966663239613361363535616332303432393165643433663461633934363535626137326664
|
|
||||||
6532646433306636393734666164613864636636626630660a636636306435343661366234343661
|
|
||||||
30326362306537633561636265666232373437353034643462656538653835653831303263306662
|
|
||||||
3361323333353935350a316539303863646434336136333862626261363031336232666562326434
|
|
||||||
39303961383563623736383962363330363439313064613632383061313438373330356366323534
|
|
||||||
6533613662373736373131363463663734656261643839383862
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
65393861336537646335613534376635343838656233646333386438653766636539333436623665
|
|
||||||
6562396637666365613562373565383263353534343931350a323563346239666534303162353432
|
|
||||||
63646562363362396333333738333664376136303066316135633633323466326233613264623366
|
|
||||||
6166613531623135660a363465636137643337626137386661306237323731353839303734653436
|
|
||||||
32643065663739303161626261393062613764346662633365336162613134633131383062646133
|
|
||||||
6437313463376164386465663365386436633466363633383366
|
|
||||||
|
|
||||||
- name: tky-proxy
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
39303737303631303963613131373734373338663232366534303832646664326365353730313665
|
|
||||||
3664643734336466613839663239613433373837633064300a373634343034323739646565326464
|
|
||||||
32343237303731656666323332656138643533323338626631626630316435623564616330333237
|
|
||||||
6339626537376163360a376663653533663332353163303363386564373233666230323735343863
|
|
||||||
66363730653134343037363739353464663834373134656639303932646635336664303537376665
|
|
||||||
3961393930616464343632363039333465633364626433363761
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
61366364303934343039356565643939613032373932356264393739343832366231653335373132
|
|
||||||
3732346666336566396133343836393961336533323530310a636131316266653132346663306461
|
|
||||||
39613036396330376235623765313166303163393264373436316236366234666532343866383235
|
|
||||||
3230366539313162310a323130663530653339623366613336616433666136336463306237326461
|
|
||||||
36363536376230313135336463386566393964613238353134663432353762626166303938323266
|
|
||||||
3963383862363236643361346165373538323332363764633131
|
|
||||||
|
|
||||||
- name: us-proxy
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
34373039646561366365363831636438633462633536343834356263396331333864396161363630
|
|
||||||
6631373964666239663064633936333135653663306464320a316463363362313336373437383937
|
|
||||||
38663665323531346536363030333637663631623765373466386664623332616432613334623933
|
|
||||||
6362353736396662300a343430633865363637313732383065613836363231623862616535383033
|
|
||||||
38333861393761633437316435306263356131353133376532323661366465616130616332366436
|
|
||||||
3430663134636430613139333238343265613764616234383362
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
62316266633037313333333966646331613830633733616438666533303735613763376632336562
|
|
||||||
3864333538333535323862333230663664306561386534340a343038356565643530323061323034
|
|
||||||
35353663643465616633346363626430623435396263646339373137303830303031326462653966
|
|
||||||
3266313038373466300a643833373063363862643533393838613266666363326363383034653366
|
|
||||||
34633063616361653762323130363832353132613531326131323336353339616166396464303337
|
|
||||||
6338353132333964376163333537363337316438313266623933
|
|
||||||
|
|
||||||
- name: ca-proxy
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
39303965663333646238656661376238653732363366653264353234396635313464316563613761
|
|
||||||
3937323936393363373265653864313034343462626633360a303036643838366465623965623365
|
|
||||||
35646332626232356661343966623637613037666336376562323864306630396536646230623664
|
|
||||||
6431636530326362320a383965356336313563336261633030666534613936653037393737356637
|
|
||||||
30323935393662333533373561303661366437626264383837376562323466323531616165643233
|
|
||||||
3233643237303764346130323139613537666132646532643864
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
61343962366534343435356236663132656636313634393563663164323630646363666264626434
|
|
||||||
3439316233626333656362623332613433313130396430610a633839393561326438636533666162
|
|
||||||
63663330313934353462663334643365323766376337363835633439653064386237373531323637
|
|
||||||
6338333364366239350a313636636438653736336563383665366661343066373761333431343933
|
|
||||||
36303062643639613632383565383534306438363461336634343662646435666231343565616333
|
|
||||||
6239326436633462346466393862336332383665313134393738
|
|
||||||
|
|
||||||
- name: icp-huawei
|
|
||||||
private_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
34356563313165386632656365393865356631663936656337316136343437363538393463363639
|
|
||||||
3562343736663335643230626335346265336365613835370a373361633064356264623932393232
|
|
||||||
63386433643761373634333232393136316333353165336463323736366363313662333863656462
|
|
||||||
3136323033626666340a623730346234396664343863656335303263376562613230373363343938
|
|
||||||
36633838303966303434336165393838346531383362316161366431393765373765396137316466
|
|
||||||
3866643163393061613732623938613035396536333837353363
|
|
||||||
public_key: !vault |
|
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
63383631656563313335646566356237333737653232656439336230633037346566626663653333
|
|
||||||
6533663536666464616537376236383734313231393762640a643962666334326261386462653233
|
|
||||||
39386632343965346161623761393034313532633236613430663261366530363638653430383864
|
|
||||||
3535323031663634320a366134323832323034373430383264353066333666323932663230336333
|
|
||||||
65643263363538653033326236623434366631366339313964646263316536643237643535313663
|
|
||||||
3062623634613961636532636438393830613132656266306539
|
|
||||||
|
|
||||||
@ -21,13 +21,12 @@ This `docs/` directory now has a bilingual canonical layer for the current repos
|
|||||||
|
|
||||||
## Current Repo Context / 当前仓库背景
|
## Current Repo Context / 当前仓库背景
|
||||||
|
|
||||||
- Root README: `ansible-playbook`
|
- Root README: `Cloud-Neutral Toolkit GitOps`
|
||||||
- Previous docs index: `Documentation`
|
- Previous docs index: `Documentation`
|
||||||
- Manifest evidence / 构建清单: repository structure and scripts only
|
- Manifest evidence / 构建清单: repository structure and scripts only
|
||||||
- Active code and ops directories / 当前主要目录: `scripts/`, `StackFlow/`, `config/`
|
- Active code and ops directories / 当前主要目录: `infra/`, `apps/`, `clusters/`, `config/`, `scripts/`
|
||||||
|
|
||||||
## Existing Docs To Reconcile / 需要继续归并的现有文档
|
## Existing Docs To Reconcile / 需要继续归并的现有文档
|
||||||
|
|
||||||
- `gpu-k8s-role.md`
|
|
||||||
- `repo-structure.md`
|
- `repo-structure.md`
|
||||||
- `stackflow/README.md`
|
- `stackflow/README.md`
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
# GitOps Repository Documentation
|
# GitOps Repository Documentation
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
## Current state snapshot
|
## Current state snapshot
|
||||||
|
|
||||||
- Root README title: `ansible-playbook`
|
- Root README title: `Cloud-Neutral Toolkit GitOps`
|
||||||
- Build/runtime evidence: repository structure and scripts only
|
- Build/runtime evidence: repository structure and scripts only
|
||||||
- Primary directories detected: `scripts/`, `StackFlow/`, `config/`
|
- Primary directories detected: `infra/`, `apps/`, `clusters/`, `config/`, `scripts/`
|
||||||
- Existing docs count: 3
|
- Existing docs count: 3
|
||||||
|
|
||||||
## Canonical pages
|
## Canonical pages
|
||||||
@ -20,6 +20,5 @@ This repository organizes GitOps assets, playbooks, and operational roles for in
|
|||||||
|
|
||||||
## Legacy docs to fold in
|
## Legacy docs to fold in
|
||||||
|
|
||||||
- `gpu-k8s-role.md`
|
|
||||||
- `repo-structure.md`
|
- `repo-structure.md`
|
||||||
- `stackflow/README.md`
|
- `stackflow/README.md`
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Architecture
|
# Architecture
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
Use this page as the canonical bilingual overview of system boundaries, major components, and repo ownership.
|
Use this page as the canonical bilingual overview of system boundaries, major components, and repo ownership.
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Deployment
|
# Deployment
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
Use this page to standardize deployment prerequisites, supported topologies, operational checks, and rollback notes.
|
Use this page to standardize deployment prerequisites, supported topologies, operational checks, and rollback notes.
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Design
|
# Design
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
Use this page to consolidate design decisions, ADR-style tradeoffs, and roadmap-sensitive implementation notes.
|
Use this page to consolidate design decisions, ADR-style tradeoffs, and roadmap-sensitive implementation notes.
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Developer Guide
|
# Developer Guide
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
Use this page to document local setup, project structure, test surfaces, and contribution conventions tied to the current codebase.
|
Use this page to document local setup, project structure, test surfaces, and contribution conventions tied to the current codebase.
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# User Guide
|
# User Guide
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
Use this page to document primary user/operator tasks, everyday workflows, and navigation to existing how-to material.
|
Use this page to document primary user/operator tasks, everyday workflows, and navigation to existing how-to material.
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Vibe Coding Reference
|
# Vibe Coding Reference
|
||||||
|
|
||||||
This repository organizes GitOps assets, playbooks, and operational roles for infrastructure delivery.
|
This repository organizes declarative GitOps assets for infrastructure delivery.
|
||||||
|
|
||||||
Use this page to align AI-assisted coding prompts, repo boundaries, safe edit rules, and documentation update expectations.
|
Use this page to align AI-assisted coding prompts, repo boundaries, safe edit rules, and documentation update expectations.
|
||||||
|
|
||||||
|
|||||||
@ -1,113 +0,0 @@
|
|||||||
# GPU Kubernetes Role
|
|
||||||
|
|
||||||
This document describes how to use the `gpu-k8s` role to deploy a simple Kubernetes cluster with NVIDIA GPU support.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The role performs four main tasks:
|
|
||||||
|
|
||||||
1. **Create the Kubernetes cluster** using [sealos](https://github.com/labring/sealos). It runs the provided `sealos run` command to bootstrap the master and worker nodes.
|
|
||||||
2. **Install NVIDIA drivers and the NVIDIA container toolkit** on the target hosts so that Kubernetes can access GPU resources.
|
|
||||||
3. **Verify the cluster state** after initialization, displaying the `sealos` version and the current Kubernetes nodes.
|
|
||||||
4. **Verify GPU access** by deploying the official NVIDIA device plugin and running a small CUDA workload.
|
|
||||||
|
|
||||||
When `sealos_version` is set to `latest` (the default), the role automatically
|
|
||||||
fetches the most recent stable release from GitHub. The Kubernetes image tag is
|
|
||||||
controlled separately via `kubernetes_version`, which defaults to `v1.25.16` but
|
|
||||||
can be overridden to any compatible release.
|
|
||||||
|
|
||||||
|
|
||||||
The following command is used to create the cluster (example with one master and one worker):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
REGISTRY=$(playbooks/roles/vhosts/gpu-k8s/files/get_labring_registry.sh)
|
|
||||||
sealos run \
|
|
||||||
${REGISTRY}/kubernetes:<kubernetes_version> \
|
|
||||||
${REGISTRY}/cilium:<cilium_version> \
|
|
||||||
${REGISTRY}/helm:<helm_version> \
|
|
||||||
--masters 172.16.11.120 \
|
|
||||||
--nodes 172.16.11.152 \
|
|
||||||
--env '{}' \
|
|
||||||
--cmd "kubeadm init --skip-phases=addon/kube-proxy"
|
|
||||||
```
|
|
||||||
If deploying with a non-root user the command also requires `--user` and
|
|
||||||
`--pk` options pointing to the user's SSH key. The host running Sealos must have
|
|
||||||
`newuidmap` and `newgidmap` installed (typically provided by the `uidmap`
|
|
||||||
package) along with the `fuse-overlayfs` binary to enable user namespaces.
|
|
||||||
|
|
||||||
After the cluster is running the role installs the NVIDIA device plugin and runs a test pod to ensure `nvidia-smi` works inside the cluster.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add the role to your playbook along with the `ssh-trust` role which configures passwordless access from the ops host to the cluster nodes:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
roles:
|
|
||||||
- ssh-trust
|
|
||||||
- gpu-k8s
|
|
||||||
```
|
|
||||||
|
|
||||||
By default the SSH key is created for the same user Ansible connects with. You
|
|
||||||
can override this by setting `ssh_user`. When `ansible_user` is defined it will
|
|
||||||
be used automatically, otherwise `root` is assumed. The role also allows you to
|
|
||||||
specify the private key path via `ssh_private_key`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
vars:
|
|
||||||
ssh_user: ubuntu
|
|
||||||
ssh_private_key: /home/ubuntu/.ssh/myuser_id_rsa
|
|
||||||
roles:
|
|
||||||
- ssh-trust
|
|
||||||
- gpu-k8s
|
|
||||||
```
|
|
||||||
|
|
||||||
The specified user must be able to log in without a password and have sudo
|
|
||||||
access on the target hosts.
|
|
||||||
|
|
||||||
|
|
||||||
Example playbook snippet defining the IP lists:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
vars:
|
|
||||||
master_ips:
|
|
||||||
- "172.16.11.120"
|
|
||||||
node_ips:
|
|
||||||
- "172.16.11.152"
|
|
||||||
roles:
|
|
||||||
- ssh-trust
|
|
||||||
- gpu-k8s
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also specify hostnames and let the role look up the IPs:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
vars:
|
|
||||||
masters:
|
|
||||||
- "k8s-1"
|
|
||||||
nodes:
|
|
||||||
- "k8s-2"
|
|
||||||
- "k8s-3"
|
|
||||||
roles:
|
|
||||||
- ssh-trust
|
|
||||||
- gpu-k8s
|
|
||||||
```
|
|
||||||
|
|
||||||
The playbook expects at least one master and one node. You can provide the
|
|
||||||
addresses directly via `master_ips` and `node_ips`, or give hostnames in the
|
|
||||||
`masters` and `nodes` variables. When hostnames are used, the role will look up
|
|
||||||
their `ansible_host` values from the inventory to obtain the IPs. Up to three
|
|
||||||
masters can be specified.
|
|
||||||
|
|
||||||
|
|
||||||
Run the playbook with your inventory that contains the master and node IP addresses.
|
|
||||||
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/hosts/all playbooks/demo_gpu_k8s.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
The final step prints the output of `nvidia-smi` from inside a Kubernetes pod, confirming that the GPU is available.
|
|
||||||
@ -1,19 +1,12 @@
|
|||||||
# Repository Structure
|
# Repository Structure
|
||||||
|
|
||||||
This repository combines Ansible playbooks with Kubernetes manifests and
|
This repository contains declarative GitOps assets only. Below is a short overview of the key directories.
|
||||||
automation scripts. Below is a short overview of the key directories.
|
|
||||||
|
|
||||||
| Directory | Purpose |
|
| Directory | Purpose |
|
||||||
|-----------|---------|
|
|-----------|---------|
|
||||||
| `playbooks` | Ansible playbooks and role definitions. |
|
|
||||||
| `apps` | Flux HelmRelease and Kustomize files for applications. |
|
| `apps` | Flux HelmRelease and Kustomize files for applications. |
|
||||||
| `clusters` | Kustomize overlays for different clusters referencing the `apps` definitions. |
|
| `clusters` | Kustomize overlays for different clusters referencing the `apps` definitions. |
|
||||||
| `helmfiles` | Sample [helmfile](https://github.com/helmfile/helmfile) declarations. |
|
| `infra` | Platform and infrastructure declarations managed by Flux. |
|
||||||
| `helm` | Local Helm charts used in some playbooks. |
|
| `scripts` | Utility scripts that support validation or operational workflows. |
|
||||||
| `inventory` | Example inventories and group variables for Ansible. |
|
| `config` | Non-sensitive configuration references and examples. |
|
||||||
| `scripts` | Utility scripts such as cluster setup or secret management. |
|
|
||||||
| `sync` | Tasks for local host setup and testing. |
|
|
||||||
| `docs` | Additional documentation. |
|
| `docs` | Additional documentation. |
|
||||||
|
|
||||||
See `docs/gpu-k8s-role.md` for an example walkthrough deploying a GPU-enabled
|
|
||||||
Kubernetes cluster.
|
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
# StackFlow (GitOps YAML Flow)
|
# StackFlow (GitOps YAML Flow)
|
||||||
|
|
||||||
StackFlow is a declarative YAML describing a full business stack deployment
|
StackFlow is a declarative YAML describing a full business stack deployment
|
||||||
across DNS, cloud resources (IAC), and Ansible-based provisioning.
|
across DNS, cloud resources (IAC), and GitOps-driven delivery.
|
||||||
|
|
||||||
This repository already contains:
|
This repository already contains:
|
||||||
- `playbooks/` (Ansible provisioning for vhosts/docker/k3s)
|
|
||||||
- `iac-template/` (Terraform reference templates)
|
- `iac-template/` (Terraform reference templates)
|
||||||
- `.github/workflows/` (bootstrap workflows)
|
- `.github/workflows/` (bootstrap workflows)
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ Top-level:
|
|||||||
- `kind`: `StackFlow`
|
- `kind`: `StackFlow`
|
||||||
- `metadata.name`: stack id
|
- `metadata.name`: stack id
|
||||||
- `global.domain`: root domain, e.g. `svc.plus`
|
- `global.domain`: root domain, e.g. `svc.plus`
|
||||||
- `global.dns_provider`: `cloudflare` (planned), `alicloud` (existing playbooks)
|
- `global.dns_provider`: `cloudflare` (planned), `alicloud` (legacy)
|
||||||
- `global.cloud`: `gcp`
|
- `global.cloud`: `gcp`
|
||||||
- `targets[]`: list of deployable targets
|
- `targets[]`: list of deployable targets
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ Planned phases:
|
|||||||
- `dns-plan`: output required DNS records (no apply)
|
- `dns-plan`: output required DNS records (no apply)
|
||||||
- `dns-apply`: apply DNS changes (provider-specific)
|
- `dns-apply`: apply DNS changes (provider-specific)
|
||||||
- `iac-apply`: provision resources via Terraform
|
- `iac-apply`: provision resources via Terraform
|
||||||
- `deploy`: deploy apps via Ansible or repo-dispatch
|
- `deploy`: deploy apps via GitOps or repo-dispatch
|
||||||
- `observe`: connect monitoring / alerts
|
- `observe`: connect monitoring / alerts
|
||||||
|
|
||||||
Today we only ship `validate` + `dns-plan` as the first step.
|
Today we only ship `validate` + `dns-plan` as the first step.
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
# GitOps 运维仓库 文档
|
# GitOps 运维仓库 文档
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
## 当前状态快照
|
## 当前状态快照
|
||||||
|
|
||||||
- 根 README 标题: `ansible-playbook`
|
- 根 README 标题: `Cloud-Neutral Toolkit GitOps`
|
||||||
- 构建与运行时证据: repository structure and scripts only
|
- 构建与运行时证据: repository structure and scripts only
|
||||||
- 自动识别的主要目录: `scripts/`, `StackFlow/`, `config/`
|
- 自动识别的主要目录: `infra/`, `apps/`, `clusters/`, `config/`, `scripts/`
|
||||||
- 现有文档数量: 3
|
- 现有文档数量: 3
|
||||||
|
|
||||||
## 核心双语文档
|
## 核心双语文档
|
||||||
@ -20,6 +20,5 @@
|
|||||||
|
|
||||||
## 待归并的历史文档
|
## 待归并的历史文档
|
||||||
|
|
||||||
- `gpu-k8s-role.md`
|
|
||||||
- `repo-structure.md`
|
- `repo-structure.md`
|
||||||
- `stackflow/README.md`
|
- `stackflow/README.md`
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 架构
|
# 架构
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
本页作为系统边界、核心组件与仓库职责的双语总览入口。
|
本页作为系统边界、核心组件与仓库职责的双语总览入口。
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 部署
|
# 部署
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
本页用于统一部署前提、支持的拓扑、运维检查项与回滚注意事项。
|
本页用于统一部署前提、支持的拓扑、运维检查项与回滚注意事项。
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 设计
|
# 设计
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
本页用于汇总设计决策、类似 ADR 的权衡记录,以及与路线图相关的实现说明。
|
本页用于汇总设计决策、类似 ADR 的权衡记录,以及与路线图相关的实现说明。
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 开发手册
|
# 开发手册
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
本页用于记录本地开发环境、项目结构、测试面与贴合当前代码库的贡献约定。
|
本页用于记录本地开发环境、项目结构、测试面与贴合当前代码库的贡献约定。
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 使用手册
|
# 使用手册
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
本页用于记录主要用户或运维角色的日常任务、常见流程,以及现有操作文档入口。
|
本页用于记录主要用户或运维角色的日常任务、常见流程,以及现有操作文档入口。
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Vibe Coding 参考
|
# Vibe Coding 参考
|
||||||
|
|
||||||
该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。
|
该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。
|
||||||
|
|
||||||
本页用于统一 AI 辅助开发提示词、仓库边界、安全编辑规则与文档同步要求。
|
本页用于统一 AI 辅助开发提示词、仓库边界、安全编辑规则与文档同步要求。
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
repositories:
|
|
||||||
- name: stable
|
|
||||||
url: https://charts.onwalk.net
|
|
||||||
username: {{ requiredEnv "ARF_USERNAME" }}
|
|
||||||
password: {{ requiredEnv "ARF_PASSWORD" | quote }}
|
|
||||||
|
|
||||||
templates:
|
|
||||||
default: &default
|
|
||||||
namespace: itsm-dev
|
|
||||||
createNamespace: true
|
|
||||||
chart: stable/app-frontend
|
|
||||||
version: 0.1.3
|
|
||||||
|
|
||||||
releases:
|
|
||||||
- name: itsm-dev
|
|
||||||
<<: *default
|
|
||||||
set:
|
|
||||||
- name: image.repository
|
|
||||||
value: ""
|
|
||||||
- name: image.tag
|
|
||||||
value: ""
|
|
||||||
- name: service.port
|
|
||||||
value: ""
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
repositories:
|
|
||||||
- name: stable
|
|
||||||
url: https://charts.onwalk.net
|
|
||||||
username: {{ requiredEnv "ARF_USERNAME" }}
|
|
||||||
password: {{ requiredEnv "ARF_PASSWORD" | quote }}
|
|
||||||
|
|
||||||
common:
|
|
||||||
namespace: itsm-tools-stg
|
|
||||||
createNamespace: false
|
|
||||||
chart: stable/app-backend
|
|
||||||
version: 0.1.3
|
|
||||||
values:
|
|
||||||
service:
|
|
||||||
type: ClusterIP
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8000
|
|
||||||
targetPort: http
|
|
||||||
protocol: TCP
|
|
||||||
- name: grpc
|
|
||||||
port: 9000
|
|
||||||
targetPort: grpc
|
|
||||||
protocol: TCP
|
|
||||||
containerPorts:
|
|
||||||
- name: http
|
|
||||||
port: 8000
|
|
||||||
protocol: TCP
|
|
||||||
- name: grpc
|
|
||||||
port: 9000
|
|
||||||
protocol: TCP
|
|
||||||
|
|
||||||
releases:
|
|
||||||
- name: itsm-ticketing
|
|
||||||
<<: {{"{{" }} include "common" . | nindent 4 {{ "}}" }}
|
|
||||||
set:
|
|
||||||
- name: image.repository
|
|
||||||
value: artifact.onwalk.net/itsm/ticketing
|
|
||||||
- name: image.tag
|
|
||||||
value: 'unknown-fa7fed7'
|
|
||||||
- name: volumeMounts
|
|
||||||
value:
|
|
||||||
- name: ticketing-config
|
|
||||||
mountPath: /ticketing/conf
|
|
||||||
- name: volumes
|
|
||||||
value:
|
|
||||||
- name: ticketing-config
|
|
||||||
secret:
|
|
||||||
secretName: itsm
|
|
||||||
defaultMode: 420
|
|
||||||
items:
|
|
||||||
- key: ticketing.yaml
|
|
||||||
path: config.yaml
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
repositories:
|
|
||||||
- name: stable
|
|
||||||
url: https://charts.onwalk.net
|
|
||||||
username: {{ requiredEnv "ARF_USERNAME" }}
|
|
||||||
password: {{ requiredEnv "ARF_PASSWORD" | quote }}
|
|
||||||
|
|
||||||
templates:
|
|
||||||
default: &default
|
|
||||||
namespace: itsm-dev
|
|
||||||
createNamespace: true
|
|
||||||
chart: stable/itsm-tools
|
|
||||||
version: 0.1.18
|
|
||||||
|
|
||||||
releases:
|
|
||||||
- name: itsm-dev
|
|
||||||
<<: *default
|
|
||||||
set:
|
|
||||||
- name: apisix.dashboard.enabled
|
|
||||||
value: true
|
|
||||||
- name: apisix.dashboard.ingress.enabled
|
|
||||||
value: true
|
|
||||||
- name: apisix.dashboard.ingress.className
|
|
||||||
value: nginx
|
|
||||||
- name: apisix.dashboard.ingress.hosts[0].host
|
|
||||||
value: apisix-dashboard.onwalk.net
|
|
||||||
- name: apisix.dashboard.ingress.hosts[0].paths[0]
|
|
||||||
value: '/*'
|
|
||||||
- name: apisix.etcd.enabled
|
|
||||||
value: true
|
|
||||||
- name: etcd-adapter.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.web.ingress.enabled
|
|
||||||
value: true
|
|
||||||
- name: novu.web.ingress.ingressClassName
|
|
||||||
value: nginx
|
|
||||||
- name: novu.web.ingress.hostname
|
|
||||||
value: 'novu.onwalk.net'
|
|
||||||
- name: novu.redis.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.externalRedis.host
|
|
||||||
value: redis.local
|
|
||||||
- name: novu.externalRedis.existingSecret
|
|
||||||
value: itsm-redis-secret
|
|
||||||
- name: novu.mongodb.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.externalDatabase.existingSecret
|
|
||||||
value: itsm-mongodb-secret-rw
|
|
||||||
- name: novu.localstack.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.externalS3.existingSecret
|
|
||||||
value: itsm-s3-secret-rw
|
|
||||||
- name: windmill.databaseUrlSecretName
|
|
||||||
value: itsm-postgresql-secret-rw
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
repositories:
|
|
||||||
- name: stable
|
|
||||||
url: https://charts.onwalk.net
|
|
||||||
|
|
||||||
templates:
|
|
||||||
default: &default
|
|
||||||
namespace: itsm-dev
|
|
||||||
createNamespace: true
|
|
||||||
chart: stable/itsm
|
|
||||||
version: 0.1.16
|
|
||||||
|
|
||||||
releases:
|
|
||||||
- name: itsm-dev
|
|
||||||
<<: *default
|
|
||||||
set:
|
|
||||||
- name: apisix.dashboard.enabled
|
|
||||||
value: true
|
|
||||||
- name: apisix.dashboard.ingress.enabled
|
|
||||||
value: true
|
|
||||||
- name: apisix.dashboard.ingress.className
|
|
||||||
value: nginx
|
|
||||||
- name: apisix.dashboard.ingress.hosts[0].host
|
|
||||||
value: apisix-dashboard.onwalk.net
|
|
||||||
- name: apisix.dashboard.ingress.hosts[0].paths[0]
|
|
||||||
value: '/*'
|
|
||||||
- name: apisix.etcd.enabled
|
|
||||||
value: true
|
|
||||||
- name: etcd-adapter.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.web.ingress.enabled
|
|
||||||
value: true
|
|
||||||
- name: novu.web.ingress.ingressClassName
|
|
||||||
value: nginx
|
|
||||||
- name: novu.web.ingress.hostname
|
|
||||||
value: 'novu.onwalk.net'
|
|
||||||
- name: novu.redis.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.externalRedis.host
|
|
||||||
value: redis.local
|
|
||||||
- name: novu.externalRedis.existingSecret
|
|
||||||
value: itsm-redis-secret
|
|
||||||
- name: novu.mongodb.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.externalDatabase.existingSecret
|
|
||||||
value: itsm-mongodb-secret-rw
|
|
||||||
- name: novu.localstack.enabled
|
|
||||||
value: false
|
|
||||||
- name: novu.externalS3.existingSecret
|
|
||||||
value: itsm-s3-secret-rw
|
|
||||||
- name: windmill.databaseUrlSecretName
|
|
||||||
value: itsm-postgresql-secret-rw
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
repositories:
|
|
||||||
- name: bitnami
|
|
||||||
url: https://charts.bitnami.com/bitnami
|
|
||||||
|
|
||||||
releases:
|
|
||||||
- name: postgresql
|
|
||||||
namespace: default
|
|
||||||
chart: bitnami/postgresql
|
|
||||||
values:
|
|
||||||
- auth:
|
|
||||||
username: my-user
|
|
||||||
password: my-password
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: accounts-env
|
name: accounts-env
|
||||||
@ -13,4 +13,3 @@ spec:
|
|||||||
dataFrom:
|
dataFrom:
|
||||||
- extract:
|
- extract:
|
||||||
key: core/pre/accounts
|
key: core/pre/accounts
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: accounts-env
|
name: accounts-env
|
||||||
@ -13,4 +13,3 @@ spec:
|
|||||||
dataFrom:
|
dataFrom:
|
||||||
- extract:
|
- extract:
|
||||||
key: core/prod/accounts
|
key: core/prod/accounts
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: console-env
|
name: console-env
|
||||||
@ -13,4 +13,3 @@ spec:
|
|||||||
dataFrom:
|
dataFrom:
|
||||||
- extract:
|
- extract:
|
||||||
key: core/pre/console
|
key: core/pre/console
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: console-env
|
name: console-env
|
||||||
@ -13,4 +13,3 @@ spec:
|
|||||||
dataFrom:
|
dataFrom:
|
||||||
- extract:
|
- extract:
|
||||||
key: core/prod/console
|
key: core/prod/console
|
||||||
|
|
||||||
|
|||||||
@ -13,4 +13,4 @@ spec:
|
|||||||
name: platform-config
|
name: platform-config
|
||||||
path: ./infra/infrastructure
|
path: ./infra/infrastructure
|
||||||
dependsOn:
|
dependsOn:
|
||||||
- name: platform-secrets-stack
|
- name: platform-stack
|
||||||
|
|||||||
@ -3,8 +3,6 @@ kind: Kustomization
|
|||||||
resources:
|
resources:
|
||||||
- namespaces.yaml
|
- namespaces.yaml
|
||||||
- platform-kustomization.yaml
|
- platform-kustomization.yaml
|
||||||
- platform-secrets-kustomization.yaml
|
|
||||||
- platform-services-kustomization.yaml
|
|
||||||
- infrastructure-kustomization.yaml
|
- infrastructure-kustomization.yaml
|
||||||
- observability-kustomization.yaml
|
- observability-kustomization.yaml
|
||||||
- console-prod-kustomization.yaml
|
- console-prod-kustomization.yaml
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
|
||||||
kind: Kustomization
|
|
||||||
metadata:
|
|
||||||
name: platform-secrets-stack
|
|
||||||
namespace: flux-system
|
|
||||||
spec:
|
|
||||||
interval: 5m0s
|
|
||||||
prune: true
|
|
||||||
wait: true
|
|
||||||
timeout: 5m0s
|
|
||||||
sourceRef:
|
|
||||||
kind: GitRepository
|
|
||||||
name: platform-config
|
|
||||||
path: ./infra/platform-secrets
|
|
||||||
dependsOn:
|
|
||||||
- name: platform-stack
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
|
||||||
kind: Kustomization
|
|
||||||
metadata:
|
|
||||||
name: platform-services-stack
|
|
||||||
namespace: flux-system
|
|
||||||
spec:
|
|
||||||
interval: 5m0s
|
|
||||||
prune: true
|
|
||||||
wait: true
|
|
||||||
timeout: 10m0s
|
|
||||||
sourceRef:
|
|
||||||
kind: GitRepository
|
|
||||||
name: platform-config
|
|
||||||
path: ./infra/platform/external-dns
|
|
||||||
dependsOn:
|
|
||||||
- name: platform-stack
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: postgresql-auth
|
name: postgresql-auth
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: postgresql-stunnel-server
|
name: postgresql-stunnel-server
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
|
||||||
kind: ClusterSecretStore
|
|
||||||
metadata:
|
|
||||||
name: vault-platform
|
|
||||||
spec:
|
|
||||||
provider:
|
|
||||||
vault:
|
|
||||||
server: http://vault.extsvc.svc.cluster.local:8200
|
|
||||||
path: secret
|
|
||||||
version: v2
|
|
||||||
auth:
|
|
||||||
kubernetes:
|
|
||||||
mountPath: kubernetes
|
|
||||||
role: external-secrets
|
|
||||||
serviceAccountRef:
|
|
||||||
name: external-secrets
|
|
||||||
namespace: platform
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
||||||
kind: Kustomization
|
|
||||||
resources:
|
|
||||||
- clustersecretstore.yaml
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
|
||||||
kind: ExternalSecret
|
|
||||||
metadata:
|
|
||||||
name: cloudflare-api-token
|
|
||||||
namespace: platform
|
|
||||||
spec:
|
|
||||||
refreshInterval: 1m
|
|
||||||
secretStoreRef:
|
|
||||||
kind: ClusterSecretStore
|
|
||||||
name: vault-platform
|
|
||||||
target:
|
|
||||||
name: cloudflare-api-token
|
|
||||||
creationPolicy: Owner
|
|
||||||
data:
|
|
||||||
- secretKey: api-token
|
|
||||||
remoteRef:
|
|
||||||
key: platform/cloudflare
|
|
||||||
property: api-token
|
|
||||||
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
|
||||||
kind: HelmRelease
|
|
||||||
metadata:
|
|
||||||
name: external-dns
|
|
||||||
namespace: platform
|
|
||||||
spec:
|
|
||||||
interval: 10m0s
|
|
||||||
chart:
|
|
||||||
spec:
|
|
||||||
chart: external-dns
|
|
||||||
version: ">=1.14.0 <2.0.0"
|
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: external-dns
|
|
||||||
namespace: flux-system
|
|
||||||
install:
|
|
||||||
remediation:
|
|
||||||
retries: 3
|
|
||||||
upgrade:
|
|
||||||
remediation:
|
|
||||||
retries: 3
|
|
||||||
values:
|
|
||||||
provider: cloudflare
|
|
||||||
policy: sync
|
|
||||||
registry: txt
|
|
||||||
txtOwnerId: svc-plus-k3s
|
|
||||||
sources:
|
|
||||||
- ingress
|
|
||||||
domainFilters:
|
|
||||||
- svc.plus
|
|
||||||
env:
|
|
||||||
- name: CF_API_TOKEN
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: cloudflare-api-token
|
|
||||||
key: api-token
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
||||||
kind: Kustomization
|
|
||||||
namespace: platform
|
|
||||||
resources:
|
|
||||||
- externalsecret.yaml
|
|
||||||
- helmrelease.yaml
|
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ spec:
|
|||||||
interval: 10m0s
|
interval: 10m0s
|
||||||
url: oci://ghcr.io/x-evor/k3s-platform-chart
|
url: oci://ghcr.io/x-evor/k3s-platform-chart
|
||||||
ref:
|
ref:
|
||||||
semver: "0.1.3"
|
semver: "0.1.4"
|
||||||
layerSelector:
|
layerSelector:
|
||||||
mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip
|
mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip
|
||||||
operation: copy
|
operation: copy
|
||||||
|
|||||||
@ -73,6 +73,59 @@ components:
|
|||||||
type: roundrobin
|
type: roundrobin
|
||||||
nodes:
|
nodes:
|
||||||
"accounts.core-pre.svc.cluster.local:80": 1
|
"accounts.core-pre.svc.cluster.local:80": 1
|
||||||
|
externalDns:
|
||||||
|
enabled: true
|
||||||
|
releaseName: external-dns
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: external-dns
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: external-dns
|
||||||
|
version: ">=1.14.0 <2.0.0"
|
||||||
|
secret:
|
||||||
|
name: cloudflare-api-token
|
||||||
|
refreshInterval: 1m
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-platform
|
||||||
|
target:
|
||||||
|
name: cloudflare-api-token
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
secretKey: api-token
|
||||||
|
remoteRef:
|
||||||
|
key: platform/cloudflare
|
||||||
|
property: api-token
|
||||||
|
values:
|
||||||
|
provider: cloudflare
|
||||||
|
policy: sync
|
||||||
|
registry: txt
|
||||||
|
txtOwnerId: svc-plus-k3s
|
||||||
|
sources:
|
||||||
|
- ingress
|
||||||
|
domainFilters:
|
||||||
|
- svc.plus
|
||||||
|
env:
|
||||||
|
- name: CF_API_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: cloudflare-api-token
|
||||||
|
key: api-token
|
||||||
|
externalSecretsStore:
|
||||||
|
enabled: true
|
||||||
|
name: vault-platform
|
||||||
|
vault:
|
||||||
|
server: http://vault.extsvc.svc.cluster.local:8200
|
||||||
|
path: secret
|
||||||
|
version: v2
|
||||||
|
auth:
|
||||||
|
kubernetes:
|
||||||
|
mountPath: kubernetes
|
||||||
|
role: external-secrets
|
||||||
|
serviceAccountRef:
|
||||||
|
name: external-secrets
|
||||||
|
namespace: platform
|
||||||
vault:
|
vault:
|
||||||
enabled: true
|
enabled: true
|
||||||
releaseName: vault
|
releaseName: vault
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
[all]
|
|
||||||
k8s-1 ansible_host=13.158.69.227
|
|
||||||
k8s-2 ansible_host=57.183.6.87
|
|
||||||
k8s-3 ansible_host=43.207.133.165
|
|
||||||
|
|
||||||
[all:vars]
|
|
||||||
ansible_port=22
|
|
||||||
ansible_ssh_user=ubuntu
|
|
||||||
ansible_ssh_private_key_file=~/.ssh/id_rsa
|
|
||||||
ansible_host_key_checking=False
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
ansible_port: 22
|
|
||||||
ansible_ssh_user: ubuntu
|
|
||||||
ansible_ssh_private_key_file: ~/.ssh/id_rsa
|
|
||||||
ansible_host_key_checking: False
|
|
||||||
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
[all]
|
|
||||||
xray-sg.svc.plus ansible_host=18.142.253.71
|
|
||||||
cn-console.svc.plus ansible_host=8.155.148.173 ansible_ssh_user=root
|
|
||||||
global-console.svc.plus ansible_host=52.195.9.10
|
|
||||||
|
|
||||||
[gateway]
|
|
||||||
vpn-gateway.svc.plus ansible_host=167.179.72.223 ansible_ssh_user=root
|
|
||||||
|
|
||||||
[all:vars]
|
|
||||||
ansible_port=22
|
|
||||||
ansible_ssh_user=ubuntu
|
|
||||||
ansible_host_key_checking=False
|
|
||||||
ansible_ssh_private_key_file=~/.ssh/id_rsa
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
[vpn-gateway]
|
|
||||||
xproxy.onwalk.net ansible_host=43.206.158.21
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
[all]
|
|
||||||
cn-gateway.svc.plus ansible_host=10.254.0.1
|
|
||||||
cn-k3s-server.svc.plus ansible_host=10.254.0.3
|
|
||||||
cn-hw-node.svc.plus ansible_host=10.254.0.4
|
|
||||||
global-gateway.svc.plus ansible_host=10.255.0.1
|
|
||||||
global-k3s-server.svc.plus ansible_host=10.255.0.3
|
|
||||||
|
|
||||||
[all:vars]
|
|
||||||
ansible_port=22
|
|
||||||
ansible_ssh_user=ubuntu
|
|
||||||
ansible_ssh_private_key_file=~/.ssh/id_rsa
|
|
||||||
ansible_host_key_checking=False
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
# HAProxy Role
|
|
||||||
|
|
||||||
This role provisions a thin, include-only HAProxy configuration tree under `/etc/haproxy/`. It follows a map-driven SNI routing strategy so that new hostnames can be added without touching the frontend logic.
|
|
||||||
|
|
||||||
## Layout
|
|
||||||
```
|
|
||||||
/etc/haproxy/
|
|
||||||
├── haproxy.cfg # Main entry point (kept thin)
|
|
||||||
├── global.cfg # global + defaults
|
|
||||||
├── frontends/
|
|
||||||
│ ├── fe_443.cfg
|
|
||||||
│ └── fe_stats.cfg
|
|
||||||
├── backends/
|
|
||||||
│ ├── console/
|
|
||||||
│ │ ├── bk_cn.cfg
|
|
||||||
│ │ └── bk_global.cfg
|
|
||||||
│ ├── xray/
|
|
||||||
│ │ ├── bk_xray_jp.cfg
|
|
||||||
│ │ ├── bk_xray_sg.cfg
|
|
||||||
│ │ └── bk_xray_hk.cfg
|
|
||||||
│ └── fallback/
|
|
||||||
│ └── bk_blackhole.cfg
|
|
||||||
├── maps/
|
|
||||||
│ ├── sni.map
|
|
||||||
│ └── sni_backend.map
|
|
||||||
├── certs/ # For HTTP/TLS termination if needed
|
|
||||||
├── scripts/
|
|
||||||
│ └── reload.sh
|
|
||||||
└── logs/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Main configuration (`haproxy.cfg`)
|
|
||||||
- Includes `global.cfg` for shared defaults.
|
|
||||||
- Includes all frontends and recursively includes business backends.
|
|
||||||
- Contains no business logic to keep reloads predictable.
|
|
||||||
|
|
||||||
### Global/defaults (`global.cfg`)
|
|
||||||
Applies TCP defaults and keeps per-node tuning minimal. HK/JP can adjust `maxconn` per-node if needed.
|
|
||||||
|
|
||||||
### Frontends
|
|
||||||
- `fe_443.cfg` performs TLS inspection and routes via the SNI map (`maps/sni_backend.map`), falling back to `bk_blackhole`.
|
|
||||||
- `fe_stats.cfg` exposes the HAProxy stats UI on `:8404`.
|
|
||||||
|
|
||||||
### Maps
|
|
||||||
- `maps/sni_backend.map` maps SNI hosts to backends; adding a domain means adding a single line.
|
|
||||||
- `maps/sni.map` documents the expected format when TLS termination is required.
|
|
||||||
|
|
||||||
### Backends
|
|
||||||
Business backends are grouped by domain family (console/xray/fallback) with TCP health checks and consistent timings. The fallback backend intentionally blackholes unmatched traffic.
|
|
||||||
|
|
||||||
### Reload helper
|
|
||||||
`scripts/reload.sh` validates the configuration and reloads HAProxy gracefully (preferring `systemctl` when present).
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
1. Include the role in a play targeting your HAProxy hosts.
|
|
||||||
2. Update `maps/sni_backend.map` with the desired hostname-to-backend mapping.
|
|
||||||
3. Adjust backend server endpoints per site; keep the directory layout identical across regions.
|
|
||||||
4. Run the play to copy the configuration tree and trigger a graceful reload via the handler.
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
haproxy_conf_dir: /etc/haproxy
|
|
||||||
haproxy_user: root
|
|
||||||
haproxy_group: root
|
|
||||||
haproxy_reload_cmd: /etc/haproxy/scripts/reload.sh
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
backend bk_console_cn
|
|
||||||
balance roundrobin
|
|
||||||
option tcp-check
|
|
||||||
default-server inter 3s fall 3 rise 2
|
|
||||||
|
|
||||||
server cn1 10.10.1.1:8443 check
|
|
||||||
server cn2 10.10.1.2:8443 check
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
backend bk_console_global
|
|
||||||
balance roundrobin
|
|
||||||
option tcp-check
|
|
||||||
default-server inter 3s fall 3 rise 2
|
|
||||||
|
|
||||||
server g1 10.10.0.1:8443 check
|
|
||||||
server g2 10.10.0.2:8443 check
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
backend bk_blackhole
|
|
||||||
server reject 127.0.0.1:1
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
backend bk_xray_hk
|
|
||||||
balance roundrobin
|
|
||||||
option tcp-check
|
|
||||||
default-server inter 3s fall 3 rise 2
|
|
||||||
|
|
||||||
server hk1 10.22.0.1:1443 check send-proxy-v2
|
|
||||||
server hk2 10.22.0.2:1443 check send-proxy-v2
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
backend bk_xray_jp
|
|
||||||
balance roundrobin
|
|
||||||
option tcp-check
|
|
||||||
default-server inter 3s fall 3 rise 2
|
|
||||||
|
|
||||||
server jp1 10.20.0.1:1443 check send-proxy-v2
|
|
||||||
server jp2 10.20.0.2:1443 check send-proxy-v2
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
backend bk_xray_sg
|
|
||||||
balance roundrobin
|
|
||||||
option tcp-check
|
|
||||||
default-server inter 3s fall 3 rise 2
|
|
||||||
|
|
||||||
server sg1 10.21.0.1:1443 check send-proxy-v2
|
|
||||||
server sg2 10.21.0.2:1443 check send-proxy-v2
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
frontend fe_443
|
|
||||||
bind :443
|
|
||||||
mode tcp
|
|
||||||
|
|
||||||
tcp-request inspect-delay 5s
|
|
||||||
tcp-request content accept if { req.ssl_hello_type 1 }
|
|
||||||
|
|
||||||
use_backend %[req.ssl_sni,lower,map(/etc/haproxy/maps/sni_backend.map)]
|
|
||||||
default_backend bk_blackhole
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
listen stats
|
|
||||||
bind :8404
|
|
||||||
stats enable
|
|
||||||
stats uri /stats
|
|
||||||
stats refresh 5s
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
global
|
|
||||||
daemon
|
|
||||||
log /dev/log local0
|
|
||||||
maxconn 20000
|
|
||||||
nbthread 1
|
|
||||||
|
|
||||||
defaults
|
|
||||||
mode tcp
|
|
||||||
log global
|
|
||||||
option dontlognull
|
|
||||||
timeout connect 3s
|
|
||||||
timeout client 1m
|
|
||||||
timeout server 1m
|
|
||||||
timeout check 3s
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
# Main HAProxy configuration file (intentionally thin)
|
|
||||||
|
|
||||||
# 引入全局参数
|
|
||||||
include /etc/haproxy/global.cfg
|
|
||||||
|
|
||||||
# Frontends
|
|
||||||
include /etc/haproxy/frontends/*.cfg
|
|
||||||
|
|
||||||
# Backends
|
|
||||||
include /etc/haproxy/backends/**/*.cfg
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
# Map SNI to certificate filenames when terminating TLS locally.
|
|
||||||
# <sni> <certificate-file>
|
|
||||||
# example.com example-com.pem
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
cn-console.sv.plus bk_console_cn
|
|
||||||
global-console.sv.plus bk_console_global
|
|
||||||
xray-jp.svc.plus bk_xray_jp
|
|
||||||
xray-sg.svc.plus bk_xray_sg
|
|
||||||
xray-hk.svc.plus bk_xray_hk
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
CONFIG="/etc/haproxy/haproxy.cfg"
|
|
||||||
PIDFILE="/var/run/haproxy.pid"
|
|
||||||
HAPROXY_BIN="${HAPROXY_BIN:-/usr/sbin/haproxy}"
|
|
||||||
SYSTEMCTL_BIN="${SYSTEMCTL_BIN:-/bin/systemctl}"
|
|
||||||
|
|
||||||
# Validate configuration before applying
|
|
||||||
if ! "${HAPROXY_BIN}" -c -f "${CONFIG}"; then
|
|
||||||
echo "HAProxy configuration validation failed" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Reload HAProxy gracefully
|
|
||||||
if command -v "${SYSTEMCTL_BIN}" >/dev/null 2>&1; then
|
|
||||||
exec "${SYSTEMCTL_BIN}" reload haproxy
|
|
||||||
else
|
|
||||||
if [[ -r "${PIDFILE}" ]]; then
|
|
||||||
exec "${HAPROXY_BIN}" -f "${CONFIG}" -sf "$(cat "${PIDFILE}")"
|
|
||||||
else
|
|
||||||
exec "${HAPROXY_BIN}" -f "${CONFIG}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
- name: reload haproxy
|
|
||||||
ansible.builtin.command: "{{ haproxy_reload_cmd }}"
|
|
||||||
listen: reload haproxy
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
galaxy_info:
|
|
||||||
role_name: haproxy
|
|
||||||
author: gitops
|
|
||||||
description: "HAProxy role with thin main config, map-driven SNI routing, and organized backends."
|
|
||||||
min_ansible_version: "2.10"
|
|
||||||
platforms:
|
|
||||||
- name: EL
|
|
||||||
versions: [8, 9]
|
|
||||||
- name: Debian
|
|
||||||
versions: [11, 12]
|
|
||||||
- name: Ubuntu
|
|
||||||
versions: [20.04, 22.04]
|
|
||||||
|
|
||||||
dependencies: []
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Ensure HAProxy base directory exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ haproxy_conf_dir }}"
|
|
||||||
state: directory
|
|
||||||
owner: "{{ haproxy_user }}"
|
|
||||||
group: "{{ haproxy_group }}"
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Ensure HAProxy subdirectories exist
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ haproxy_conf_dir }}/{{ item }}"
|
|
||||||
state: directory
|
|
||||||
owner: "{{ haproxy_user }}"
|
|
||||||
group: "{{ haproxy_group }}"
|
|
||||||
mode: "0755"
|
|
||||||
loop:
|
|
||||||
- frontends
|
|
||||||
- backends
|
|
||||||
- backends/console
|
|
||||||
- backends/xray
|
|
||||||
- backends/fallback
|
|
||||||
- maps
|
|
||||||
- certs
|
|
||||||
- scripts
|
|
||||||
- logs
|
|
||||||
|
|
||||||
- name: Deploy HAProxy configuration files
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: "etc/haproxy/{{ item.src }}"
|
|
||||||
dest: "{{ haproxy_conf_dir }}/{{ item.dest | default(item.src) }}"
|
|
||||||
owner: "{{ haproxy_user }}"
|
|
||||||
group: "{{ haproxy_group }}"
|
|
||||||
mode: "{{ item.mode | default('0644') }}"
|
|
||||||
loop:
|
|
||||||
- { src: "haproxy.cfg" }
|
|
||||||
- { src: "global.cfg" }
|
|
||||||
- { src: "frontends/fe_443.cfg" }
|
|
||||||
- { src: "frontends/fe_stats.cfg" }
|
|
||||||
- { src: "backends/console/bk_cn.cfg" }
|
|
||||||
- { src: "backends/console/bk_global.cfg" }
|
|
||||||
- { src: "backends/xray/bk_xray_jp.cfg" }
|
|
||||||
- { src: "backends/xray/bk_xray_sg.cfg" }
|
|
||||||
- { src: "backends/xray/bk_xray_hk.cfg" }
|
|
||||||
- { src: "backends/fallback/bk_blackhole.cfg" }
|
|
||||||
- { src: "maps/sni_backend.map" }
|
|
||||||
- { src: "maps/sni.map" }
|
|
||||||
- { src: "certs/.gitkeep" }
|
|
||||||
- { src: "logs/.gitkeep" }
|
|
||||||
- { src: "scripts/reload.sh", mode: "0755" }
|
|
||||||
notify: reload haproxy
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
# Required
|
|
||||||
cloudflare_dns_domain: ""
|
|
||||||
cloudflare_dns_rr: ""
|
|
||||||
cloudflare_dns_type: ""
|
|
||||||
cloudflare_dns_value: ""
|
|
||||||
|
|
||||||
# Optional
|
|
||||||
# Cloudflare TTL supports 1 (automatic) or a provider-dependent range.
|
|
||||||
cloudflare_dns_ttl: 1
|
|
||||||
cloudflare_dns_proxied: false
|
|
||||||
cloudflare_dns_priority: null
|
|
||||||
|
|
||||||
# Secret (pass via extra-vars / env / vault; never commit real values)
|
|
||||||
cloudflare_api_token: ""
|
|
||||||
|
|
||||||
@ -1,194 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import json
|
|
||||||
import urllib.parse
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
|
|
||||||
|
|
||||||
API_BASE = "https://api.cloudflare.com/client/v4"
|
|
||||||
|
|
||||||
|
|
||||||
def _request(method, path, api_token, payload=None, query=None):
|
|
||||||
url = API_BASE + path
|
|
||||||
if query:
|
|
||||||
url += "?" + urllib.parse.urlencode(query)
|
|
||||||
|
|
||||||
body = None
|
|
||||||
if payload is not None:
|
|
||||||
body = json.dumps(payload).encode("utf-8")
|
|
||||||
|
|
||||||
req = urllib.request.Request(url=url, data=body, method=method)
|
|
||||||
req.add_header("Authorization", "Bearer " + api_token)
|
|
||||||
req.add_header("Content-Type", "application/json")
|
|
||||||
|
|
||||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
||||||
raw = resp.read().decode("utf-8")
|
|
||||||
return json.loads(raw)
|
|
||||||
|
|
||||||
|
|
||||||
def _api_ok(data):
|
|
||||||
return isinstance(data, dict) and data.get("success") is True
|
|
||||||
|
|
||||||
|
|
||||||
def _api_first_result(data):
|
|
||||||
if not _api_ok(data):
|
|
||||||
return None
|
|
||||||
res = data.get("result")
|
|
||||||
if isinstance(res, list) and res:
|
|
||||||
return res[0]
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _zone_id(api_token, zone_name):
|
|
||||||
data = _request("GET", "/zones", api_token, query={"name": zone_name, "per_page": 50})
|
|
||||||
z = _api_first_result(data)
|
|
||||||
if not z:
|
|
||||||
return None
|
|
||||||
return z.get("id")
|
|
||||||
|
|
||||||
|
|
||||||
def _record_fqdn(zone, rr):
|
|
||||||
rr = rr.strip()
|
|
||||||
if rr in ("@", zone):
|
|
||||||
return zone
|
|
||||||
return rr + "." + zone
|
|
||||||
|
|
||||||
|
|
||||||
def _get_record(api_token, zone_id, record_type, fqdn):
|
|
||||||
data = _request(
|
|
||||||
"GET",
|
|
||||||
f"/zones/{zone_id}/dns_records",
|
|
||||||
api_token,
|
|
||||||
query={"type": record_type, "name": fqdn, "per_page": 50},
|
|
||||||
)
|
|
||||||
return _api_first_result(data)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=dict(
|
|
||||||
state=dict(type="str", choices=["present", "absent"], default="present"),
|
|
||||||
zone=dict(type="str", required=True),
|
|
||||||
rr=dict(type="str", required=True),
|
|
||||||
type=dict(type="str", required=True),
|
|
||||||
value=dict(type="str"),
|
|
||||||
ttl=dict(type="int", default=1),
|
|
||||||
proxied=dict(type="bool", default=False),
|
|
||||||
priority=dict(type="int", required=False),
|
|
||||||
api_token=dict(type="str", required=True, no_log=True),
|
|
||||||
),
|
|
||||||
supports_check_mode=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
state = module.params["state"]
|
|
||||||
zone = module.params["zone"]
|
|
||||||
rr = module.params["rr"]
|
|
||||||
record_type = module.params["type"].upper()
|
|
||||||
value = module.params["value"]
|
|
||||||
ttl = module.params["ttl"]
|
|
||||||
proxied = module.params["proxied"]
|
|
||||||
priority = module.params.get("priority", None)
|
|
||||||
api_token = module.params["api_token"]
|
|
||||||
|
|
||||||
if state == "present" and not value:
|
|
||||||
module.fail_json(msg="value is required when state=present")
|
|
||||||
|
|
||||||
try:
|
|
||||||
zid = _zone_id(api_token, zone)
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=f"Failed to query Cloudflare zone id: {e}")
|
|
||||||
|
|
||||||
if not zid:
|
|
||||||
module.fail_json(msg=f"Cloudflare zone not found: {zone}")
|
|
||||||
|
|
||||||
fqdn = _record_fqdn(zone, rr)
|
|
||||||
|
|
||||||
try:
|
|
||||||
existing = _get_record(api_token, zid, record_type, fqdn)
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=f"Failed to query Cloudflare DNS record: {e}")
|
|
||||||
|
|
||||||
# ----------------------------
|
|
||||||
# ABSENT
|
|
||||||
# ----------------------------
|
|
||||||
if state == "absent":
|
|
||||||
if not existing:
|
|
||||||
module.exit_json(changed=False, msg="Record already absent")
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
rid = existing.get("id")
|
|
||||||
try:
|
|
||||||
data = _request("DELETE", f"/zones/{zid}/dns_records/{rid}", api_token)
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=f"Failed to delete record: {e}")
|
|
||||||
if not _api_ok(data):
|
|
||||||
module.fail_json(msg="Cloudflare API error deleting record", details=data)
|
|
||||||
module.exit_json(changed=True, msg="Record deleted", record_id=rid, fqdn=fqdn)
|
|
||||||
|
|
||||||
# ----------------------------
|
|
||||||
# PRESENT (create/update)
|
|
||||||
# ----------------------------
|
|
||||||
desired = {
|
|
||||||
"type": record_type,
|
|
||||||
"name": fqdn,
|
|
||||||
"content": value,
|
|
||||||
"ttl": ttl,
|
|
||||||
"proxied": proxied,
|
|
||||||
}
|
|
||||||
if priority is not None:
|
|
||||||
desired["priority"] = priority
|
|
||||||
|
|
||||||
if existing:
|
|
||||||
cur = {
|
|
||||||
"type": existing.get("type"),
|
|
||||||
"name": existing.get("name"),
|
|
||||||
"content": existing.get("content"),
|
|
||||||
"ttl": existing.get("ttl"),
|
|
||||||
"proxied": existing.get("proxied"),
|
|
||||||
}
|
|
||||||
if priority is not None:
|
|
||||||
cur["priority"] = existing.get("priority")
|
|
||||||
|
|
||||||
if cur == desired:
|
|
||||||
module.exit_json(
|
|
||||||
changed=False,
|
|
||||||
msg="Record already up to date",
|
|
||||||
record_id=existing.get("id"),
|
|
||||||
fqdn=fqdn,
|
|
||||||
)
|
|
||||||
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
|
|
||||||
rid = existing.get("id")
|
|
||||||
try:
|
|
||||||
data = _request("PUT", f"/zones/{zid}/dns_records/{rid}", api_token, payload=desired)
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=f"Failed to update record: {e}")
|
|
||||||
if not _api_ok(data):
|
|
||||||
module.fail_json(msg="Cloudflare API error updating record", details=data)
|
|
||||||
module.exit_json(changed=True, msg="Record updated", record_id=rid, fqdn=fqdn)
|
|
||||||
|
|
||||||
# CREATE
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = _request("POST", f"/zones/{zid}/dns_records", api_token, payload=desired)
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=f"Failed to create record: {e}")
|
|
||||||
if not _api_ok(data):
|
|
||||||
module.fail_json(msg="Cloudflare API error creating record", details=data)
|
|
||||||
|
|
||||||
rec = data.get("result") or {}
|
|
||||||
module.exit_json(changed=True, msg="Record created", record_id=rec.get("id"), fqdn=fqdn)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Ensure Cloudflare DNS Record
|
|
||||||
cloudflare_dns_record:
|
|
||||||
state: present
|
|
||||||
zone: "{{ cloudflare_dns_domain }}"
|
|
||||||
rr: "{{ cloudflare_dns_rr }}"
|
|
||||||
type: "{{ cloudflare_dns_type }}"
|
|
||||||
value: "{{ cloudflare_dns_value }}"
|
|
||||||
ttl: "{{ cloudflare_dns_ttl }}"
|
|
||||||
proxied: "{{ cloudflare_dns_proxied }}"
|
|
||||||
priority: "{{ cloudflare_dns_priority }}"
|
|
||||||
api_token: "{{ cloudflare_api_token }}"
|
|
||||||
register: dns_result
|
|
||||||
|
|
||||||
- debug:
|
|
||||||
var: dns_result
|
|
||||||
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
---
|
|
||||||
cloudflare_dns_sync_domain: ""
|
|
||||||
cloudflare_dns_sync_records: []
|
|
||||||
cloudflare_dns_sync_output: "/tmp/dns_records.yaml"
|
|
||||||
|
|
||||||
# Secret: set via extra-vars / env / vault; do not commit real values.
|
|
||||||
cloudflare_api_token: ""
|
|
||||||
|
|
||||||
@ -1,118 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import urllib.parse
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
|
|
||||||
API_BASE = "https://api.cloudflare.com/client/v4"
|
|
||||||
|
|
||||||
|
|
||||||
def _req(method: str, path: str, token: str, payload=None, query=None):
|
|
||||||
url = API_BASE + path
|
|
||||||
if query:
|
|
||||||
url += "?" + urllib.parse.urlencode(query)
|
|
||||||
body = None
|
|
||||||
if payload is not None:
|
|
||||||
body = json.dumps(payload).encode("utf-8")
|
|
||||||
req = urllib.request.Request(url=url, data=body, method=method)
|
|
||||||
req.add_header("Authorization", "Bearer " + token)
|
|
||||||
req.add_header("Content-Type", "application/json")
|
|
||||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
||||||
return json.loads(resp.read().decode("utf-8"))
|
|
||||||
|
|
||||||
|
|
||||||
def _ok(d):
|
|
||||||
return isinstance(d, dict) and d.get("success") is True
|
|
||||||
|
|
||||||
|
|
||||||
def zone_id(token: str, zone_name: str) -> str:
|
|
||||||
d = _req("GET", "/zones", token, query={"name": zone_name, "per_page": 50})
|
|
||||||
if not _ok(d) or not d.get("result"):
|
|
||||||
raise RuntimeError(f"zone not found: {zone_name}")
|
|
||||||
return d["result"][0]["id"]
|
|
||||||
|
|
||||||
|
|
||||||
def fqdn(zone: str, rr: str) -> str:
|
|
||||||
rr = rr.strip()
|
|
||||||
if rr in ("@", zone):
|
|
||||||
return zone
|
|
||||||
return rr + "." + zone
|
|
||||||
|
|
||||||
|
|
||||||
def get_record(token: str, zid: str, rtype: str, name: str):
|
|
||||||
d = _req("GET", f"/zones/{zid}/dns_records", token, query={"type": rtype, "name": name, "per_page": 50})
|
|
||||||
if not _ok(d):
|
|
||||||
raise RuntimeError("query dns_records failed")
|
|
||||||
res = d.get("result") or []
|
|
||||||
return res[0] if res else None
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_record(token: str, zid: str, zone: str, rec: dict):
|
|
||||||
rr = rec["rr"]
|
|
||||||
rtype = rec["type"].upper()
|
|
||||||
value = rec["value"]
|
|
||||||
ttl = int(rec.get("ttl", 1))
|
|
||||||
proxied = bool(rec.get("proxied", False))
|
|
||||||
priority = rec.get("priority", None)
|
|
||||||
|
|
||||||
name = fqdn(zone, rr)
|
|
||||||
desired = {"type": rtype, "name": name, "content": value, "ttl": ttl, "proxied": proxied}
|
|
||||||
if priority is not None:
|
|
||||||
desired["priority"] = int(priority)
|
|
||||||
|
|
||||||
cur = get_record(token, zid, rtype, name)
|
|
||||||
if not cur:
|
|
||||||
print("CREATE:", desired)
|
|
||||||
d = _req("POST", f"/zones/{zid}/dns_records", token, payload=desired)
|
|
||||||
if not _ok(d):
|
|
||||||
raise RuntimeError("create failed: " + json.dumps(d))
|
|
||||||
return
|
|
||||||
|
|
||||||
cur_slim = {
|
|
||||||
"type": cur.get("type"),
|
|
||||||
"name": cur.get("name"),
|
|
||||||
"content": cur.get("content"),
|
|
||||||
"ttl": cur.get("ttl"),
|
|
||||||
"proxied": cur.get("proxied"),
|
|
||||||
}
|
|
||||||
if priority is not None:
|
|
||||||
cur_slim["priority"] = cur.get("priority")
|
|
||||||
|
|
||||||
if cur_slim == desired:
|
|
||||||
print("OK:", desired["name"], desired["type"])
|
|
||||||
return
|
|
||||||
|
|
||||||
print("UPDATE:", desired)
|
|
||||||
rid = cur["id"]
|
|
||||||
d = _req("PUT", f"/zones/{zid}/dns_records/{rid}", token, payload=desired)
|
|
||||||
if not _ok(d):
|
|
||||||
raise RuntimeError("update failed: " + json.dumps(d))
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv: list[str]) -> int:
|
|
||||||
if len(argv) != 2:
|
|
||||||
print(f"usage: {sys.argv[0]} <dns_records.yaml>", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
fn = argv[1]
|
|
||||||
token = os.environ.get("CLOUDFLARE_API_TOKEN", "").strip()
|
|
||||||
if not token:
|
|
||||||
print("CLOUDFLARE_API_TOKEN is required", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
cfg = yaml.safe_load(open(fn, "r", encoding="utf-8")) or {}
|
|
||||||
for zone, recs in cfg.items():
|
|
||||||
zid = zone_id(token, zone)
|
|
||||||
for rec in recs or []:
|
|
||||||
ensure_record(token, zid, zone, rec)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main(sys.argv))
|
|
||||||
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Generate DNS records file from template
|
|
||||||
template:
|
|
||||||
src: dns_records.yaml.j2
|
|
||||||
dest: "{{ cloudflare_dns_sync_output }}"
|
|
||||||
|
|
||||||
- name: Upload dns_sync.py
|
|
||||||
copy:
|
|
||||||
src: dns_sync.py
|
|
||||||
dest: /tmp/dns_sync.py
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Sync DNS records
|
|
||||||
command: >
|
|
||||||
python3 /tmp/dns_sync.py
|
|
||||||
{{ cloudflare_dns_sync_output }}
|
|
||||||
environment:
|
|
||||||
CLOUDFLARE_API_TOKEN: "{{ cloudflare_api_token }}"
|
|
||||||
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
{{ cloudflare_dns_sync_domain }}:
|
|
||||||
{% for rec in cloudflare_dns_sync_records %}
|
|
||||||
- rr: "{{ rec.rr }}"
|
|
||||||
type: "{{ rec.type }}"
|
|
||||||
value: "{{ rec.value }}"
|
|
||||||
ttl: {{ rec.ttl | default(1) }}
|
|
||||||
proxied: {{ rec.proxied | default(false) }}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user