<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Codefresh</title>
    <description>The latest articles on Forem by Codefresh (@codefreshio).</description>
    <link>https://forem.com/codefreshio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3138%2Fa894848c-dd79-44fd-b477-3af28338d874.jpg</url>
      <title>Forem: Codefresh</title>
      <link>https://forem.com/codefreshio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/codefreshio"/>
    <language>en</language>
    <item>
      <title>How to Preview and Diff Your Argo CD Deployments</title>
      <dc:creator>Kostis Kapelonis</dc:creator>
      <pubDate>Tue, 17 Jan 2023 14:36:25 +0000</pubDate>
      <link>https://forem.com/codefreshio/how-to-preview-and-diff-your-argo-cd-deployments-2knj</link>
      <guid>https://forem.com/codefreshio/how-to-preview-and-diff-your-argo-cd-deployments-2knj</guid>
      <description>&lt;p&gt;Adopting Kubernetes has introduced several new complications on how to verify and validate all the manifests that describe your application. There are several tools out there for checking the syntax of manifests, scanning them for security issues, enforcing policies etc.&lt;/p&gt;

&lt;p&gt;But at the most basic case one of the major challenges is to actually understand what each change means for your application (and optionally approve/reject the pull request that contains that change).&lt;/p&gt;

&lt;p&gt;This challenge was already present even outside &lt;a href="https://codefresh.io/learn/gitops/" rel="noopener noreferrer"&gt;GitOps&lt;/a&gt;, but it has become even more important for teams that use GitOps tooling (such as Argo CD) for their Kubernetes deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Any major Git platform has built-in support for showing diffs between the proposed change and the current code when a Pull Request is created. In theory, the presented diff should be enough for a human to understand what the changes contain and how they will affect the target environment.&lt;/p&gt;

&lt;p&gt;In practice however several teams have adopted a templating tool (such as Kustomize or Helm) that is responsible for rendering the actual Kubernetes manifests for a target cluster.&lt;/p&gt;

&lt;p&gt;As a quick example let’s say that you need to review a Pull Request with the following changes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w4y2zhva7ge4fne1w3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w4y2zhva7ge4fne1w3i.png" alt="No context diff" width="774" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This seems simple enough. You assume that this change will increase the number of replicas to 20 (let’s say it is Black Friday and you want to increase the capacity of your web store ASAP). You merge the pull request and … nothing happens.&lt;/p&gt;

&lt;p&gt;What you didn’t know is that there is a &lt;a href="https://github.com/kostis-codefresh/argocd-preview-diff/blob/no-context-pr/envs/prod-us/replicas.yml" rel="noopener noreferrer"&gt;downstream Kustomize overlay&lt;/a&gt; that also defines replicas on its own. So the proposed change has no effect at all. The problem was that the pull request contains only the segment of a Kustomize source manifest and doesn’t show a diff for the end result (the full rendered manifest).&lt;/p&gt;

&lt;p&gt;The problem is even more apparent when your organization is using Helm. Let’s say that you need to approve a pull request with the following changes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo2uqghygdas8k8vpx2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo2uqghygdas8k8vpx2e.png" alt="No context Helm diff" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a human, it is very difficult to understand what exactly is happening here. You need to mentally run the templates in your head and decide if this change is correct or not. Wouldn’t it be nice if the diff had the actual manifest that is created from this chart?&lt;/p&gt;

&lt;p&gt;Essentially the diff functionality found in your Git system is not enough when it comes to complex Kubernetes applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the built-in Diff functionality in the Argo CD GUI
&lt;/h2&gt;

&lt;p&gt;One of the main benefits of using the Argo CD UI during a deployment is the built-in diff feature. When a resource is “out-of-sync” (i.e. it differs from what is in git) Argo CD will mark it with a special color/icon. In the following example, somebody has changed the service resource of an application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7rpsdpjot0kwsq1drbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7rpsdpjot0kwsq1drbc.png" alt="Out of Sync resource" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can then click on the service and see the diff&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznhv3qq6ur4vkf11ur4h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznhv3qq6ur4vkf11ur4h.jpg" alt="Argo CD UI diff" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The big advantage here is that Argo CD has already integrated support for Kustomize and Helm. The diff you will see is on the final rendered manifests which is exactly what you want as you can preview changes in their full context.&lt;/p&gt;

&lt;p&gt;Unfortunately, this method also has several disadvantages.&lt;/p&gt;

&lt;p&gt;The first one is that Argo CD shows only diffs for applications when the &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/" rel="noopener noreferrer"&gt;auto-sync&lt;/a&gt; (and self-heal) behavior are disabled. This means that you are losing the main benefit of GitOps. The proper way to follow GitOps is to have auto-sync enabled (and self-heal as well) as this way guarantees the basic premise that the cluster and the Git repository contain the same thing, that is, that the desired state and actual state have not diverged.&lt;/p&gt;

&lt;p&gt;But the second problem regarding Continuous Delivery is that the diff on the manifests is shown when the changes are already committed and pushed. And this is too late to perform any serious review. Ideally you want to review changes as early as possible. A Pull Request allows you to add comments, talk with your team about the changes and also reject the Pull Request altogether without affecting a production system.&lt;/p&gt;

&lt;p&gt;Using the built-in diff functionality in the Argo CD GUI is great for validating a change and doing a last sanity check just before production. But it should not be the main review milestone of a manifest change. And ideally &lt;a href="https://www.cncf.io/blog/2020/12/17/solving-configuration-drift-using-gitops-with-argo-cd/" rel="noopener noreferrer"&gt;you should setup all your applications to sync automatically&lt;/a&gt;, so having this diff process is not available in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the local Diff feature of the Argo CD CLI
&lt;/h2&gt;

&lt;p&gt;We have seen the built-in diff UI in Argo CD is shown very late in the delivery process. Can we use the same diff approach earlier in the life of a change?&lt;/p&gt;

&lt;p&gt;It turns out that the Argo CD CLI also comes with &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_app_diff/" rel="noopener noreferrer"&gt;a diff command&lt;/a&gt;. This diff command takes a “–local” parameter that allows you to compare what is happening in the cluster against ANY local files which don’t have to be pushed (or even committed at all). It will also automatically run your favorite template tool as it is defined in the Argo CD application.&lt;/p&gt;

&lt;p&gt;Here is how it looks&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsl52ezeycrmjv89g0p2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsl52ezeycrmjv89g0p2x.png" alt="Argo CD Local diff" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This approach is very promising as you could in theory use it inside a CI system with the following process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a pull request with the suggested changes&lt;/li&gt;
&lt;li&gt;Have your CI system checkout the pull request&lt;/li&gt;
&lt;li&gt;Run inside a CI pipeline &lt;code&gt;argocd diff –local&lt;/code&gt; against the cluster where the pull request is destined (It also uses again the built-in support for kustomize/Helm within Argo CD)&lt;/li&gt;
&lt;li&gt;Present the diff to the user in order to take decisions about the pull request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This sounds great in theory but in practice has several shortcomings.&lt;/p&gt;

&lt;p&gt;The most obvious one is that you need to provide your CI pipeline with credentials that access the cluster where Argo CD is installed. This forfeits one of the main benefits of GitOps – the pull mechanism where the credentials stay within the cluster.&lt;/p&gt;

&lt;p&gt;An even bigger concern however is what happens when you have multiple clusters. Which cluster should you pick to compare against? What if the chosen cluster has CRDs or other resources that are custom to it?&lt;/p&gt;

&lt;p&gt;This process can also become very complex with remote or secure cluster instances. For example if you have an Argo CD cluster in Asia and your CI system is running in the US, connectivity between the two might be very slow or even impossible.&lt;/p&gt;

&lt;p&gt;In summary “argocd diff –local” is great for local experimentation and quick adhoc checks, but for a production deployment process there is a better way to achieve the same result (spoiler: it doesn’t involve the Argo CD CLI at all neither needs cluster access).&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-rendering manifests in a second Git repository
&lt;/h2&gt;

&lt;p&gt;Let’s take a step back. We have been looking for ways to show an enhanced diff as part of a pull request and ignore the existing diff that is already provided by the Git provider (as we have seen that this doesn’t work with the final manifest).&lt;/p&gt;

&lt;p&gt;There is a way however to enhance the built-in diff and make it work on the final manifests.&lt;/p&gt;

&lt;p&gt;The solution is to use 2 GitOps repositories, for each application/cluster. &lt;a href="https://github.com/kostis-codefresh/crossplane-iam-pod-role" rel="noopener noreferrer"&gt;One git repository&lt;/a&gt; has the manifests in their unprocessed form (e.g. as Kustomize overlays) as before. There is now &lt;a href="https://github.com/kostis-codefresh/rendered-manifests" rel="noopener noreferrer"&gt;a second Git repository&lt;/a&gt; that has the final rendered manifests. And Argo CD is pointed at the latter.&lt;/p&gt;

&lt;p&gt;Here is how it would look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjigxqtjxtzpw5j2s6p2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjigxqtjxtzpw5j2s6p2.png" alt="Prerender manifests in second Git repository" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This process should be familiar to you if you have ever used a preprocessor or code generator. Essentially there is an automated process (can be the CI system or something else) that does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A human creates a pull request on “Source” Git repo with the suggested change&lt;/li&gt;
&lt;li&gt;A “copy” process takes the contents of the pull request and applies the respective template tool (i.e. Helm/Kustomize) to create the final rendered manifest&lt;/li&gt;
&lt;li&gt;A second pull request is opened automatically on the “Rendered” Git repo with the contents of the manifests&lt;/li&gt;
&lt;li&gt;A human sees the diff of the second pull request and this time the diff is between rendered manifests and not snippets/segments.&lt;/li&gt;
&lt;li&gt;If the Pull Request is approved it is merged on both Git repositories. Thus the second repository has always rendered manifests&lt;/li&gt;
&lt;li&gt;Argo CD monitors the second repository and applies the changes (the integrated support for Helm and Kustomize within Argo CD itself is not used at all, Argo CD is only syncing raw manifests)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a very valid process and I have seen it used in several companies with success.&lt;/p&gt;

&lt;p&gt;The big advantage of course is that &lt;a href="https://github.com/kostis-codefresh/rendered-manifests/pull/1/files" rel="noopener noreferrer"&gt;the diff you get in the Git provider&lt;/a&gt; provides you with the full information about what will change in the application AFTER all manifests are processed:&lt;/p&gt;

&lt;p&gt;Here is the same example with the Helm chart, but this time we are using a second Git repository that has the rendered manifest stored.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv3sp5waehxi9f3j3kq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv3sp5waehxi9f3j3kq2.png" alt="Helm diff with full context" width="800" height="719"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, I am personally against this process, as it complicates things a lot and increases the number of moving parts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doubles the number of repositories for any given application (or branches if multiple branches are used)&lt;/li&gt;
&lt;li&gt;It introduces another point of failure which is the copy process that converts source YAML to final manifests&lt;/li&gt;
&lt;li&gt;It completely bypasses the effort put in Argo CD to process manifests on its own.&lt;/li&gt;
&lt;li&gt;It might be confusing for people who now have 2 Git repositories to work with and opens the possibility of mistakes in both ends (either committing stuff on the “source” repo that never makes it to “rendered” repo or vice versa).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general I think that this is an overkill solution for a problem that can be solved more elegantly as we will see later in the article. Still, if you follow this approach and it works for you, make sure that you have safeguards and monitoring in place (especially for the copy/commit automated process).&lt;/p&gt;

&lt;h2&gt;
  
  
  Intermission: Preview Terraform plans
&lt;/h2&gt;

&lt;p&gt;You might think that previewing the full manifests for a pull request is a new problem that Kubernetes introduced. It isn’t. There have been several tools before Kubernetes that had to deal with the exact same issue and it would make sense to look at what they do.&lt;/p&gt;

&lt;p&gt;The most obvious candidate to examine is terraform. If you are not familiar with terraform it is a declarative tool that allows you to define your infrastructure in a &lt;a href="https://developer.hashicorp.com/terraform/language/syntax/configuration" rel="noopener noreferrer"&gt;HCL file&lt;/a&gt; and then &lt;a href="https://developer.hashicorp.com/terraform/cli/commands/apply" rel="noopener noreferrer"&gt;“apply”&lt;/a&gt; your changes.&lt;/p&gt;

&lt;p&gt;Terraform users have a very similar problem. A pull request that contains terraform changes (especially in big projects) is not immediately clear for a human to understand (unless you are an expert on running terraform mentally in your head).&lt;/p&gt;

&lt;p&gt;To solve this issue, terraform has a &lt;a href="https://developer.hashicorp.com/terraform/cli/commands/plan" rel="noopener noreferrer"&gt;“plan”&lt;/a&gt; command which reads the changes, decides what it will do and prints a nice summary of all the proposed changes without actually doing anything.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gs44ca86w28aoqbl55c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gs44ca86w28aoqbl55c.png" alt="Terraform plan" width="800" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The plan functionality in terraform is crucial to terraform teams as it removes the guesswork on what terraform will do when the changes are applied.&lt;/p&gt;

&lt;p&gt;With this summary at hand, the next step is obvious. We can simply attach the output of the plan command to the pull request. Humans can now look at both the diff of the hcl files but also the plan summary and decide if the change is valid or not.&lt;/p&gt;

&lt;p&gt;This workflow is so common that an open source project – &lt;a href="https://www.runatlantis.io/" rel="noopener noreferrer"&gt;https://www.runatlantis.io/&lt;/a&gt; does exactly that.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You make your changes on the terraform files&lt;/li&gt;
&lt;li&gt;You create a pull request&lt;/li&gt;
&lt;li&gt;Atlantis runs the “plan” command and attaches the result in the PR&lt;/li&gt;
&lt;li&gt;You can then approve/comment the PR as a human&lt;/li&gt;
&lt;li&gt;Atlantis then runs the “apply” command to actually modify your infrastructure&lt;/li&gt;
&lt;li&gt;Atlantis locks the workspace until the PR is merged, preventing a second PR from overriding the changes before the first PR is merged.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This workflow is very effective for end-users but has several security drawbacks which are similar to the &lt;code&gt;argo CLI diff&lt;/code&gt; approach&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need bidirectional communication between your Git provider and the server that runs Atlantis&lt;/li&gt;
&lt;li&gt;The server that runs Atlantis will run terraform on its own and thus &lt;a href="https://www.runatlantis.io/docs/provider-credentials.html" rel="noopener noreferrer"&gt;it needs all credentials that terraform has&lt;/a&gt; in your organization.&lt;/li&gt;
&lt;li&gt;The server that runs Atlantis also needs to have access to your remote terraform state. Essentially Atlantis has the keys to your kingdom.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another downside of Atlantis is that it’s Pull Request based, whereas proprietary Terraform CD tools on the market feature a dashboard where every project / workspace can be browsed (similar to how you have a dashboard in ArgoCD where you can see your Applications and whether or not they are synced).&lt;/p&gt;

&lt;p&gt;In theory we could create a similar system for &lt;code&gt;argocd diff –local&lt;/code&gt; but given the security implications, there is a much better approach that is helped by the GitOps principles.&lt;/p&gt;

&lt;p&gt;Still, the basic idea of attaching a diff in a pull request for greater context offers several advantages for the end user that cannot be overstated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render Kubernetes manifests on the fly
&lt;/h2&gt;

&lt;p&gt;One of the most important principles of GitOps is that at any given time the cluster state is the same as what is described in the git state. We really like how terraform Atlantis works but there is a way to improve the workflow and make it more secure and more robust by taking advantage of the Argo CD guarantee for GitOps.&lt;/p&gt;

&lt;p&gt;The Terraform CLI that runs on the Atlantis instance needs credentials to your infrastructure because it must both read &lt;a href="https://developer.hashicorp.com/terraform/language/state" rel="noopener noreferrer"&gt;the terraform state&lt;/a&gt; and also create the actual infrastructure once changes are “applied”.&lt;/p&gt;

&lt;p&gt;With Argo CD we can completely bypass this limitation because we already have the cluster state right there. It is stored in the target of the Pull Request!&lt;/p&gt;

&lt;p&gt;This means that we don’t need any credentials either to the cluster or to Argo CD. We can simply run a diff between the files of the Pull request and the branch it is targeted at. The extra addition here is that we will also run a preprocessing step for the template solution (Helm or Kustomize) in order to get the full manifest.&lt;/p&gt;

&lt;p&gt;So the full process is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Somebody opens a Pull request to the manifest repo&lt;/li&gt;
&lt;li&gt;We check out the code of the pull request and run Kustomize, Helm or other templating tool in order to have the final rendered manifests of what is changed&lt;/li&gt;
&lt;li&gt;We check out the code of the branch that is targeted by the Pull Request (e.g. main) and find the same environment and again run the same templating tool to get the final manifest&lt;/li&gt;
&lt;li&gt;We run a diff between the final manifests from the two previous steps&lt;/li&gt;
&lt;li&gt;We show the diff to the human operator that will decide if the pull request will be merged or not&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The beauty of this approach is that &lt;a href="https://www.runatlantis.io/docs/security.html" rel="noopener noreferrer"&gt;unlike Atlantis&lt;/a&gt;, we never access the Argo CD cluster. All information is coming from Git (an advantage of using GitOps). This means that your Argo CD cluster could be in China with a very slow connection (or even an isolated connection) and your CI server doesn’t need to know anything about it. In fact the location and security access of your Argo CD server is now irrelevant as we don’t interact with it in any way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41s82mp2mlxxjzpq1btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41s82mp2mlxxjzpq1btd.png" alt="Render manifests on the fly" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice in the diagram above that unlike Atlantis, our CI server has a direct connection only to the Git repository. The Argo CD instance still cares only about the Git repository it monitors.&lt;/p&gt;

&lt;p&gt;This makes our approach much more secure as the credentials of the cluster still stay within the cluster itself and we only interact with the Git repository.&lt;/p&gt;

&lt;p&gt;One thing to notice here is that unlike Atlantis or &lt;code&gt;argocd diff&lt;/code&gt; command we are not comparing desired state in Git to actual state (acquired from cloud provider’s API or Kubernetes API), we are comparing two versions of desired state stored in different branches of a Git repository. While being a good enough approximation, this approach is not 100% equivalent to the &lt;code&gt;argocd diff&lt;/code&gt; one.&lt;/p&gt;

&lt;p&gt;A corner case scenario would be Helm Capabilities – built-in variables populated by querying k8s cluster for API version and available resources. Some Helm templates use this information to render correct resource versions, appropriate for specific cluster’s version and available CRDs. This information has to be supplied manually to “helm template” command to achieve parity with &lt;code&gt;argocd diff&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attaching the full manifest diff to a pull request
&lt;/h2&gt;

&lt;p&gt;The icing on the cake is that we will also attach the full manifest diff to the Pull request (as Atlantis does).. This is how it would look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyat11oofk6m7364vvlt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyat11oofk6m7364vvlt1.png" alt="Environment diff" width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now need to explain to users that the automatic diff of the pull request is not what they should look at anymore because it only has part of the story (see the problem description at the beginning of this article). Instead, they should look at our attached diff and get the full picture of what has changed and make decisions accordingly.&lt;/p&gt;

&lt;p&gt;The attached diff is especially important for people that use Helm as you can see a diff between plain YAML instead of trying to run manually Golang templates in your head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcing changes during environment promotion
&lt;/h2&gt;

&lt;p&gt;If you follow this diff approach where the full manifests changes are shown in the Pull Request it will be much easier for you and your team to collaborate on GitOps changes as everybody will have the full context of each incoming change.&lt;/p&gt;

&lt;p&gt;A secondary benefit however of this diff approach is also to know what is NOT changed.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://codefresh.io/blog/how-to-model-your-gitops-environments-and-promote-releases-between-them/" rel="noopener noreferrer"&gt;my previous article about promotions between GitOps environments using folders&lt;/a&gt;, a lot of people asked about how you can guarantee that extracting a common setting from downstream Kustomize overlays and promoting it your base overlay can be safely executed in a single step.&lt;/p&gt;

&lt;p&gt;I was really puzzled by this query, until I realized that most people that were asking this question looked at the simpler diff of the pull request and thus lacked the full context of the change.&lt;/p&gt;

&lt;p&gt;Let’s take an example. You have two environments qa and staging with the following settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;UI_THEME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;light&lt;/span&gt;
&lt;span class="py"&gt;CACHE_SIZE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2048kb&lt;/span&gt;
&lt;span class="py"&gt;SORTING&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ascending&lt;/span&gt;
&lt;span class="py"&gt;N_BUCKETS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to add a new setting called &lt;code&gt;PAGE_LIMIT=25&lt;/code&gt; and promote it gradually first to qa and then to staging&lt;/p&gt;

&lt;p&gt;You modify/commit the &lt;a href="https://github.com/kostis-codefresh/manifest-refactoring/blob/main/envs/qa/application.properties" rel="noopener noreferrer"&gt;qa environment&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;UI_THEME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;light&lt;/span&gt;
&lt;span class="py"&gt;CACHE_SIZE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2048kb&lt;/span&gt;
&lt;span class="py"&gt;PAGE_LIMIT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;25&lt;/span&gt;
&lt;span class="py"&gt;SORTING&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ascending&lt;/span&gt;
&lt;span class="py"&gt;N_BUCKETS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;42  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deployment goes ok and you make &lt;a href="https://github.com/kostis-codefresh/manifest-refactoring/blob/main/envs/staging/application.properties" rel="noopener noreferrer"&gt;the same change to the Staging environment&lt;/a&gt;. It works fine there as well.&lt;/p&gt;

&lt;p&gt;Now you decide that this new setting should be the same across both environments and you decide to move it to &lt;a href="https://github.com/kostis-codefresh/manifest-refactoring/blob/refactoring-of-settings/variants/non-prod/application.properties" rel="noopener noreferrer"&gt;the parent overlay&lt;/a&gt; (which is common to all non-prod environments).&lt;/p&gt;

&lt;p&gt;So the actions you take are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Delete the setting from the QA environment&lt;/li&gt;
&lt;li&gt;Delete the setting from the Staging environment&lt;/li&gt;
&lt;li&gt;Add the setting into the parent overlay that both environments depend on&lt;/li&gt;
&lt;li&gt;Commit/Push all the above in a single step&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A lot of people were concerned about this process and asked how you can enforce that the whole process will work without affecting the existing environments.&lt;/p&gt;

&lt;p&gt;We can finally answer this question by simply looking at &lt;a href="https://github.com/kostis-codefresh/manifest-refactoring/pull/1" rel="noopener noreferrer"&gt;the enhanced diff of the above commit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8bnsidskfjxi1lhwwmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8bnsidskfjxi1lhwwmt.png" alt="No change in the final manifests" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s right. All diffs are completely empty. Even though there are changes in the individual Kustomize files the end result (the rendered manifests) are &lt;strong&gt;EXACTLY&lt;/strong&gt; the same.&lt;/p&gt;

&lt;p&gt;This means that if you approve this Pull request Argo CD will do absolutely nothing and you are certain that all environments will be oblivious to this refactoring.&lt;/p&gt;

