argoproj / argo-cd

Declarative Continuous Deployment for Kubernetes
https://argo-cd.readthedocs.io
Apache License 2.0
16.75k stars 5.07k forks source link

Provide Example For Local Rendering of argocd-example-apps #11722

Open samba2 opened 1 year ago

samba2 commented 1 year ago

We have a rather large ArgoCd installation with frequent changes in our Helm charts. To debug + and study the potential manifests, I am looking for an option to locally render not only Helm charts but a full Argo app. As simple start, I used the argocd-example-apps.

Here is the command I tried:

cd argocd-example-apps/
argocd app manifests helm-guestbook --local apps                                              
FATA[0000] Argo CD server address unspecified

I was hoping to get a long list of K8s manifests which Argo would (if running remote) apply to K8s. Two questions ? 1) Do I really need an Argo CD server specified to render the template ? 2) The command line is probably in-correct. How is the correct call ?

Thank you!

crenshaw-dev commented 1 year ago

To render manifests, the CLI needs to know things about the application (e.g. build parameters). To retrieve that information, it needs to connect to the server.

fabricepipart1a commented 1 year ago

Hi! I am unsure that is a good idea to jump into that issue but I have a related question. Tell me if I should open a separate case.

No problem for me to be logged on the server to be able to render the manifests or diff list. I need to render the manifests of my Application in order to analyze what changed before making a pull request. I tried various approaches.

Running argocd app diff for each application. I looks like a nice idea and quite natural. The issue is that you need to have a complete Application list. Unfortunately, argocd app list can only return the current Applications taht exist server-side. I had hoped that --server-side-generate could help but I have the checksum errors that some others seem to have

Running argocd app manifests for each application. Same issue, I can't have a reliable Application list. Or did not find how to generate it from my local.

Using the pull request revision That would be an option for me if the --local does not work. But that option is not available for argocd app list so I stay with the same issue. I am lacking the app list that corresponds to that revision. And if I specify the name of the new Application that would be generated with my new ApplicationSet, it is not known.

Can you think of any way to make a diff if your application list is modified by your local modifications?

fabricepipart1a commented 1 year ago

The answer to my questions above could be here: https://github.com/argoproj/argo-cd/issues/10895

nrvnrvn commented 1 year ago

@crenshaw-dev we are in a similar to @samba2 's situation and let me provide a use case:

An Application is defined in a declarative way as in this example. As part of the CI we want to render the Kubernetes manifests in a given folder and validate/lint/run whatever tests on those objects without involving a Kubernetes cluster of any kind.

The rationale is simple: to keep feedback loops as short as possible to be able to quickly fix the code in question.

In absence of "dry-run" mode in argo cli the workaround is to parse Application files, extract the spec and pass its values/parameters to the tool being used (helm or kustomize for instance) which sounds a bit backwards given that argocd already does that and invokes helm/kustomize.

samba2 commented 1 year ago

@nrvnrvn This is precisely what we want to achieve. We have meanwhile a huge code base containing of internal and external argoapps which are backed by either customize or helm. Currently our PR just shows the changes made to e.g. helm values values or changes in the template coding. However - it does not show the rendered end result (the manifests) which Argo would try to apply eventually.

What we like to to: locally render out the manifests of the current branch and compare the result with rendering on main. The diff will be attached to the PR so that the reviewer actually sees what changing this little boolean flag in the values file actually causes.

Like @nrvnrvn our current approach would be to parse the argo files and then run customize or helm resp. I am still surprised that a local render is such an issue.

damarvin commented 1 year ago

Same here, and as ChatGPT proposed too (!), it should be possible as with helm to call something like argocd appset template -f my-app-set.yaml > all-in-one.yaml to be able to check the rendered before applying! (if needed against a running Argo CD server, better without)

jackson-chris commented 2 months ago

We have the a similar use case as @nrvnrvn. We maintain our argo manifests in varying repos for prod, dev, uat. The helm charts are maintained in yet another repo. When developers make changes to the helm chart we want to validate/lint all the various overrides used for each environment (as expressed in the argo manifests) to ensure there will be no problems. Rationale again is to keep feedback loop as short as possible and minimize churn of the repos if issues do arise and have to be fixed.

A workaround for us right now is to fetch the argo manifests, parse the various overrides referenced in it, and then run the equivalent helm install dry-run or helm template command with those overrides to get the rendered resources which we pass to kubeconform.

Would be nice to have a single argo cd call where we override the version of the helm chart and potentially the chart url to get the render from an existing argo manifest.

mihaigalos commented 1 month ago

As an 80% temporary solution until this gets implemented, I think kustomize projects can be locally rendered directly at the top-level kustomize (the folder containing the kustomization.yaml referencing all other files) via a kustomize build.

For Helm, one would need to read in the appset.yaml, extract the repos for values and for overlays, clone them and run a helm template . to get the dry run.

I'm thinking something along the lines of this Python implementation:

import yaml

class AppSet:
    def __init__(self, appset_yaml):
        with open(appset_yaml, "r") as file:
            self.yaml = yaml.safe_load(file)

    def get_git_generators(self):
        result = []
        i = 0
        for e in self.yaml["spec"]["generators"]:
            for k, v in e.items():
                if k == "git":
                    entry = {}
                    entry["files"] = v["files"]
                    entry["revision"] = v["revision"]
                    entry["repoURL"] = v["repoURL"]
                    try:
                        sources = v["template"]["spec"]["sources"]
                        for source in sources:
                            if "helm" in source.keys():
                                entry["valueFiles"] = source["helm"]["valueFiles"]
                            elif "ref" in source.keys():
                                entry["reference"] = {}
                                entry["reference"]["ref"] = source["ref"]
                                entry["reference"]["repoURL"] = source["repoURL"]

                        result.append(entry)

                    except Exception as e:
                        print(f"⏩Skipping no matching keys git generator number {i}")
                        pass
                i += 1
        return result