{"id":22919348,"url":"https://github.com/jlsalvador/simple-cicd","last_synced_at":"2026-03-11T17:02:42.600Z","repository":{"id":196296753,"uuid":"694500051","full_name":"jlsalvador/simple-cicd","owner":"jlsalvador","description":"Simple CI/CD operator for Kubernetes. Create workflows that can be trigged by webhooks.","archived":false,"fork":false,"pushed_at":"2024-03-05T18:36:20.000Z","size":282,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-01T02:53:57.156Z","etag":null,"topics":["cd","ci","ci-cd","cicd","controller","k8s","k8s-controller","k8s-operator","kubebuilder","kubernetes","kubernetes-controller","kubernetes-operator","operator","pipeline","webhook","webhook-server"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jlsalvador.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-21T05:59:27.000Z","updated_at":"2024-09-26T09:20:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"fec31991-1745-4180-814e-f62afb0850d7","html_url":"https://github.com/jlsalvador/simple-cicd","commit_stats":null,"previous_names":["jlsalvador/simple-cicd"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlsalvador%2Fsimple-cicd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlsalvador%2Fsimple-cicd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlsalvador%2Fsimple-cicd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlsalvador%2Fsimple-cicd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jlsalvador","download_url":"https://codeload.github.com/jlsalvador/simple-cicd/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253814988,"owners_count":21968561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cd","ci","ci-cd","cicd","controller","k8s","k8s-controller","k8s-operator","kubebuilder","kubernetes","kubernetes-controller","kubernetes-operator","operator","pipeline","webhook","webhook-server"],"created_at":"2024-12-14T07:11:48.908Z","updated_at":"2025-10-23T02:37:44.394Z","avatar_url":"https://github.com/jlsalvador.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simple CI/CD Operator for Kubernetes\n\n![Simple CI/CD Logo](img/logo.png)\n\nThe Simple CI/CD operator for Kubernetes empowers users to create workflows triggered by webhooks, facilitating the orchestration of Kubernetes Jobs according to specific requirements.\n\n\n## Table of Contents\n1. [Getting Started](#getting-started)\n2. [Description](#description)\n3. [Contributing](#contributing)\n4. [License](#license)\n\n\n## Getting Started\n\n### Installation by Manifest\n\nTo install Simple CI/CD directly from the internet, use the following command:\n\n```sh\nkubectl apply -k 'github.com/jlsalvador/simple-cicd/config/default?ref=stable'\n```\n\nIf you have forked the Simple CI/CD repository and want to install it from your local copy, use the following command:\n\n```sh\nkubectl apply -k config/default\n```\n\n### Installation by Helm\n\n```sh\nhelm upgrade --install --create-namespace --namespace simple-cicd --repo https://jlsalvador.github.io/simple-cicd simple-cicd simple-cicd\n```\n\n\n## Description\n\nSimple CI/CD offers users the ability to trigger Kubernetes Jobs through webhooks, providing control over \u003cins\u003ewhen\u003c/ins\u003e and \u003cins\u003ehow\u003c/ins\u003e multiple Jobs and their dependencies are executed.\n\n### Features\n\n- Easy to understand\n- Uses standard Kubernetes resources\n- No external cloud dependencies\n- Low resource usage\n\n### Custom Resource Definitions\n\n- **Workflow**: Responsible for cloning Jobs and triggering subsequent Workflows based on the exit status of completed Jobs.\n- **WorkflowWebhook**: Serves as the trigger for Workflows, allowing the Simple CI/CD operator to listen for HTTP requests on a path named as the WorkflowWebhook (`/namespace/name`).\n- **WorkflowWebhookRequest**: Initiates WorkflowWebhooks.\n\n### Example:\n\nIn this example, we demonstrate the Simple CI/CD system's functionality:\n\n1. **Receive HTTP Request**: The Simple CI/CD operator receives an HTTP request.\n\n2. **Create a Random Exit Pod**: A Kubernetes pod is created, which generates a random exit code (either 0 or 1) upon execution.\n\n3. **Error Handling**: If the previous pod's exit status indicates a failure (1), the system initiates another pod that echoes the content of the original HTTP request.\n\n```mermaid\nsequenceDiagram\n  participant User as User\n  participant Ingress as Ingress Controller\n  participant SimpleCI/CD as Simple CI/CD Operator\n  participant Pod1 as \"Random Exit\" Pod\n  participant Pod2 as \"Error Handling\" Pod\n\n  User-\u003e\u003eIngress: HTTP Request (Outside Cluster)\n  Ingress-\u003e\u003eSimpleCI/CD: HTTP Request\n  SimpleCI/CD-\u003e\u003ePod1: Create Random Exit Pod\n  Note right of Pod1: Generates Random Exit Code (0 or 1)\n  Pod1--\u003e\u003eSimpleCI/CD: Exit Status (0 or 1)\n\n  alt Exit Status = 1 (KO)\n    SimpleCI/CD-\u003e\u003ePod2: Create Error Handling Pod\n    Pod2--\u003e\u003eSimpleCI/CD: Echo HTTP Request\n  end\n\n  SimpleCI/CD--\u003e\u003eIngress: HTTP Response\n  Ingress--\u003e\u003eUser: HTTP Response (Outside Cluster)\n```\n\n```yaml\n# Job that randomly exits with code 0 or 1 (OK or Error)\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: job-example-random-exit\nspec:\n  suspend: true # Required to be true to disallow Kubernetes to start this job when it will be created\n  backoffLimit: 0 # If this Job fail do not try to run it again\n  template:\n    spec:\n      containers:\n        - name: random-exit\n          image: bash\n          command: [\"sh\", \"-c\", \"exit $$(($RANDOM % 2))\"] # Sometimes will fails\n      restartPolicy: Never # Do not re-run the pod if something fails\n---\n# Job that echoes \"ERROR\"\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: job-example-error\n  namespace: default # Job namespace. Optional\nspec:\n  suspend: true # Required to be true to disallow Kubernetes to start this job when it will be created\n  template:\n    spec:\n      containers:\n        - name: error\n          image: bash\n          command: [\"echo\", \"ERROR\"]\n        - name: echo-request\n          image: bash\n          command:\n            - cat # Simple CI/CD will mounts the next request payloads inside all Pods\n            - /var/run/secrets/kubernetes.io/request/body\n            - /var/run/secrets/kubernetes.io/request/headers\n            - /var/run/secrets/kubernetes.io/request/host\n            - /var/run/secrets/kubernetes.io/request/method\n            - /var/run/secrets/kubernetes.io/request/url\n      restartPolicy: Never # Do not re-run the pod if something fails\n---\n# Workflow that will clones the \"job-example-error\" Job\napiVersion: simple-cicd.jlsalvador.online/v1alpha1\nkind: Workflow\nmetadata:\n  name: workflow-example-some-failures\n  namespace: default # Workflow namespace. Optional.\nspec:\n  jobsToBeCloned:\n    - name: job-example-error # Job name that will cloned\n      namespace: default # Job namespace. Optional.\n---\n# Workflow that will clones the \"job-example-random-exit\" Job and\n# triggers the \"workflow-example-some-failures\" Workflow on any Job failure\napiVersion: simple-cicd.jlsalvador.online/v1alpha1\nkind: Workflow\nmetadata:\n  name: workflow-example\nspec:\n  jobsToBeCloned:\n    - name: job-example-random-exit # Job name that will cloned\n  next:\n    - name: workflow-example-some-failures\n      namespace: default # Workflow namespace. Optional.\n      when: OnAnyFailure # Only run this Workflow if some of the jobsToBeCloned fails\n---\n# WorkflowWebhook set the simple-cicd operator to listen for requests on the path \"$namespace/$name\"\napiVersion: simple-cicd.jlsalvador.online/v1alpha1\nkind: WorkflowWebhook\nmetadata:\n  name: workflowwebhook-example\nspec:\n  workflows:\n    - name: workflow-example # Workflow that will be initiated\n---\n# Optional, recommended for public requests.\n# Secret for the next Ingress, recommended for preventing undesired requests.\napiVersion: v1\nkind: Secret\nmetadata:\n  name: basic-auth-example\n  namespace: simple-cicd-system # Namespace where the ingress-example is deployed\ntype: Opaque\nstringData:\n  auth: |\n    # user:pass\n    user:$apr1$j.P.ucaS$hHtkMN19glS9.ffLns2Eh/\n---\n# Optional, allows external requests from the cluster.\n# Public Ingress listening at http://example.org/default/workflowwebhook-example with basic authorization.\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: ingress-example\n  namespace: simple-cicd-system # Namespace where the simple-cicd-controller-manager is deployed\n  annotations:\n    nginx.ingress.kubernetes.io/auth-type: basic\n    nginx.ingress.kubernetes.io/auth-secret: basic-auth-example\nspec:\n  ingressClassName: nginx\n  rules:\n    - host: example.org\n      http:\n        paths:\n          - path: /default/workflowwebhook-example # The WorkflowWebhook namespace/name\n            pathType: Prefix\n            backend:\n              service:\n                name: simple-cicd-controller-manager # The simple-cicd operator service name\n                port:\n                  name: http\n```\n\n```sh\n# To trigger the WorkflowWebhook from outside the cluster:\ncurl -u user:pass http://example.org/default/workflowwebhook-sample\n\n# To trigger the WorkflowWebhook from inside the cluster:\ncurl http://simple-cicd-controller-manager.simple-cicd-system:9000/default/workflowwebhook-sample\n```\n\n### Motivation\n\nThe motivation behind developing Simple CI/CD arises from the need for a tool that aligns with specific requirements, as outlined in the table below. Existing solutions either impose excessive requirements or fail to meet desired expectations. The primary objective is to launch Jobs within the Kubernetes environment using webhooks to control timing and execution, without the need for virtual machines, Docker-in-Docker configurations, external dependencies, or components external to the Kubernetes ecosystem.\n\n\u003ctable\u003e\n  \u003ccaption\u003eDisclaimer: Based in my personal opinion. Please, do your own investigations.\u003c/caption\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eAlternative\u003c/th\u003e\n      \u003cth\u003eAdvantages\u003c/th\u003e\n      \u003cth\u003eDisadvantages\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://github.com/features/actions\"\u003eGithub Actions\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eDe-facto CI/CD for public GIT repositories at \u003ca href=\"https://github.com\"\u003eGithub\u003c/a\u003e.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eSupported by \u003ca href=\"https://microsoft.com\"\u003eMicrosoft\u003c/a\u003e.\u003c/li\u003e\n          \u003cli\u003eClosed garden.\u003c/li\u003e\n          \u003cli\u003eActions requires to be public publishing.\u003c/li\u003e\n          \u003cli\u003eLimited by a paywall.\u003c/li\u003e\n          \u003cli\u003eNot suitable for air-gap environments or private clusters.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://www.jenkins.io\"\u003eJenkins\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eOpen-source.\u003c/li\u003e\n          \u003cli\u003eSupported by the community and company foundations.\u003c/li\u003e\n          \u003cli\u003eStable and real-world tested.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eResource hungry.\u003c/li\u003e\n          \u003cli\u003eRequires Groovy for advanced tasks.\u003c/li\u003e\n          \u003cli\u003eRequires addons for Kubernetes.\u003c/li\u003e\n          \u003cli\u003eLimited CLI support.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://tekton.dev\"\u003eTekton\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eOpen-source.\u003c/li\u003e\n          \u003cli\u003eSupported by \u003ca href=\"https://cd.foundation\"\u003eCD Foundation\u003c/a\u003e.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eCan not use more than one PersistentVolume on the same Pod.\u003c/li\u003e\n          \u003cli\u003eDeprecated tasks from Catalog because its new on-going API version.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://drone.io\"\u003eDrone\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eOpen-source.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eSupported by \u003ca href=\"https://www.harness.io\"\u003eHarness\u003c/a\u003e.\u003c/li\u003e\n          \u003cli\u003eLimited community pull requests support. Personal example: \u003ca href=\"https://github.com/harness/gitness/pull/3030\"\u003ehttps://github.com/harness/gitness/pull/3030\u003c/a\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://woodpecker-ci.org\"\u003eWoodpecker CI\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eOpen-source (community fork of Drone).\u003c/li\u003e\n          \u003cli\u003eSupported by the community.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eForget about namespaced PersistentVolume for multiples tasks.\u003c/li\u003e\n          \u003cli\u003eLimited Kubernetes support.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://gitea.com/gitea/act_runner\"\u003eGitea act_runner\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eCommunity effort for on-premise Github Actions.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eRequires Virtual Machine-like setup, as Github Actions.\u003c/li\u003e\n          \u003cli\u003eLacks Kubernetes integrations.\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ca href=\"https://github.com/jlsalvador/simple-cicd\"\u003eSimple CI/CD\u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eOpen-source.\u003c/li\u003e\n          \u003cli\u003eSupported by the community.\u003c/li\u003e\n          \u003cli\u003eSimple.\u003c/li\u003e\n          \u003cli\u003eKubernetes native component as an operator.\u003c/li\u003e\n          \u003cli\u003ePlatform agnostic (cloud, on-premise, hybrid).\u003c/li\u003e\n          \u003cli\u003eLow resource usage (around 32Mb RAM).\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\n        \u003cul\u003e\n          \u003cli\u003eExperimental and not yet real-world tested.\u003c/li\u003e\n          \u003cli\u003eMaintained by a single individual.\u003c/li\u003e\n          \u003cli\u003eNo web interface (yet).\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\n## Contributing\n\n### Design rules\n\n- Keep it Simple\n- Be Explicit\n- Embrace Minimalism\n\n### How it works\n\nThis project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/).\n\nIt uses [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/),\nwhich provide a reconcile function responsible for synchronizing resources until the desired state is reached on the cluster.\n\nYou’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster.\n**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows).\n\n### Test It Out\n\n1. Install the CRDs into your cluster:\n\n```sh\nmake install\n```\n\n2. Run your controller (this will run in the foreground, so switch to a new terminal if you want to leave it running):\n\n```sh\nmake run\n```\n\n**NOTE:** You can also run this in one step by running: `make install run`\n\n### Running on the cluster\n\n1. Build and push your image to the location specified by `IMG`:\n\n```sh\nmake docker-build docker-push IMG=\u003csome-registry\u003e/simple-cicd:tag\n```\n\n2. Deploy the controller to the cluster with the image specified by `IMG`:\n\n```sh\nmake deploy IMG=\u003csome-registry\u003e/simple-cicd:tag\n```\n\n### Uninstall CRDs\n\nTo delete the CRDs from the cluster:\n\n```sh\nmake uninstall\n```\n\n### Undeploy controller\n\nUnDeploy the controller from the cluster:\n\n```sh\nmake undeploy\n```\n\n### Modifying the API definitions\n\nIf you are editing the API definitions, generate the manifests such as CRs or CRDs using:\n\n```sh\nmake manifests\n```\n\n**NOTE:** Run `make --help` for more information on all potential `make` targets\n\nMore information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)\n\n\n## License\n\nCopyright 2023 José Luis Salvador Rufo \u003csalvador.joseluis@gmail.com\u003e.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlsalvador%2Fsimple-cicd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjlsalvador%2Fsimple-cicd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlsalvador%2Fsimple-cicd/lists"}