&lt;p&gt;Of course the basic diff of the pull request is not that smart and shows &lt;a href="https://github.com/kostis-codefresh/manifest-refactoring/pull/1/files" rel="noopener noreferrer"&gt;the diff changes in text in the individual files&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6d4wg2vng2apnlnfz96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6d4wg2vng2apnlnfz96.png" alt="Plain diff shows changes" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So in this scenario we have the extreme case when the built-in diff of the pull request doesn’t have the full context of what is going on because it doesn’t understand the full manifests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Previewing changes before applying them is a pillar of modern software automation and in the case of Kubernetes applications this is not always a straightforward process because of the templating of the manifests.&lt;/p&gt;

&lt;p&gt;In this article we have seen several ways of previewing the changes in Argo CD applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Basic diff of the Git platform (not recommended)&lt;/li&gt;
&lt;li&gt;Native diff of the Argo CD UI&lt;/li&gt;
&lt;li&gt;Diff local files with the Argo CD CLI&lt;/li&gt;
&lt;li&gt;Pre-rendering manifests in a second Git repository&lt;/li&gt;
&lt;li&gt;Rendering manifests on the fly for each Pull request (recommended)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We hope that this process is helpful for you and your team when of course it is combined with static analysis, syntax validation, security scans and other sanity checks that run against your Kubernetes manifests.&lt;/p&gt;

&lt;p&gt;Happy diffing!&lt;/p&gt;

</description>
      <category>devmeme</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>How to Install and Upgrade Argo CD</title>
      <dc:creator>Kostis Kapelonis</dc:creator>
      <pubDate>Tue, 17 Jan 2023 12:28:49 +0000</pubDate>
      <link>https://forem.com/codefreshio/how-to-install-and-upgrade-argo-cd-5hj0</link>
      <guid>https://forem.com/codefreshio/how-to-install-and-upgrade-argo-cd-5hj0</guid>
      <description>&lt;p&gt;We have already covered several aspects of Argo CD in this blog such as &lt;a href="https://codefresh.io/blog/argo-cd-best-practices/"&gt;best practices&lt;/a&gt;, &lt;a href="https://codefresh.io/blog/scaling-argo-cd-securely-in-2022/"&gt;cluster topologies&lt;/a&gt; and even &lt;a href="https://codefresh.io/blog/argo-cd-application-dependencies/"&gt;application ordering&lt;/a&gt;, but it is always good to get back to basics and talk about installation and more importantly about maintenance.&lt;/p&gt;

&lt;p&gt;Chances are that one of your first Argo CD installations happened with kubectl as explained in the &lt;a href="https://argo-cd.readthedocs.io/en/stable/getting_started/"&gt;getting started guide&lt;/a&gt;. While this form of installation is great for quick experimentation and for trying Argo CD, there are many more installation methods that are recommended for production deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual installation and manual upgrade
&lt;/h2&gt;

&lt;p&gt;The most obvious installation method is using the official manifests or the respective Helm chart. Note that the Helm chart for Argo CD is not official and sometimes it lags behind the regular Argo CD releases.&lt;/p&gt;

&lt;p&gt;While the initial installation of Argo CD using just the manifests is quick and straightforward it also suffers from several shortcomings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuration changes (e.g. SSO and notifications) must be also applied manually without any option for rollbacks or auditing&lt;/li&gt;
&lt;li&gt;No disaster recovery option if your Argo CD instance goes down&lt;/li&gt;
&lt;li&gt;Extra effort is needed for modifications on the base install (e.g. for Argo CD plugins)&lt;/li&gt;
&lt;li&gt;It becomes very cumbersome to manage multiple Argo CD instances in a manual way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the biggest challenge is actually upgrading Argo CD in a safe way. New Argo CD versions come with their &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/overview/"&gt;own notes and incompatibilities&lt;/a&gt; and trying to manually upgrade your instance without any backup plan is a recipe for disaster.&lt;/p&gt;

&lt;p&gt;In summary, you should only employ manual installation via manifests for quick prototypes and demo installations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a hosted Argo CD instance
&lt;/h2&gt;

&lt;p&gt;If you are searching for the easiest way to use Argo CD while still having a production installation, look no further than a hosted Argo CD instance. At Codefresh, we already announced &lt;a href="https://codefresh.io/blog/hosted-gitops-platform-powered-by-argocd/"&gt;our hosted Argo CD offering&lt;/a&gt; earlier this year. This Argo CD instance is completely managed by Codefresh personnel. The only thing you need to do is connect your cluster for deploying your applications.&lt;/p&gt;

&lt;p&gt;The main advantage of this method is that all maintenance effort is handled by Codefresh and not you. All version updates, security fixes and other upgrades are automatically handled behind the scenes by Codefresh and you can focus on deploying applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qAcGT-WO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pghtar279ycnb0h8ybk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qAcGT-WO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pghtar279ycnb0h8ybk.png" alt="Runtime Components" width="880" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hosted version of Argo is available to everyone that &lt;a href="https://codefresh.io/codefresh-signup/"&gt;signs-up with Codefresh&lt;/a&gt;, including free accounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Argo CD to manage Argo CD
&lt;/h2&gt;

&lt;p&gt;Using a hosted instance of Argo CD can be great for many organizations, but may not be a fit if you need to deploy behind the firewall, or need more customization. Ideally you would like to customize your Argo CD installation, setup different settings, configure your own plugins, pin down specific Argo CD versions etc&lt;/p&gt;

&lt;p&gt;Hosting your own Argo CD instance is popular, but instead of doing it manually you should use a management platform on top of it. And the most obvious choice &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#manage-argo-cd-using-argo-cd"&gt;would be managing Argo CD with itself&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This use case is perfectly valid and a lot of organizations use self-managed Argo CD. The advantages are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using GitOps to handle not just applications but also the Argo CD installation&lt;/li&gt;
&lt;li&gt;Full audit via Git&lt;/li&gt;
&lt;li&gt;Easy rollbacks&lt;/li&gt;
&lt;li&gt;Automatic drift detection for any manual changes&lt;/li&gt;
&lt;li&gt;Complete changelog of all configuration changes (e.g. notifications SSO)&lt;/li&gt;
&lt;li&gt;Easy disaster recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a great way to handle a production instance of Argo CD. Depending on the size of your organization it will still suffer however from some important challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You still have to perform manual upgrades and make sure that each new version of Argo CD “sits” cleanly on top of the previous one&lt;/li&gt;
&lt;li&gt;Handling a large number of Argo CD installations and keeping them all in sync (pun intended) is still a big challenge.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using Argo CD Autopilot
&lt;/h2&gt;

&lt;p&gt;The use case for using Argo CD to manage Argo CD is very popular as a concept but there are no best practices yet on how to get started and how to bootstrap the whole environment.&lt;/p&gt;

&lt;p&gt;We use the same approach internally and we fully open-sourced our solution at &lt;a href="https://argocd-autopilot.readthedocs.io/en/stable/"&gt;https://argocd-autopilot.readthedocs.io/en/stable/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Argo CD autopilot provides a CLI installing and managing Argo CD that does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connects to your Git provider&lt;/li&gt;
&lt;li&gt;Bootstraps Git repositories for handling both applications and itself&lt;/li&gt;
&lt;li&gt;Setup Applications and ApplicationSet for auto-upgrading itself and other managed apps&lt;/li&gt;
&lt;li&gt;Provides a best practice Git repo structure for both internal and external applications&lt;/li&gt;
&lt;li&gt;Comes with a CLI that allows you to manage and maintain the installation&lt;/li&gt;
&lt;li&gt;Introduces the concepts of deployment environments/projects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Argo CD Autopilot is under active development. You are welcome to participate in &lt;a href="https://github.com/argoproj-labs/argocd-autopilot"&gt;Github&lt;/a&gt; as well as the &lt;code&gt;#argo-cd-autopilot&lt;/code&gt; channel in the &lt;a href="https://slack.cncf.io/"&gt;CNCF slack&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a control plane
&lt;/h2&gt;

&lt;p&gt;Handling one or two Argo CD instances is pretty straightforward if you choose any of the above installation methods. Several organizations however have a large number Argo CD instances that need to be kept in sync or rolled gradually as new versions come out.&lt;/p&gt;

&lt;p&gt;Argo CD can natively support a management instance that handles multiple deployment clusters. So in theory you could have a single Argo CD instance for all your environments. We have already talked about this pattern in our article about &lt;a href="https://codefresh.io/blog/scaling-argo-cd-securely-in-2022/"&gt;scaling Argo&lt;/a&gt;. In the end, having a single instance is a single point of failure and also comes with its own issues for security and redundancy.&lt;/p&gt;

&lt;p&gt;On the other hand having an Argo CD instance for each deployment cluster is also excessive and can lead to a cumbersome setup where maintaining Argo CD instances becomes tedious and unmanageable, especially across virtual private clouds and firewalls.&lt;/p&gt;

&lt;p&gt;Ideally you would like a single management interface that can handle all possible combinations (Argo CD management cluster and deployment clusters) allowing you to craft your perfect topology.&lt;/p&gt;

&lt;p&gt;This management interface exists in the form of the Codefresh GitOps control plane!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oizblFU7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jdspimwo3bpycpiodkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oizblFU7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jdspimwo3bpycpiodkf.png" alt="Control plane" width="794" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Codefresh platform gives you a unified interface for handling all Argo CD instances no matter where they are located. All possible configurations are supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Argo CD management clusters&lt;/li&gt;
&lt;li&gt;Argo CD deployment clusters&lt;/li&gt;
&lt;li&gt;Hosted Argo CD installations&lt;/li&gt;
&lt;li&gt;Deployment clusters managed by the hosted instance&lt;/li&gt;
&lt;li&gt;Argo CD instances that deploy on the same cluster they are installed on&lt;/li&gt;
&lt;li&gt;Argo CD instances that are deployed behind a firewall or on-premise environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Via the control plane interface you can then&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect Argo CD instances&lt;/li&gt;
&lt;li&gt;Connect target deployment clusters&lt;/li&gt;
&lt;li&gt;See the status of each Argo CD instance and each connected cluster&lt;/li&gt;
&lt;li&gt;Upgrade Argo CD instances on a new version in a controlled manner&lt;/li&gt;
&lt;li&gt;Keep track of versions/security alerts, and easily upgrade&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The unified control plane is the perfect tool for all organizations that need a management interface on top of all their Argo CD instances without all the hassle for manual upgrades.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this blog post we have seen most Argo CD installation methods from the simplest one (just the manifests) to the most powerful one (the unified control plane). Depending on the size and complexity of your organization you should choose a management method that allows you to focus on the things that matter most – deploying applications, instead of handling the instances themselves&lt;/p&gt;

&lt;p&gt;For more information on the hosted instance and the control plane &lt;a href="https://codefresh.io/codefresh-signup/"&gt;sign-up with Codefresh&lt;/a&gt;. See also our &lt;a href="https://codefresh.io/blog/argo-cd-best-practices/"&gt;best practices article&lt;/a&gt; and &lt;a href="https://codefresh.io/blog/getting-started-with-gitops-and-argo-cd/"&gt;getting started guides&lt;/a&gt;. And of course, don’t forget to get &lt;a href="https://learning.codefresh.io/"&gt;GitOps with Argo CD Certified&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>devops</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Deploying Microservices with GitOps</title>
      <dc:creator>Hannah</dc:creator>
      <pubDate>Thu, 28 Apr 2022 20:50:52 +0000</pubDate>
      <link>https://forem.com/codefreshio/deploying-microservices-with-gitops-3ln8</link>
      <guid>https://forem.com/codefreshio/deploying-microservices-with-gitops-3ln8</guid>
      <description>&lt;p&gt;&lt;a id="post-22229-_fklv3mbvlb17"&gt;&lt;/a&gt; Learn how to adopt GitOps for your microservices deployments.&lt;/p&gt;

&lt;p&gt;This blog post will explain the highlights listed below and how it's possible to adopt GitOps and the benefits of deploying with Argo for your microservices.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;What are microservices?&lt;/li&gt;
    &lt;li&gt;What are some of the challenges with microservices?&lt;/li&gt;
    &lt;li&gt;What is GitOps?&lt;/li&gt;
    &lt;li&gt;What is Argo CD?&lt;/li&gt;
    &lt;li&gt;How can GitOps and Argo CD help your deployments for your microservices?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-22229-_j6miu69v4mbk"&gt;&lt;/a&gt;Microservices&lt;/h3&gt;

&lt;p&gt;Microservices are a software architecture pattern for building scalable distributed applications. It's essentially a framework that helps break down monolithic architectures into small independent services that can communicate over common patterns like APIs, event-driven, or even messages. An organization might do this because monolithic architectures are tightly coupled and run as a single service. So, if a particular process of your application with a monolithic architecture experiences a spike in demand, this affects your entire architecture and must be scaled.&lt;/p&gt;

&lt;p&gt;It's also important to note that any features or experiments made to this type of application become more complex and therefore can experience more issues and failures.&lt;/p&gt;

&lt;p&gt;Breaking down a monolithic application with API services allows you to build and version each function of an application independently. Because of this, microservices enable an organization to run, modify, deploy and scale each service for an application much more quickly.&lt;/p&gt;

&lt;p&gt;(include visual of monolithic architecture vs. microservice)&lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-22229-_jcj0n5hgdsz2"&gt;&lt;/a&gt;Challenges of Microservices&lt;/h3&gt;

&lt;p&gt;Microservices provide several benefits for organizations by enabling autonomy amongst development teams, allowing applications to scale, deploying those applications efficiently, and increasing flexibility and resilience for those applications. However, microservices include challenges that we will dive into and explain.&lt;/p&gt;

&lt;p&gt;Those challenges are:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;The exploding number of pipelines.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As the number of applications increases, the management of such pipelines becomes more complex. Often this can result in messy scripts and needing to leverage configuration management tools. With all of that comes maintenance, and operators spend a lot of time fixing pipelines. We have a &lt;a href="https://codefresh.io/continuous-deployment/ci-cd-pipelines-microservices/"&gt;blog post&lt;/a&gt; that dives deeper into this issue if you'd like to learn more.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Difficulty managing deployments (all at once, in sequence, and with dependencies).&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While deploying a single microservice is more manageable than deploying a monolithic legacy application, there are still challenges. Suddenly, only a few pipelines for a monolithic application have turned into 20 or more pipelines with multiple microservices. These numbers will vary based on your organization, but it's no doubt that now managing multiple microservice repositories and pipelines is more complicated as more and more are created.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Difficult to monitor.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that there are multiple pipelines and multiple applications with an increase in deployments, those deployments and pipelines need to be monitored for any issues. Previously when using a monolithic architecture, these things could be monitored manually. However, the increased complexity of a distributed system can lead to chances of failure.&lt;/p&gt;

&lt;p&gt;This is why it’s so important to ensure you’re monitoring for total failures, network failures, cascading failures caused by remote procedure calls between your microservices, and even ensuring that you’re honoring your SLAs (service level agreements). With a microservice architecture, we need to keep in mind that services can even be temporarily unavailable due to broken releases, configurations, and any changes due to human error. Clients of services should be architected in a resilient way so they do not suffer catastrophic failure when a service is down.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Difficult to debug (when things go wrong).&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This topic itself could be a blog post. However, some of the critical challenges when debugging a microservice is fragmentation and ensuring that you create the same environment where the bug was identified. This means you need to ensure an identical setup to production, this may include specific cluster versions, serverless functions, the correct environment where the bug was reported, etc. In addition to the asynchronous call complications, the technicalities of running the microservice locally, and the cost it can take to execute all of these things in what you hope is a timely execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2022/04/word-image-1.png" rel="noopener"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QUCdUqRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/04/word-image-1-1024x891.png" alt="Monolithic vs Microservices" width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even with the above example of the complexity that microservices can create when transitioning from a monolithic architecture to a microservice architecture, the benefits of moving to microservices can’t be understated. To gain the full benefits of microservices in scaling, reliability, and security we need to address these challenges head-on&lt;/p&gt;

&lt;p&gt;So, what could help you with some of the challenges organizations face when managing, monitoring, deploying, and maintaining their microservices? Let me introduce you to GitOps, how you can apply it to your microservices, and how it might help!&lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-22229-_y4bb54vbtqko"&gt;&lt;/a&gt;GitOps&lt;/h3&gt;

&lt;p&gt;Before we dive into microservices and explain what they are and what sort of challenges they create for us. First, let's dive into what &lt;a href="https://codefresh.io/learn/gitops/" rel="noopener"&gt;GitOps&lt;/a&gt; is so you can begin to percolate your thoughts as to WHY this might be helpful for your microservices as we explain them.&lt;/p&gt;

&lt;p&gt;Perhaps you're familiar with Git and use it already for your source control and recognize how it enables a source of truth for your source code, but what if we expanded on that idea and applied it to our entire system? This is where GitOps comes into play.&lt;/p&gt;

&lt;p&gt;GitOps is a paradigm that leverages a Git repository as the source of truth to manage continuous deployments and infrastructure management as code. This allows you to drive automation, bring repeatability, reduce downtime and eliminate human interventions in constant release cycles.&lt;/p&gt;

&lt;p&gt;Now that we better understand GitOps let's explore a potential solution for deploying your microservices with GitOps that can be enabled by using Argo CD.&lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-22229-_6yto5ouqmeap"&gt;&lt;/a&gt;Argo CD&lt;/h3&gt;

&lt;p&gt;When determining the best deployment process and tools for GitOps, &lt;a href="https://codefresh.io/learn/argo-cd/" rel="noopener"&gt;Argo CD&lt;/a&gt; is a great solution. Argo CD is a declarative CD (Continuous Delivery) tool that automatically synchronizes and deploys your applications whenever a change is made to your Git repository. This is why it’s one of the leading GitOps solutions.&lt;/p&gt;

&lt;p&gt;It allows you to manage the lifecycle of your application and deployments while also providing version control, configuration management, and application definitions with a Kubernetes manifest. This allows you to organize your environments and complex infrastructure data with more ease.&lt;/p&gt;

&lt;p&gt;Within this post, we will highlight ways that you can use Argo CD to deploy your microservices while applying GitOps to your workflow.&lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-22229-_nhe8sc9avj9"&gt;&lt;/a&gt;How GitOps and Argo can help&lt;/h3&gt;

&lt;p&gt;When trying to determine the best strategy to manage your Kubernetes applications, an increasingly popular approach is GitOps. Argo CD makes GitOps practical for you to use because Argo CD is a Kubernetes-native declarative continuous delivery tool that follows GitOps principles. Argo CD also enables you to accelerate the frequency of your application deployments and lifecycle management by maintaining your configurations and ensuring they’re in sync, applying your desired state directly from Git.&lt;/p&gt;

&lt;p&gt;Essentially, Argo CD helps support your deployments while effectively providing several other benefits for your microservices which we’ll explain more below!&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;No more deployment pipelines -&amp;gt; Argo CD deploys them from Git&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Previously we mentioned the explosion of pipelines when converting from a monolithic architecture to a microservice architecture. However, by leveraging Argo CD it can reduce the number of pipelines by simply eliminating them. This is because you can use Argo to deploy your microservice you rely on your Git repository instead of using a pipeline. When you add an Argo CD &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#applications" rel="noopener"&gt;Application&lt;/a&gt; and an &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#projects" rel="noopener"&gt;AppProject&lt;/a&gt;, your app's configuration settings can be defined using the Application Custom Resource (CRD) that your Kubernetes resource object represents.&lt;/p&gt;

&lt;p&gt;Argo CD fully automates the deployment of an application by recognizing your configuration details from your manifest files and synchronizes any changes made to your system within your targeted namespace. Argo CD allows you to eliminate the use of a deployment pipeline.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Reduce files -&amp;gt; use an ApplicationSet&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While microservices do make it easier to deploy more frequently, there’s also the increase in files for your configurations. Even when a service is deployed and managed using GitOps, this doesn’t reduce the number of files, such as your Kubernetes manifests, your services, secrets, and configmaps, all stored within your Git repository.&lt;/p&gt;

&lt;p&gt;Luckily, Argo CD offers a controller known as an &lt;a href="https://argocd-applicationset.readthedocs.io/en/stable/" rel="noopener"&gt;ApplicationSet&lt;/a&gt; to help us manage our deployments and files easier. The ApplicationSet allows you to create multiple Argo CD Applications and organize your microservices per Application. The controller also allows you to use a single manifest to target numerous clusters and a single manifest to deploy multiple applications, not just from one repository but multiple!&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Always know their health -&amp;gt; Argo CD health&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whenever you make any change to your microservices or your system there’s a risk of a potential failure. For example, if you make a change and apply it to your manifest YAML file, Kubernetes does not wait until the resource reports back its status, nor do your automation tools typically report back, either. Instead, Kubernetes will apply the manifest and move on to the following manifest without waiting to know if the first one succeeded and was created or not. Something that can help alert you and provide observability for the state of your service is the Argo CD &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/health/#resource-health" rel="noopener"&gt;health status&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Argo CD offers a built-in health assessment that provides an overall Application health status for you. Argo CD checks the health for the following resources: services, ingress, deployment, replicaset, statefulset, daemonset, and a persistentvolumeclaim. You can also add custom health checks for custom resources or any persistent known issues affecting your Ingress or StatefulState. These custom health checks can be done two ways: within a ConfigMap or with a script and implemented with a YAML file. If you cannot find a health check for your resource, you can create one yourself for whatever use case you need it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2022/04/word-image-2.png" rel="noopener"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ETQTfXRA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/04/word-image-2.png" alt="" width="206" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above is an example of the Argo CD Application health status within the Argo CD Web UI. Since Git is our source of truth, this sort of observability and information about your service provides that source of truth for the actual state of your running system.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Deployment cadence -&amp;gt; Argo CD sync phases/waves&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typically when managing several microservices and making frequent deployments, it can be a challenge when needing to deploy a specific service in a particular order or, let's say, you want to deploy a service with a database, apart from deployment files. It would help if you had some solution for this. Whatever your use case may be, Argo CD provides a solution for this!&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/#how-do-i-configure-waves" rel="noopener"&gt;Syncwave&lt;/a&gt; allows you to order how Argo CD applies the manifest files stored in your Git repository. By default, all manifests have a wave of zero, but you can set these by using an argocd.argoproj.io/sync-wave annotation.&lt;/p&gt;

&lt;p&gt;For example, if you wanted to specify a wave, it would look something like this:&lt;/p&gt;

&lt;pre&gt;metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "5"&lt;/pre&gt;

&lt;p&gt;When Argo CD starts a sync action, the manifest gets placed in the following order of their Phase.&lt;/p&gt;

&lt;p&gt;When you apply the manifest in a &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/#how-do-i-configure-phases" rel="noopener"&gt;Phase&lt;/a&gt;, you're using a resource hook to control the sync operation. Those operations are defined by the three primary phases known as the pre-sync, sync, and post-sync phases. To enable a sync, annotate the specific object manifest with argocd.argoproj.io/hook with the type of sync you want to use for that resource.&lt;/p&gt;

&lt;p&gt;For example, if you wanted to use the PostSync hook, it would look something like this:&lt;/p&gt;

