Light Dark Auto

Create and Deploy a Tenant Project

Generating a project from the CLI and deploying it into the mesh


The greymatter GitOps pipeline expects application’s networking configurations to exist in a tenant project, otherwise it will not apply them. Tenant projects have a specific structure but the greymatter CLI can quickly and easily generate it for you with the init command.

This guide will walk you through creating a tenant project using the greymatter CLI and deploying it into your Kubernetes cluster. At the end of the guide, you will have a newly generated project with its application edge node and sync service running inside the mesh.


  • A greymatter v1.8.x installation.
  • An installed copy of the greymatter CLI.
  • A git repository.
  • mTLS certificates (optional in the case of an insecure project generation).
  • SSH private key with access to the above git repository (optional in the case of git over HTTPS).

You will also need to reach out to your mesh administrator to add the project’s Kubernetes namespace into operator’s watched_namespace field.

1. Create the Project

Navigate to the directory where you want to store the project configurations and run:

greymatter init --dir <project directory name> --git-remote <git repo URL> <project name>

The project name and the kubernetes namespace you will run this project in must match.

The --dir flag will create a folder. Drop that flag and run the command inside a directory if you do not want this behavior.

After running the command, the contents of your project directory will look like:

├── .greymatter
├── cue.mod
├── greymatter
   ├── policies
   ├── core
   │   └── edge.cue
   ├── globals.cue
   └── <project name>
└── k8s
    ├── manifests.yaml
    └── sync.yaml

2. Commit and Push the Project

It is good practice to immediately populate the tenant repository with the newly generated project. Initialize a local git repository and commit your changes:

git init
git remote add origin <git repo URL>
git add .
git commit -m "Initialized project"
git push --set-upstream origin main

3. Upload mTLS Certificates as Secrets

This step is only required if you did not generate an insecure project in the first step. Skip this section if you are using a project configured for plaintext communications.

Tenant projects have a few different TLS deployment configurations. By default, the init commands enable manual mTLS on the application edge node and on the tenant services. Both the edge and the services expect x509 certificates loaded on their filesystems when mTLS is enabled. Kubernetes Secrets are the best way to mount those certificates.

Navigate to the directory that contains the certificate and key file (and optional CA certificate) and run:

kubectl create secret generic greymatter-<name of the project>-edge-certs \
	--from-file=ca.crt=./ca.crt \
	--from-file=server.crt=./server.crt \
	--from-file=server.key=./server.key \
	-n <project namespace>

If you plan on also using mTLS between services in the tenant project, you need to create a Secret containing the certificates used by the services.

Navigate into the directory containing the certificates you want to use for the services. Run:

kubectl create secret generic gm-edge-ingress-certs \
	--from-file=ca.crt=./ca.crt \
	--from-file=server.crt=./server.crt \
	--from-file=server.key=./server.key \
	-n <project namespace>

4. Upload a SSH Private Key as a Secret

For the sync service to connect to the tenant git repository over SSH, it requires a private key. Just like the previous section, the best way to mount this file is through a Kubernetes Secret:

kubectl create secret generic greymatter-sync-secret \
    --from-file=ssh-private-key=</path/to/key/file> \
    -n <project namespace>

Providing Sync with a Key Password (optional)

If the SSH key is password-protected, you need to provide Sync with the password. Create another secret with the SSH key’s password:

kubectl create secret generic sync-ssh-passphrase --from-literal=passphrase=<password> -n <project namespace>

Open Sync’s manifest file found at k8s/sync.yaml and add this YAML block to the env array:

	  name: sync-ssh-passphrase
	  key: passphrase
	  optional: true

This allows Kubernetes to write the value in the Secret into the Pod’s environment.

5. Deploy the Edge and Sync Service

Deploy all the Kubernetes manifests found under the k8s directory:

kubectl apply -f ./k8s

6. Verify the Project Deployment

List the pods within your tenant namespace:

kubectl get pods -n <project namespace>

Both the Edge proxy and Sync’s pods should show a ready status. Check Sync’s logs by running

kubectl logs -n <project namespace> sts/greymatter-sync

Ensure that the sync service pulled the latest commit from your tenant repository.

If you discover any issues during this step, please check out the Troubleshooting section of this document for help.

7. Set the edge_host for the Project

The edge node comes with a Kubernetes Service manifest that provisions an external IP. Find this value by running:

kubectl get svc -n <project namespace>

Copy the value for external IP.

Open the file at greymatter/globals.cue. This is the GSL globals file and it contains values used across the project. Paste the external IP into the edge_host field. You must include the port.

8. Set the Mesh Name for the Project (optional)

If your mesh was installed with a custom mesh name, you must set that value in the globals file as well. If you do not, your services will not appear in the mesh. Contact your mesh administrator for the correct value.

Set the mesh name by updating the name field inside the mesh object.


Congratulations, you have successfully created and deployed a tenant project! You can now immediately start creating and deploying tenant services.

Next Steps



A few things can go wrong while creating and deploying a project. See the sections below for some common problems and solutions

Image Pull Errors

Make sure the gm-docker-secret exists within your namespace. You can list secrets by running

kubectl get secrets -n <project namespace>

If you cannot find it, you may have forgotten to add the namespace into the Operator’s watched_namespace field.

Crash Loop Back-offs

If the edge node or Sync cannot find their secrets, they will likely crash until you populate them. Evaluate the status of the failing service by running

kubectl describe pod -n <project namespace> <name of pod>

Double check that the necessary secrets are populated and spelled correctly.

Sync Failures

If Sync complains about “empty password”, then your SSH key is password-protected. Follow the instructions to pass this value into Sync.

If Sync complains about the git remote not being a ref, then the issue is most likely one of the following:

  1. the identity asserted by the private key does not have access

  2. the git repository URI is incorrect

    If you accidentally mistyped the repository in step one, you can change it in k8s/sync.yaml. You’ll see a ConfigMap manifest containing the URI. Update it, and re-apply the sync.yaml file

  3. the git repository does not contain a main branch

    Sync also expects the git repository to have a main branch. If your remote repository does not contain one, please rename it or point Sync at the correct branch.