Managing the ‘Git’ in ‘GitOps’: 4 Ways to Structure Code in Your GitOps Repos
Tags: gitops, devops, git, kubernetes
Published: 2022-06-15 14:57:55

Implementing [GitOps](https://harness.io/blog/devops/gitops/) practices will take your software delivery pipelines to the next level. [Declarative](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/), [immutable](https://www.cncf.io/online-programs/immutable-infrastructure-in-the-age-of-kubernetes/), and continuously [reconciled](https://github.com/open-gitops/documents/blob/v1.0.0/GLOSSARY.md#reconciliation) infrastructure brings many [benefits](https://harness.io/blog/devops/gitops-benefits/) when managed through [GitOps best practices](https://harness.io/blog/devops/gitops-best-practices/). Over the years, I have helped many development teams build and improve their GitOps workflows. In this blog, I will share four approaches to managing code used in those pipelines.

The “Ops” half of “GitOps” refers to configuration code, or [Infrastructure as Code](https://harness.io/blog/devops/infrastructure-as-code/) (IaC). Software depends on the resources managed by this code to function. Managing this configuration in [Git](https://git-scm.com/) repositories offers many benefits. Often the structure of this code is an afterthought, which leads to significant refactoring in the future.

## Application and Infrastructure Code in One Repository

The first example manages application code and infrastructure code in the same repository. A single [long-lived](https://medium.com/@peter.hozak/long-lived-git-branches-survival-guide-f3b1028d21d) branch exists ([main](https://www.theserverside.com/feature/Why-GitHub-renamed-its-master-branch-to-main)).

### Example

Below is a Node.js project with application code in the root, and YAML files in the kubernetes directory. Changes to development.yaml apply to the development environment, changes to production.yaml apply to the production environment.

![Node.js project with application code in the root](https://blog.harness.io/wp-content/uploads/2022/06/Screen-Shot-2022-06-10-at-11.23.21-AM.png)

### Benefits

- Infrastructure code and application code in the same repository keeps everything versioned together. There is no need to connect the dots between multiple repositories to reproduce the state of the application and configuration at a certain point in time.
- One repository means less [context switching](https://pacohq.com/blog/guide/the-high-price-of-context-switching-for-developers/) for developers. Developers don’t need to change repositories when making changes to infrastructure code.

### Drawbacks

- No [privilege separation](https://harness.io/blog/devops/pipeline-security-devsecops-catalyst/). Developers with access to the repository will be able to change both application and infrastructure code.

Some organizations require separation between application and infrastructure code. The examples below all manage application and infrastructure code in their own repositories. This improves privilege separation as each Git repository can set its own user privileges.

## Separate Infrastructure Repository, Multiple Branches

You may be familiar with Git branching workflows such as [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). Gitflow has fallen [out of favor](https://georgestocker.com/2020/03/04/please-stop-recommending-git-flow/) recently as [trunk-based](https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development) development has gained popularity. There are good reasons to avoid more than one long-lived branch in your Git repository. Yet, multiple long-lived branches are still worth considering in certain cases.

### Example

Below is a [Helm](https://helm.sh/) chart repository with two long-lived branches, development, and production. Changes always originate in the development branch. Promotion to production requires [merging](https://git-scm.com/docs/git-merge) development into production. The development environment uses the development-values.yaml [values](https://helm.sh/docs/chart_template_guide/values_files/) file in the development branch. The production environment uses the production-values.yaml values file in the production branch.

![Helm chart repo](https://blog.harness.io/wp-content/uploads/2022/06/image.png)

### Benefits

- Low risk of [configuration drift](https://harness.io/blog/devops/infrastructure-as-code/#consistency) when promoting changes between environments. Merging branches ensures that no changes will be missed.
- Improved privilege separation between development and production changes. For example, GitHub supports branch [protection rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule). The owner of the repository can control which users can commit to a branch.

### Drawbacks

- This is a “one lane road” for your infrastructure code. Changes in the development branch can block production changes (without [cherry-picking](https://git-scm.com/docs/git-cherry-pick) desired changes).

## Separate Infrastructure Repository, Directory-Based

Now, let’s consider a repository where a single long-lived branch exists (main). Each environment has its own directory.

### Example

Below is a [Terraform](https://harness.io/blog/devops/terraform-201-tutorial/) repository with separate development and production directories. Changes to development use the development.tfvars [tfvars](https://www.terraform.io/language/values/variables#variable-definitions-tfvars-files) file in the development directory. Changes to production use the production.tfvars tfvars file in the production directory.

![Terraform repository](https://blog.harness.io/wp-content/uploads/2022/06/image-1.png)

### Benefits

- Changes made in the development directory do not affect the production directory.

### Drawbacks

- Increased risk of configuration drift between environments. There is a high burden on the developer to understand differences between directories.
- No privilege separation. Users can make changes to both development and production environments.

## Multiple Infrastructure Repositories, One per Environment

Let’s consider an approach where each [environment](https://harness.io/blog/continuous-delivery/deployment-environments/) has its own dedicated repository. Each repository has a single long-lived branch (main).

### Example

Here is an example Terraform project, where development and production are separate repositories. Changes to development use the development.tfvars tfvars file in the development repository. Changes to production use the production.tfvars tfvars file in the production repository.

![Terraform project](https://blog.harness.io/wp-content/uploads/2022/06/image-2.png)

### Benefits

- Highest level of privilege separation. Any feature that your Git host provides around user/group access at the repository level will be available to you. Only users that need to make changes to production will be able to commit changes to the production repository.
- Easier to bring up new environments, or migrate existing environments. When bringing up a new environment, create a new repository. There is no need to integrate with an existing repository to bring up a new environment. 

### Drawbacks

- Higher risk for configuration drift between environments. There is a high burden on the developer to understand differences between repositories.

## Conclusion

In my experience, one repository per environment is the most [future-proof](https://en.wikipedia.org/wiki/Future-proof) method for managing your GitOps code. The privilege and environment separation benefits outweigh the potential drawbacks. If you decide the separation is not required in the future, you can collapse multiple repositories into one. The good news is that whatever method you choose, **Harness’ suite of products supports them all.**

Whether you are building, testing, and publishing artifacts with [Harness CI](https://harness.io/products/continuous-integration), deploying with [Harness CD](https://harness.io/products/continuous-delivery), or taking your pipelines to the next level with [Harness GitOps](https://harness.io/gitops-beta/) (currently in beta), we’ve got you covered! Also, every Harness pipeline can take advantage of advanced features around [governance](https://harness.io/blog/continuous-delivery/ci-cd-pipeline-governance/), [chaos engineering](https://harness.io/blog/product-updates/introducing-harness-chaos-engineering/), and more.

Come see how Harness can help accelerate your GitOps journey. Sign up for a [14-day free trial](https://harness.io/pricing) and follow our [Kubernetes CD Quickstart](https://ngdocs.harness.io/article/knunou9j30-kubernetes-cd-quickstart) guide to deploy an application to your cluster. If you are looking for a guided tour, [book a demo](https://harness.io/demo/).

We would love to answer any questions you might have in our [forum](https://community.harness.io/), [community Slack](https://harnesscommunity.slack.com/), or at an upcoming [Harness & Drone User Group](https://www.meetup.com/harness/) virtual meetup.

The post [Managing the ‘Git’ in ‘GitOps’: 4 Ways to Structure Code in Your GitOps Repos](https://dev.to/davenielsen/managing-the-git-in-gitops-4-ways-to-structure-code-in-your-gitops-repos-3ff4-temp-slug-4938802) appeared first on [Harness](https://blog.harness.io).