&lt;pre&gt;metadata:
  annotations:
    argocd.argoproj.io/hook: PostSync&lt;/pre&gt;

&lt;p&gt;Whenever Argo CD starts a sync, it orders the resources in the following precedence: the phase, the wave they are in, by kind (e.g., namespaces first and then other Kubernetes resources, followed by custom resources), and by name.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Dependencies -&amp;gt; See the graphical view of Argo CD&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that you have containerized your microservices and wrapped your brain around the Kubernetes ecosystem. Suddenly an extra layer of complexity is added when trying to deploy all of those microservices and reference the never-ending Kubernetes documentation. This is where having some visualization for your deployments is helpful! Enabling some sort of topology for your application and infrastructure would allow you to better understand, monitor, and control your containerized microservice.&lt;/p&gt;

&lt;p&gt;Argo CD does just that. The web UI provides a real-time view of application activity and dependencies and continuously monitors running applications when using Argo CD. Monitoring all deployed applications allows you to compare the current, live state against the desired target state (as specified within your Git repository). Any deployed application whose live state deviates from the target state is reported and allows you to view the differences while also providing facilities to automatically or manually sync the live state back to the desired target state of your system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2022/04/word-image-3.png" rel="noopener"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZYE_9pCC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/04/word-image-3.png" alt="" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/argoproj/argo-cd/blob/master/docs/assets/argocd-ui.gif" rel="noopener"&gt;Image from Argo CD&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above exemplifies an Argo CD Application with a topology view that shows all of the dependencies of that application.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Fast rollbacks/progressive delivery -&amp;gt; Argo Rollouts&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When beginning to plan your deployment process for your new microservices, it's essential to determine which deployment strategy is best for you and your organization.&lt;/p&gt;

&lt;p&gt;Potential strategies could include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rolling&lt;/strong&gt;: Services that don't need to be available 24/7 can utilize a pattern of swapping in the new for old and essentially hitting the restart button. This allows minimal disruption should there be a service outage. The simplicity aspect is compelling, and the disruptions to end users are less so.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progressive delivery&lt;/strong&gt; (this includes blue-green deployments and canary): A blue-green deployment is simple, has excellent rollback, and has minimal downtime in best-case scenarios. Canary deployments tie together the best of all worlds for minimizing downtime, fast rollback, and minimal disruptions in the case of failed deployments.&lt;/p&gt;

&lt;p&gt;However, while progressive delivery improves the reliability and stability of deployments, applying it within your complex microservice environments doesn't come easy. Kubernetes was built as a container orchestrator, not a deployment system, requiring manual work to execute progressive delivery. Kubernetes also has a default rolling update strategy that is simple to deploy yet provides little control over user traffic and rollback compared to the more advanced deployment methods like blue-green and canary.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://codefresh.io/learn/argo-rollouts/" rel="noopener"&gt;Argo Rollouts&lt;/a&gt; walks down the red carpet as an open source Kubernetes controller with a GitOps-based progressive delivery strategy.&lt;/p&gt;

&lt;p&gt;Argo Rollouts introduces a new Kubernetes CRD for a rollout entity. It has the same functionality as a Kubernetes Deployment entity, but the Argo Rollouts will monitor for changes and can control the rollout. Users can define a specific rollout strategy configured with a manifest file. Argo Rollouts helps you simplify your release processes and provide full support of progressive delivery with automated deployment rollout and management in one!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2022/04/word-image-4.png" rel="noopener"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WohRCjln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/04/word-image-4.png" alt="" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://argoproj.github.io/argo-rollouts/dashboard/#individual-rollout-view" rel="noopener"&gt;Argo Rollout Image of UI Dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This image above exemplifies a visualization of an individual Rollout using a Canary deployment strategy.&lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-22229-_wpmw7qt4ftus"&gt;&lt;/a&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;As you transition from a monolithic architecture to microservices, this process shares a common goal with GitOps: making it easier to deploy more frequently.&lt;/p&gt;

&lt;p&gt;We have shared the benefits and possibilities of adopting GitOps with Argo for your microservices deployments within this blog post. To help you leverage these benefits and get started with your GitOps journey, make sure you understand what GitOps is and the fundamentals of this paradigm. To get started, you can check out our &lt;a href="https://codefresh.learnworlds.com/" rel="noopener"&gt;GitOps Fundamentals&lt;/a&gt; course for free, which allows you to learn about GitOps and get started with the basics of Argo, in tandem with receiving a certificate of completion to share with your employer and others!&lt;/p&gt;

&lt;p&gt;Once you’ve completed this course, you should put your knowledge to the test and try Codefresh GitOps CD to help manage your Argo CD instances. This will provide you with a visualization of your services and any possible failures tied to a commit, a test, pipeline, etc. You can quickly pinpoint issues with access to a release timeline and functionality to execute rollbacks when needed.&lt;/p&gt;

&lt;p&gt;Learn more about Codefresh GitOps CD and sign up &lt;a href="https://codefresh.io/codefresh-signup/" rel="noopener"&gt;here&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>gitop</category>
      <category>microservices</category>
      <category>cd</category>
      <category>argo</category>
    </item>
    <item>
      <title>GitOps Benefits and Considerations</title>
      <dc:creator>Tracy Holmes</dc:creator>
      <pubDate>Wed, 13 Apr 2022 21:41:53 +0000</pubDate>
      <link>https://forem.com/codefreshio/gitops-benefits-and-considerations-3je8</link>
      <guid>https://forem.com/codefreshio/gitops-benefits-and-considerations-3je8</guid>
      <description>&lt;p&gt;&lt;a href="https://codefresh.io/learn/gitops/" rel="noopener noreferrer"&gt;GitOps&lt;/a&gt;. The term appears everywhere, but what are its benefits? And is it as difficult as it sounds? Well, GitOps is a pretty easy paradigm to integrate with your current processes. However, my saying it is “easy” doesn’t help you decide whether you want to adopt it or not. So, let’s talk about it.&lt;/p&gt;

&lt;p&gt;This post will briefly discuss common software delivery challenges, DORA metrics and what they are, how GitOps can help with those metrics, and what to consider if you would like to adopt it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Software Delivery Challenges&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Most existing processes for infrastructure configuration management face challenges like failed deployments, poor infrastructure design, server outages, etc. Some common challenges are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;“Eventual Consistency” or lack of configuration consistency in your environment&lt;/strong&gt;. For example, how do you know if “System A” and “System B” match? The actual configuration and a declared one can alter and change when using manual processes, even when using a centralized configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No idea as to how or where an application is running&lt;/strong&gt;. Implicit infrastructure, its state, and configuration. This sometimes entails a full-scale investigation to determine the “how” and the “where.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failed deployments relying on a &lt;a href="https://containerjournal.com/topics/container-security/backup-and-dr-in-the-age-of-gitops/" rel="noopener noreferrer"&gt;disaster recovery&lt;/a&gt; strategy&lt;/strong&gt;. With manual or semi-manual processes, disaster recovery requires a strict process that teams are disciplined to tackle, which isn’t always reliable—resulting in unplanned downtime that takes away from developers’ skills and productivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing documentation or unknown development history&lt;/strong&gt;. It can be challenging to figure out how some applications were built initially and who managed them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relying on a system’s previous state for success&lt;/strong&gt;. This can be unpredictable, which affects the stability and success of a project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or, to state these challenges in another way: inconsistent configurations can lead to failed deployments, leading to revenue loss. GitOps can help with all of these challenges. We are going to dive into GitOps more in a bit. But first, let’s talk about DORA metrics and why they matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;DevOps and DORA metrics&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DevOps is a collaboration paradigm, and sometimes it is mistaken for being too abstract or too generic. In an effort to quantify the benefits of adopting DevOps, Dora Research (acquired by Google in 2018) has introduced four key metrics that define specific goals for improving the software lifecycle in companies that are interested in DevOps.&lt;/p&gt;

&lt;p&gt;These four key metrics and their organizational effects have been published as part of the “&lt;a href="https://www.devops-research.com/research.html#reports" rel="noopener noreferrer"&gt;State of DevOps&lt;/a&gt;” reports since 2014. The reports include a survey (with more than 32,000 industry professionals in the last years) that categorize the organizations that responded. These categorizations or performance levels are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Elite performers (companies that have fully adopted DevOps and have exceptional results in the four metrics)&lt;/li&gt;
&lt;li&gt;High performers (companies with excellent results in the four metrics)&lt;/li&gt;
&lt;li&gt;Medium performers (companies with some positive results)&lt;/li&gt;
&lt;li&gt;Low performers (all other companies)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The researchers responsible for the survey apply these different categorizations by examining how teams develop, deliver, and operate software systems, and then segmenting respondents into four performance clusters: elite, high, medium, and low performers.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The 4 Key DevOps Metrics + 1&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The four metrics of software delivery performance are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deployment Frequency (DF) – How frequently a team successfully releases to production, e.g., daily, weekly, monthly, yearly.&lt;/li&gt;
&lt;li&gt;Lead Time for Changes (MLT) – The median amount of time for a commit to be deployed into production.&lt;/li&gt;
&lt;li&gt;Time to Restore Service(s) (MTTR) – How long it takes an organization to recover from a failure in production. For a failure, the median amount of time between the deployment that caused the failure and the remediation. The remediation is measured by closing an associated bug/incident report.&lt;/li&gt;
&lt;li&gt;Change Failure Rate (CR) – The number of failures per the number of deployments. For example, if there are four deployments in a day and one causes a failure, that is a 25% change failure rate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F04%2F2021-State-of-DevOps-Software-delivery-performance-metric.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F04%2F2021-State-of-DevOps-Software-delivery-performance-metric.png" alt="https://codefresh.io/wp-content/uploads/2022/04/2021-State-of-DevOps-Software-delivery-perform![2021 State of DevOps – Software Delivery Performance Metric](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ugp3xx8kc88dtldhd63.png)&amp;lt;br&amp;gt;
 ance-metric.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2021 State of DevOps – Software Delivery Performance Metric&lt;/p&gt;

&lt;p&gt;Since 2018, a fifth metric around operational performance has also been included: reliability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reliability – the degree to which a team can keep promises and assertions about the software they operate. Reliability was chosen so that availability, latency, performance, and scalability are more broadly represented.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Companies’ DevOps teams ranked as elite or high-performing in these five categories tend to have outstanding performance around market share and profits.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is GitOps?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What exactly is GitOps? If you are not familiar with GitOps, head over to &lt;a href="https://opengitops.dev/" rel="noopener noreferrer"&gt;https://opengitops.dev&lt;/a&gt;, which is the official page of the GitOps working group. In short, GitOps is a set of standards and best practices that can be applied to application configuration and delivery, all the way to infrastructure management. GitOps is not a tool but works by relying on a single source of truth (typically Git) for declarative applications and infrastructure. The principles of GitOps are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system is described in a declarative manner.&lt;/li&gt;
&lt;li&gt;The definition of the system is versioned and audited. This tends to be Git though it is not limited to it.&lt;/li&gt;
&lt;li&gt;A software agent automatically pulls the Git state and matches the platform state.&lt;/li&gt;
&lt;li&gt;The state is continuously reconciled. This means that any changes in Git should also be reflected in the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will usually see GitOps paired with Kubernetes, though Kubernetes is not necessarily required. You can use GitOps to build pipelines, provision clusters, manage configurations, and much more.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why GitOps is beneficial for DORA metrics&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DORA metrics are great, especially when demonstrating critical areas for improvement to organizations. However, while organizations know about the metrics, it can be tough to have good performance numbers there. Adopting GitOps principles can help tackle these issues.&lt;/p&gt;

&lt;p&gt;For example, because GitOps adds a structure of repeatability to your organization’s different environments, you can reduce MTTR and the change failure rate. This is because you now have a declarative reference architecture in place of your entire system. You also eliminate delivery as the last step in your Continuous Integration (CI) pipeline because of synchronization. That synchronization also means because you use Git for your systems’ versioning, you can now ensure that your deployments match your desired state. All of this combined means your MTTR is significantly reduced from days or hours to just minutes.&lt;/p&gt;

&lt;p&gt;Also, you now have more frequent releases because you are using continuous deployment, which translates into increased speed and productivity. This increased speed and productivity translate into happier customers because of the potential for new features or functionality due to decreased turnaround time.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Know what is deployed where&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine having a magic wand that handles your deployments. GitOps can do that for you.Some CI tools follow an authoritative or ad-hoc approach and use things like custom kubectl scripts to deploy. The urge to change or edit something manually in environments is significant – it is perceived as quicker or easier. So, for example, you may have “cowboy deployments” or “cowboy engineering” where your DevOps team may be performing manual changes to the cluster. But when this happens, you have no idea what’s going on since those changes aren’t recorded anywhere, and the modifications can be pretty delicate.GitOps gets rid of those manual changes because whatever agent you’re using is in charge of the deployment. The deployment process or synchronization is a consolidation of whatever your current cluster state is to the desired state. The agent is also in charge of monitoring. Because of this, things are alike and in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Faster deployments and rollbacks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There are times when you or a colleague may want to know, “What are the current deployment versions in environments A and B?” or “Is it possible to roll back to version XYZ?” When using a traditional CI/CD solution, these questions may be tough to answer because any number of ad-hoc patches, hotfixes, or other changes may have occurred since the initial deployment.&lt;/p&gt;

&lt;p&gt;However, using GitOps, things are a bit simpler. Your Git repository will be able to tell you what deployments are in the cluster because your commit history can pretty much work as your cluster deployment history. The state of your cluster should look very similar to your latest git commit.&lt;/p&gt;

&lt;p&gt;Rollbacks are also easier with GitOps. Things are more “hands-on” when working with traditional CI/CD. With conventional CI/CD, you have to research your deployment pipeline to find the correct version of what you need and then manually trigger it. With GitOps, this is not the case, as you only need to perform a reset in Git, and once things are synchronized, the cluster will reflect the necessary changes. Or, depending on what agent you are using, you could do something as simple as selecting the appropriate Git release and let the synchronization process handle the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;No configuration drift&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Configuration drift is usually due to manual changes and updates across an organization’s environments. It is a problem that existed even with traditional Virtual Machines and has plagued production deployments long before Kubernetes appeared on the scene. The more environments you have and the longer your configuration drift is present, the more crucial things will become.&lt;/p&gt;

&lt;p&gt;Remember when I mentioned monitoring earlier? Well, even though your agent’s sync process is crucial for performing the initial deployment of your application, one of the true strengths is the continuous monitoring of both states (cluster and Git) after the deployment takes place. The reconciler takes care of eliminating configuration drift by staying true to ONLY to the Git state. This uni-directional reconciliation is vital for solving configuration drift which is a widespread issue in organizations with large numbers of deployment targets.&lt;/p&gt;

&lt;p&gt;If you would like to get an idea of how your team or organization’s software delivery performance compares to the rest of the industry, you can take the DORA “DevOps Quick Check” &lt;a href="https://www.devops-research.com/quickcheck.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Considerations for Adopting GitOps&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There are two things to consider when deciding whether or not to embrace GitOps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You need to have a CI in place already&lt;/li&gt;
&lt;li&gt;You need a GitOps Agent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first one is simple. If you already have a CI solution in place, keep using what you have. So, let's tackle the second. &lt;/p&gt;

&lt;p&gt;If you need a GitOps agent, &lt;a href="https://codefresh.io/learn/argo-cd/" rel="noopener noreferrer"&gt;Argo CD&lt;/a&gt; is a great choice. Argo CD is a popular deployment solution for Kubernetes. When following a GitOps deployment pattern, Argo CD makes it easy to define a set of applications with their desired state in a repository and where the deployment should happen. After a deployment, Argo CD continuously monitors a Git repository with Kubernetes manifests and listens for commit events.&lt;/p&gt;

&lt;p&gt;When a commit happens (usually one that updates the versions of the image artifacts), Argo CD starts a “synchronization” process responsible for bringing the cluster configuration to the same state as described in Git.&lt;/p&gt;

&lt;p&gt;When the sync process is complete, we know that the application configuration is the same as the Git manifests.&lt;/p&gt;

&lt;p&gt;The Argo CD deployment process is the embodiment of the core ideas behind GitOps that we discussed at the beginning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All application configuration is stored in Git (usually in a separate repository than the source code)&lt;/li&gt;
&lt;li&gt;Deployments are happening in a “pull” manner where the cluster is fetching manifests from Git (instead of traditional solutions where updates are “pushed” to the cluster)&lt;/li&gt;
&lt;li&gt;A deployment is a  uni-directional reconciliation process between the two states (what is described in Git versus what is deployed in the cluster)&lt;/li&gt;
&lt;li&gt;Even though the sync process is vital for performing the initial deployment of the application, one of the true strengths of Argo CD is the continuous monitoring of both states (cluster and Git) after the deployment takes place. This continuous monitoring is essential for solving configuration drift – a common issue in organizations with a considerable number of deployment targets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To clarify: your CI will stay the same. Nothing is changing except GitOps making things simpler. You no longer have to do certain things manually. If you were using Git? Continue to use Git. If you were using Kubernetes? Continue using Kubernetes. GitOps is less painful than you may imagine, and you are not starting over from scratch. Things are now streamlined.&lt;/p&gt;

&lt;p&gt;You can learn how to get started with Argo CD &lt;a href="https://codefresh.io/argo-platform/getting-started-with-gitops-and-argo-cd/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and read about Argo CD best practices &lt;a href="https://codefresh.io/argo-platform/argo-cd-best-practices/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I mentioned earlier that GitOps was not just for Kubernetes. And that’s true! Kubernetes isn’t a requirement. GitOps can absolutely integrate with other deployment pipelines or infrastructure, including containers and VMs.&lt;/p&gt;

&lt;p&gt;GitOps is also not just for applications. You can also use it with infrastructure toolings such as Terraform or Crossplane. If it is transactional, can be described declaratively, and Infrastructure-as-Code (IaC) tools are available, you can use GitOps in your environment.&lt;/p&gt;

&lt;p&gt;Hopefully, now that you’ve learned more about GitOps you can find ways to introduce this paradigm to your workflow, whether it’s containerizing your application or adding your configuration to your repository. By doing so, you’ll be in good company: CapitalOne, Intuit, Tesla, Red Hat, Google, Codefresh, and many others are using Argo and GitOps to eliminate challenges in their environments. And if you’d like to learn more about how Codefresh has embraced GitOps or get started on your GitOps journey, you can try out the free Community Edition &lt;a href="https://codefresh.io/product/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>gitops</category>
      <category>cicd</category>
      <category>argocd</category>
      <category>devops</category>
    </item>
    <item>
      <title>Best Practices for Argo CD</title>
      <dc:creator>Hannah</dc:creator>
      <pubDate>Mon, 04 Apr 2022 15:20:18 +0000</pubDate>
      <link>https://forem.com/codefreshio/best-practices-for-argo-cd-4h38</link>
      <guid>https://forem.com/codefreshio/best-practices-for-argo-cd-4h38</guid>
      <description>&lt;h4&gt;What are some best practices when using Argo CD?&lt;/h4&gt;

&lt;p&gt;Within this blog post, we’ll be highlighting some best practices tied to &lt;a href="https://argo-cd.readthedocs.io/en/stable/#what-is-argo-cd"&gt;Argo CD&lt;/a&gt;, that allow you to leverage GitOps easily within your deployment workflow.&lt;br&gt;
Below we will explain the following:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;What is Argo CD&lt;/li&gt;
    &lt;li&gt;What are some best practices with Argo CD?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;What is Argo CD&lt;/h3&gt;

&lt;p&gt;Argo CD is the most popular and fastest-growing &lt;a href="https://codefresh.io/gitops/" rel="noopener"&gt;GitOps&lt;/a&gt; tool for Kubernetes. When following a GitOps deployment pattern, Argo CD makes it easy to define a set of applications with their desired state in a repository and where they should be deployed. After a deployment, Argo CD constantly monitors the state and can even catch configuration drift.&lt;/p&gt;

&lt;p&gt;Argo CD's core component is the &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/" rel="noopener"&gt;Applications Controller&lt;/a&gt; that executes continuous monitoring of applications and then compares them to the live application state against your target state defined within your Git repository.&lt;/p&gt;

&lt;p&gt;The Application controller retrieves the desired resource manifest from the Git repository and compares it to the live resource from your Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;This approach enables GitOps for your deployment workflow by leveraging Git as your source of truth. Now, let's further explore how we can leverage Argo CD best for our deployments!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PfQvSxVZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/app-status-in-sync.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PfQvSxVZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/app-status-in-sync.png" alt="App Status - In Sync" width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows the primary Argo CD dashboard with a single Argo application successfully deployed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lh3.googleusercontent.com/AQ28k1lG1SA_xvJjki5PQJD3Cy4RrxL7BlNca30kW3L_scMn6b9LHPfQkLHrj2dyuetUMQQvQyO2loFmQ0l8V742f3V29ow1ztan82FLuJoXhJCy7AoFERrpT34uRBR-pmTqWaS9"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--di-Zya5w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/hierarchical-view-of-all-kubernetes-resources.png" alt="Hierarchical view of all Kubernetes resources" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dashboard above provides a detailed view of the same Argo application deployed in the image above. However, it also provides an understanding of the status of the Kubernetes resources.&lt;/p&gt;

&lt;p&gt;Now, let's explore how we can apply best practices to our Argo CD deployments!&lt;/p&gt;

&lt;h3&gt;
&lt;a id="post-21871-_m13x9eymh82e"&gt;&lt;/a&gt;&lt;strong&gt;Argo CD Best Practices&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Argo CD has several best practices; however, we will review some of the most important ones we've gathered from the Argo community and prioritized below.&lt;/p&gt;

&lt;ol&gt;
&lt;h4&gt;1. &lt;strong&gt;Separate your Git repositories&lt;/strong&gt;
&lt;/h4&gt;
&lt;/ol&gt;

&lt;p&gt;It's super important to separate your configurations and source code into different Git repositories. Separating your configs in their repository limits commit access to avoid something being pushed to production environments. For example, if you accidentally push manifest changes to the config repo, it can trigger an infinite loop of build jobs and Git commit triggers. Using an automated CI pipeline, you can also prevent pushing manifest changes to the same repo.&lt;/p&gt;

&lt;p&gt;Separating your repositories is also more secure and restricts commit access, so someone does not accidentally misconfigure an application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jC7TEfcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/word-image-20220330-174003.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jC7TEfcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/word-image-20220330-174003.png" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Argo CD does not connect to your source code repository. However, if you make a change to your code and you want to deploy the change to a specific environment, you can do the following:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Build a new application code version and then merge a pull request (PR) in the configuration repo to use the new application version you created.&lt;/li&gt;
    &lt;li&gt;Utilize automation for the update you made to your source code by using a pipeline in the source code repository.&lt;/li&gt;
    &lt;li&gt;Argo CD Image Updater allows you to update your container images of the Kubernetes workload managed by Argo CD.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These approaches allow you to maintain logs for any auditing process. You can quickly identify development activity and reference your Git history for easy traceability.&lt;/p&gt;

