{"id":22933436,"url":"https://github.com/bluebrown/argocd-cmp-kpt","last_synced_at":"2025-08-12T16:32:51.868Z","repository":{"id":111479867,"uuid":"549815613","full_name":"bluebrown/argocd-cmp-kpt","owner":"bluebrown","description":"Use kpt as argocd configuration management plugin","archived":false,"fork":false,"pushed_at":"2022-10-14T23:03:45.000Z","size":41,"stargazers_count":8,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-01T08:37:58.383Z","etag":null,"topics":["argocd","gitops","kpt","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bluebrown.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2022-10-11T19:31:25.000Z","updated_at":"2024-07-17T08:07:46.000Z","dependencies_parsed_at":"2023-03-09T00:15:27.915Z","dependency_job_id":null,"html_url":"https://github.com/bluebrown/argocd-cmp-kpt","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bluebrown/argocd-cmp-kpt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluebrown%2Fargocd-cmp-kpt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluebrown%2Fargocd-cmp-kpt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluebrown%2Fargocd-cmp-kpt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluebrown%2Fargocd-cmp-kpt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bluebrown","download_url":"https://codeload.github.com/bluebrown/argocd-cmp-kpt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluebrown%2Fargocd-cmp-kpt/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270097295,"owners_count":24526643,"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","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["argocd","gitops","kpt","kubernetes"],"created_at":"2024-12-14T11:29:38.926Z","updated_at":"2025-08-12T16:32:51.851Z","avatar_url":"https://github.com/bluebrown.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ArgoCD KPT Configuration Management Plugin\n\nThis repo contains an example implementation of [kpt](https://kpt.dev/) as\n[ArgoCD](https://argo-cd.readthedocs.io/en/stable/) configuration management\nplugin. The source for the CMP is in the [plugin directory](./plugin/). A\n`kustomize` component to patch the `ArgoCD` repo server can be found in the\n[configuration directory](./configuration/component/).\n\n## Quick Start\n\nBelow commands will deploy the stable ArgoCD stack into your cluster, in the\nargocd namespace, including the component patch to run kpt as CMP sidecar. Make\nsure you don't run this in your production cluster or somewhere where you have\nalready ArgoCD configured.\n\n```bash\nkustomize build configuration/ -o .out/\n```\n\nOnce you have generated the manifests to the [.out](./.out/) folder, you can review the\n[repo server manifest](./.out/apps_v1_deployment_ArgoCD-repo-server.yaml) to see\nhow the plugin is integrated.\n\nIf you want, you can apply the manifests to your cluster.\n\n```bash\nkubectl create namespace argocd\nkubectl apply -f .out/\n```\n\nIf you want to add the component to your existing configuration, review the\ncomponent and integrate it into your own configuration.\n\nFor example you could add the component as [remote\ntarget](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/remoteBuild.md)\nto your existing kustomization.\n\n```yaml\napiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nnamespace: argocd\nresources:\n  - https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml\ncomponents:\n  - https://github.com/bluebrown/argocd-cmp-kpt//configuration/component/?rev=main\nimages:\n  - name: index.docker.io/bluebrown/argocd-cmp-kpt\n    newTag: v1.0.0-beta.21\n```\n\n## The Concept\n\nArgoCD comes with a few configuration management tools build in. At the time of\nwriting, these are `helm`, `kustomize` and `jsonnet`. However, it is possible to\nconfigure your own CMP (configuration management plugin).\n\nThe basic idea is that ArgoCD will not sync raw manifests directly to the\ncluster but invoke one of the included tools or user provided CMPs to obtain the\nfinal yaml manifests that should be synced to the cluster. For example, one\ncould use helm to render a chart using the `helm template` command.\n\nKpt is a tool to manage so called packages, which are collections of kubernetes\nmanifests. The goal of this project is to integrate kpt as CMP such that it will\nproduce the yaml manifests and have ArgoCD sync them to the cluster.\n\nThere are a few challenges which come along with this. This repo aims to provide\nonly exemplary solutions to those, with room for improvement.\n\nThe first challenge is to use kpt to output the final manifests instead of\nrelying on its `live` mechanism. This is because ArgoCD should decide wether the\ncluster state is in sync with the produced yaml or not. This can be solved\nrelatively easy by using its `unwrap` output option. Before outputting the\nmanifests any local configs, including the `Kptfile` itself, are removed using\nthe [remove-local-config-resource\nfunction](https://catalog.kpt.dev/remove-local-config-resources/v0.1/).\n\n```bash\nkpt fn eval --exec remove-local-config-resources-v0.1.0 --output unwrap\n```\n\nThe second and greater challenge is actually the function management. This is\nbecause kpt usually works by running each function in container. This\narchitecture is tricky to realize when running kpt as a CMP sidecar. The\nworkaround presented here is to use `exec` instead of `image`, which allows to\nuse local executables as functions. You can actually see an example of this in\nthe above code snippet. However, this comes with a number of problems around the\navailability and versioning of the functions. These problems have been naively\nsolved by including some common functions in the CMP image. That means kpt\npackages deployed in this fashion are limited in the functions and versions they\ncan use. One can imagine more elaborate setups to spawn containers to run the\nfunctions, or fetch the executables on demand.\n\n```dockerfile\nCOPY --from=gcr.io/kpt-dev/kpt:v1.0.0-beta.21 /usr/local/bin/kpt /usr/local/bin/kpt\nCOPY --from=gcr.io/kpt-fn/remove-local-config-resources:v0.1.0 /usr/local/bin/function /usr/local/bin/remove-local-config-resources-v0.1.0\nCOPY --from=gcr.io/kpt-fn/set-annotations:v0.1.4 /usr/local/bin/function /usr/local/bin/set-annotations-v0.1.4\n```\n\n## Hands On\n\nIn order to build the CMP we need a few ingredients:\n\n- A container image containing kpt and common functions\n- A plugin configuration\n- A script to use as generate command\n- A patch for the ArgoCD repo server to inject the CMP sidecar\n\n### The Plugin Config\n\nThis configuration will be used by the `cmp-server` to register the plugin with\n`repo-server`. Every time the repo server finds a file matching the discovery\ncriteria it will delegate the production of the final yaml manifests to the\nplugin.\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: ConfigManagementPlugin\nmetadata:\n  name: kpt\nspec:\n  version: v1.0\n  discover:\n    fileName: Kptfile\n  lockRepo: true\n  generate:\n    command:\n      - cmp-generate\n```\n\n### The Generate Script\n\nThis script will run inside the configured [argo application\npath](https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#applications)\nevery time ArgoCD detects changes to the upstream repository. It will use kpt to\nemit the desired kubernetes manifests and let ArgoCD decide what and how it\nshould be synced.\n\nYou may notice this hackish `find + sed` combination. This is to replace all\n`image` references in all `Ktpfiles` with `exec` references so that the local\nbinaries included in the image will be used, when issuing the `kpt fn render\n--allow-exec` command.\n\n```bash\n#!/bin/bash\n\nset -euo pipefail\n\n# the prefix is used to annotate the resources with\n# the ArgoCD build environment\n: \"${ANNOTATION_DOMAIN:=argocd.my-org.io}\"\n\n# replace all image refs with exec refs, in Ktptfile pipelines\n# this could be more solid, perhaps writing a custom fn to exec ;)\nfind . -name Kptfile -print0 |\n    xargs -0 --no-run-if-empty \\\n        sed --in-place -E 's|image:.+/(.+):(.+)|exec: \\1-\\2|'\n\n# render the configuration with the Kptfile pipelines\nkpt fn render --allow-exec\n\n# Set annotations from the ArgoCD environment\nkpt fn eval --exec set-annotations-v0.1.4 -- \\\n    \"$ANNOTATION_DOMAIN/app=$ARGOCD_APP_NAME\" \\\n    \"$ANNOTATION_DOMAIN/rev=$ARGOCD_APP_REVISION\" \\\n    \"$ANNOTATION_DOMAIN/repo=$ARGOCD_APP_SOURCE_REPO_URL\" \\\n    \"$ANNOTATION_DOMAIN/branch=$ARGOCD_APP_SOURCE_TARGET_REVISION\" \\\n    \"$ANNOTATION_DOMAIN/path=$ARGOCD_APP_SOURCE_PATH\"\n\n# Lastly, emit the final config by using the remove-local-config-resources\n# function which strips all local configs including Kpt files, from the output\nkpt fn eval --exec remove-local-config-resources-v0.1.0 --output unwrap\n```\n\n### The Dockerfile\n\nIt is crucial to create a user with the id 999 since that is the user id inside\nthe ArgoCD repo server. This is very important because the entrypoint of the\nsidecar will be ultimately the mounted `argocd-cmp-server` binary which listens\non a socket. This socket will be accessible for the repo server through a shared\nvolume. In order for the two programs to communicate, the repo server must have\nwrite permission on the socket. This is ensured by using the same uid 999. This\nwill make more sense further down, when we get to the patch.\n\n```dockerfile\nFROM alpine\n\n# git is required by kpt and bash is used to have\n# a more solid script since pipefail is available\nRUN apk --no-cache add git bash\n\n# its important to use the id 999 since the ArgoCD repo server user will write\n# to the the socket file created by the mounted entrypoint\nRUN adduser --system --disabled-password --gecos \"\" --shell /bin/bash --uid 999 argocd\n\n# add the kpt binary which is the core piece of this cpm as  well a some functions.\n# remove-local-config-resources is required to make it all work since it allows to purge local configs.\n# set-annotations is used to annotate the rendered config with the ArgoCD app name and environment\nCOPY --from=gcr.io/kpt-dev/kpt:v1.0.0-beta.21 /usr/local/bin/kpt /usr/local/bin/kpt\nCOPY --from=gcr.io/kpt-fn/remove-local-config-resources:v0.1.0 /usr/local/bin/function /usr/local/bin/remove-local-config-resources-v0.1.0\nCOPY --from=gcr.io/kpt-fn/set-annotations:v0.1.4 /usr/local/bin/function /usr/local/bin/set-annotations-v0.1.4\n\n# add some other functions that you want to use\nCOPY --from=gcr.io/kpt-fn/set-image:v0.1.1 /usr/local/bin/function /usr/local/bin/set-image-v0.1.1\nCOPY --from=gcr.io/kpt-fn/set-labels:v0.1.5 /usr/local/bin/function /usr/local/bin/set-labels-v0.1.5\n\n# the plugin definition can also be mounted from a config map, if **preferred**\nCOPY plugin.yaml /home/argocd/cmp-server/config/plugin.yaml\n\n# the generate script is executed to render the kubernetes manifests\n# as defined in the plugin.yaml\nCOPY --chmod=755 generate.sh /usr/local/bin/cmp-generate\n\nWORKDIR /home/argocd\nUSER 999\nENTRYPOINT [\"/bin/bash\"]\n```\n\n### The Patch\n\nThis patch injects the CMP container as sidecar to the ArgoCD repo server. It\nmounts the `var-files` volume which is already in the `argocd-repo-server` pod\nspec. Through this shared volume the entrypoint\n`/var/run/argocd/argocd-cmp-server` is available. And the socket created by the\nentrypoint will be created in this volume so that the repo server can\ncommunicate with the CMP server.\n\nThe CMP server does all the heavy lifting of sending the yaml back and forth\nand invoking our plugin in the right directory. So our plugin only cares about\ndealing with the current path containing a `Kptfile`.\n\n```yaml\n# inject the sidecar to the repo server\n# ref: https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/#3-register-the-plugin-sidecar\n- op: add\n  path: /spec/template/spec/containers/-\n  value:\n    name: cmp-kpt\n    # change this image to your own or keep it\n    # to use the one build from this repo\n    image: index.docker.io/bluebrown/argocd-cmp-kpt\n    command: [/var/run/argocd/argocd-cmp-server]\n    securityContext:\n      allowPrivilegeEscalation: false\n      readOnlyRootFilesystem: true\n      capabilities:\n        drop:\n          - ALL\n    resources:\n      requests:\n        cpu: 10m\n        memory: 32Mi\n      limits:\n        cpu: 1000m\n        memory: 256Mi\n    volumeMounts:\n      # mount the var files and plugins directory\n      # in order to get access to the entrypoint,\n      # allow communication between cmp and repo server\n      # via a socket, and register the plugin\n      - name: var-files\n        mountPath: /var/run/argocd\n      - name: plugins\n        mountPath: /home/argocd/cmp-server/plugins\n      - name: cmp-tmp\n        mountPath: /tmp\n# create a volume for tmp files since we don't have\n# write permission on the root file system\n- op: add\n  path: /spec/template/spec/volumes/-\n  value:\n    name: cmp-tmp\n    emptyDir: {}\n```\n\n## Example\n\nIf you have deployed the ArgoCD server with the cmp sidecar, you can use the\nresources in the [example directory](./example/). The [ArgoCD\napplication](./example/argo-app.yaml) will monitor the [kpt\npackage](./example/kpt-app/) in this repository and since there is a `Kptfile`,\nit will use the CMP to render the final yaml.\n\nThe below commands provisions ArgoCD with plugin as well as the example app.\n\n```bash\n# deploy ArgoCD and CMP\nkubectl create ns ArgoCD\nkustomize build configuration/ | kubectl apply -f -\n# create an example application\nkubectl apply -f example/argo-app.yaml -n argocd\n```\n\nOnce deployed, we can visit the ArgoCD UI to check on our application. Run the\nbelow commands and then visit\n\u003chttps://localhost:8080/applications/echoserver?view=tree\u003e. Use the username\n`admin` and the password you have obtained via `kubectl`.\n\n```bash\nkubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=\"{.data.password}\" | base64 -d; echo\nkubectl port-forward svc/argocd-server -n argocd 8080:443\n```\n\nWe can see that ArgoCD knows about our echoserver and that its out of sync.\n\n![ArgoCD echoserver state](assets/echoserver.png)\n\nIf we look at the service, for example, we see that the kpt CMP has added the\nannotations as written in the generate script. You can also see that the\npipeline in specified in the Kptfile has been run and thus the `set-labels`\nfunction. I would actually recommend to keep in cluster pipeline usage to a\nminium though. Kpt has good support for in-place changes and updates from\nupstream. So there should be little need to actually run complex pipelines in\ncluster.\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n  annotations:\n    argocd.my-org.io/app: echoserver\n    argocd.my-org.io/branch: main\n    argocd.my-org.io/path: example/kpt-app/\n    argocd.my-org.io/repo: 'https://github.com/bluebrown/argocd-cmp-kpt'\n    ArgoCD.my-org.io/rev: f62b5a47018aadf1ff3723a05ffb7f234858fb69\n  labels:\n    app.kubernetes.io/instance: echoserver\n    env: test\n  name: echoserver\n  namespace: default\nspec:\n  ports:\n    - port: 80\n      targetPort: 8080\n  selector:\n    app: echoserver\n    env: test\n```\n\n## Clean up\n\n```bash\nkubectl delete -f example/argo-app.yaml -n argocd\nkustomize build configuration/ | kubectl delete -f -\nkubectl delete ns argocd\n```\n\n## Next Steps\n\nIf you like the idea and would like to develop it further. I would be glad to\ncollaborate. You can reach out via slack in the [kubernetes\ngroup](https://kubernetes.slack.com/archives/D02AB567WKY) or the [cncf\ngroup](https://cloud-native.slack.com/archives/D03BKR5584E).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluebrown%2Fargocd-cmp-kpt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbluebrown%2Fargocd-cmp-kpt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluebrown%2Fargocd-cmp-kpt/lists"}