Skip to content
EgyKode
Beginner20 min

Repository Structure

After this chapter you can

  • Find any file in the platform without searching

Why this comes after the requirements#

You know what the platform is, how a request moves through it, and what you need to build it. One question is left before the first command: where does any of it go?

The answer matters more than it sounds. Each phase of this build produces files — Terraform for the infrastructure, Ansible for the Jenkins host, manifests for the cluster, a chart, a pipeline definition. If they land wherever is convenient, the GitOps loop later has no single place to watch, and you have a pile of folders rather than a platform.

A repository layout is not tidiness. It is the contract that lets a pipeline find what to build and a reconciler find what to deploy — and it lets an engineer who joins on Monday see how the platform fits together from the folder names alone.

In the capstone, this is where each phase of the build lives.


Level 1 — Beginner#

What is a Repository Structure?#

Imagine a massive library. If you just dumped 10,000 books into the middle of the room, nobody could find anything. You need shelves labeled "History", "Science", and "Fiction".

This repository takes that idea further than most: the shelves are numbered in the order you build them. 01 is the application in containers, 07 is watching it in production, and the numbers in between are the journey from one to the other. You can read the repository top to bottom and it tells you the story in sequence.

ASCII Diagram: The Folder Tree#

text
CloudDevOpsProject/
├── src/                <-- The application itself (three services)
│   ├── frontend/           Node.js — the only one users reach
│   ├── auth-service/       Python — logins
│   └── roadmap-service/    Java — the domain logic

├── 01-Docker/          <-- Containerise it, and run the stack locally
├── 02-Terraform/       <-- Build the AWS account
│   ├── modules/            network · eks · ecr · server
│   └── bootstrap/          the S3 state backend, created once
├── 03-Ansible/         <-- Configure the Jenkins host
│   ├── roles/              nine of them, one per tool
│   └── playbook.yml        the entry point
├── 04-Kubernetes/      <-- Run it on the cluster
│   └── manifests/          00-namespace … 12-network-policies
├── 05-Jenkins/         <-- Build, test and scan it (CI)
│   ├── vars/               the shared library — logic lives here
│   └── Jenkinsfiles/       one per service, thin
├── 06-ArgoCD/          <-- Deploy it (CD)
│   └── applications/       what Argo CD reconciles
├── 07-Monitoring/      <-- Watch it
│   ├── dashboards/         committed JSON, not clicked in the UI
│   └── manifests/          alert rules and probes

├── docs/               <-- Architecture and decisions
└── scripts/            <-- The helpers you would otherwise retype

Notice what the numbering encodes: you cannot deploy to a cluster that does not exist, and you cannot build an image of an application you have not containerised. The order is the dependency graph.


Level 2 — Intermediate#

Deep Dive: What is in these folders?#

Let's look at the intermediate mechanics of why these folders exist.

1. 02-Terraform/#

  • What it does: HashiCorp Configuration Language (HCL) describing the AWS account — around eighty resources, including the ACM certificate that puts the load balancer on HTTPS.
  • Subfolders:
    • modules/: four reusable blocks — network (VPC, subnets, NAT, route tables, NACLs, flow logs), eks (the cluster, its node group, OIDC and the IRSA roles), ecr (the registry, with immutable tags) and server (the Jenkins instance and its IAM profile).
    • bootstrap/: the S3 bucket that holds the state. It is separate for a reason — the thing that stores your state cannot itself be stored in that state, so it is created once, first, on its own.

2. 03-Ansible/#

  • What it does: Turns the bare EC2 instance Terraform created into a working Jenkins host.
  • Subfolders:
    • inventory/: not a list of IP addresses. It uses the aws_ec2 plugin to discover hosts by tag, so replacing an instance does not mean editing a file.
    • roles/: nine of them — aws_cli, common, docker, java, jenkins, kubectl, helm, sonarqube, trivy. One tool each, so they can be reordered or reused.
    • playbook.yml: the entry point that calls the roles in order.
  • Why isn't Ansible building the cluster? On a self-managed cluster it would — that is what kubeadm is for. Here the control plane is AWS's responsibility and the node group comes from Terraform, so Ansible's remaining job is the machine that is genuinely yours: the build host.

3. 04-Kubernetes/#

  • What it does: The manifests, numbered in apply order: namespace, RBAC, config, storage, database, the two backends, the frontend, ingress, the Jenkins and SonarQube proxies, the Argo CD ingress, and the network policies last.
  • Why separate it from Terraform? Terraform builds the cluster. These manifests run inside it. Mixing them creates a chicken-and-egg problem — Terraform would need a cluster that its own run is still creating.

4. 06-ArgoCD/#

  • What it does: Holds the Argo CD Application resources and the project definition.
  • The Concept: It watches 04-Kubernetes/manifests/. Change a file there, and Argo CD notices and reconciles the cluster to match — with prune and selfHeal on, so removals are applied and manual edits are reverted.