&lt;ol&gt;
&lt;h4&gt;2. &lt;strong&gt;Create a directory structure to enable a multi-application system for your Argo CD deployments&lt;/strong&gt;
&lt;/h4&gt;
&lt;/ol&gt;

&lt;p&gt;Once you've separated your source code and configs into separate repositories, it's essential to set up a directory structure that applies GitOps for Argo CD deployments. You can leverage several approaches for your Git repository structure that best serves your organization's needs.&lt;/p&gt;

&lt;p&gt;However, we'll highlight some tips to best structure your directory when using Argo CD.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Do: We suggest modeling your environments or clusters using different folders instead of branches in your configuration repository (e.g., prod, staging, testing, etc.).&lt;/li&gt;
    &lt;li&gt;Do: Make sure your cluster and environment configurations repositories are separated (i.e., separate your prod configuration in a different repository from staging).&lt;/li&gt;
    &lt;li&gt;Do: Utilize some sort of manifest management, such as a raw Kubernetes YAML file, Kustomize, or Helm for your environment definitions for your apps.&lt;/li&gt;
    &lt;li&gt;Do: Create an 'argocd' folder in your configuration repository for each cluster and create an Argo CD Application manifest for each app in the cluster's repository.
&lt;ul&gt;
    &lt;li&gt;By creating the separate 'argocd' folder, you can also implement role-based access control for different clusters if you wish with Git repository permissions.&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

    &lt;li&gt;Do: Leverage a multi-folder or a multi-repo structure instead of a multi-branch approach. You should NOT have permanent branches for your clusters or environments.&lt;/li&gt;

    &lt;li&gt;Don't: Never put any independent applications or applications managed by different teams in the same repository.&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;&lt;br&gt;
Implementing these strategies above for your directory structure provides several advantages. Those advantages include improved security, easy rollbacks, audit log, easier testing, and automating your manifest updates. It also allows you to create and delete applications dynamically. If you'd like to see some examples of these directory structures, look &lt;a href="https://github.com/argoproj/argocd-example-apps" rel="noopener"&gt;here&lt;/a&gt;.

&lt;ol&gt;
&lt;h4&gt;3. &lt;strong&gt;Determine a promotion strategy&lt;/strong&gt;
&lt;/h4&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you've established a directory structure, you may face a challenge regarding the best promotion practice between clusters. When deploying multiple applications with Argo CD, it's best to pick one promotion strategy that suits your directory structure and stick with it. Below we'll highlight how you can do this based on your own needs.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_9m9qm130wnjz"&gt;&lt;/a&gt;Group your applications&lt;/h5&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://argocd-applicationset.readthedocs.io/en/stable/" rel="noopener"&gt;ApplicationSets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First and foremost, once you've established a way to manage your applications and deployments, and there are too many apps to keep track of - the ApplicationSet is your best solution. We should also note that the ApplicationSet was previously an external controller that you had to install on your own, and now it's integrated and makes things much easier! However, you need some extra support when using the ApplicationSet instead of the App of Apps pattern that is easy enough to use right away without any additional help or a learning curve.&lt;/p&gt;

&lt;p&gt;Yet, when deploying to production, an ApplicationSet is the best choice. This is because an ApplicationSet is a Kubernetes controller/custom resource definition (CRD) that enables automation and allows flexibility when managing multiple applications across several clusters.&lt;/p&gt;

&lt;p&gt;The ApplicationSet consists of two main components:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://argocd-applicationset.readthedocs.io/en/stable/Generators/" rel="noopener"&gt;Generators&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://argocd-applicationset.readthedocs.io/en/stable/Template/#templates" rel="noopener"&gt;Application template&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are essentially allowing the ApplicationSet to act as a templating agent.&lt;/p&gt;

&lt;p&gt;The generators used with the ApplicationSet are responsible for generating params, utilizing the template to consume the variables, and then applying them to the cluster as Argo CD applications. So, any changes made to an ApplicationSet template and its fields will automatically be applied to each application created.&lt;/p&gt;

&lt;p&gt;This way, you can simultaneously deploy your Argo apps to multiple Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4U0R2Dwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/word-image-20220330-174007.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4U0R2Dwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/word-image-20220330-174007.png" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://argoproj.github.io/argo-cd/operator-manual/cluster-bootstrapping/#app-of-apps-pattern" rel="noopener"&gt;App of Apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When managing ten or fewer applications, it's best to use the App of Apps pattern.&lt;/p&gt;

&lt;p&gt;App of Apps was the pioneer before ApplicationSets that allowed us to deploy multiple applications at once with ease.&lt;/p&gt;

&lt;p&gt;You are leveraging the actual app itself, aka a "Root App," to contain the other applications instead of individual Kubernetes objects. This, in turn, allows you to manage a group of applications that you can deploy declaratively. Essentially this pattern supports the declaration of children apps in a recursive way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wrz38Uea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/word-image-20220330-174013.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wrz38Uea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2022/03/word-image-20220330-174013.png" width="678" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/"&gt;Image from the Argo CD documentation&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Another possible approach to promoting changes is the &lt;a href="https://argocd-image-updater.readthedocs.io/en/stable/#argo-cd-image-updater" rel="noopener"&gt;Argo CD Image Updater&lt;/a&gt;. It's still a relatively new project, but it provides a manual way to update your manifest versions.&lt;/p&gt;

&lt;p&gt;However, we should note that this approach is not GitOps friendly. Meaning it goes against the declarative nature of GitOps, but perhaps its functionality is what you and your team needs.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_ojk5dlxw0p0e"&gt;&lt;/a&gt;Which to choose?&lt;/h5&gt;

&lt;p&gt;One does not "need" a promotion strategy when beginning to deploy with Argo CD. The strategies listed above are needed when trying to solve "too many apps." This problem dramatically depends on the number of Argo CD applications you are managing and whether or not you already have a deployment process in place or not.&lt;/p&gt;

&lt;p&gt;The Argo community has developed the strategies listed above to help you manage all your Argo CD application deployments, depending on your scale, directory structure, and manifest types, amongst other factors.&lt;/p&gt;

&lt;p&gt;However, it's ultimately up to you and your workload, which is best for you and your team.&lt;/p&gt;

&lt;ol&gt;
&lt;h4&gt;4. &lt;strong&gt;Manage your secrets securely&lt;/strong&gt;
&lt;/h4&gt;
&lt;/ol&gt;

&lt;p&gt;No one solution for &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/secret-management/" rel="noopener"&gt;secret management&lt;/a&gt; will work for all organizations. However, some common approaches for how to best handle your secrets with Argo CD can help based on these two significant factors:&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_w2ry0j4kjmyh"&gt;&lt;/a&gt;Encrypt your secrets directly in your Git repository:&lt;/h5&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://engineering.bitnami.com/" rel="noopener"&gt;Bitnami Sealed Secrets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sealed secrets are one way to encrypt secrets created by anyone but can only be decrypted by the controller running within the target cluster.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/mozilla/sops" rel="noopener"&gt;SOPS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SOPS (Secret OperationS) is an open source solution that allows you to encrypt and decrypt an entire file or field for your Kubernetes secrets. This approach will enable you to store your secrets, and other Kubernetes manifests directly in your Git repository.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_22nwzap9k2bt"&gt;&lt;/a&gt;Externalizing your secrets from your Git repository:&lt;/h5&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/argoproj-labs/argocd-vault-plugin" rel="noopener"&gt;Argo CD Vault plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solution creates debate about whether it's GitOps or not. Nonetheless, it's a solution using Kubernetes auth in Vault. The Argo CD repo server authorizes Vault to use the service account token in the secret manifest, substituting the required value and creating a secret for you.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Cloud Provider Secrets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cloud provider secrets are created by your cloud service providers (CSP) depending on the cloud service. It depends on what your CSP offers and if their secret management solution meets your needs. Ensure you evaluate which strategy secures your data best.&lt;/p&gt;

&lt;p&gt;Firstly, storing your secrets in a Git repository isn't easy! Perhaps your organization has a different policy for secrets, or you already have a system in place, so in this case, you may want to externalize your secrets.&lt;/p&gt;

&lt;p&gt;However, if you want to store your secrets in your Git repository, plaintext secrets cannot be stored in your repo, and you never want to risk storing sensitive data and exposing it!&lt;/p&gt;

&lt;p&gt;But, Git can truly be the source of truth, including your secrets, and you won't have to risk getting fired when they are encrypted asymmetrically. You can use Argo CD to manage your deployment state from Git into your cluster, including your secrets, by ensuring processes are put in place, and the tools above are used safely.&lt;/p&gt;

&lt;ol&gt;
&lt;h4&gt;5. &lt;a id="post-21871-_igoj40bhubr"&gt;&lt;/a&gt;&lt;strong&gt;Confirm how your team accesses Argo CD &lt;/strong&gt;
&lt;/h4&gt;
&lt;/ol&gt;

&lt;p&gt;Essentially, we cannot say what the best practice for you and your team is to access Argo CD. However, we can advise you and your team to choose which approach works best for your organization and set a standard for your team.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_u8z9ow43nf9v"&gt;&lt;/a&gt;Developers require access to Argo CD, so you need to set security measures and role-based access control (RBAC).&lt;/h5&gt;

&lt;p&gt;This approach allows your developers to access the Argo CD UI and ensure that each team has the appropriate access to their applications and their applications only.&lt;/p&gt;

&lt;p&gt;Argo CD provides an &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#rbac-configuration" rel="noopener"&gt;RBAC configuration&lt;/a&gt; that includes two pre-defined roles:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Read-only&lt;/li&gt;
    &lt;li&gt;Admin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also implement a permissions definition for your applications and other resource types with Argo CD. You can then sync these roles and permissions together to create a policy to define access to your system.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_vmpdf9n1pfnd"&gt;&lt;/a&gt;No one within your organization requires access to Argo CD.&lt;/h5&gt;

&lt;p&gt;Some organizations do not want anyone to access the Argo CD UI or the API server. Perhaps the organization would like to use the automation but does not want to leverage the UI component. In this case, you can use a variant of Argo CD, also known as &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/installation/#core" rel="noopener"&gt;Argo CD Core&lt;/a&gt;. This allows developers to make a commit and ignore the UI aspects and reduce complexity. However, we should note that you lose multi-tenancy benefits by installing Argo CD Core.&lt;/p&gt;

&lt;p&gt;So, whichever approach you choose above - as long as it benefits you and your team, you're making the right choice.&lt;/p&gt;

&lt;ol&gt;
&lt;h4&gt;6. &lt;a id="post-21871-_twnsu4heyo9s"&gt;&lt;/a&gt;&lt;strong&gt;Increase automation for your system with the other Argo projects&lt;/strong&gt;
&lt;/h4&gt;
&lt;/ol&gt;

&lt;p&gt;If you're using &lt;a href="https://codefresh.io/learn/argo-cd/" rel="noopener"&gt;Argo CD for Continuous Delivery (CD)&lt;/a&gt;, you want to elevate the rest of your workflow to automate everything in Kubernetes to reduce downtime. Then, you should check out the other &lt;a href="https://github.com/argoproj" rel="noopener"&gt;Argo projects&lt;/a&gt; and learn more about how they can help.&lt;/p&gt;

&lt;p&gt;We don't encourage you to use any specific projects to leverage best practices, but instead, we encourage you to use those that will help you and your system best.&lt;/p&gt;

&lt;p&gt;In the meantime, we can explore how we could use Argo Events, Workflows, and Rollouts to enhance your system if you choose to.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_xfyh0qwuofic"&gt;&lt;/a&gt;Progressive Delivery&lt;/h5&gt;

&lt;p&gt;Progressive delivery is a set of practices that roll out new features gradually instead of all at once.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/argoproj/argo-rollouts" rel="noopener"&gt;Argo Rollouts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rollouts provide advanced deployment capabilities and rolling updates for progressive delivery approaches you might already know, such as blue-green, canary, etc.&lt;/p&gt;

&lt;h5&gt;
&lt;a id="post-21871-_cr8bufalkf5s"&gt;&lt;/a&gt; Advanced Deployment with CI&lt;/h5&gt;

&lt;p&gt;Argo Workflows and Events require you to have an existing Continuous Integration (CI) process to leverage these projects.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/argoproj/argo-workflows" rel="noopener"&gt;Argo Workflows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Workflows allow you to build and orchestrate parallel jobs and utilize a pipeline on Kubernetes.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/argoproj/argo-events" rel="noopener"&gt;Argo Events&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Events is an event-driven workflow automation framework that is used with Kubernetes.&lt;/p&gt;

&lt;p&gt;By utilizing these other Argo projects, you can easily manage your clusters, run workflows, and implement GitOps for your Kubernetes system! However, not all organizations are ready to implement automation for everything in Kubernetes. Combining all these tools requires time and understanding of how your system works before identifying which tool will best help your team's process.&lt;/p&gt;

&lt;h4&gt;
&lt;a id="post-21871-_sbcsl1bw8rj8"&gt;&lt;/a&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Argo CD and the other Argo projects certainly make life easier by allowing you to automate each step for a production release, migration, and the operation workflows for your system!&lt;/p&gt;

&lt;p&gt;By leveraging these best practices above, you're on the right track to empower your teams and apply GitOps for your infrastructure so you can deploy to prod more frequently.&lt;/p&gt;

&lt;p&gt;I'd like to thank those who are part of the Argo community who participated and provided feedback for this blog. If you have any questions or think there are better ways to work with Argo CD, please reach out and let me know!&lt;/p&gt;

</description>
      <category>argocd</category>
      <category>gitops</category>
      <category>bestpractices</category>
      <category>cd</category>
    </item>
    <item>
      <title>How to Model Your Gitops Environments and Promote Releases between Them</title>
      <dc:creator>Kostis Kapelonis</dc:creator>
      <pubDate>Wed, 23 Mar 2022 11:49:56 +0000</pubDate>
      <link>https://forem.com/codefreshio/how-to-model-your-gitops-environments-and-promote-releases-between-them-1p6i</link>
      <guid>https://forem.com/codefreshio/how-to-model-your-gitops-environments-and-promote-releases-between-them-1p6i</guid>
      <description>&lt;p&gt;Two of the most important questions that people ask themselves on day 2 after adopting GitOps are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How should I represent different environments on Git?&lt;/li&gt;
&lt;li&gt;How should I handle promoting releases between environments?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In &lt;a href="https://codefresh.io/about-gitops/branches-gitops-environments/"&gt;the previous article of the series&lt;/a&gt;, I focused on what NOT to do and explained why using Git branches for different environments is a bad idea. I also hinted that the “environment-per-folder” approach is a better idea. This article has proved hugely popular and several people wanted to see all the details about the suggested structure for environments when folders are used.&lt;/p&gt;

&lt;p&gt;In this article, I am going to explain how to model your GitOps environments using different folders on the same Git branch, and as an added bonus, how to handle environment promotion (both simple and complex) with simple file copy operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z1Aoaz7K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xd34ou4vc1lwvnm71vc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z1Aoaz7K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xd34ou4vc1lwvnm71vc.png" alt="GitOps promotion" width="851" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully this article will help with the endless stream of &lt;a href="https://github.com/argoproj/argocd-example-apps/issues/57"&gt;questions&lt;/a&gt; and &lt;a href="https://github.com/argoproj/argo-cd/discussions/5667"&gt;discussions&lt;/a&gt; on this hot topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn your application first
&lt;/h2&gt;

&lt;p&gt;Before creating your folder structure you need to do some research first and understand the “settings” of your application. Even though several people talk about application configuration in a generic manner, in reality not all configuration settings are equally important.&lt;/p&gt;

&lt;p&gt;In the context of a Kubernetes application, we have the following categories of “environment configuration”:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;application version&lt;/strong&gt; in the form of the container tag used. This is probably the most important setting in a Kubernetes manifest (as far as environment promotions are concerned). Depending on your use case, you might get away with simply changing the version of the container image. However, several times a new change in the source code also requires a new change in the deployment environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes specific settings&lt;/strong&gt; for your application. This includes the replicas of the application and other Kubernetes related information such as resource limits, health checks, persistent volumes, affinity rules, etc.&lt;/li&gt;
&lt;li&gt;Mostly &lt;strong&gt;static business settings&lt;/strong&gt;. This is the set of settings that are unrelated to Kubernetes but have to do with the business of your application. It might be external URLs, internal queue sizes, UI defaults, authentication profiles, etc. By “mostly static,” I mean settings that are defined once for each environment and then never change afterwards. For example, you always want your production environment to use production.paypal.com and your non-production environments to use staging.paypal.com. This is a setting that you never want to promote between environments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-static business settings&lt;/strong&gt;. This is the same thing as the previous point, but it includes settings that you DO want to promote between environments. This could be a global VAT setting, your recommendation engine parameters, the available bitrate encodings, and any other setting that is specific to your business.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is imperative that you understand what all the different settings are and, more importantly, which of them belong to category 4 as these are the ones that you also want to promote along with your application version.&lt;/p&gt;

&lt;p&gt;This way you can cover all possible promotion scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your application moves from version 1.34 to 1.35 in QA. This is a simple source code change. Therefore you only need to change the container image property in your QA environment.&lt;/li&gt;
&lt;li&gt;Your application moves from version 3.23 to 3.24 in Staging. This is not a simple source code change. You need to update the container image property and also bring the new setting “recommender.batch_size” from QA to staging.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I see too many teams that don’t understand the distinction between different configuration parameters and have a single configuration file (or mechanism) with values from different areas (i.e. both runtime and application business settings).&lt;/p&gt;

&lt;p&gt;Once you have the list of your settings and which area they belong to, you are ready to create your environment structure and optimize the file copy operations for the settings that change a lot and need to be moved between environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example with 5 GitOps environments and variations between them
&lt;/h2&gt;

&lt;p&gt;Let’s see an actual example. I thought about doing the classic QA/Staging/Production trilogy, but this is rather boring so let’s dive into a more realistic example. &lt;/p&gt;

&lt;p&gt;We are going to model the environment situation mentioned in the first article of the series. The company that we will examine has 5 distinct environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load Testing&lt;/li&gt;
&lt;li&gt;Integration Testing&lt;/li&gt;
&lt;li&gt;QA&lt;/li&gt;
&lt;li&gt;Staging&lt;/li&gt;
&lt;li&gt;Production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then let’s assume that the last 2 environments are also deployed to EU, US, and Asia while the first 2 also have GPU and Non-GPU variations. This means that the company has a total of 11 environments. &lt;/p&gt;

&lt;p&gt;You can find the suggested folder structure at  &lt;a href="https://github.com/kostis-codefresh/gitops-environment-promotion"&gt;https://github.com/kostis-codefresh/gitops-environment-promotion&lt;/a&gt;. All environments are different folders in the same branch. There are NO branches for the different environments. If you want to know what is deployed in an environment, you simply look at envs/ in the main branch of the repo.&lt;/p&gt;

&lt;p&gt;Before we explain the structure, here are some disclaimers: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer 1:&lt;/strong&gt; Writing this article took a long time because I wasn’t sure if I should cover &lt;a href="https://kustomize.io/"&gt;Kustomize&lt;/a&gt; or &lt;a href="https://helm.sh/"&gt;Helm&lt;/a&gt; or plain manifests. I chose Kustomize as it makes things a bit easier (and I also mention Helm at the end of the article). Note however that the Kustomize templates in the example repo are simply for illustration purposes. The present article is NOT a Kustomize tutorial. In a real application, you might have &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/configmapgenerator/"&gt;Configmap generators&lt;/a&gt;, &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesstrategicmerge/"&gt;custom patches&lt;/a&gt; and adopt a completely different “component” structure than the one I am showing here. If you are not familiar with Kustomize, spend some time understanding its capabilities first and then come back to this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer 2:&lt;/strong&gt; The &lt;a href="https://github.com/kostis-codefresh/gitops-promotion-source-code"&gt;application I use&lt;/a&gt; for the promotions is completely dummy, and its configuration misses several best practices mainly for brevity and simplicity reasons. For example, some deployments are missing &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/"&gt;health checks&lt;/a&gt;, and all of them are missing &lt;a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/"&gt;resource limits&lt;/a&gt;. Again, this article is NOT about how to create Kubernetes deployments. You should already know how proper deployment manifests look. If you want to learn more about production-grade best practices, then see my other article at &lt;a href="https://codefresh.io/kubernetes-tutorial/kubernetes-antipatterns-1/"&gt;https://codefresh.io/kubernetes-tutorial/kubernetes-antipatterns-1/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the disclaimers out of the way, here is the repository structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NmdZpVhJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kluawshadkmduowh8wa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NmdZpVhJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kluawshadkmduowh8wa.jpg" alt="GitOps folder structure" width="566" height="627"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The base directory holds configuration which is common to all environments. It is not expected to change often. If you want to do changes to multiple environments at the same time, it is best to use the “variants” folder.&lt;/p&gt;

&lt;p&gt;The variants folder (a.k.a mixins, a.k.a. components) holds common characteristics between environments. It is up to you to define what exactly you think is “common” between your environments after researching your application as discussed in the previous section.&lt;/p&gt;

&lt;p&gt;In the example application, we have variants for all prod and non-prod environments and also the regions. Here is an example of the &lt;a href="https://raw.githubusercontent.com/kostis-codefresh/gitops-environment-promotion/main/variants/prod/prod.yml"&gt;prod variant&lt;/a&gt; that applies to ALL production environments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simple-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webserver-simple&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENV_TYPE&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAYPAL_URL&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production.paypal.com"&lt;/span&gt;   
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_USER&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod_username"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod_password"&lt;/span&gt;                     
        &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, we make sure that all production environments are using the production DB credentials, the production payment gateway, and a liveness probe (this is a contrived example, please see disclaimer 2 at the start of this section). These settings belong to the set of configuration that we don’t expect to promote between environments, but we assume that they will be static across the application lifecycle.&lt;/p&gt;

&lt;p&gt;With the base and variants ready, we can now define every final environment with a combination of those properties.&lt;/p&gt;

&lt;p&gt;Here is an example of the &lt;a href="https://github.com/kostis-codefresh/gitops-environment-promotion/tree/main/envs/staging-asia"&gt;staging ASIA environment&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
&lt;span class="na"&gt;namePrefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging-asia-&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../../base&lt;/span&gt;

&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../../variants/non-prod&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../../variants/asia&lt;/span&gt;

&lt;span class="na"&gt;patchesStrategicMerge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;version.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;replicas.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;settings.yml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we define some common properties. We inherit all configuration from base, from non-prod environments, and for all environments in Asia.&lt;/p&gt;

&lt;p&gt;The key point here is the patches that we apply. The &lt;a href="https://github.com/kostis-codefresh/gitops-environment-promotion/blob/main/envs/staging-asia/version.yml"&gt;version.yml&lt;/a&gt; and &lt;a href="https://github.com/kostis-codefresh/gitops-environment-promotion/blob/main/envs/staging-asia/replicas.yml"&gt;replicas.yml&lt;/a&gt; are self-explanatory. They only define the image and replicas on their own and nothing else.&lt;/p&gt;

