# Custom Resources & Operators Guide ## 🎯 **Overview** This guide explains **Custom Resources (CRs)**, **Custom Resource Definitions (CRDs)**, **Kubernetes Operators**, and how your `freeleaps-devops-reconciler` works as an operator to manage your DevOps infrastructure. --- ## πŸ“Š **What Are Custom Resources?** ### **πŸ”„ CR vs CRD Relationship** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CRD vs CR RELATIONSHIP β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ CUSTOM RESOURCE DEFINITION (CRD) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ apiVersion: apiextensions.k8s.io/v1 β”‚ β”‚ β”‚ β”‚ β”‚ kind: CustomResourceDefinition β”‚ β”‚ β”‚ β”‚ β”‚ metadata: β”‚ β”‚ β”‚ β”‚ β”‚ name: devopsprojects.freeleaps.com β”‚ β”‚ β”‚ β”‚ β”‚ spec: β”‚ β”‚ β”‚ β”‚ β”‚ group: freeleaps.com β”‚ β”‚ β”‚ β”‚ β”‚ names: β”‚ β”‚ β”‚ β”‚ β”‚ kind: DevOpsProject β”‚ β”‚ β”‚ β”‚ β”‚ plural: devopsprojects β”‚ β”‚ β”‚ β”‚ β”‚ scope: Namespaced β”‚ β”‚ β”‚ β”‚ β”‚ versions: β”‚ β”‚ β”‚ β”‚ β”‚ - name: v1alpha1 β”‚ β”‚ β”‚ β”‚ β”‚ schema: β”‚ β”‚ β”‚ β”‚ β”‚ # Schema definition... β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ CUSTOM RESOURCE (CR) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ apiVersion: freeleaps.com/v1alpha1 β”‚ β”‚ β”‚ β”‚ β”‚ kind: DevOpsProject β”‚ β”‚ β”‚ β”‚ β”‚ metadata: β”‚ β”‚ β”‚ β”‚ β”‚ name: my-project β”‚ β”‚ β”‚ β”‚ β”‚ namespace: freeleaps-devops-system β”‚ β”‚ β”‚ β”‚ β”‚ spec: β”‚ β”‚ β”‚ β”‚ β”‚ projectName: "My Awesome Project" β”‚ β”‚ β”‚ β”‚ β”‚ projectId: "my-awesome-project" β”‚ β”‚ β”‚ β”‚ β”‚ git: β”‚ β”‚ β”‚ β”‚ β”‚ url: "https://github.com/myorg/myproject" β”‚ β”‚ β”‚ β”‚ β”‚ branch: "main" β”‚ β”‚ β”‚ β”‚ β”‚ registry: β”‚ β”‚ β”‚ β”‚ β”‚ url: "https://harbor.example.com" β”‚ β”‚ β”‚ β”‚ β”‚ project: "myproject" β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### **🎯 Why Custom Resources?** ```yaml # Instead of managing multiple resources manually: # - Namespace # - ServiceAccount # - Role/RoleBinding # - ConfigMap # - Secret # - Deployment # - Service # - Ingress # You can create ONE custom resource: apiVersion: freeleaps.com/v1alpha1 kind: DevOpsProject metadata: name: my-project spec: projectName: "My Project" projectId: "my-project" git: url: "https://github.com/myorg/myproject" branch: "main" registry: url: "https://harbor.example.com" project: "myproject" ``` --- ## 🏭 **Your DevOps Reconciler Architecture** ### **πŸ“Š Reconciler vs DevOps Repo Relationship** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ RECONCILER + DEVOPS ARCHITECTURE β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ FRELEAPS.COM PLATFORM β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ User β”‚ β”‚ Project β”‚ β”‚ Git β”‚ β”‚ Registry β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Creates β”‚ β”‚ Manager β”‚ β”‚ Webhook β”‚ β”‚ Manager β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Project β”‚ β”‚ Creates β”‚ β”‚ Triggers β”‚ β”‚ Creates β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ DevOps β”‚ β”‚ Event β”‚ β”‚ Repo β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Project β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ RABBITMQ MESSAGE QUEUE β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚DevOpsInit β”‚ β”‚DevOpsReconcileβ”‚ β”‚DevOpsDeploy β”‚ β”‚DevOpsDelete β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Event β”‚ β”‚Event β”‚ β”‚Event β”‚ β”‚Event β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ FRELEAPS-DEVOPS-RECONCILER (OPERATOR) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ CONTROLLERS β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚DevOpsProjectβ”‚ β”‚ArgoSettings β”‚ β”‚Jenkins β”‚ β”‚... β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Controller β”‚ β”‚Controller β”‚ β”‚Settings β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Controller β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ CUSTOM RESOURCES β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚DevOpsProjectβ”‚ β”‚ArgoSettings β”‚ β”‚Jenkins β”‚ β”‚... β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚CR β”‚ β”‚CR β”‚ β”‚Settings β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚CR β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ KUBERNETES RESOURCES β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ArgoCD β”‚ β”‚Jenkins β”‚ β”‚Harbor β”‚ β”‚Namespaces β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Applications β”‚ β”‚Pipelines β”‚ β”‚Repositories β”‚ β”‚Services β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Projects β”‚ β”‚Jobs β”‚ β”‚Credentials β”‚ β”‚Deployments β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Ingresses β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ”§ **Your Custom Resources** ### **1. DevOpsProject CRD** ```yaml # 🏭 ACTUAL CRD FROM YOUR CODEBASE # freeleaps-devops-reconciler/deploy/crds.yaml apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: devopsprojects.freeleaps.com spec: group: freeleaps.com scope: Namespaced names: kind: DevOpsProject plural: devopsprojects shortNames: [dop, dops] versions: - name: v1alpha1 served: true storage: true schema: openAPIV3Schema: type: object required: ['spec'] properties: spec: type: object required: - projectName - projectId - git - registry - environments properties: projectName: type: string description: "Human readable project name" projectId: type: string description: "Unique project identifier" pattern: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" git: type: object required: [url, branch] properties: url: type: string description: "Git repository URL" branch: type: string description: "Default git branch" default: "main" registry: type: object required: [url, project] properties: url: type: string description: "Container registry URL" project: type: string description: "Registry project name" ``` ### **2. DevOpsProject CR Example** ```yaml # 🏭 ACTUAL CR EXAMPLE apiVersion: freeleaps.com/v1alpha1 kind: DevOpsProject metadata: name: magicleaps-frontend namespace: freeleaps-devops-system labels: app.kubernetes.io/name: magicleaps-frontend app.kubernetes.io/instance: magicleaps-frontend spec: projectName: "Magicleaps Frontend" projectId: "magicleaps-frontend" git: url: "https://github.com/freeleaps/magicleaps-frontend" branch: "main" credentialsRef: name: "github-credentials" namespace: "freeleaps-devops-system" registry: url: "https://harbor.freeleaps.mathmast.com" project: "magicleaps" credentialsRef: name: "harbor-credentials" namespace: "freeleaps-devops-system" environments: - name: "production" domain: "magicleaps.mathmast.com" replicas: 3 - name: "alpha" domain: "alpha.magicleaps.mathmast.com" replicas: 1 ``` ### **3. Other Custom Resources** ```yaml # 🏭 YOUR COMPLETE CRD SET # From freeleaps-devops-reconciler/docs/design/one-click-deployment.md # DevOpsProject - Main project configuration # ArgoSettings - ArgoCD settings for the DevOpsProject # JenkinsSettings - Jenkins settings and generated pipelines # ContainerRegistry - Container registry information # ContainerImage - Every image manufactured by Jenkins pipeline # DeploymentRecord - Track deployment records # GitCredential - Git repository credentials # IngressResource - Ingress configuration ``` --- ## πŸ€– **How Your Operator Works** ### **πŸ”„ Reconciliation Loop** ```python # 🏭 ACTUAL CODE FROM YOUR RECONCILER # freeleaps-devops-reconciler/reconciler/controllers/devops_projects/controller.py @kopf.on.create(group=consts.GROUP, version=consts.VERSION, kind=consts.DEVOPS_PROJECT_KIND) def on_devops_proj_created(name: str, namespace: Optional[str], body: Body, logger: Logger, **kwargs): logger.info(f"Newly created DevOpsProject resource and named {name} in namespace {namespace}, start to reconciling...") devops_proj = DevOpsProject(body) try: devops_proj.parse_spec() devops_proj.get_spec().validate(logger) except SpecError as e: devops_proj.update_status({ 'devopsProject': { 'status': DevOpsProjectDiagStatus.INVALID.value, 'synced': False, 'ready': False, 'lastProbeTime': isotime(), } }) devops_proj.error(action='CreateDevOpsProject', reason='InvalidSpecArgument', msg=str(e)) raise kopf.TemporaryError(f"Error found in DevOpsProject spec: {e}") # Create resource manager and handle the project resource_manager = DevOpsProjectResourceManager(namespace, logger) # ... implementation details ``` ### **πŸ“Š Event Flow** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ EVENT FLOW β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ User β”‚ β”‚ RabbitMQ β”‚ β”‚ Operator β”‚ β”‚ Kubernetes β”‚ β”‚ β”‚ β”‚ Action β”‚ β”‚ Message β”‚ β”‚ Controllerβ”‚ β”‚ Resources β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 1. Create β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Project β”‚ β”‚ β”‚ β”‚ β”‚ │───────────────▢│ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 2. DevOpsInit β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Event β”‚ β”‚ β”‚ β”‚ β”‚ │───────────────▢│ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 3. Create CR β”‚ β”‚ β”‚ β”‚ β”‚ │───────────────▢│ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 4. CR Created β”‚ β”‚ β”‚ β”‚ β”‚ │◀───────────────│ β”‚ β”‚ β”‚ β”‚ 5. Reconcile β”‚ β”‚ β”‚ β”‚ β”‚ │◀───────────────│ β”‚ β”‚ β”‚ β”‚ β”‚ 6. Create β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Resources β”‚ β”‚ β”‚ β”‚ β”‚ │───────────────▢│ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 7. Resources β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Ready β”‚ β”‚ β”‚ β”‚ β”‚ │◀───────────────│ β”‚ β”‚ β”‚ β”‚ 8. Update β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Status β”‚ β”‚ β”‚ β”‚ β”‚ │◀───────────────│ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## 🎯 **Understanding the Relationship** ### **πŸ“Š Reconciler vs DevOps Repo** | Component | Purpose | Location | Responsibility | |-----------|---------|----------|----------------| | **freeleaps-devops-reconciler** | **Kubernetes Operator** | `freeleaps-ops/freeleaps-devops-reconciler/` | Watches CRs, creates K8s resources | | **freeleaps.com Platform** | **Business Logic** | `freeleaps-service-hub/` | User interface, project management | | **RabbitMQ** | **Message Queue** | Infrastructure | Event communication | | **ArgoCD** | **GitOps** | `freeleaps-ops/cluster/manifests/` | Application deployment | | **Jenkins** | **CI/CD** | Infrastructure | Pipeline execution | ### **πŸ”„ How They Work Together** ```yaml # 1. User creates project on freeleaps.com # 2. Platform sends DevOpsInit event to RabbitMQ # 3. Reconciler receives event and creates DevOpsProject CR # 4. Reconciler watches CR and creates: # - ArgoCD Application # - Jenkins Pipeline # - Harbor Repository # - Namespace and RBAC # 5. ArgoCD deploys the application # 6. Jenkins runs the pipeline ``` --- ## πŸ”§ **Practical Examples** ### **1. Creating a DevOpsProject** ```bash # Create a DevOpsProject CR kubectl apply -f - < -n # Check CR YAML kubectl get devopsproject -n -o yaml ``` ### **3. Check Created Resources** ```bash # Check what resources were created kubectl get all -n # Check ArgoCD applications kubectl get applications -n freeleaps-devops-system # Check Jenkins pipelines kubectl get jenkinssettings --all-namespaces ``` --- ## πŸ“š **Next Steps** ### **1. Learn More About Operators** - [Kubernetes Operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) - [Kopf Framework](https://kopf.readthedocs.io/) (what your reconciler uses) - [Operator SDK](https://sdk.operatorframework.io/) ### **2. Understand Your Architecture** - Study your `freeleaps-devops-reconciler` code - Understand the event flow from RabbitMQ - Learn how CRs trigger resource creation ### **3. Extend Your Operator** - Add new custom resources - Implement new controllers - Add validation and error handling --- **Last Updated**: September 3, 2025 **Version**: 1.0 **Maintainer**: Infrastructure Team