diff --git a/README.md b/README.md index 334f6d5..885159c 100644 --- a/README.md +++ b/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). -Additional documentation is stored under the `docs/` folder. +## Scope -## 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 进行容器化管理。 -2. playbooks/roles/charts:面向大规模的 Kubernetes 集群,使用 Helm 和标准化 Chart 部署模式进行高可用和可扩展的管理。 -3. playbooks/roles/vhosts:传统的非容器化部署方式,通常涉及手动配置服务器和虚拟主机,适用于不使用容器的应用场景。 +## Layout +- `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 - -| 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. - +For a quick structure overview, see [docs/repo-structure.md](docs/repo-structure.md). diff --git a/config/sit/vpn-keys.md b/config/sit/vpn-keys.md deleted file mode 100644 index 2294d75..0000000 --- a/config/sit/vpn-keys.md +++ /dev/null @@ -1,19 +0,0 @@ -只加密 private_key 字段 -1. 原始 vpn-keys.yaml -yaml -keys: - - name: master-1 - private_key: - 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 diff --git a/config/sit/vpn-keys.yaml b/config/sit/vpn-keys.yaml deleted file mode 100644 index 6586bdc..0000000 --- a/config/sit/vpn-keys.yaml +++ /dev/null @@ -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 - diff --git a/docs/README.md b/docs/README.md index 86a685e..6a2ba8e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,13 +21,12 @@ This `docs/` directory now has a bilingual canonical layer for the current repos ## Current Repo Context / 当前仓库背景 -- Root README: `ansible-playbook` +- Root README: `Cloud-Neutral Toolkit GitOps` - Previous docs index: `Documentation` - 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 / 需要继续归并的现有文档 -- `gpu-k8s-role.md` - `repo-structure.md` - `stackflow/README.md` diff --git a/docs/en/README.md b/docs/en/README.md index 0c42527..aaef831 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -1,12 +1,12 @@ # 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 -- Root README title: `ansible-playbook` +- Root README title: `Cloud-Neutral Toolkit GitOps` - 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 ## Canonical pages @@ -20,6 +20,5 @@ This repository organizes GitOps assets, playbooks, and operational roles for in ## Legacy docs to fold in -- `gpu-k8s-role.md` - `repo-structure.md` - `stackflow/README.md` diff --git a/docs/en/architecture.md b/docs/en/architecture.md index 8ad2ace..66ac22b 100644 --- a/docs/en/architecture.md +++ b/docs/en/architecture.md @@ -1,6 +1,6 @@ # 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. diff --git a/docs/en/deployment.md b/docs/en/deployment.md index c36d318..f748569 100644 --- a/docs/en/deployment.md +++ b/docs/en/deployment.md @@ -1,6 +1,6 @@ # 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. diff --git a/docs/en/design.md b/docs/en/design.md index ea398f3..57a663e 100644 --- a/docs/en/design.md +++ b/docs/en/design.md @@ -1,6 +1,6 @@ # 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. diff --git a/docs/en/developer-guide.md b/docs/en/developer-guide.md index 6064394..3cd899e 100644 --- a/docs/en/developer-guide.md +++ b/docs/en/developer-guide.md @@ -1,6 +1,6 @@ # 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. diff --git a/docs/en/user-guide.md b/docs/en/user-guide.md index d940bac..f7407bb 100644 --- a/docs/en/user-guide.md +++ b/docs/en/user-guide.md @@ -1,6 +1,6 @@ # 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. diff --git a/docs/en/vibe-coding-reference.md b/docs/en/vibe-coding-reference.md index acf5caf..cf65cc0 100644 --- a/docs/en/vibe-coding-reference.md +++ b/docs/en/vibe-coding-reference.md @@ -1,6 +1,6 @@ # 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. diff --git a/docs/gpu-k8s-role.md b/docs/gpu-k8s-role.md deleted file mode 100644 index 472d847..0000000 --- a/docs/gpu-k8s-role.md +++ /dev/null @@ -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: \ - ${REGISTRY}/cilium: \ - ${REGISTRY}/helm: \ - --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. diff --git a/docs/repo-structure.md b/docs/repo-structure.md index b1a4052..6ab15d3 100644 --- a/docs/repo-structure.md +++ b/docs/repo-structure.md @@ -1,19 +1,12 @@ # Repository Structure -This repository combines Ansible playbooks with Kubernetes manifests and -automation scripts. Below is a short overview of the key directories. +This repository contains declarative GitOps assets only. Below is a short overview of the key directories. | Directory | Purpose | |-----------|---------| -| `playbooks` | Ansible playbooks and role definitions. | | `apps` | Flux HelmRelease and Kustomize files for applications. | | `clusters` | Kustomize overlays for different clusters referencing the `apps` definitions. | -| `helmfiles` | Sample [helmfile](https://github.com/helmfile/helmfile) declarations. | -| `helm` | Local Helm charts used in some playbooks. | -| `inventory` | Example inventories and group variables for Ansible. | -| `scripts` | Utility scripts such as cluster setup or secret management. | -| `sync` | Tasks for local host setup and testing. | +| `infra` | Platform and infrastructure declarations managed by Flux. | +| `scripts` | Utility scripts that support validation or operational workflows. | +| `config` | Non-sensitive configuration references and examples. | | `docs` | Additional documentation. | - -See `docs/gpu-k8s-role.md` for an example walkthrough deploying a GPU-enabled -Kubernetes cluster. diff --git a/docs/stackflow/README.md b/docs/stackflow/README.md index be60c05..bf270c5 100644 --- a/docs/stackflow/README.md +++ b/docs/stackflow/README.md @@ -1,10 +1,9 @@ # StackFlow (GitOps YAML Flow) 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: -- `playbooks/` (Ansible provisioning for vhosts/docker/k3s) - `iac-template/` (Terraform reference templates) - `.github/workflows/` (bootstrap workflows) @@ -27,7 +26,7 @@ Top-level: - `kind`: `StackFlow` - `metadata.name`: stack id - `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` - `targets[]`: list of deployable targets @@ -52,7 +51,7 @@ Planned phases: - `dns-plan`: output required DNS records (no apply) - `dns-apply`: apply DNS changes (provider-specific) - `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 Today we only ship `validate` + `dns-plan` as the first step. diff --git a/docs/zh/README.md b/docs/zh/README.md index d440457..622ce2d 100644 --- a/docs/zh/README.md +++ b/docs/zh/README.md @@ -1,12 +1,12 @@ # GitOps 运维仓库 文档 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 ## 当前状态快照 -- 根 README 标题: `ansible-playbook` +- 根 README 标题: `Cloud-Neutral Toolkit GitOps` - 构建与运行时证据: repository structure and scripts only -- 自动识别的主要目录: `scripts/`, `StackFlow/`, `config/` +- 自动识别的主要目录: `infra/`, `apps/`, `clusters/`, `config/`, `scripts/` - 现有文档数量: 3 ## 核心双语文档 @@ -20,6 +20,5 @@ ## 待归并的历史文档 -- `gpu-k8s-role.md` - `repo-structure.md` - `stackflow/README.md` diff --git a/docs/zh/architecture.md b/docs/zh/architecture.md index 3325ae5..355b1f5 100644 --- a/docs/zh/architecture.md +++ b/docs/zh/architecture.md @@ -1,6 +1,6 @@ # 架构 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 本页作为系统边界、核心组件与仓库职责的双语总览入口。 diff --git a/docs/zh/deployment.md b/docs/zh/deployment.md index 4170f84..ddab27a 100644 --- a/docs/zh/deployment.md +++ b/docs/zh/deployment.md @@ -1,6 +1,6 @@ # 部署 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 本页用于统一部署前提、支持的拓扑、运维检查项与回滚注意事项。 diff --git a/docs/zh/design.md b/docs/zh/design.md index 70238ad..8bb5cdb 100644 --- a/docs/zh/design.md +++ b/docs/zh/design.md @@ -1,6 +1,6 @@ # 设计 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 本页用于汇总设计决策、类似 ADR 的权衡记录,以及与路线图相关的实现说明。 diff --git a/docs/zh/developer-guide.md b/docs/zh/developer-guide.md index 1eae4e3..29fe92c 100644 --- a/docs/zh/developer-guide.md +++ b/docs/zh/developer-guide.md @@ -1,6 +1,6 @@ # 开发手册 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 本页用于记录本地开发环境、项目结构、测试面与贴合当前代码库的贡献约定。 diff --git a/docs/zh/user-guide.md b/docs/zh/user-guide.md index 7e72a44..73003c1 100644 --- a/docs/zh/user-guide.md +++ b/docs/zh/user-guide.md @@ -1,6 +1,6 @@ # 使用手册 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 本页用于记录主要用户或运维角色的日常任务、常见流程,以及现有操作文档入口。 diff --git a/docs/zh/vibe-coding-reference.md b/docs/zh/vibe-coding-reference.md index a45bc1b..ea586a7 100644 --- a/docs/zh/vibe-coding-reference.md +++ b/docs/zh/vibe-coding-reference.md @@ -1,6 +1,6 @@ # Vibe Coding 参考 -该仓库组织 GitOps 资产、Playbook 与基础设施交付所需的运维角色。 +该仓库仅组织声明式 GitOps 资产,用于基础设施与应用交付。 本页用于统一 AI 辅助开发提示词、仓库边界、安全编辑规则与文档同步要求。 diff --git a/helmfiles/app-frontend.yaml b/helmfiles/app-frontend.yaml deleted file mode 100644 index e53c708..0000000 --- a/helmfiles/app-frontend.yaml +++ /dev/null @@ -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: "" diff --git a/helmfiles/itsm-backend-ticketing.yaml b/helmfiles/itsm-backend-ticketing.yaml deleted file mode 100644 index 86e4cfd..0000000 --- a/helmfiles/itsm-backend-ticketing.yaml +++ /dev/null @@ -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 diff --git a/helmfiles/itsm.yaml b/helmfiles/itsm.yaml deleted file mode 100644 index b668a0a..0000000 --- a/helmfiles/itsm.yaml +++ /dev/null @@ -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 diff --git a/helmfiles/itsm/helmfile.yaml b/helmfiles/itsm/helmfile.yaml deleted file mode 100644 index 49abac3..0000000 --- a/helmfiles/itsm/helmfile.yaml +++ /dev/null @@ -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 diff --git a/helmfiles/test/helmfile.yaml b/helmfiles/test/helmfile.yaml deleted file mode 100644 index 738b193..0000000 --- a/helmfiles/test/helmfile.yaml +++ /dev/null @@ -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 diff --git a/infra/apps/core/accounts/pre/externalsecret.yaml b/infra/apps/core/accounts/pre/externalsecret.yaml index 5b91669..2bddd98 100644 --- a/infra/apps/core/accounts/pre/externalsecret.yaml +++ b/infra/apps/core/accounts/pre/externalsecret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: accounts-env @@ -13,4 +13,3 @@ spec: dataFrom: - extract: key: core/pre/accounts - diff --git a/infra/apps/core/accounts/prod/externalsecret.yaml b/infra/apps/core/accounts/prod/externalsecret.yaml index e8541c1..8c809bc 100644 --- a/infra/apps/core/accounts/prod/externalsecret.yaml +++ b/infra/apps/core/accounts/prod/externalsecret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: accounts-env @@ -13,4 +13,3 @@ spec: dataFrom: - extract: key: core/prod/accounts - diff --git a/infra/apps/core/console/pre/externalsecret.yaml b/infra/apps/core/console/pre/externalsecret.yaml index e29e6fa..0c9c935 100644 --- a/infra/apps/core/console/pre/externalsecret.yaml +++ b/infra/apps/core/console/pre/externalsecret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: console-env @@ -13,4 +13,3 @@ spec: dataFrom: - extract: key: core/pre/console - diff --git a/infra/apps/core/console/prod/externalsecret.yaml b/infra/apps/core/console/prod/externalsecret.yaml index 67d2824..344e0e0 100644 --- a/infra/apps/core/console/prod/externalsecret.yaml +++ b/infra/apps/core/console/prod/externalsecret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: console-env @@ -13,4 +13,3 @@ spec: dataFrom: - extract: key: core/prod/console - diff --git a/infra/clusters/prod/infrastructure-kustomization.yaml b/infra/clusters/prod/infrastructure-kustomization.yaml index 82df881..603c68d 100644 --- a/infra/clusters/prod/infrastructure-kustomization.yaml +++ b/infra/clusters/prod/infrastructure-kustomization.yaml @@ -13,4 +13,4 @@ spec: name: platform-config path: ./infra/infrastructure dependsOn: - - name: platform-secrets-stack + - name: platform-stack diff --git a/infra/clusters/prod/kustomization.yaml b/infra/clusters/prod/kustomization.yaml index 36719a9..6ab8ebd 100644 --- a/infra/clusters/prod/kustomization.yaml +++ b/infra/clusters/prod/kustomization.yaml @@ -3,8 +3,6 @@ kind: Kustomization resources: - namespaces.yaml - platform-kustomization.yaml - - platform-secrets-kustomization.yaml - - platform-services-kustomization.yaml - infrastructure-kustomization.yaml - observability-kustomization.yaml - console-prod-kustomization.yaml diff --git a/infra/clusters/prod/platform-secrets-kustomization.yaml b/infra/clusters/prod/platform-secrets-kustomization.yaml deleted file mode 100644 index fa82f49..0000000 --- a/infra/clusters/prod/platform-secrets-kustomization.yaml +++ /dev/null @@ -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 diff --git a/infra/clusters/prod/platform-services-kustomization.yaml b/infra/clusters/prod/platform-services-kustomization.yaml deleted file mode 100644 index 5311926..0000000 --- a/infra/clusters/prod/platform-services-kustomization.yaml +++ /dev/null @@ -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 diff --git a/infra/infrastructure/postgresql/externalsecret.yaml b/infra/infrastructure/postgresql/externalsecret.yaml index 3b79ab5..8ae9815 100644 --- a/infra/infrastructure/postgresql/externalsecret.yaml +++ b/infra/infrastructure/postgresql/externalsecret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: postgresql-auth diff --git a/infra/infrastructure/postgresql/stunnel-externalsecret.yaml b/infra/infrastructure/postgresql/stunnel-externalsecret.yaml index d3bec2e..d360b6f 100644 --- a/infra/infrastructure/postgresql/stunnel-externalsecret.yaml +++ b/infra/infrastructure/postgresql/stunnel-externalsecret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: postgresql-stunnel-server diff --git a/infra/platform-secrets/clustersecretstore.yaml b/infra/platform-secrets/clustersecretstore.yaml deleted file mode 100644 index ed57d74..0000000 --- a/infra/platform-secrets/clustersecretstore.yaml +++ /dev/null @@ -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 diff --git a/infra/platform-secrets/kustomization.yaml b/infra/platform-secrets/kustomization.yaml deleted file mode 100644 index a9d66de..0000000 --- a/infra/platform-secrets/kustomization.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clustersecretstore.yaml diff --git a/infra/platform/external-dns/externalsecret.yaml b/infra/platform/external-dns/externalsecret.yaml deleted file mode 100644 index 91da99b..0000000 --- a/infra/platform/external-dns/externalsecret.yaml +++ /dev/null @@ -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 - diff --git a/infra/platform/external-dns/helmrelease.yaml b/infra/platform/external-dns/helmrelease.yaml deleted file mode 100644 index 5d6030b..0000000 --- a/infra/platform/external-dns/helmrelease.yaml +++ /dev/null @@ -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 diff --git a/infra/platform/external-dns/kustomization.yaml b/infra/platform/external-dns/kustomization.yaml deleted file mode 100644 index 93594b4..0000000 --- a/infra/platform/external-dns/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -namespace: platform -resources: - - externalsecret.yaml - - helmrelease.yaml - diff --git a/infra/platform/k3s-platform/oci-repository.yaml b/infra/platform/k3s-platform/oci-repository.yaml index 690027e..3d50c45 100644 --- a/infra/platform/k3s-platform/oci-repository.yaml +++ b/infra/platform/k3s-platform/oci-repository.yaml @@ -7,7 +7,7 @@ spec: interval: 10m0s url: oci://ghcr.io/x-evor/k3s-platform-chart ref: - semver: "0.1.3" + semver: "0.1.4" layerSelector: mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip operation: copy diff --git a/infra/platform/k3s-platform/values.yaml b/infra/platform/k3s-platform/values.yaml index 4d90d96..f167b3e 100644 --- a/infra/platform/k3s-platform/values.yaml +++ b/infra/platform/k3s-platform/values.yaml @@ -73,6 +73,59 @@ components: type: roundrobin nodes: "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: enabled: true releaseName: vault diff --git a/inventory/gpu_k8s_cluster b/inventory/gpu_k8s_cluster deleted file mode 100644 index 36e0b65..0000000 --- a/inventory/gpu_k8s_cluster +++ /dev/null @@ -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 diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml deleted file mode 100644 index f04e15a..0000000 --- a/inventory/group_vars/all.yml +++ /dev/null @@ -1,5 +0,0 @@ -ansible_port: 22 -ansible_ssh_user: ubuntu -ansible_ssh_private_key_file: ~/.ssh/id_rsa -ansible_host_key_checking: False - diff --git a/inventory/hosts/all b/inventory/hosts/all deleted file mode 100644 index ff98fb1..0000000 --- a/inventory/hosts/all +++ /dev/null @@ -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 diff --git a/inventory/hosts/vpn b/inventory/hosts/vpn deleted file mode 100644 index 24ab9dd..0000000 --- a/inventory/hosts/vpn +++ /dev/null @@ -1,2 +0,0 @@ -[vpn-gateway] -xproxy.onwalk.net ansible_host=43.206.158.21 diff --git a/inventory/k3s-cluster b/inventory/k3s-cluster deleted file mode 100644 index 117c650..0000000 --- a/inventory/k3s-cluster +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/README.md b/playbooks/roles/vhosts/HAProxy/README.md deleted file mode 100644 index 5443bca..0000000 --- a/playbooks/roles/vhosts/HAProxy/README.md +++ /dev/null @@ -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. diff --git a/playbooks/roles/vhosts/HAProxy/defaults/main.yml b/playbooks/roles/vhosts/HAProxy/defaults/main.yml deleted file mode 100644 index e149261..0000000 --- a/playbooks/roles/vhosts/HAProxy/defaults/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -haproxy_conf_dir: /etc/haproxy -haproxy_user: root -haproxy_group: root -haproxy_reload_cmd: /etc/haproxy/scripts/reload.sh diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/console/bk_cn.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/console/bk_cn.cfg deleted file mode 100644 index 8ae7991..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/console/bk_cn.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/console/bk_global.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/console/bk_global.cfg deleted file mode 100644 index 63a8c59..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/console/bk_global.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/fallback/bk_blackhole.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/fallback/bk_blackhole.cfg deleted file mode 100644 index 706179c..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/fallback/bk_blackhole.cfg +++ /dev/null @@ -1,2 +0,0 @@ -backend bk_blackhole - server reject 127.0.0.1:1 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_hk.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_hk.cfg deleted file mode 100644 index 74ce711..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_hk.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_jp.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_jp.cfg deleted file mode 100644 index d6d5c81..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_jp.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_sg.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_sg.cfg deleted file mode 100644 index 78c391d..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/backends/xray/bk_xray_sg.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/certs/.gitkeep b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/certs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/frontends/fe_443.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/frontends/fe_443.cfg deleted file mode 100644 index 9ad2f96..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/frontends/fe_443.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/frontends/fe_stats.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/frontends/fe_stats.cfg deleted file mode 100644 index 249edc3..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/frontends/fe_stats.cfg +++ /dev/null @@ -1,5 +0,0 @@ -listen stats - bind :8404 - stats enable - stats uri /stats - stats refresh 5s diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/global.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/global.cfg deleted file mode 100644 index b7e5816..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/global.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/haproxy.cfg b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/haproxy.cfg deleted file mode 100644 index 395b18f..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/haproxy.cfg +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/logs/.gitkeep b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/logs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/maps/sni.map b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/maps/sni.map deleted file mode 100644 index 9ff76a9..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/maps/sni.map +++ /dev/null @@ -1,3 +0,0 @@ -# Map SNI to certificate filenames when terminating TLS locally. -# -# example.com example-com.pem diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/maps/sni_backend.map b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/maps/sni_backend.map deleted file mode 100644 index a86c3d6..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/maps/sni_backend.map +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/scripts/reload.sh b/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/scripts/reload.sh deleted file mode 100644 index da2a75d..0000000 --- a/playbooks/roles/vhosts/HAProxy/files/etc/haproxy/scripts/reload.sh +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/HAProxy/handlers/main.yml b/playbooks/roles/vhosts/HAProxy/handlers/main.yml deleted file mode 100644 index b609bda..0000000 --- a/playbooks/roles/vhosts/HAProxy/handlers/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -- name: reload haproxy - ansible.builtin.command: "{{ haproxy_reload_cmd }}" - listen: reload haproxy diff --git a/playbooks/roles/vhosts/HAProxy/meta/main.yml b/playbooks/roles/vhosts/HAProxy/meta/main.yml deleted file mode 100644 index a384687..0000000 --- a/playbooks/roles/vhosts/HAProxy/meta/main.yml +++ /dev/null @@ -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: [] diff --git a/playbooks/roles/vhosts/HAProxy/tasks/main.yml b/playbooks/roles/vhosts/HAProxy/tasks/main.yml deleted file mode 100644 index c0cd6c4..0000000 --- a/playbooks/roles/vhosts/HAProxy/tasks/main.yml +++ /dev/null @@ -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 diff --git a/playbooks/roles/vhosts/cloudflare_dns_record/defaults/main.yml b/playbooks/roles/vhosts/cloudflare_dns_record/defaults/main.yml deleted file mode 100644 index 0d1c8ad..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_record/defaults/main.yml +++ /dev/null @@ -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: "" - diff --git a/playbooks/roles/vhosts/cloudflare_dns_record/library/cloudflare_dns_record.py b/playbooks/roles/vhosts/cloudflare_dns_record/library/cloudflare_dns_record.py deleted file mode 100644 index b71d5a7..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_record/library/cloudflare_dns_record.py +++ /dev/null @@ -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() - diff --git a/playbooks/roles/vhosts/cloudflare_dns_record/tasks/main.yml b/playbooks/roles/vhosts/cloudflare_dns_record/tasks/main.yml deleted file mode 100644 index 53163e0..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_record/tasks/main.yml +++ /dev/null @@ -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 - diff --git a/playbooks/roles/vhosts/cloudflare_dns_sync/defaults/main.yml b/playbooks/roles/vhosts/cloudflare_dns_sync/defaults/main.yml deleted file mode 100644 index daaac63..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_sync/defaults/main.yml +++ /dev/null @@ -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: "" - diff --git a/playbooks/roles/vhosts/cloudflare_dns_sync/files/dns_sync.py b/playbooks/roles/vhosts/cloudflare_dns_sync/files/dns_sync.py deleted file mode 100644 index 9f795a7..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_sync/files/dns_sync.py +++ /dev/null @@ -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]} ", 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)) - diff --git a/playbooks/roles/vhosts/cloudflare_dns_sync/tasks/main.yaml b/playbooks/roles/vhosts/cloudflare_dns_sync/tasks/main.yaml deleted file mode 100644 index 8795efa..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_sync/tasks/main.yaml +++ /dev/null @@ -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 }}" - diff --git a/playbooks/roles/vhosts/cloudflare_dns_sync/templates/dns_records.yaml.j2 b/playbooks/roles/vhosts/cloudflare_dns_sync/templates/dns_records.yaml.j2 deleted file mode 100644 index 4282fa1..0000000 --- a/playbooks/roles/vhosts/cloudflare_dns_sync/templates/dns_records.yaml.j2 +++ /dev/null @@ -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 %} -