&lt;p&gt;The version.yml file (which is the most important thing to promote between environments) defines only the image of the application and nothing else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simple-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webserver-simple&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.io/kostiscodefresh/simple-env-app:2.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The associated settings for each release that we &lt;strong&gt;DO&lt;/strong&gt; expect to promote between environments are also defined in &lt;a href="https://github.com/kostis-codefresh/gitops-environment-promotion/blob/main/envs/staging-asia/settings.yml"&gt;settings.yml&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simple-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webserver-simple&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UI_THEME&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dark"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CACHE_SIZE&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1024kb"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAGE_LIMIT&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;25"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SORTING&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascending"&lt;/span&gt;    
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;N_BUCKETS&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;42"&lt;/span&gt;         
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to look at the &lt;a href="https://github.com/kostis-codefresh/gitops-environment-promotion"&gt;whole repository&lt;/a&gt; to understand the way all kustomizations are formed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performing the initial deployment via GitOps
&lt;/h2&gt;

&lt;p&gt;To deploy an application to its associated environment, just point your GitOps controller to the respective “env” folder and kustomize will create the complete hierarchy of settings and values.&lt;/p&gt;

&lt;p&gt;Here is the &lt;a href="https://github.com/kostis-codefresh/gitops-promotion-source-code"&gt;example application&lt;/a&gt; as it runs in Staging/Asia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xh2Td7RF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jthmsbi5qg1hsfhf46wq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xh2Td7RF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jthmsbi5qg1hsfhf46wq.jpg" alt="GitOps application example" width="537" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also use Kustomize on the command line to preview what is going to be deployed for each environment. Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kustomize build envs/staging-asia
kustomize build envs/qa
kustomize build envs/integration-gpu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can of course pipe the output to kubectl to deploy each environment, but in the context of GitOps, you should always let your GitOps controller deploy your environments and avoid manual kubectl operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing the configuration of two environments
&lt;/h2&gt;

&lt;p&gt;A very common need for a software team is to understand what is different between two environments. I have seen several teams who have the misconception that only with branches you can easily find differences between environments.&lt;/p&gt;

&lt;p&gt;This could not be further from the truth. You can easily use mature file-diffing utilities to find what is different between environments just by comparing files and folders.&lt;/p&gt;

&lt;p&gt;The simplest way is to diff only the settings that are critical to the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vimdiff envs/integration-gpu/settings.yml envs/integration-non-gpu/settings.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wLakkrDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xsimyy6qbq5920lqkf6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wLakkrDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xsimyy6qbq5920lqkf6.jpg" alt="GitOps settings diff" width="880" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And with the help of kustomize, you can compare any number of whole environments for the full picture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kustomize build envs/qa/&amp;gt; /tmp/qa.yml
kustomize build envs/staging-us/ &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/staging-us.yml
kustomize build envs/prod-us/ &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/prod-us.yml
vimdiff /tmp/staging-us.yml /tmp/qa.yml /tmp/prod-us.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5wSVXrSB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mjwjvvgiu2i9vgokr0n3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5wSVXrSB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mjwjvvgiu2i9vgokr0n3.jpg" alt="GitOps environment diff" width="880" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I personally don’t see any disadvantage between this method and performing “git diff” between environment branches.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to perform promotions between GitOps environments
&lt;/h2&gt;

&lt;p&gt;Now that the file structure is clear, we can finally answer the age-old question “how do I promote releases with GitOps”?&lt;/p&gt;

&lt;p&gt;Let’s see some promotion scenarios. If you have been paying attention to the file structure, you should already understand how all promotions resolve to simple file copy operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Promote application version from QA to staging environment in the US:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/qa/version.yml envs/staging-us/version.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Promote application version from integration testing (GPU) to load testing (GPU) and then to QA. This is a 2 step process&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/integration-gpu/version.yml  envs/load-gpu/version.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;li&gt;cp envs/load-gpu/version.yml  envs/qa/version.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Promote an application from prod-eu to prod-us along with the extra configuration. Here we also copy our setting file(s).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/prod-eu/version.yml  envs/prod-us/version.yml&lt;/li&gt;
&lt;li&gt;cp envs/prod-eu/settings.yml  envs/prod-us/settings.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Make sure that QA has the same replica count as staging-asia&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/staging-asia/replicas.yml envs/qa/replicas.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Backport all settings from qa to integration testing (non-gpu variant)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/qa/settings.yml envs/integration-non-gpu/settings.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Make a global change to all non-prod environments at once (but see also next section for some discussion on this operation)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make your change in variants/non-prod/non-prod.yml &lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Add a new configuration file to all US environments (both production and staging).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the new manifest in the variants/us folder&lt;/li&gt;
&lt;li&gt;Modify the variants/us/kustomization.yml file to include the new manifest&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In general, all promotions are just copy operations. Unlike the environment-per-branch approach, you are now free to promote anything from any environment to any other environment without any fear of taking the wrong changes. Especially when it comes to back-porting configuration, environment-per-folder really shines as you can simply move configuration both “upwards” and “backwards” even between unrelated environments.&lt;/p&gt;

&lt;p&gt;Note that I am using cp operations just for illustration purposes. In a real application, this operation would be performed automatically by your CI system or other orchestration tool. And depending on the environment, you might want to create a Pull Request first instead of directly editing the folder in the main branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making changes to multiple environments at once
&lt;/h2&gt;

&lt;p&gt;Several people have asked in the comments of the &lt;a href="https://codefresh.io/about-gitops/branches-gitops-environments/"&gt;first article&lt;/a&gt; about the use-case of changing multiple environments at once and how to achieve and/or prevent this scenario.&lt;/p&gt;

&lt;p&gt;First of all, we need to define what exactly we mean by “multiple” environments. We can assume the following 2 cases.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Changing multiple environments at once that are on the same “level.” As an example, you want to make a change that affects prod-us, prod-eu and prod-asia at the same time&lt;/li&gt;
&lt;li&gt;Changing multiple environments at once that are &lt;strong&gt;NOT&lt;/strong&gt; on the same level. As an example, you want to make a change to “integration” and “staging-eu” at the same time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first case is a valid scenario, and we will cover this below. However, I consider the second scenario an anti-pattern. The whole point of having different environments is to be able to release things in a gradual way and promote a change from one environment to the next. So if you find yourself deploying the same change in environments of different importance, ask yourself if this is really needed and why.&lt;/p&gt;

&lt;p&gt;For the valid scenario of deploying a single change to multiple “similar” environments, there are two strategies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you are absolutely certain that the change is “safe” and you want it to reach all environments at once, you can make that change in the appropriate variant (or respective folders). For example, if you commit/push a change in the variants/non-prod folder then all non-production environments will get this change at the same time. I am personally &lt;strong&gt;against&lt;/strong&gt; this approach because several changes look “safe” in theory but can be problematic in practice&lt;/li&gt;
&lt;li&gt;The preferable approach is to apply the change to each individual folder and then move it to the “parent” variant when it is live on all environments.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s take an example. We want to make a change that affects all EU environments (e.g. a GDPR feature). The naive way would be to commit/push the configuration change directly to variants/eu folder. This would indeed affect all EU environments (prod-eu and staging-eu). However this is a bit risky, because if the deployment fails, you have just brought down a production environment.&lt;/p&gt;

&lt;p&gt;The suggested approach is the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make the change to envs/staging-eu first&lt;/li&gt;
&lt;li&gt;Then make the same change to envs/prod-eu&lt;/li&gt;
&lt;li&gt;Finally, delete the change from both environments and add it in variants/eu (in a single commit/push action).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mWt2fn1G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aidbyxfyiw4e5zq80wh6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mWt2fn1G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aidbyxfyiw4e5zq80wh6.png" alt="Gradual GitOps promotion" width="880" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might recognize this pattern from gradual &lt;a href="https://databaserefactoring.com/"&gt;database refactorings&lt;/a&gt;. The final commit is “transitional” in the sense that it doesn’t really affect any environments in any way. Kustomize will create the exact same definition in both cases. Your GitOps controller shouldn’t find any differences at all.&lt;/p&gt;

&lt;p&gt;The advantages of this approach are of course the easy way to rollback/revert the change as you move it through environments. The disadvantage is the increased effort (and commits) you need to promote the change to all environments, but I believe that the effort outweighs the risks.&lt;/p&gt;

&lt;p&gt;If you adopt this approach, it means that you &lt;strong&gt;never&lt;/strong&gt; apply new changes to the base folder directly. If you want a change to happen to all environments, you first apply the change to individual environments and/or variants and then backport it to the base folder while simultaneously removing it from all downstream folders.&lt;/p&gt;

&lt;h2&gt;
  
  
  The advantages of the “environment-per-folder” approach
&lt;/h2&gt;

&lt;p&gt;Now that we have analyzed all the inner workings of the “environment-per-folder” approach, it is time to explain why it is better than the “environment-per-branch” approach. If you have been paying attention to the previous sections, you should already understand how the “environment-per-folder” approach directly avoids all the problems analyzed in the &lt;a href="https://codefresh.io/about-gitops/branches-gitops-environments/"&gt;previous article&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The most glaring issues with environment branches is the order of commits and the danger of bringing unwanted changes when you merge from one environment to another. With the folder approach, this problem is completely eliminated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The order of commits on the repo is now irrelevant. When you copy a file from one folder to the next, you don’t care about its commit history, just its content&lt;/li&gt;
&lt;li&gt;By only copying files around, you only take exactly what you need and nothing else. When you copy envs/qa/version.yml to envs/staging-asia/version.yml you can be certain that you only promote the container image and nothing else. If somebody else has changed the replicas in the QA environment in the meantime, it doesn’t affect your promotion action.&lt;/li&gt;
&lt;li&gt;You don’t need to use git cherry-picks or any other advanced git method to promote releases. You only copy files around and have access to the mature ecosystem of utilities for file processing.&lt;/li&gt;
&lt;li&gt;You are free to take any change from any environment to either an upstream or downstream environment without any constraints about the correct “order” of environments. If for example you want to backport your settings from production US to staging US, you can do a simple copy operation of envs/prod-us/settings.yml to envs/staging-us/settings.yml without the fear that you might take inadvertently unrelated hotfixes that were supposed to be only in production.&lt;/li&gt;
&lt;li&gt;You can easily use file diff operations to understand what is different between environments in all directions (both from source and target environments and vice versa)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I consider these advantages very important for any non-trivial application, and I bet that several “failed deployments” in big organizations could be directly or indirectly attributed to the problematic environment-per-branch model.&lt;/p&gt;

&lt;p&gt;The second problem mentioned in the previous article was the presence of configuration drift when you merge a branch to the next environment. The reason for this is that when you do a “git merge,” git only notifies you about the changes it will bring, and it doesn’t say anything about what changes are already in the target branch.&lt;/p&gt;

&lt;p&gt;Again this problem is completely eliminated with folders. As we said already, file diff operations have no concept of “direction.” You can copy any setting from any environment either upwards or downwards, and if you do a diff operation on the files, you will see all changes between environments regardless of their upstream/downstream position.&lt;/p&gt;

&lt;p&gt;The last point about environment branches was the linear complexity of branches as the number of environments grows. With 5 environments, you need to juggle changes between 5 branches, and with 20 environments, you need to have 20 branches. Moving a release correctly between a large number of branches is a cumbersome process, and in the case of production environments, it is a recipe for disaster.&lt;/p&gt;

&lt;p&gt;With the folder approach, the number of branches is not only static but it is exactly 1. If you have 5 environments you manage them all with your “main” branch, and if you need more environments, you only add extra folders. If you have 20 environments, you still need a single Git branch. Getting a centralized view on what is deployed where is trivial when you have a single branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Helm with GitOps environments
&lt;/h2&gt;

&lt;p&gt;If you don’t use Kustomize but prefer Helm instead, it is also possible to create a hierarchy of folders with “common” stuff for all environments, specific features/mixins/components, and final folders specific to each environment.&lt;/p&gt;

&lt;p&gt;Here is how the folder structure would look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chart/
  [...chart files here..]
common/
  values-common.yml
variants/
  prod/
     values-prod.yml
  non-prod/
    Values-non-prod.yml
  [...other variants…]
 envs/
     prod-eu/
           values-env-default.yaml
           values-replicas.yaml
           values-version.yaml
           values-settings.yaml
   [..other environments…]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again you need to spend some time to examine your application properties and decide how to split them into different value files for optimal promotion speed.&lt;/p&gt;

&lt;p&gt;Other than this, most of the processes are the same when it comes to environment promotion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Promote application version from  QA to staging environment in the US:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/qa/values-version.yml envs/staging-us/values-version.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Promote application version from integration testing (GPU) to load testing (GPU) and then to QA. This is a 2 step process&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/integration-gpu/values-version.yml  envs/load-gpu/values-version.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;li&gt;cp envs/load-gpu/values-version.yml  envs/qa/values-version.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Promote an application from prod-eu to prod-us along with the extra configuration. Here we also copy our setting file(s).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cp envs/prod-eu/values-version.yml  envs/prod-us/values-version.yml&lt;/li&gt;
&lt;li&gt;cp envs/prod-eu/values-settings.yml  envs/prod-us/values-settings.yml&lt;/li&gt;
&lt;li&gt;commit/push changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is also critical to understand how Helm (or your GitOps agent which handles Helm) works with multiple value files and the order in which they override each other.&lt;/p&gt;

&lt;p&gt;If you want to preview one of your environments, instead of “kustomize build” you can use the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm template chart/ &lt;span class="nt"&gt;--values&lt;/span&gt; common/values-common.yaml &lt;span class="nt"&gt;--values&lt;/span&gt; variants/prod/values-prod.yaml –values envs/prod-eu/values-env-default.yml –values envs/prod-eu/values-replicas.yml –values envs/prod-eu/values-version.yml –values envs/prod-eu/values-settings.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that Helm is a bit more cumbersome than Kustomize, if you have a large number of variants or files in each environment folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “environment-per-git-repo” approach
&lt;/h2&gt;

&lt;p&gt;When I talk with big organizations about the folder approach, one of the first objections I see is that people (especially security teams) don’t like to see a single branch in a single Git repository that contains both prod and non-prod environments.&lt;/p&gt;

&lt;p&gt;This is an understandable objection and arguably can be the single weak point of the folder approach against the “environment-per-branch” paradigm. After all, it is much easier to secure individual branches in a Git repository instead of folders in a single branch.&lt;/p&gt;

&lt;p&gt;This problem can be easily solved with automation, validation checks, or even manual approvals if you think it is critical for your organization. I want to stress again that I only use “cp” in the file operations for promoting releases just for illustration purposes. It doesn't mean that an actual human should run cp manually in an interactive terminal when a promotion happens.&lt;/p&gt;

&lt;p&gt;Ideally you should have an automated system that copies files around and commits/pushes them. This can be your Continuous Integration (CI) system or other platform that deals with your software lifecycle. And if you still have humans that make the changes themselves, they should never commit to “main” directly. They should open a Pull Request instead. Then you should have a proper workflow that checks that Pull Request before merging.&lt;/p&gt;

&lt;p&gt;I realize however that some organizations are particularly sensitive to security issues and they prefer a bulletproof approach when it comes to Git protection. For these organizations, you can employ 2 Git repositories. One has the base configuration, all prod variants, and all prod environments (and everything else related to production) while the second Git repository has all non-production stuff.&lt;/p&gt;

&lt;p&gt;This approach makes promotions a bit harder, as now you need to checkout 2 git repositories before doing any promotion. On the other hand, it allows your security team to place extra security constraints to the “production” Git repository, and you still have a static number of Git repositories (exactly 2) regardless of the amount of environments you deploy to.&lt;/p&gt;

&lt;p&gt;I personally consider this approach an overkill that, at least to me, shows a lack of trust against developers and operators. The discussion on whether or not people should have direct access to production environments is a complex one and probably deserves a blog post on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embrace folders and forget branches
&lt;/h2&gt;

&lt;p&gt;We hope that with this blog post we addressed all the questions that arose from the “don’t use branches for environments” article and you now have a good understanding about the benefits of the folder approach and why you should use it.&lt;/p&gt;

&lt;p&gt;If you have other interesting use cases or have extra questions on the subject of organizing your GitOps environments, please ask in the comments section.&lt;/p&gt;

&lt;p&gt;Happy GitOps deployments!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>gitops</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Getting Started with GitOps and Argo CD</title>
      <dc:creator>Tracy Holmes</dc:creator>
      <pubDate>Thu, 24 Feb 2022 01:15:42 +0000</pubDate>
      <link>https://forem.com/codefreshio/getting-started-with-gitops-and-argo-cd-1j2f</link>
      <guid>https://forem.com/codefreshio/getting-started-with-gitops-and-argo-cd-1j2f</guid>
      <description>&lt;p&gt;Today we are going to explore getting started using Argo CD. This post is going to assume you know a bit about containers, and that you already have an empty cluster in place (or know how to create one). If any of this is unfamiliar, head over to &lt;a href="https://argo-cd.readthedocs.io/en/stable/understand_the_basics/" rel="noopener noreferrer"&gt;Understanding the Basics&lt;/a&gt; to get a bit of practice. Before we get started, let’s talk about GitOps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GitOps?
&lt;/h2&gt;

&lt;p&gt;If you are not familiar with GitOps, head over to &lt;a href="https://opengitops.dev/" rel="noopener noreferrer"&gt;https://opengitops.dev&lt;/a&gt; which is the official page of the GitOps working group. In short, GitOps is a paradigm that incorporates best practices applied to the application development workflow all the way to the operating infrastructure of a system. The principles of GitOps are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system is described in a declarative manner.&lt;/li&gt;
&lt;li&gt;The definition of the system is versioned and audited. This tends to be Git.&lt;/li&gt;
&lt;li&gt;A software agent automatically pulls the Git state and matches the platform state.&lt;/li&gt;
&lt;li&gt;The state is continuously reconciled. This means that any changes happening in Git should also be reflected in the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A GitOps tool that follows this approach of a Git-based workflow is Argo CD. It’s a continuous delivery tool for Kubernetes that is essentially a GitOps controller that does two-way synchronization. Argo continuously monitors running applications, compares the live state against the desired state in Git, and applies it to the cluster. Please note this monitoring is for both directions: Git &amp;gt; cluster AND cluster &amp;gt; Git!&lt;/p&gt;

&lt;p&gt;GitOps relies on Git as the single source of truth for declarative configuration and active reconciliation. What does this mean?&lt;/p&gt;

&lt;p&gt;This means Argo CD implements active reconciliation by automatically monitoring your cluster and detecting any manual changes that are not in the Git state. Adopting the GitOps methodology provides transparency between the application configuration deployed in a cluster and the one residing in Git.&lt;/p&gt;

&lt;p&gt;Additionally, some benefits of GitOps are deploying faster and more often, easier and quicker error handling and recovery, and self-documenting deployments. And most importantly? You also get the complete elimination of configuration drift. These benefits make it easier to handle the applications and allow teams to deliver quality software faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this exercise, you can absolutely use a local cluster such as Docker Desktop, minikube, k3s, etc. And if you have access to a cloud cluster? That’s even better.&lt;/p&gt;

&lt;p&gt;However, if you don’t have access to those things, let's make sure we have &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt; installed. &lt;code&gt;kubectl&lt;/code&gt; is a Kubernetes command-line tool that allows you to run commands against Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;We also need a &lt;code&gt;kubeconfig&lt;/code&gt; file. If you already have an empty cluster, then that part of things has most likely already been done for you! In case you want to check, the default location for the config file is &lt;code&gt;~/.kube/config&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Argo CD
&lt;/h2&gt;

&lt;p&gt;Let’s start off by installing Argo CD. To do this, we’ll first create a new namespace, &lt;code&gt;argocd&lt;/code&gt;, where Argo CD services and application resources will live.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create namespace argocd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s apply our resource configuration file on the &lt;code&gt;argocd&lt;/code&gt; namespace we just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once your installation completes, you can use the watch command to check the status of your Kubernetes pods and make sure they are ready.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;watch kubectl get pods -n argocd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we are using a stock Argo CD installation, you should see five pods with a &lt;code&gt;Running&lt;/code&gt; status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                                  READY   STATUS    RESTARTS   AGE
argocd-redis-d486999b7-cd275          1/1     Running   0          8m57s
argocd-dex-server-65bf5f4fc7-p6kv8    1/1     Running   0          8m57s
argocd-repo-server-8465d84869-z4mqb   1/1     Running   0          8m57s
argocd-application-controller-0       1/1     Running   0          8m56s
argocd-server-87b47d787-pbnw8         1/1     Running   0          8m57s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once things are up and running, you can use &lt;code&gt;Ctrl+C&lt;/code&gt; to exit the watch interface. This is only one of the possible ways to install Argo CD! You are also able to use a &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/helm/" rel="noopener noreferrer"&gt;Helm chart&lt;/a&gt; or a smart installer like &lt;a href="https://argocd-autopilot.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Argo Autopilot&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access The Argo CD API Server
&lt;/h2&gt;

&lt;p&gt;By default, the Argo CD API server is not exposed with an external IP. For the purposes of this post, we are going to utilize kubectl port-forwarding to connect to the API server without actually exposing the service. We do that using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl port-forward svc/argocd-server -n argocd 8080:443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make things easier for us as we can now access the API server using &lt;code&gt;localhost:8080&lt;/code&gt;. &lt;strong&gt;Note&lt;/strong&gt;: this method is only for local development or demonstration purposes.&lt;/p&gt;

&lt;p&gt;There are two other techniques you can use to access the API server: Service Type Load Balancer and Ingress. If you’d like to learn more about those methods, definitely check out the &lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt; guide for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download Argo CD CLI
&lt;/h2&gt;

&lt;p&gt;Now that we’ve gotten Argo CD downloaded, installed, and configured for access, it is time to login. There are two ways we can get this done: via the UI (or web interface) and the CLI. The UI and the CLI are mostly similar in capabilities. The CLI is great for changing settings and working with your Argo CD instance. Also, while you can deploy an application using the web interface, it’s typically quicker to deploy via the command line. I tend to use both depending on what I need. We will use both throughout this post.&lt;/p&gt;

&lt;p&gt;I also work across different operating systems, so &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; is usually my goto installation method as it is available for Linux, Mac, and WSL. To install Argo CD using Homebrew, you will use the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install argocd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and check that it has installed correctly using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also download the latest Argo CD version from &lt;a href="https://github.com/argoproj/argo-cd/releases/latest" rel="noopener noreferrer"&gt;https://github.com/argoproj/argo-cd/releases/latest&lt;/a&gt;. If you run into any issues, more detailed installation instructions can be found via the &lt;a href="https://argo-cd.readthedocs.io/en/stable/cli_installation/" rel="noopener noreferrer"&gt;CLI installation documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Login Using The CLI
&lt;/h2&gt;

&lt;p&gt;We are going to login using an admin account. The initial password for this account is auto-generated and stored in your namespace as clear text in the field password and in a secret named &lt;code&gt;argocd-initial-admin-secret&lt;/code&gt;. Let’s retrieve this password using &lt;code&gt;kubectl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d &amp;amp;&amp;amp; echo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve added &lt;code&gt;&amp;amp;&amp;amp; echo&lt;/code&gt; to the end of that command to make it easier for us to copy &amp;amp; paste the generated password. Make sure to save it, as we will need it in the next steps.&lt;/p&gt;

