Using a Monorepo
  • 11 Apr 2024
  • 6 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

Using a Monorepo

  • Dark
    Light
  • PDF

Article summary

Greymatter v1.8.5 introduced the ability for playbooks to operate from a mono-repository (monorepo), where multiple tenants reside in different subdirectories.

Some benefits that come from a monorepo setup:

  • Simplified configuration management

    • Configuration can be managed by fewer people

    • Centralized for ease of access and reduced fan-out of config

  • Streamlined upgrade-ability

    • Upgrades can be scripted to simply greymatter upgrade across each folder.

Some drawbacks that come from a monorepo:

  • Security and identity management

    • Who is allowed to push/merge/etc… (it’s global for the repo, can’t limit on folders)

  • Redundancy

    • Single point of failure if repository is accidentally lost.

Setting Up a Repo

Each individual folder MUST be unique and contain a single “tenant” configuration set. greymatter init may be run within each unique folder and each folder must contain it’s own cue.mod.

It’s recommended, but not required, that folder names match the provisioned namespace for each tenant.

An example directory tree may look like the following:

.
├── .git
├── README.md
├── team-a
│   ├── README.md
│   ├── TUTORIAL.md
│   ├── cue.mod
│   │   ├── module.cue
│   │   └── pkg
│   ├── greymatter
│   │   ├── core
│   │   ├── globals.cue
│   │   ├── grocerylist
│   │   └── policies
│   └── k8s
│       ├── grafana-config.yaml
│       ├── grafana.yaml
│       ├── manifests.yaml
│       └── sync.yaml
└── team-b
    ├── README.md
    ├── TUTORIAL.md
    ├── cue.mod
    │   ├── module.cue
    │   └── pkg
    ├── greymatter
    │   ├── core
    │   ├── globals.cue
    │   ├── grocerylist
    │   └── policies
    └── k8s
        ├── grafana-config.yaml
        ├── grafana.yaml
        ├── manifests.yaml
        └── sync.yaml

Note that each folder is a full instantiation of a GSL project.

Creation of these projects and folders can be automated by utilizing the --dir flag within greymatter init:

greymatter init --dir <unique_dir> <project_name>

Namespacing

Tenant namespacing conventions have NOT changed in Greymatter v1.8.5. Each tenant must be issued their own namespace in accordance with their core administrator’s guidelines.

See greymatter init --help for more information on matching namespaces and configuration files.

Deployment

Each sub-folder of a monorepo will receive it’s own Greymatter Sync service instance within the target namespace of deployment.

The sync.yaml must be modified to enter “monorepo” mode and only sync against a target folder. This is to prevent configuration collision when others in the repository make commits to their own folders.

Open <sub_folder>/k8s/sync.yaml and find the command argument list for the container:

        command: ["/usr/local/bin/greymatter"]
        args: [
          "--api", "http://controlensemble.greymatter.svc.cluster.local:5555", 
          "--catalog", "http://catalog.greymatter.svc.cluster.local:8080", 
          "--log-level", "info",
          "sync", 
          "--ssh-private-key", "/var/lib/greymatter/.ssh/ssh-private-key", 
          "--git", "--forever", 
          "--branch", "main",
          "--interval", "5s", 
          "--git-dir", "/var/lib/greymatter/checkout", 
          "--redis-addr", "greymatter-datastore.greymatter.svc.cluster.local:6379",
          "--redis-db", "0"
        ]

Make any modifications to the argument list as needed, but to configure Sync to watch a sub-directory of a monorepo, add following line after the "sync" subcommand of the argument list:

"--relative-path", "<sub_folder>",

It’s important to note that this path is from the base of the repository. Building off the example directory tree provided above, if this Sync instance is only supposed to be watching the Tenant configuration of “Team B”, the --relative-path argument would be: --relative-path: team-b.

The final result should look something like the following:

        command: ["/usr/local/bin/greymatter"]
        args: [
          "--api", "http://controlensemble.greymatter.svc.cluster.local:5555", 
          "--catalog", "http://catalog.greymatter.svc.cluster.local:8080", 
          "--log-level", "info",
          "sync", 
          "--ssh-private-key", "/var/lib/greymatter/.ssh/ssh-private-key", 
          "--git", "--forever", 
          "--branch", "main",
          "--relative-path", "<sub_folder>",
          "--interval", "5s", 
          "--git-dir", "/var/lib/greymatter/checkout", 
          "--redis-addr", "greymatter-datastore.greymatter.svc.cluster.local:6379",
          "--redis-db", "0"
        ]

A brief description of this argument list is as follows:

  • I’m connecting to Greymatter’s ControlEnsemble and Catalog APIs at the following addresses specified at --api and --catalog

  • My global --log-level is "info" but can be changed to "debug, warn, error, or trace"

  • I’m executing the sync subcommand of the Greymatter CLI

  • I’m using the SSH private specified at the path of --ssh-private-keywhen communicating with Git.

  • I’m in --git mode and I will be syncing --forever unless told otherwise.

  • I’m pointing at branch main of my configured repository

  • I’m only syncing the configuration module found at --relative-path of my repository.

  • I’m pinging Git every 5 seconds to see if there have been any changes to my repository/folder that I must fetch and apply.

  • The local repository stored on disk will be at the path of --git-dir.

  • I’m connecting to the specified Redis instance so I can manage internally track state to complete my reconciliation process.

Config Map

Alternatively, instead of supplying a flag argument to the command list within the StatefulSet, a config map can be used (as apart of the sync.yaml file) to supply the relative path config option.

From within the supplied Config Map, add a new entry for the relative-path:

data:
  # property-like keys; each key maps to a simple value
  GREYMATTER_GIT_REMOTE: "<repository url>"
  GREYMATTER_RELATIVE_PATH: "<sub_folder>"

Now within the sync stateful set, add the following environment variable:

        - name: GREYMATTER_RELATIVE_PATH
          valueFrom:
            configMapKeyRef:
              name: greymatter-sync-config
              key: GREYMATTER_RELATIVE_PATH

This will now point sync at the relative path specified from within the config map.

Final Steps

After properly provisioning the namespace, secrets, and successfully modifying sync.yaml, deployment of Sync manifests may commence.

If all is configured correctly, each Sync will note in it’s logs the folder it’s watching and the latest commit it has fetched on startup. Configuration will be watched and synchronized with the main Greymatter mesh deployment.

Troubleshooting

If you receive the following error when running greymatter sync --dry-run, you may have a relative path setting that is pointing to a non-existent path.

encountered errors during evaluation: load: cue: "./..." matched no packages

Double check that you have correctly set any relative path config. Including, the relative_path config in ~/.config/greymatter/config.toml.


Was this article helpful?