Level 3 — Advanced#

Production Monorepo vs. Polyrepo#

This repository is a Monorepo (Monolithic Repository). We put the Infrastructure, the CI pipelines, and the Kubernetes manifests all in one giant GitHub repository.

  • The Alternative (Polyrepo): We could have 4 separate Git repositories: platform-terraform, platform-ansible, app-backend, app-frontend.
  • Why we chose Monorepo: In a learning or unified platform engineering team, a Monorepo ensures that a single Pull Request can contain a Terraform change (adding a new subnet) AND the Kubernetes change that relies on it. It ensures atomic commits.
  • Disadvantage: As the team grows to 500 engineers, the Monorepo becomes chaotic. CI pipelines take hours to figure out which folder changed. At that scale, companies often migrate to Polyrepos or use advanced build systems like Bazel.

The "App-of-Apps" Directory Pattern#

Notice the 06-ArgoCD/applications/ directory. This is not an accident; it is the App-of-Apps pattern. Instead of writing a complex deployment script, our Root ArgoCD application literally points to this directory and says: "Deploy every YAML file inside this folder." If we want to add a new microservice to our company, we don't touch Kubernetes or AWS. We just drop a new 10-line YAML file into this folder, commit it to Git, and ArgoCD instantly deploys it.


Level 4 — Enterprise#

Enterprise Directory Structure Best Practices#

In a Fortune 500 company, repository structure is enforced by Compliance teams.

  1. Separation of Duties (SoD): A junior developer should be able to edit 04-Kubernetes/manifests/07-frontend.yaml, but be blocked from editing 02-Terraform/modules/eks/main.tf. We enforce this using GitHub CODEOWNERS.
  2. The CODEOWNERS file: We place a .github/CODEOWNERS file at the root of the repo:
    text
    /02-Terraform/ @company/senior-cloud-architects
    /04-Kubernetes/manifests/12-network-policies.yaml @company/security-team
    If a developer tries to modify a production Terraform file, GitHub will automatically block the Pull Request until a Senior Cloud Architect explicitly approves it. This satisfies SOC2 access control requirements.

GitOps Folder Segregation#

Enterprise GitOps repositories often split the "App Code" from the "Manifest Code".

  • Repo 1 (App Code): Developers write Java code here. The CI pipeline compiles it and pushes image:v2.0 to Docker Hub.
  • Repo 2 (Manifest Repo - THIS PROJECT): The CI pipeline from Repo 1 automatically commits a change to kubernetes/base/api-deployment.yaml in this repository, updating the image tag. ArgoCD only watches this repository. This isolates application logic from deployment logic.

Interview Questions#

Beginner#

Q: Why don't we put all our files in one single folder? A: Organization and predictability. If a team member needs to fix a Jenkins pipeline, they know exactly where to look (jenkins/pipelines/) without having to search through hundreds of Terraform and Kubernetes files.

Intermediate#

Q: What is the difference between the terraform/modules folder and the terraform/environments folder? A: modules contains generic, reusable templates (like a blueprint for a house). environments contains the specific instances of that blueprint (like building the house at a specific address in dev or prod). You write the code once in modules, and call it multiple times from environments.

Senior#

Q: Explain the chicken-and-egg problem of mixing Terraform and Kubernetes YAML in the same state file. A: If you use the Terraform kubernetes provider to apply YAML manifests in the exact same main.tf file that builds the EKS cluster, Terraform will evaluate the plan before creating anything. It will try to connect to the Kubernetes API to plan the YAML changes, but the API doesn't exist yet because the cluster hasn't been built. This causes Terraform to crash. This is why 02-Terraform/ and 04-Kubernetes/ are separate directories applied in separate steps.

Principal/Architect#

Q: In an enterprise setting, how do you handle secrets management across a Monorepo that contains multiple environments (Dev/Stage/Prod)? A: You never store plaintext secrets in the repo. You structure the repo to integrate with a dynamic secrets manager (like HashiCorp Vault or AWS Secrets Manager). For Terraform, you use data sources to fetch secrets at runtime. For Kubernetes, you use the External Secrets Operator (ESO) configured in the kubernetes/ directory. ESO authenticates with AWS Secrets Manager via IRSA (IAM Roles for Service Accounts) and dynamically injects the secrets into the cluster memory, keeping the Git repository completely devoid of sensitive data while maintaining a unified directory structure. Contents | The Foundation (Linux) |

Check yourself

4 questions from this chapter. Try answering before you look.

  • Why don't we put all our files in one single folder?
  • What is the difference between the `terraform/modules` folder and the `terraform/environments` folder?
  • Explain the chicken-and-egg problem of mixing Terraform and Kubernetes YAML in the same state file.
  • In an enterprise setting, how do you handle secrets management across a Monorepo that contains multiple environments (Dev/Stage/Prod)?
Questions from the curriculum

Related chapters