&lt;p&gt;Now that we have that password, we can login! So, let’s do that using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd login &amp;lt;ARGOCD_SERVER&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will substitute Argo CD’s IP or hostname where you see &lt;code&gt;&amp;lt;ARGOCD_SERVER&amp;gt;&lt;/code&gt; in that command. Remember when we set up port forwarding for easy access earlier in this post? Now it will come in handy!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd login localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will prompt you for a username and password. The default username is &lt;code&gt;admin&lt;/code&gt;, and the password is the one we exposed up above. You will not see the password while entering it.&lt;/p&gt;

&lt;p&gt;We also want to change the password while we’re here as the generated one was in cleartext, and that’s not safe. The following command will ask you for your current password, the new password you’d like to use, and lastly, to confirm the new password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd account update-password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you do so, make sure to place your new password somewhere safe, as you will need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create An Application From A Git Repository
&lt;/h2&gt;

&lt;p&gt;In order for us to create an application to demonstrate how Argo CD works, we are going to use an example repository containing a guestbook application. If you would like to check it out or follow along, it is available at &lt;a href="https://github.com/argoproj/argocd-example-apps.git" rel="noopener noreferrer"&gt;https://github.com/argoproj/argocd-example-apps.git&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Remember how I said earlier there are two ways we can get things done? You can definitely use one or the other (or both!) according to personal preference. I am a big fan of using the UI when first learning something in order to get a better idea of things I can do. So let’s start there to create our app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating Apps Via UI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open a browser to the Argo CD external UI by visiting &lt;code&gt;localhost:8080&lt;/code&gt;, and login using the admin credentials we set up earlier. Your login page should look similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo1.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo1.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After logging in, click the “+ New App” button as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo2.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo2.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your app the name &lt;code&gt;guestbook&lt;/code&gt;, use the project &lt;code&gt;default&lt;/code&gt;, and leave the sync policy as &lt;code&gt;Manual&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo3.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo3.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connect the &lt;a href="https://github.com/argoproj/argocd-example-apps.git" rel="noopener noreferrer"&gt;https://github.com/argoproj/argocd-example-apps.git&lt;/a&gt; repo to Argo CD by setting repository URL to the GitHub repo URL, leave revision as &lt;code&gt;HEAD&lt;/code&gt;, and set the path to &lt;code&gt;guestbook&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo4.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo4.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Destination&lt;/strong&gt;, set cluster to &lt;code&gt;in-cluster&lt;/code&gt; and namespace to &lt;code&gt;default&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo5.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo5.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;in-cluster&lt;/code&gt; because when deploying internally (i.e. to the same cluster that Argo CD is running in), the &lt;code&gt;https://kubernetes.default.svc&lt;/code&gt; hostname should be used as the application's Kubernetes API server address.&lt;/p&gt;

&lt;p&gt;After filling out the information above, click &lt;strong&gt;Create&lt;/strong&gt; at the top of the UI to create the guestbook application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo6.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo6.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating Apps Via CLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To create that same app using the CLI, you would use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I do use the CLI, I still like to double-check myself using the UI occasionally. Do whichever is comfortable for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Sync (Deploy) The Application
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Syncing via UI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the guestbook application is created, you can now view its status:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo7.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo7.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the application status is &lt;code&gt;OutOfSync&lt;/code&gt;! &lt;code&gt;OutOfSync&lt;/code&gt; means the git state is different from the cluster state. You can see this information in multiple ways while in the UI. When the state is not in sync, you can usually tell as it is in a helpful yellow color. You can also filter by status on the left side of the dashboard. I highly recommend poking around the dashboard to see which configuration works for you!&lt;/p&gt;

&lt;p&gt;That said, the application status is initially in &lt;code&gt;OutOfSync&lt;/code&gt; state since the application has yet to be deployed. Also, no Kubernetes resources have been created. To sync (deploy) the application, we’ll use the “Sync” button.&lt;/p&gt;

&lt;p&gt;This will bring up a second set of options. Select “Synchronize”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo8.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo8.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Synchronizing is how we deploy the application. When we “Sync” or “Synchronize”, it means we are updating the cluster state to match the Git state. This is one of the most important tenets of GitOps.&lt;/p&gt;

&lt;p&gt;Once things are complete and you return to the dashboard, you will see the guestbook app is now running. Select the app and see what information you can find!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo9.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo9.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo10.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo10.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click on the application name, you will see a hierarchical view of all the Kubernetes resources that take part in the application. You will also see additional details related to the health and synchronization status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Syncing via CLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Of course, everything we have done via the UI, can be done via CLI. Since we created the guestbook application, you can now check the status of your application using &lt;code&gt;argocd app get&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd app get guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name:               guestbook
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://localhost:8080/applications/guestbook
Repo:               https://github.com/howmybrainworks/argocd-example-apps.git
Target:
Path:               guestbook
SyncWindow:         Sync Allowed
Sync Policy:        &amp;lt;none&amp;gt;
Sync Status:        OutOfSync from  (13b08f1)
Health Status:      Missing

GROUP  KIND        NAMESPACE  NAME          STATUS     HEALTH   HOOK  MESSAGE
       Service     default    guestbook-ui  OutOfSync  Missing
apps   Deployment  default    guestbook-ui  OutOfSync  Missing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at the “Sync Status” you will see the application status is initially in &lt;code&gt;OutOfSync&lt;/code&gt; state since the application has yet to be deployed, and no Kubernetes resources have been created. To sync (deploy) the application, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd app sync guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Modifying and redeploying the Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here is where I feel Argo CD really shines. Now that we have a healthy system, let's initiate a change. Let’s scale the deployment by modifying the replicas in the &lt;code&gt;deployment.yaml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;deployment.yaml&lt;/code&gt; file, increase the number of replicas from 1 to 2. Since we are following &lt;a href="https://codefresh.io/gitops/" rel="noopener noreferrer"&gt;GitOps&lt;/a&gt;, we want our modification to be declarative. So, we are going to commit and submit this change via Git. This will show things &lt;code&gt;OutOfSync&lt;/code&gt; as well as identify configuration drift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resyncing (redeploying) via UI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you go back to the UI, you should now see that we are now once again &lt;code&gt;OutOfSync&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo11.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo11.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I sincerely love this feature, because not only does Argo CD let us know the application is no longer in sync, it also gives you a nice “App Diff” view to give more detail about what was changed! Click on the application name again, and you will see this option at the top of the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo12.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo12.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the default “Diff” view can potentially contain an enormous amount of information, so I like to select the “Compact Diff” option in order to immediately see any changes. As you can see, we increased our replicas from 1 &amp;gt; 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo13.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo13.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the same steps to deploy an application by using the “Sync” button, and we should be back to a healthy app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2022%2F02%2FArgo14.png" alt="https://codefresh.io/wp-content/uploads/2022/02/Argo14.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resyncing (redeploying) via CLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's initiate another change. Let’s scale the deployment by modifying the number of replicas using &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;kubectl&lt;/code&gt;, decrease the number of replicas from 2 to 1. You’ll do this using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl scale --current-replicas=2 --replicas=1 deployment/guestbook-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the same steps as above to retrieve our application status using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd app get guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name:               guestbook
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://localhost:8080/applications/guestbook
Repo:               https://github.com/howmybrainworks/argocd-example-apps.git
Target:
Path:               guestbook
SyncWindow:         Sync Allowed
Sync Policy:        &amp;lt;none&amp;gt;
Sync Status:        OutOfSync from  (13b08f1)
Health Status:      Healthy

GROUP  KIND        NAMESPACE  NAME          STATUS     HEALTH   HOOK  MESSAGE
       Service     default    guestbook-ui  Synced     Healthy        service/guestbook-ui created
apps   Deployment  default    guestbook-ui  OutOfSync  Healthy        deployment.apps/guestbook-ui created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you check your output, you will again see we are &lt;code&gt;OutOfSync&lt;/code&gt;. In order to see what’s changed, you’ll  use &lt;code&gt;argocd app diff&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd app diff guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;===== apps/Deployment default/guestbook-ui ======
109c109
&amp;lt;   replicas: 1
--
&amp;gt;   replicas: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the sync command once again to deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;argocd app sync guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything should be back healthy and in order!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, adopting GitOps is beneficial in many ways! Among other things, you gain faster and more frequent deployments, the ability to avoid configuration drift, and easier error handling. This is shown especially when coupled with Argo CD as it can help leverage your deployment process by performing commits automatically and can also execute rollbacks if there are any issues.&lt;/p&gt;

&lt;p&gt;Argo CD is great by itself, but it is even better when connected to other &lt;a href="https://argoproj.github.io/" rel="noopener noreferrer"&gt;Argo projects&lt;/a&gt; such as Argo Workflows, Rollouts, or Events. Combined with any of these, you can elevate your continuous deployment process.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>opensource</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Stop Using Branches for Deploying to Different GitOps Environments</title>
      <dc:creator>Kostis Kapelonis</dc:creator>
      <pubDate>Fri, 17 Dec 2021 13:20:56 +0000</pubDate>
      <link>https://forem.com/codefreshio/stop-using-branches-for-deploying-to-different-gitops-environments-5bmj</link>
      <guid>https://forem.com/codefreshio/stop-using-branches-for-deploying-to-different-gitops-environments-5bmj</guid>
      <description>&lt;p&gt;In our big guide &lt;a href="https://codefresh.io/about-gitops/pains-gitops-1-0/" rel="noopener noreferrer"&gt;for GitOps problems&lt;/a&gt;, we briefly explained (see points 3 and 4) how the current crop of GitOps tools don’t really cover the case of promotion between different environments or how even to model multi-cluster setups. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hz1b2h79cvw9qk5ngpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hz1b2h79cvw9qk5ngpv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The question of “How do I promote a release to the next environment?” &lt;a href="https://github.com/argoproj/argocd-example-apps/issues/57" rel="noopener noreferrer"&gt;is becoming increasingly popular&lt;/a&gt; among organizations that want to adopt GitOps. And even though there are several possible answers, in this particular article I want to focus on what you should NOT do.&lt;/p&gt;

&lt;p&gt;You should NOT use Git branches for modeling different environments. If the Git repository holding your configuration (manifests/templates in the case of Kubernetes) has branches named “staging”, “QA”, “Production” and so on, then you have fallen into a trap. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lq4pdn51s90e92evaq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lq4pdn51s90e92evaq4.png" alt="Branch for environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me repeat that. Using Git branches for modeling different environments is an anti-pattern. Don’t do it!&lt;/p&gt;

&lt;p&gt;We will explore the following points on why this practice is an anti-pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using different Git branches for deployment environments is a relic of the past.&lt;/li&gt;
&lt;li&gt;Pull requests and merges between different branches is problematic.&lt;/li&gt;
&lt;li&gt;People are tempted to include environment specific code and create configuration drift.&lt;/li&gt;
&lt;li&gt;As soon as you have a large number of environments, maintenance of all environments gets quickly out of hand.&lt;/li&gt;
&lt;li&gt;The branch-per-environment model goes against the existing Kubernetes ecosystem.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using branches for different environments should only be applied to legacy applications.
&lt;/h2&gt;

&lt;p&gt;When I ask people why they chose to use Git branches for modelling different environments, almost always the answer is a variation of “we’ve always done it that way,” “it feels natural,” “this is what our developers know,” and so on.&lt;/p&gt;

&lt;p&gt;And that is true. Most people are familiar with using branches for different environments. This practice was heavily popularized by the &lt;a href="https://nvie.com/posts/a-successful-git-branching-model/" rel="noopener noreferrer"&gt;venerable Git-Flow model&lt;/a&gt;. But since the introduction of this model, things have changed a lot. Even the original author has placed a huge warning at the top advising people &lt;strong&gt;against&lt;/strong&gt; adopting this model without understanding the repercussions.&lt;/p&gt;

&lt;p&gt;The fact is that the Git-flow model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is focused on application source code and not environment configuration (let alone Kubernetes manifests).&lt;/li&gt;
&lt;li&gt;Is best used when you need to support multiple versions of your application in production. This happens, but is not usually the case.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am not going to talk too much about Git-flow here and its disadvantages because the present article is about GitOps environments and not application source code, but in summary, you should follow &lt;a href="https://trunkbaseddevelopment.com/" rel="noopener noreferrer"&gt;trunk-based development&lt;/a&gt; and use &lt;a href="https://trunkbaseddevelopment.com/feature-flags/" rel="noopener noreferrer"&gt;feature-flags&lt;/a&gt; if you need to support different features for different environments.&lt;/p&gt;

&lt;p&gt;In the context of GitOps, the application source code and your configuration should also be in different Git repositories (one repository with just application code and one repository with Kubernetes manifests/templates). This means that your choice of branching for the application source code should not affect how branches are used in the environment repository that defines your environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76yb7to3r790jvn7nl52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76yb7to3r790jvn7nl52.png" alt="Different Git repos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you adopt GitOps for your next project, you should start with a clean slate.  Application developers can choose whatever branching strategy they want for the application source code (and even use Git-flow), but the configuration Git repository (that has all the Kubernetes manifests/templates) should NOT follow the branch-per-environment model. &lt;/p&gt;

&lt;h2&gt;
  
  
  Promotion is never a simple Git merge
&lt;/h2&gt;

&lt;p&gt;Now that we know the history of using a branch-per-environment approach for deployments, we can talk about the actual disadvantages.&lt;/p&gt;

&lt;p&gt;The main advantage of this approach is the argument that “Promotion is a simple git merge.” In theory, if you want to promote a release from QA to staging, you simply merge your QA branch into the staging branch. And when you are ready for production, you again merge the staging branch into the production branch, and you can be certain that all changes from staging have reached production. &lt;/p&gt;

&lt;p&gt;Do you want to see what is different between production and staging? Just do a standard &lt;a href="https://git-scm.com/docs/git-diff" rel="noopener noreferrer"&gt;git diff&lt;/a&gt; between the two branches. Do you want to backport a configuration change from staging to QA? Again, a simple Git merge from the staging branch to qa will do the trick.&lt;/p&gt;

&lt;p&gt;And if you want to place extra restrictions on promotions, you can use Pull Requests. So even though anybody could merge from qa to staging, if you want to merge something in the production branch, you can use a Pull Request and demand manual approval from all critical stakeholders.&lt;/p&gt;

&lt;p&gt;This all sounds great in theory, and some trivial scenarios can actually work like this. But in practice, this is never the case. Promoting a release via a Git merge can suffer from merge conflicts, unwanted changes, and even the wrong order of changes.&lt;/p&gt;

&lt;p&gt;As a simple example, let’s take this Kubernetes deployment that is currently sitting in the staging branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app:2.2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your QA team has informed you that version 2.3 (which is in the QA branch) looks good, and it is ready to be moved to staging. You merge the QA branch to the staging branch, promoting the application and think that everything is good.&lt;/p&gt;

&lt;p&gt;What you didn’t know is that somebody also changed the number of replicas in the QA branch to 2 because of some resource limitations. With your Git merge, you not only deployed 2.3 to staging, but you also scaled the replicas to 2 (instead of 15), and that is probably something that you don’t want.&lt;/p&gt;

&lt;p&gt;You might argue that it would be easy to look at the replica count before merging, but remember that in a real scenario you have a large number of applications with a big number of manifests that are almost always templated (via Helm or Kustomize). So understanding what changes you want to bring and what to leave behind is not a trivial task.&lt;/p&gt;

&lt;p&gt;And even if you do find changes that should not be promoted, you need to manually choose the “good” parts using &lt;a href="https://git-scm.com/docs/git-cherry-pick" rel="noopener noreferrer"&gt;git cherry-pick&lt;/a&gt; or other non-standard methods which are a far cry from the original “simple” Git merge.&lt;/p&gt;

&lt;p&gt;But even if you are aware of all the changes that can be promoted, there are several cases where the order of promotion is not the same as the order of committing. As an example, the following 4 changes happen to the QA environment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/" rel="noopener noreferrer"&gt;ingress of the application&lt;/a&gt; is updated with an extra hostname.&lt;/li&gt;
&lt;li&gt;Release 2.5 is promoted to the QA branch and all QA people start testing.&lt;/li&gt;
&lt;li&gt;A problem is found with 2.5 and a Kubernetes configmap is fixed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" rel="noopener noreferrer"&gt;Resource limits&lt;/a&gt; are fine-tuned and committed to QA.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is then decided that the ingress setting and the resource limits should move to the next environment (staging). But the QA team has not finished testing with the 2.5 release. &lt;/p&gt;

&lt;p&gt;If you blindly merge the QA branch to the staging branch, you will get all 4 changes at once, including the promotion of 2.5.&lt;/p&gt;

&lt;p&gt;To resolve this, again you need to use git cherry-pick or other manual methods.&lt;/p&gt;

&lt;p&gt;There are even more complicated cases where the commits have dependencies between them, so even cherry-pick will not work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmixt5bdlgy02wrrux4pk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmixt5bdlgy02wrrux4pk.png" alt="Git dependencies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example above, release 1.24 must be promoted to production. The problem is that one of the commits (the hotfix) contains a multitude of changes where some of them depend on another commit (the ingress config change) which itself cannot be moved to production (as it only applies only to staging). So even with cherry-picks, it is impossible to bring only the required changes from staging to production.&lt;/p&gt;

&lt;p&gt;The end result is that promotion is never a simple Git merge. Most organizations will also have a large number of applications that go on a large number of clusters, composed by a large number of manifests. Manually choosing commits is a losing battle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration drift can be easily created by environment-specific changes
&lt;/h2&gt;

&lt;p&gt;In theory, configuration drift should not be an issue with Git merges. If you make a change in staging and then merge that branch to production, then all your changes should transfer to the new environment.&lt;/p&gt;

&lt;p&gt;In practice, however, things are different because most organizations only merge to one direction, and team members are easily tempted to change upstream environments and never back-port the changes to downstream environments.&lt;/p&gt;

&lt;p&gt;In the classic example with 3 environments for QA, Staging, and Production, the direction of Git merges only goes to one direction. People merge the qa branch to staging and the staging branch to production. This means that changes only flow upwards.&lt;/p&gt;

&lt;p&gt;QA -&amp;gt; Staging -&amp;gt; Production.&lt;/p&gt;

&lt;p&gt;The classic scenario is that a quick configuration change is needed in production (a hotfix), and somebody applies the fix there. In the case of Kubernetes, this hotfix can be anything such as a change in an existing manifest or even a brand new manifest.&lt;/p&gt;

&lt;p&gt;Now Production has a completely different configuration than staging. Next time a release is promoted from Staging to Production, Git will only notify you on what you will bring from Staging. The ad hoc change on production will never appear anywhere in the Pull Request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnnywcgta49ahrbcwox8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnnywcgta49ahrbcwox8.png" alt="One direction only"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means that all subsequent deployments can fail, as production now has an undocumented change that will never be detected by any subsequent promotions.&lt;/p&gt;

&lt;p&gt;In theory, you could backport such changes and merge periodically all commits from production to staging (and staging to QA). In practice, this never happens due to the reasons outlined in the previous point.&lt;/p&gt;

&lt;p&gt;You can imagine that a large number of environments (and not just 3) further increases the problem. &lt;/p&gt;

&lt;p&gt;In summary, promoting releases by Git merges does not solve configuration drift and in fact makes it even more problematic as teams are tempted to make ad hoc changes that are never promoted in sequence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing different Git branches for a large number of environments is a losing battle
&lt;/h2&gt;

&lt;p&gt;In all the previous examples, I only used 3 environments (qa-&amp;gt; staging-&amp;gt; production) to illustrate the disadvantages of branch-based environment promotion.&lt;/p&gt;

&lt;p&gt;Depending on the size of your organization, you will have many more environments. If you factor in other dimensions such as geographical location, the number of environments can quickly skyrocket.&lt;/p&gt;

&lt;p&gt;For example, let’s take a company that has 5 environments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load Testing &lt;/li&gt;
&lt;li&gt;Integration testing &lt;/li&gt;
&lt;li&gt;QA&lt;/li&gt;
&lt;li&gt;Staging&lt;/li&gt;
&lt;li&gt;Production&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then let’s assume that the last 3 environments are also deployed to EU, US, and Asia while the first 2 also have GPU and Non-GPU variations. This means that the company has a total of 13 environments. And this is for a single application.&lt;/p&gt;

&lt;p&gt;If you follow a branch-based approach for your environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to have 13 long living Git branches at all times.&lt;/li&gt;
&lt;li&gt;You need 19 pull requests for promoting a single change across all environments.&lt;/li&gt;
&lt;li&gt;You have a two dimensional promotion matrix with 5 steps upwards and 2-3 steps outwards.&lt;/li&gt;
&lt;li&gt;The possibilities for wrong merges, configuration drift and ad-hoc changes is now non-trivial across all environment combinations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the context of this example organization, all previous issues are now more prevalent. &lt;/p&gt;

&lt;h2&gt;
  
  
  The branch-per-environment model goes against Helm/Kustomize
&lt;/h2&gt;

&lt;p&gt;Two of the most popular Kubernetes tools for describing applications are Helm and Kustomize. Let’s see how these two tools recommend modeling different environments.&lt;/p&gt;

&lt;p&gt;For Helm, you need to create a generic chart that itself accepts parameters in the form of a values.yaml file. If you want to have different environments, &lt;a href="https://codefresh.io/helm-tutorial/helm-deployment-environments/" rel="noopener noreferrer"&gt;you need multiple values files&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3z0yl4gtd03ukjrghdxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3z0yl4gtd03ukjrghdxt.png" alt="Helm environments"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Kustomize, you need to create a “base” configuration, and then each environment is modeled as &lt;a href="https://codefresh.io/about-gitops/applied-gitops-with-kustomize/" rel="noopener noreferrer"&gt;an overlay that has its own folder&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xtgokjcisalztqsy7t3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xtgokjcisalztqsy7t3.png" alt="Kustomize Overlays"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In both cases, different environments are modeled with different folders/files. Helm and Kustomize know nothing about Git branches or Git merges or Pull Requests. They use just plain files.&lt;/p&gt;

&lt;p&gt;Let me repeat that again: Both Helm and Kustomize use plain files for different environments and not Git branches. This should be a good hint on how to model different Kubernetes configurations using either of these tools.&lt;/p&gt;

&lt;p&gt;If you introduce Git branches in the mix, you not only introduce extra complexity, but you also go against your own tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The recommended way to promote releases in GitOps environments
&lt;/h2&gt;

&lt;p&gt;Modeling different Kubernetes environments and promoting a release between them is a very common issue for all teams that adopt GitOps. Even though a very popular method is to use Git branches for each environment and assume that a promotion is a “simple” Git merge, we have seen in this article that this is an anti-pattern.&lt;/p&gt;

&lt;p&gt;In the next article, we will see a better approach to model your different environments and promote releases between your Kubernetes cluster. The last point of the article (regarding Helm/Kustomize) should already give you a hint on how this approach works.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>gitops</category>
      <category>kubernetes</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Using GitOps for Infrastructure and Applications With Crossplane and Argo CD</title>
      <dc:creator>Kostis Kapelonis</dc:creator>
      <pubDate>Mon, 13 Dec 2021 13:43:05 +0000</pubDate>
      <link>https://forem.com/codefreshio/using-gitops-for-infrastructure-and-applications-with-crossplane-and-argo-cd-1mgd</link>
      <guid>https://forem.com/codefreshio/using-gitops-for-infrastructure-and-applications-with-crossplane-and-argo-cd-1mgd</guid>
      <description>&lt;p&gt;If you have been following the Codefresh blog for a while, you might have noticed a common pattern in all the articles that talk about Kubernetes deployments. Almost all of them start with a Kubernetes cluster that is already there, and then the article explains how to deploy an application on top.&lt;/p&gt;

&lt;p&gt;The reason for this simplification comes mainly from brevity and simplicity. We want to focus on the deployment part of the application and not its infrastructure just to make the article easier to follow. This is the obvious reason.&lt;/p&gt;

&lt;p&gt;The hidden reason is that until recently infrastructure deployments were handled in a different manner than applications deployments. Especially in large enterprise companies, the skillset of people that deal with infrastructure and application can vary a lot as the tools of the trade are completely different. &lt;/p&gt;

&lt;p&gt;For example, a lot of people that deal with infrastructure &lt;a href="https://codefresh.io/docs/docs/yaml-examples/examples/terraform/"&gt;prefer to use Terraform templates&lt;/a&gt;, but employ Kustomize/Helm or other similar tools for application development. While this is a very valid solution, it doesn’t have to be this way. &lt;/p&gt;

&lt;p&gt;Now with GitOps you can have a uniform way of dealing with infrastructure and applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitOps and Terraform
&lt;/h2&gt;

&lt;p&gt;If you are not familiar with GitOps, head over to &lt;a href="https://opengitops.dev/"&gt;https://opengitops.dev/&lt;/a&gt; which is the official page of the GitOps working group. The principles of GitOps are the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The system is described in a declarative manner. (In practice, this means Kubernetes manifests.)&lt;/li&gt;
&lt;li&gt;The definition of the system is versioned and audited. (In practice, it is stored in Git.)&lt;/li&gt;
&lt;li&gt;A software agent automatically pulls the Git state and matches the platform state. (In practice, this means &lt;a href="https://fluxcd.io/"&gt;Flux&lt;/a&gt;/&lt;a href="https://argo-cd.readthedocs.io/en/stable/"&gt;ArgoCD&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;The state is continuously reconciled. This means that any changes happening in Git should also be reflected in the system, as well as the opposite scenario.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you have already worked with Terraform, you should already understand why it is difficult to apply GitOps to the Terraform CLI. While Terraform only has the first requirement (declarative format), it doesn’t satisfy the other three requirements around Git storage, automatic reconciliation, and two-way sync. As soon as Terraform finishes its job, it doesn’t interface with the system in any way. If you manually delete a Virtual Machine that was created by Terraform, vanilla Terraform doesn’t know about it. And regarding state, Terraform stores its own state which is completely different from the definition files in Git.&lt;/p&gt;

&lt;p&gt;So at first glance, getting GitOps to work with infrastructure is a complicated task. You realize that you need to add something on top of vanilla Terraform in order to satisfy the GitOps requirements.&lt;/p&gt;

&lt;p&gt;But there is a new kid on the block, and that is &lt;a href="https://crossplane.io/"&gt;Crossplane&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  GitOps and Crossplane
&lt;/h2&gt;

&lt;p&gt;Crossplane has similar capabilities to Terraform (creating infrastructure) but with the following major differences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crossplane itself is a Kubernetes application. (The infrastructure it creates can be anything.)&lt;/li&gt;
&lt;li&gt;Crossplane definitions are Kubernetes manifests.&lt;/li&gt;
&lt;li&gt;You can either use manifests that describe resources in the common cloud providers or create your own resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As a simple example here is an EC2 instance describe in Crossplane:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ec2.aws.crossplane.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Instance&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample-instance&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;forProvider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
    &lt;span class="na"&gt;imageId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ami-0dc2d3e4c0f9ebd18&lt;/span&gt;
    &lt;span class="na"&gt;securityGroupRefs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample-cluster-sg&lt;/span&gt;
    &lt;span class="na"&gt;subnetIdRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample-subnet1&lt;/span&gt;  
  &lt;span class="na"&gt;providerConfigRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find more examples for &lt;a href="https://github.com/crossplane/provider-aws/tree/master/examples"&gt;Amazon&lt;/a&gt;, &lt;a href="https://github.com/crossplane/provider-gcp/tree/master/examples"&gt;Google&lt;/a&gt;, and &lt;a href="https://github.com/crossplane/provider-azure/tree/master/examples"&gt;Azure&lt;/a&gt;. Crossplane supports several other providers, and of course you can &lt;a href="https://github.com/crossplane/provider-template"&gt;add your own&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The important point here is that the file above is a standard Kubernetes manifest. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apply it with kubectl.&lt;/li&gt;
&lt;li&gt;Verify it with manifest verification tools (&lt;a href="https://www.kubeval.com/"&gt;kubeval&lt;/a&gt; or &lt;a href="https://github.com/stackrox/kube-linter"&gt;kube-linter&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Template it with Helm/Kustomize.&lt;/li&gt;
&lt;li&gt;Use any of the tools in the Kubernetes ecosystem to read/manage/store it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And since it is a standard manifest, you can of course store it in Git and manage it with ArgoCD for a Full GitOps workflow. The importance of this capability cannot be overstated.&lt;/p&gt;

&lt;p&gt;If you combine ArgoCD and Crossplane, you have a full solution for following the GitOps principles with infrastructure and not just applications. Imagine if your ArgoCD dashboard contained this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cU97kSbR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4xtnny6c5lw4cdyrfur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cU97kSbR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4xtnny6c5lw4cdyrfur.png" alt="ArgoCD and Crossplane" width="880" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isn’t that cool?&lt;/p&gt;

&lt;h2&gt;
  
  
  How ArgoCD and Crossplane work together
&lt;/h2&gt;

&lt;p&gt;Crossplane offers an easy way to model your infrastructure as Kubernetes manifests. This is great on its own, but if you &lt;a href="https://argo-cd.readthedocs.io/en/stable/getting_started/"&gt;put ArgoCD in the mix&lt;/a&gt;, you essentially gain all the advantages of GitOps for your infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You know exactly what infrastructure you have simply by looking at the Git repository.&lt;/li&gt;
&lt;li&gt;You know exactly what was changed and when by looking at Git history.&lt;/li&gt;
&lt;li&gt;The infrastructure state IS the same as the Git state. Terraform has its own state that is used a the single source of truth&lt;/li&gt;
&lt;li&gt;You don’t need any external credentials any more.&lt;/li&gt;
&lt;li&gt;You can easily rollback to a previous version of your infra with a git reset/git-revert.
You completely avoid the dreaded configuration drift.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point is very critical. Terraform only knows what is in your infrastructure during deployment. If you make any manual changes afterwards (e.g. delete some infra), terraform knows absolutely nothing. You need to rerun terraform and pray that the correct action is taken. There are many terraform horror stories about incomplete/invalid states. Here is one of my &lt;a href="https://www.youtube.com/watch?v=ix0Tw8uinWs"&gt;favorite tfstate stories from Spotify&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ArgoCD will instantly detect any manual changes in your infrastructure, present you a diff, and even allow you to completely discard them if you want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Js7o0JZT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qs4m8i78akely3vy2j5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Js7o0JZT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qs4m8i78akely3vy2j5z.png" alt="Argo Everywhere" width="880" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essentially ArgoCD is agnostic as to what exactly is described by the Kubernetes manifests it manages. They can be plain Kubernetes applications, Virtual machines, Container registries, Load balancers, object storage, firewall rules, etc. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create infrastructure and deploy to it using GitOps
&lt;/h2&gt;

&lt;p&gt;Now that we saw that you can use ArgoCD and Crossplane together for managing infrastructure, we are now ready to treat applications and the platform they need in the same way.&lt;/p&gt;

&lt;p&gt;This means that we can do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start from nothing.&lt;/li&gt;
&lt;li&gt;Use Crossplane to create a Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;Commit the crossplane manifest and manage it with ArgoCD.&lt;/li&gt;
&lt;li&gt;Use a standard manifest (e.g. deployment) to deploy an application to the cluster that was just created.&lt;/li&gt;
&lt;li&gt;Commit that manifest in Git too. Like the application one, ArgoCD will manage it like any other Kubernetes manifest (even though it represents infrastructure).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the whole workflow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y9CxfvWf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7nnuu0othvd5oh46et9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y9CxfvWf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7nnuu0othvd5oh46et9.png" alt="GitOps Everywhere" width="880" height="668"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Kubernetes cluster that Crossplane is running on is only used to bootstrap crossplane. It doesn’t get any production workloads on its own. For simple demos, this can be any cluster (even a local one running on your workstation).&lt;/p&gt;

&lt;p&gt;The end result is that now you have a unified way to handle both infrastructure and applications right from Argo CD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VoH35Eh---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tzc4rxnuf7ypp8pjx2we.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VoH35Eh---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tzc4rxnuf7ypp8pjx2we.png" alt="Application and Infrastructure management" width="880" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process of changing either of them is exactly the same. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to change infrastructure, you commit a change and ArgoCD takes care of it (with the help of Crossplane).&lt;/li&gt;
&lt;li&gt;If you want to change your application, you commit a change and ArgoCD takes care of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They also both gain all the benefits of GitOps. If for example somebody changes the number of replicas in the deployment or tampers with the cluster nodes, ArgoCD will detect the manual changes automatically and give you the ability to discard them completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why GitOps is the way forward
&lt;/h2&gt;

&lt;p&gt;The whole point of DevOps is to make everything self-service and promote collaboration between developers and operators. Adopting Crossplane in a GitOps setting means that now both parties have a common language that they can communicate with. &lt;/p&gt;

&lt;p&gt;There is no need anymore for separate workflows that are confusing to either of them. Adopting a common workflow for both infrastructure and applications is the embodiment of the DevOps spirit.&lt;/p&gt;

&lt;p&gt;If you want to learn more about &lt;a href="https://codefresh.io/gitops/"&gt;GitOps&lt;/a&gt; and how Codefresh has embraced it, check out the &lt;a href="https://codefresh.io/codefresh-argo-platform/"&gt;Codefresh DevOps platform for Argo&lt;/a&gt;. For more information about Crossplane, see &lt;a href="https://crossplane.io/"&gt;the official site&lt;/a&gt; and the hosted solution by &lt;a href="https://www.upbound.io/"&gt;Upbound&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Using Codefresh with GKE Autopilot for native Kubernetes pipelines and GitOps deployment</title>
      <dc:creator>Hannah</dc:creator>
      <pubDate>Mon, 06 Dec 2021 18:16:39 +0000</pubDate>
      <link>https://forem.com/codefreshio/using-codefresh-with-gke-autopilot-for-native-kubernetes-pipelines-and-gitops-deployment-4ned</link>
      <guid>https://forem.com/codefreshio/using-codefresh-with-gke-autopilot-for-native-kubernetes-pipelines-and-gitops-deployment-4ned</guid>
      <description>&lt;p&gt;Several companies nowadays offer a cloud-native solution that manages Kubernetes applications and services. While these solutions seem easy at first glance, in reality, they still require manual maintenance.&lt;/p&gt;

&lt;p&gt;As an example, an important decision for any Kubernetes cluster is the number of nodes and the autoscaling rules you define. You want to ensure that the size is just right and matches your workload, otherwise, this could become costly, unstable, and decrease the availability of your workload when you need it most!&lt;/p&gt;

&lt;h4&gt;GKE Autopilot Cluster&lt;/h4&gt;

&lt;p&gt;A solution to these problems is &lt;a href="https://cloud.google.com/blog/products/containers-kubernetes/introducing-gke-autopilot"&gt;Google Kubernetes Engine (GKE) Autopilot&lt;/a&gt; from Google Cloud. GKE's cluster autoscaler adjusts the node pools based on whatever the demand is for your workload. For example, if the workload is high or low GKE Autopilot will scale depending on which and provide control on costs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-11-16-at-3.30.21-PM.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cppYg4uD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-11-16-at-3.30.21-PM.png" alt="" width="728" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows you and your teams to no longer worry about maintaining your node pools or provisioning them - with Autopilot clusters these jobs are automatically done. This streamlined approach follows best practices for a cluster and workload setup, in addition to other best practices about security and observability. Allowing you to specify configurations needed for deployment to production and simplifying operations needed to manage an application’s infrastructure, nodes, and the control plane. &lt;/p&gt;

&lt;p&gt;The Codefresh platform fully supports GKE Autopilot. By combining the two platforms you can easily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run CI/CD pipelines on your cluster to compile source code, run unit tests, perform security checks, etc.&lt;/li&gt;
&lt;li&gt;Deploy your containers to your cluster by following the &lt;a href="https://codefresh.io/gitops/"&gt;GitOps principles&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Deploying applications to your GKE Autopilot cluster following the GitOps principles&lt;/h2&gt;

&lt;h4&gt;Codefresh GitOps Controller&lt;/h4&gt;

&lt;p&gt;Like any Kubernetes cluster integrations or the GKE Standard cluster, the GKE Autopilot Cluster integrates the same way with the Codefresh GitOps dashboard. The GitOps dashboard allows you to look at all your deployments in greater detail and instantly know the critical information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Git commit was deployed&lt;/li&gt;
&lt;li&gt;Which cluster was affected&lt;/li&gt;
&lt;li&gt;Who initiated the change&lt;/li&gt;
&lt;li&gt;What features were shipped&lt;/li&gt;
&lt;li&gt;Which pipelines took part in the deployment&lt;/li&gt;
&lt;li&gt;What Kubernetes services were affected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;To achieve this level of GitOps visibility, a GKE autopilot cluster can be the target of the &lt;a href="https://codefresh.io/docs/docs/integrations/argo-cd/"&gt;Codefresh GitOps Controller&lt;/a&gt;, which is an agent installed in the cluster that monitors both the cluster and any defined Git repositories for changes. It installs an ArgoCD instance within the cluster and the associated GitOps Controller. This is done through the Codefresh CLI and can be authenticated with a Codefresh account, simply by creating an API token. This agent can also manage the runtime environment for a pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-11-17-at-7.01.44-PM.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qvnVHfEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-11-17-at-7.01.44-PM.png" alt="" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the GitOps controllers are installed, you can easily deploy any kind of application to your GKE Autopilot cluster using GitOps. This means that you can combine all the benefits of GitOps such as audibility, visibility, reduced downtime with the easy management of the GKE Autopilot capabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/GitOpsDashboard.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rw8BGfMC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/GitOpsDashboard.png" alt="" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;GKE Autopilot cluster allows you to pursue a production-ready and scalable workflow for both your application and infrastructure systems. Its ability to configure cluster autoscaling and node auto-provisioning can improve resource utilization and reduce day-to-day challenges for organizations. These features reduce the operational cost of managing clusters and optimize them for production.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;Google Cloud also provides a user-friendly experience, creating, configuring, and operating a Kubernetes cluster that you can integrate with the &lt;a href="https://codefresh.io/codefresh-argo-platform/"&gt;Codefresh DevOps Platform&lt;/a&gt; with a GitOps Controller, powered by &lt;a href="https://codefresh.io/argo-codefresh/"&gt;ArgoCD&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>gke</category>
      <category>gitops</category>
      <category>argo</category>
    </item>
    <item>
      <title>Applied GitOps with Kustomize</title>
      <dc:creator>Hannah</dc:creator>
      <pubDate>Wed, 01 Dec 2021 18:07:50 +0000</pubDate>
      <link>https://forem.com/codefreshio/applied-gitops-with-kustomize-3d7</link>
      <guid>https://forem.com/codefreshio/applied-gitops-with-kustomize-3d7</guid>
      <description>&lt;h3&gt;
  
  
  What is Kustomize?
&lt;/h3&gt;

&lt;p&gt;Have you always wanted to have different settings between production and staging but never knew how? You can do this with Kustomize!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kustomize.io/"&gt;Kustomize&lt;/a&gt; is a CLI configuration manager for Kubernetes objects that leverage layering to preserve the base settings of the application. This is done by overlaying the declarative YAML artifacts to override default settings without actually making any changes to the original manifest.&lt;/p&gt;

&lt;p&gt;Kustomize settings are defined in a kustomization.yaml file. Kustomize is also integrated with kubectl. With Kustomize, you can configure raw, template-free YAML files, which allows you to modify settings between deployment and production easily. This enables troubleshooting misconfigurations and keeps use-case-specific customization overrides intact.&lt;/p&gt;

&lt;p&gt;Kustomize also allows you to scale easily by reusing a base file across all your environments (development, production, staging, etc.) and then overlay specifications for each.&lt;/p&gt;


&lt;li&gt;
&lt;strong&gt;Base Layer&lt;/strong&gt;: This layer specifies the most common resources and original configuration.&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;
&lt;strong&gt;Overlays Layer&lt;/strong&gt;: This layer specifies use-case-specific resources by utilizing patches to override other kustomization files and Kubernetes manifests.&lt;/li&gt;
&lt;br&gt;
Overlays are what help us accomplish our goal by producing variants without templating.
&lt;h3&gt;
  
  
  Benefits of Kustomize
&lt;/h3&gt;

&lt;p&gt;Kustomize offers some of the following benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reusability&lt;/strong&gt;&lt;br&gt;
With Kustomize you can reuse one of the base files across all environments (development, staging, production, etc.) and overlay specifications for each of those environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick Generation&lt;/strong&gt;&lt;br&gt;
Since Kustomize doesn't utilize templates, a standard YAML file can be used to declare configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debug Easily&lt;/strong&gt;&lt;br&gt;
Using a YAML file allows easy debugging, along with patches that isolate configurations, allowing you to pinpoint the root cause of performance issues quickly. You can also compare performance to the base configuration and other variations that are running.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kubernetes Native Configuration&lt;/strong&gt;&lt;br&gt;
Kustomize understands Kubernetes resources and their fields and is not just a simple text templating solution like other tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See below an example of a Kustomize file structure including the base and overlays within an application. You can also reference a code-based demo project on &lt;a href="https://github.com/hseligson1/kustomize-gitops-example"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-12-01-at-10.32.44-AM.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6kwgmVOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-12-01-at-10.32.44-AM-300x175.png" alt="" width="300" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tree structure above is a simple example of how you can deploy a single application to 2 different environments (staging and production). Let's dig deeper into each directory and create an overlay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;base folder&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#base"&gt;base&lt;/a&gt; folder holds common resources, such as the deployment.yaml, service.yaml, and configuration files. It contains the initial manifest and includes a namespace and label for the resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;overlays folder&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#overlay"&gt;overlays&lt;/a&gt; folder houses environment-specific overlays, which use patches to allow YAML files to be defined and overlaid on top of the base for any changes. Let's take a look at a couple of the environments within the overlays folder below that also includes the kustomization.yaml.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;kustomization.yaml&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each directory contains &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#kustomization-root"&gt;a kustomization file&lt;/a&gt;, which is essentially a list of resources or manifests that describes how to generate or transform Kubernetes objects. There are &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/"&gt;multiple fields&lt;/a&gt; that can be added, and when this list is injected, the kustomization action can be referenced as an overlay that refers to the base.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Overlays
&lt;/h3&gt;

&lt;p&gt;Let's explore a simple example of how overlays work.&lt;br&gt;
We'll make the following changes within our production and staging directories:&lt;br&gt;
&lt;/p&gt;
&lt;li&gt;Within the staging overlay, we will enable a risky feature that is NOT enabled in production.&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Within the production overlay, we'll assign a higher replica count.&lt;/li&gt;

&lt;p&gt;We'll also ensure the web server from the cluster variants is different from one another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;overlays/staging/kustomization.yaml&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the staging directory, let's make a kustomization defining a new name prefix and different labels.&lt;/p&gt;

&lt;pre&gt;namePrefix: staging-
commonLabels:
 variant: staging
commonAnnotations:
  note: “Welcome to staging!”
bases:
- ../../base
patchesStrategicMerge:
- config-map.yaml
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Staging patch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a configMap kustomization to change the server greeting from "Hello!" to "Kustomize rules!" We'll also enable the risky flag.&lt;/p&gt;

&lt;pre&gt;apiVersion: v1
kind: ConfigMap
metadata:
 name: the-map
data:
 altGreeting: “Kustomize rules!”
 enableRisky: “true”
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;overlays/production/kustomization.yaml&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Within the production directory, we will make a kustomization with a different name prefix and label.&lt;/p&gt;

&lt;pre&gt;namePrefix: production-
commonLabels:
 variant: production
commonAnnotations:
  note: “Welcome to production!”
bases:
- ../../base
patchesStrategicMerge:
- deployment.yaml
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Production patch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll make a production patch that will increase the replica count.&lt;/p&gt;

&lt;pre&gt;apiVersion: apps/v1
kind: Deployment
metadata:
 name: the-deployment
spec:
 replicas: 10
&lt;/pre&gt;

&lt;p&gt;Now, we can compare these overlays - the kustomizations and patches are required to create noticeable differences between staging and production variants within the Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;Based on the changes above, the output would look something like this:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;   altGreeting: Kustomize rules!
&amp;lt;   enableRisky: "true"
---
&amp;gt;   altGreeting: Hello!
&amp;gt;   enableRisky: "false"

&amp;lt;     note: Welcome, I am staging!
---
&amp;gt;     note: Welcome, I am production!

&amp;lt;     variant: staging
---
&amp;gt;     variant: production
&lt;/pre&gt;

&lt;p&gt;You can now see the difference between the staging and production overlays.&lt;br&gt;
Overlays contain a kustomization.yaml, and can also include manifests as new or additional resources, or to patch resources. The kustomization file is what defines how the overlays should be applied to the base and this is what we refer to as a &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#variant"&gt;variant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each time a change is made to an application, like the example above - it is the overlays that are doing the heavy lifting.&lt;/p&gt;

&lt;p&gt;So, now that you have learned a bit about Kustomize, you might be wondering how you can apply the GitOps workflow to it. Below we'll explain more about GitOps and how you can apply it to your Kustomize project and deploy it.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitOps works with all your existing tools
&lt;/h3&gt;

&lt;p&gt;Now, let's learn more about how to apply GitOps to your Kustomize application deployment!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/gitops/"&gt;GitOps&lt;/a&gt; is a paradigm that incorporates best practices applied to both an application development workflow and the infrastructure of a system. This is done to empower organizations and developers to operate their systems from a single source of truth enabled by Git.&lt;br&gt;
A couple of key aspects of GitOps that most aren't as familiar with and are crucial are the:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GitOps controller&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The controller reads the declarative configuration and uses the reconciliation loops to converge the desired end state. This controller detects the differences between states and makes the necessary changes to maintain the desired state.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Automation reconciliation loop&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The concept of the reconciliation loop is used to keep the state as defined within a manifest. This is such an important principle for the GitOps paradigm because these loops are what drive the entire cluster to the desired state in Git.&lt;/p&gt;

&lt;p&gt;Now that you have a basic understanding of what both Kustomize and &lt;a href="https://opengitops.dev/"&gt;GitOps&lt;/a&gt; are and what some of their capabilities are, perhaps you've considered applying GitOps to your existing or future application and infrastructure workflow.&lt;/p&gt;

&lt;p&gt;We'll explore 2 approaches on how to use Kustomize with or without GitOps:&lt;br&gt;
&lt;/p&gt;
&lt;li&gt;Using only Kustomize&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Using Kustomize with ArgoCD&lt;/li&gt;
&lt;h3&gt;
  
  
  What is ArgoCD?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/argoproj/argo-cd"&gt;ArgoCD&lt;/a&gt; is a GitOps controller specifically created for Kubernetes deployments. It supports a variety of configuration management tools like Helm (take a look at &lt;a href="https://codefresh.io/helm-tutorial/using-helm-with-gitops/"&gt;our documentation&lt;/a&gt; for more information), Ksonnet, Kustomize, &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/application_sources/"&gt;etc&lt;/a&gt;. The core component is the Application Controller, which continuously monitors any running applications and compares the live state against the desired state defined in a Git repository.&lt;/p&gt;

&lt;p&gt;If a deployed application whose live state drifts from the target state, ArgoCD is then considered OutOfSync. It then provides reports and visualizations to identify these changes and can provide automation when any modifications are made so that the target environments reflect the desired state of a system in Git.&lt;/p&gt;

&lt;p&gt;If you'd like to explore these different deployment approaches with Kustomize from a code-based perspective, here is an &lt;a href="https://github.com/hseligson1/kustomize-gitops-example"&gt;example project&lt;/a&gt; that you can follow along with on GitHub. However, we will explore both of these approaches below with some more details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach #1: Deploying only with Kustomize
&lt;/h2&gt;

&lt;p&gt;If you want to use Kustomize, but your organization isn't ready to implement GitOps with your workflow, you can still use Kustomize on its own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install Kustomize&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, install Kustomize and this can be done either by utilizing kubectl version 1.14 or later, otherwise you can install based on your operating system and reference the &lt;a href="https://kubectl.docs.kubernetes.io/installation/kustomize/"&gt;Kustomize documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a base directory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, in order to deploy an application with Kustomize, you need a kustomization.yaml file, and this is added to the base directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-12-01-at-11.17.06-AM.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3cOH-EyI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-12-01-at-11.17.06-AM-300x213.png" alt="" width="300" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The kustomization.yaml file specifies what resources to manage due to the complexity of multiple resource types and different environments when handling configuration files for Kubernetes.&lt;/p&gt;

&lt;p&gt;Within the base directory, there is also a service and deployment resource.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create an Overlays directory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll want to create an overlays directory, and this directory is what allows you to kustomize the base and apply any changes with a &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/"&gt;patch&lt;/a&gt; to modify a resource.&lt;/p&gt;

&lt;p&gt;The overlays still use the same resources as the base but may vary in the number of replicas in a deployment, the CPU for a specific pod, or the data source used in the ConfigMap, etc.&lt;/p&gt;

&lt;p&gt;Within our example, we have a staging and production overlay. These overlay directories contain the kustomizations and patches previously mentioned that are required to create distinct staging and production &lt;a href="https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#variant"&gt;variants&lt;/a&gt; in a cluster. However, with Kustomize you can use the overlays for anything needed to organize environments, whether it's based on location: USA, Asia, Europe or internal/external, team A/team B, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-12-01-at-11.18.43-AM.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AE79yh-P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-12-01-at-11.18.43-AM-293x300.png" alt="" width="293" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kustomize is essentially an overlay-based engine that functions by finding and replacing specific sections in the manifest and replacing it with required fields and values. These values are then merged and deployed!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a namespace for specific environments&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;kubectl create ns staging
&lt;/pre&gt; 

&lt;p&gt;or &lt;/p&gt;

&lt;pre&gt;kubectl create ns production
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Build and Deploy to environments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can then apply the overlays to your cluster and deploy with the command:&lt;/p&gt;

&lt;pre&gt;kubectl apply -k overlays/staging
&lt;/pre&gt; 

&lt;p&gt;or &lt;/p&gt;

&lt;pre&gt;kubectl apply -k overlays/production
&lt;/pre&gt;

&lt;p&gt;You are now successfully using Kustomize to manage your Kubernetes configurations and deploy your application to production and staging environments!&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach #2: Deploying using Kustomize with GitOps
&lt;/h2&gt;

&lt;p&gt;In the previous approach, you learned how to deploy an application using only Kustomize, so let's see how it fits into ArgoCD and how it can be used in a GitOps workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/kustomize/"&gt;ArgoCD supports Kustomize&lt;/a&gt; and has the ability to read a kustomization.yaml file to enable deployment with Kustomize and allow ArgoCD to manage the state of the YAML files.&lt;/p&gt;

&lt;p&gt;ArgoCD monitors the resources within the git repository for any changes, ensuring that the live state of your system matches the desired state. Each time customization is made, ArgoCD detects those modifications and updates the deployment.&lt;/p&gt;

&lt;p&gt;So, let's begin walking through the process to deploy a Kustomize project using ArgoCD!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install ArgoCD and access a Kubernetes Cluster&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we need to ensure the Kubernetes cluster is set up and you are logged into ArgoCD so that these resources are provided and can be deployed. You can use any Kubernetes cluster and &lt;a href="https://github.com/argoproj/argo-cd/blob/master/docs/cli_installation.md"&gt;install&lt;/a&gt; the argocd CLI.&lt;/p&gt;

&lt;p&gt;Once you've accessed the argocd CLI you can &lt;a href="https://argo-cd.readthedocs.io/en/stable/getting_started/#4-login-using-the-cli"&gt;access the ArgoCD server and log in&lt;/a&gt; to the ArgoCD UI. However, if you're more of a terminal fan, you can also deploy the application through the argocd CLI. Feel free to reference the &lt;a href="https://github.com/hseligson1/kustomize-gitops-example"&gt;demo application&lt;/a&gt; that will walk you through the deployment process through your terminal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create an ArgoCD application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, we can set up the Kustomize Project. Similar to &lt;a href="https://codefresh.io/helm-tutorial/using-helm-with-gitops/"&gt;using Helm with GitOps&lt;/a&gt;, we will approach this deployment the same way within the UI by creating an ArgoCD application.&lt;/p&gt;

&lt;p&gt;Let's begin! First, click on the +NEW APP and include the name of the ArgoCD application, select the default project, and enable the Automatic SYNC POLICY.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-11-22-at-11.55.41-AM.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YuJsPfsm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/Screen-Shot-2021-11-22-at-11.55.41-AM.png" alt="" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, when adding your Kustomize project it helps to include a specific Path to segregate the application manifests inside the Git repository. We can then ask ArgoCD to only read the specific directories in the repository and read manifests within that path. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/argocd-source-ui-staging.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NpI4zfzG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/argocd-source-ui-staging.png" alt="" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, within the Destination section, you need to provide the destination of the Kubernetes cluster details. Also, make sure to click on the checkbox for auto-create namespace when adding the input field value, or you can add a custom namespace you've created prior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/argocd-ns-ui.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lCGlih8i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/argocd-ns-ui.png" alt="" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ArgoCD will read the kustomization.yaml file in the path you provided and prompt you to allow override with different values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/12/argocd-kustomize-ui-staging.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--smT0_G9y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://codefresh.io/wp-content/uploads/2021/12/argocd-kustomize-ui-staging.png" alt="" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synchronize Application and Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assuming you enabled auto-synchronization when creating your ArgoCD application, it will read the parameters and the Kubernetes manifests. Then, once the manifests are applied, you can review the application health and resources you deployed.&lt;/p&gt;

&lt;p&gt;If your application has an error when trying to synchronize, you can execute the argocd history command, allowing you to view the application deployment history to identify a possible error:&lt;/p&gt;

&lt;pre&gt;
argocd app history argocd_app_name
&lt;/pre&gt;

&lt;p&gt;If you need to rollback you can do so by executing this command:&lt;/p&gt;

&lt;pre&gt;
argocd app rollback argocd_app_name history_id
&lt;/pre&gt;

&lt;p&gt;These commands leverage a faster and more secure deployment by enabling the tracking from the Git repository. This allows you to track the active Kubernetes resources and events. These actions can also be done within the UI.&lt;/p&gt;

&lt;p&gt;Once the application is healthy and synchronized, each time you create a new kustomization.yaml file and the file changes, ArgoCD will be able to detect those changes and make updates to your deployment. You can even mention specific &lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/kustomize/"&gt;Kustomize tags&lt;/a&gt; and set up custom build options for your Kustomize build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Kustomize allows you to use different configurations of a base Kubernetes manifest. Within this post, we've covered the Kustomize basics and how to deploy using just Kustomize and deploying with GitOps. This allows you to leverage the power of Kustomize to define the Kubernetes files without using a templating system.&lt;/p&gt;

&lt;p&gt;To start deploying your Kustomize application, sign up for a &lt;a href="https://codefresh.io/codefresh-signup/"&gt;Codefresh&lt;/a&gt; account today to apply &lt;a href="https://codefresh.io/gitops/"&gt;GitOps&lt;/a&gt; to your deployment process!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>kustomize</category>
      <category>gitops</category>
      <category>continuousdeployment</category>
    </item>
    <item>
      <title>Using Helm with GitOps</title>
      <dc:creator>Hannah</dc:creator>
      <pubDate>Thu, 30 Sep 2021 15:15:45 +0000</pubDate>
      <link>https://forem.com/codefreshio/using-helm-with-gitops-2had</link>
      <guid>https://forem.com/codefreshio/using-helm-with-gitops-2had</guid>
      <description>&lt;p&gt;&lt;span&gt;This is the first of many posts highlighting GitOps topics that we’ll be exploring. Within this post, we will explore Helm, a tool used for Kubernetes package management, that also provides templating. Helm provides utilities that assist Kubernetes application deployment.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;In order to better understand how Helm charts are mapped to Kubernetes manifests, we’ll explain more details below and how to use Helm with and without GitOps.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;What is Kubernetes?&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;&lt;span&gt;Kubernetes&lt;/span&gt;&lt;/a&gt;&lt;span&gt; is an orchestrator for containers that allows you to automate scheduling, deployments, networking, scaling, and health monitoring for the containers.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Kubernetes was needed because we increased the usage of the following:&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;span&gt;Microservices&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Containers&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;span&gt;This was difficult to manage with scripts and self-made tools and caused the need for orchestration technology like Kubernetes. It provides features like scalability, disaster recovery, and less downtime.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;What is Helm?&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;&lt;span&gt;Helm&lt;/span&gt;&lt;/a&gt;&lt;span&gt; is a package manager for Kubernetes. It’s a convenient way for packaging collections of YAML files with a Helm chart for the Kubernetes application and allowing distribution with a Helm repository. &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Maintaining Kubernetes manifests is time-consuming and tedious and this is why Helm is helpful!&lt;/span&gt;&lt;/p&gt;

&lt;h4&gt;Helm Charts&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;Helm Charts are deployable units for Kubernetes applications. These charts are a collection of files inside a directory. This directory is the name of the Helm chart and consists of a self-descriptor file, YAML file, and one or more Kubernetes manifests. Helm charts are typically written in the &lt;/span&gt;&lt;a href="https://pkg.go.dev/text/template" rel="noopener noreferrer"&gt;&lt;span&gt;Go template language&lt;/span&gt;&lt;/a&gt;&lt;span&gt;. Charts are created as such files, describing a related set of Kubernetes resources. Here’s an example of a Helm chart directory and it’s layout:&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/09/helm-chart-example.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2021%2F09%2Fhelm-chart-example.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;This particular directory contains a &lt;/span&gt;&lt;span&gt;Chart.yaml&lt;/span&gt;&lt;span&gt; file and this is where the global variables, versions, and descriptions are stored. Then, the templates directory is what contains the YAML files for Kubernetes, otherwise known as the Kubernetes manifests.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Files such as the &lt;/span&gt;&lt;span&gt;deployment&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;service&lt;/span&gt;&lt;span&gt;, and &lt;/span&gt;&lt;span&gt;ingress&lt;/span&gt;&lt;span&gt; files contain variables from the &lt;/span&gt;&lt;span&gt;values.yaml&lt;/span&gt;&lt;span&gt; file when the chart is deployed. The &lt;/span&gt;&lt;span&gt;_helpers.tpl&lt;/span&gt;&lt;span&gt; incorporates helpful functions for variable calculations.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;You can then share the Helm chart to increase easy reusability for others to use. Sharing is done by storing the chart to a Helm repository. This repository can then be shared with others to deploy the application with the chart.&lt;/span&gt;&lt;/p&gt;

&lt;h4&gt;Helm Repositories&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;Helm supports a chart repository service that can be used to store the Helm charts. You can use any web server host or source code host for the Helm repository.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;The repository has an &lt;/span&gt;&lt;span&gt;index.yaml&lt;/span&gt;&lt;span&gt; file that contains metadata about the package, including the &lt;/span&gt;&lt;span&gt;Chart.yaml&lt;/span&gt;&lt;span&gt; file. The index will contain information about each Helm chart in the chart repository. Then the server can serve your index and charts or the packages can be stored in the repository for shareable access.&lt;/span&gt;&lt;/p&gt;

&lt;h4&gt;Helm Release&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;Each install or upgrade will create a Helm release. A Helm release is a running instance of your Helm chart running within a Kubernetes cluster or a namespace. It’s essentially an instance of a versioned, templated chart. &lt;/span&gt;&lt;span&gt;It’s also possible to have multiple releases of the same chart in a single cluster or namespace since the chart is self-contained. You can also roll back a Helm release to a previous version in case there are any failures.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/09/Helm-WF.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2021%2F09%2FHelm-WF-1024x632.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Assuming you’re a developer with an existing cluster, perhaps you’d like to share your Helm application with an external vendor. Let's recap the Helm workflow and release process:&lt;/span&gt;&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;
&lt;span&gt;To share an application with others, you need to create a Helm chart. The chart is a package that contains templates for a set of resources necessary for the application. The template uses variables applied to the &lt;/span&gt;&lt;span&gt;Values.yaml&lt;/span&gt;&lt;span&gt; file when the manifest is created and describes how to configure the resources.&lt;/span&gt;
&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;The Helm charts are then hosted within a repository that can then be downloaded or accessed from a server. This chart will contain all the necessary resource definitions needed for the developer to run an application.&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Now that you have access to the cluster, you can add new features or bug fixes to the application and update the Helm chart. Helm offers useful tools to manage your releases. You can upgrade the chart and create a new deployment. In Helm a deployed instance of your application is referred to as the release. &lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;You can now deploy your packaged application to the cluster.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;span&gt;Within this workflow we identified how Helm packages files and deploys them to a cluster. So, how do you apply GitOps to the workflow above? Let’s explore this below...&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;What is GitOps?&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/gitops/" rel="noopener noreferrer"&gt;&lt;span&gt;GitOps&lt;/span&gt;&lt;/a&gt;&lt;span&gt; is a paradigm that incorporates best practices applied to the application development workflow all the way to the operating infrastructure of a system.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Some benefits of GitOps are:&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;span&gt;Deploying faster and more often&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Easier and quicker error handling and recovery&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Self documenting deployments&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Increased developer productivity and an enhanced experience for teams&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Greater visibility on the lifecycle of developed features&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;span&gt;These benefits make it easier to handle the applications and allow teams to deliver quality software faster.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;GitOps relies on Git as the single source of truth for declarative configuration and active reconciliation. By adopting the GitOps methodology it provides transparency between the application configuration deployed in a cluster and the one residing in Git. &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;A GitOps tool that follows this approach of a Git-based workflow is Argo CD. It’s a continuous delivery tool for Kubernetes that is essentially a GitOps controller that does two-way synchronization. Argo continuously monitors running applications and compares the live state against the desired state in Git and applies it to the cluster. In addition, it also monitors the container registry for new images and updates the workload definitions based on the deployment policies.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;We will mention Argo CD again in this post and can assume that it’s already been installed and implemented within our workflow!&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;GitOps works with all of your existing tools&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Now that you have a good understanding of what Helm is and it’s capabilities, perhaps you’ve considered applying GitOps to your existing or future applications.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Let’s explore the various approaches of how to use GitOps with or without Helm:&lt;/span&gt;&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;span&gt;Using only Helm (without GitOps)&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Using GitOps (without Helm)&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Using Helm with GitOps&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;span&gt;If you’d like to explore these different approaches from a code-base perspective, here is an &lt;/span&gt;&lt;a href="https://github.com/codefresh-contrib/helm-gitops-example/blob/main/README.md" rel="noopener noreferrer"&gt;&lt;span&gt;example project&lt;/span&gt;&lt;/a&gt;&lt;span&gt; that you should check out on GitHub that digs deeper into how you can:&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;span&gt;Install an application with Helm and deploy locally&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;Install an application with Argo CD and deploy locally both within the UI and command line&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;span&gt;If not, then we’ll be sure to highlight these approaches below!&lt;/span&gt;&lt;/p&gt;

&lt;h4&gt;Approach #1: Using only Helm without GitOps&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;If you want to use Helm but your organization isn’t quite ready to implement the GitOps workflow, that’s perfectly fine. Helm was created before the GitOps methodology came to fruition, but can still work with GitOps (as we will see in the latter point).&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;The workflow allows you to search through Helm repositories for charts and install them to clusters, creating releases. This process enables execution of application deployments on a cluster. The maintenance of YAML manifests for Kubernetes objects is still the same as before. Helm releases are what keeps track of the version history of each chart installation and change and still allows rolling back to the previous cluster version. When installing a chart it creates a release of the new package and it’s the Helm release that deploys the Helm application.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;When using Helm there are some powerful commands you will find useful, please see below.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To install a new package:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm install &amp;lt;release_name&amp;gt; &amp;lt;name_of_chart_you_want_to_install&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;To view currently deployed releases:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm list&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm ls&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;To view revision numbers for a particular release:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm history &amp;lt;release_name&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;span&gt;To learn more details about these commands and how to use them, reference the &lt;/span&gt;&lt;a href="https://github.com/codefresh-contrib/helm-gitops-example/blob/main/README.md" rel="noopener noreferrer"&gt;&lt;span&gt;example project&lt;/span&gt;&lt;/a&gt;&lt;span&gt; in GitHub.&lt;/span&gt;&lt;/p&gt;

&lt;h4&gt;Approach #2: Using GitOps without Helm&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;If you’re sold on the idea of GitOps, there are alternative tools that can be used if you’re unable to use Helm or choose not to. &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;You can use ArgoCD on its own. It is pretty flexible and can work with other templating solutions or even plain manifests. &lt;/span&gt;&lt;span&gt;Another templating tool that can be used instead of Helm is &lt;/span&gt;&lt;a href="https://kustomize.io/" rel="noopener noreferrer"&gt;&lt;span&gt;Kustomize&lt;/span&gt;&lt;/a&gt;&lt;span&gt;. This tool is built into &lt;/span&gt;&lt;span&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/span&gt;&lt;span&gt; and is native to Kubernetes. It allows you to customize Kubernetes configurations using only the Kubernetes API resource files.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Now, let’s explore our third approach about how to implement GitOps using Helm and Argo CD...&lt;/span&gt;&lt;/p&gt;

&lt;h4&gt;Approach #3: Using Helm with GitOps&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;Now that you’ve seen how GitOps can be applied without Helm, let’s explore how you can use it with Helm. &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;First, the Helm chart and any application changes must be committed in Git prior to being applied to the cluster. Meaning all of your workload definitions in a YAML format, the Helm charts, and any other Kubernetes custom resources that define the cluster’s desired state must be committed to the repo. This way rollbacks and logs are accessible and the state of production can be restored easily.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Within Argo CD you can connect the Git repository using HTTPS and add the URL directly. This then allows you to enable auto-synchronization to automatically synchronize the cluster to the desired state in the Git repository. Once synced successfully, the application status is recognized as Healthy. Otherwise, if the application is OutOfSync, you can rollback or view the release history to resolve the issue.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Here’s an example of a Healthy application in the Argo CD UI.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/09/HelmGitOpsArgoUI.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2021%2F09%2FHelmGitOpsArgoUI-1024x455.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;When the application is running you can view its resource components, logs, events, and the health status.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;For good measure, here’s a visual of the Argo CD UI exemplifying an OutOfSync application when the live state deviates from the target state.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/09/OutOfSyncArgoUI.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2021%2F09%2FOutOfSyncArgoUI.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;If your application had an error or was OutOfSync like the example above, you could execute the argo history command that allows you to view the application deployment history:&lt;/span&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;argocd app history &amp;lt;argocd_app_name&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Then, if you need to rollback the deployment you can do so by executing this command:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;argocd app rollback &amp;lt;argocd_app_name&amp;gt; &amp;lt;history_id&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Essentially, these commands leverage a faster and more secure deployment, by enabling the tracking from the Git repository. It also allows you to track the active Kubernetes resources and events.&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Therefore, using source control like this is what classifies this application deployment as GitOps!&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Something important to note is that Argo CD provides native support for Helm, meaning you can directly connect a packaged Helm chart and Argo CD will monitor it for new versions. When this takes place the Helm chart will no longer function as a Helm chart and instead, is rendered with the Helm template when Argo is installed, using the Argo CD application manifest.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Argo CD then deploys and monitors the application components until both states are identical. The application is no longer a Helm application and is now recognized as an Argo app and can only operate by Argo CD. Hence if you execute the &lt;/span&gt;&lt;span&gt;helm list&lt;/span&gt;&lt;span&gt; command, you should no longer be able to view your &lt;/span&gt;&lt;span&gt;helm release&lt;/span&gt;&lt;span&gt; because the Helm metadata no longer exists.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Here’s an example of the command output. As you can see, the Argo CD application is NOT detected as a Helm application.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codefresh.io/wp-content/uploads/2021/09/Empty-Helm-List.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodefresh.io%2Fwp-content%2Fuploads%2F2021%2F09%2FEmpty-Helm-List.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Helm is a powerful tool that is used often with Kubernetes deployments and provides tracking for each release. This helps ensure reliable and quick deployments for development teams. &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;So, if you’re completely new to Helm, I suggest referring to our documentation to learn more about it, here: &lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://codefresh.io/helm-tutorial/helm-deployment-environments/" rel="noopener noreferrer"&gt;&lt;span&gt;Helm Deployment Environments&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://codefresh.io/docs/docs/new-helm/helm-best-practices/" rel="noopener noreferrer"&gt;&lt;span&gt;Helm Best Practices&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://codefresh.io/helm-tutorial/simplify-kubernetes-helm-deployments/" rel="noopener noreferrer"&gt;&lt;span&gt;How to Simplify your Kubernetes Helm Deployments&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;span&gt;We'll discuss additional tools in our next post that can help you and your team continue implementing a GitOps process to your development and infrastructure systems.&lt;/span&gt;&lt;/p&gt;

</description>
      <category>gitops</category>
      <category>helm</category>
      <category>argocd</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
