Getting started with ArgoCD
ArgoCD on Platon is currently in a testing phase. If you want your team to be included, contact the Platon team on #platon on Slack and include the path to your GitLab project.
This guide walks you through deploying your first application to Platon using ArgoCD. By the end, your GitLab pipeline will render your Kubernetes manifests on every push, and ArgoCD will deploy them to the cluster.
Prerequisites
Before you begin, you need:
- A GitLab project at gitlab.sikt.no
- Access to [ArgoCD UI](https://argocd.argocd-test.sandbox.platon.sikt.no/ #TODO: Update with the prod cluster URL). Log in via gitlab.
How it works
Platon's ArgoCD setup involves three repositories:
source repo (your project) deploy repo (argocd-apps/gl-proj-<id>)
────────────────────────── ──────────────────────────────────────
1. generate-manifests job ───────► 2. Downstream pipeline commits the
renders manifests/ with manifests into one directory per
envsubst environment:
prod/ staging/ rev-<branch>/
│
▼
app-config repo (Platon-managed) 3. ArgoCD deploys each directory to
──────────────────────────────── its own namespace:
Defines the ArgoCD AppProject, gl-proj-<id>-prod
Applications (prod, staging) and gl-proj-<id>-staging
ApplicationSet (review) gl-proj-<id>-review-<branch>
Understanding the three repositories
Source repository (your responsibility)
This is where your application code lives, along with your Kubernetes YAML templates in manifests/. The templates use placeholders that the pipeline replaces with real values.
Deploy repository (created when your project is bootstrapped)
The repository that ArgoCD watches, at argocd-apps/gl-proj-<id>, where <id> is your GitLab project ID. Its contents are managed entirely by CI: your source repository's pipeline triggers the deploy repository's own pipeline, which commits the rendered manifests into a directory named after each environment. Do not edit it manually: the next deployment overwrites any changes made there.
App-config repository (managed by Platon) Holds the ArgoCD resources for every project. You have read-only access to it, so you can see how your project is configured, but changes are made by the Platon team:
- AppProject (
gl-proj-<id>): controls who can do what (RBAC) and which namespaces your applications may deploy to - Applications for production and staging: one fixed Application per environment
- ApplicationSet for review environments: creates one Application per branch automatically
As a user, you work only with the source repository. The deploy repo is handled by your pipeline, and the app-config repo is managed by Platon.
Step 1 — Prepare your manifest templates
Create a manifests/ directory in your repository with your Kubernetes YAML files. Both .yaml and .yml files are processed, and you can organise them into subdirectories:
my-app/
├── manifests/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── httpRoute.yaml
│ └── vaultStaticSecret.yaml # only needed if reading secrets from Vault
└── .gitlab-ci.yml
Use CI variables as placeholders for values that differ between environments or builds, for example $CI_COMMIT_SHA for the image tag. Resource names can stay the same in every environment: each environment, including each review branch, gets its own namespace, so deployments do not overwrite each other.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: $REPLICAS
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Leave out metadata.namespace. ArgoCD places every resource in the namespace for that environment.
Platon creates each environment's namespace, with default network policies, image pull credentials and resource policies already applied. Do not add Namespace resources to your manifests.
Do not put kind: Secret resources in your manifests. They would be committed in plain text to the deploy repository. The pipeline checks for them and fails the job if it finds one. Manage secrets through Vault instead, as described below.
For a complete working example with several apps, HTTPRoutes, network policies and a Vault secret, see hello-world-all-resources-gitops.
Accessing Vault secrets
Every namespace Platon creates for you already contains a VaultAuth resource called vault-auth, which lets the namespace read your project's secrets in Vault. You only need to add a VaultStaticSecret saying which secret to fetch:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: my-app-secret
spec:
vaultAuthRef: vault-auth
type: kv-v2
mount: secret
path: gitlab/<group>/<project>/<secret-name>
refreshAfter: 30s
destination:
name: my-app-secret
create: true
The Vault Secrets Operator reads the KV-v2 secret at path, creates a Kubernetes Secret named by destination.name, and refreshes it on the refreshAfter interval. Your pods can then use that Secret as usual.
The values you need to adjust:
path: where your secret is stored in Vault. Your project can read secrets undergitlab/<group>/<project>/(see Vault structure).destination.name: the name of the KubernetesSecretto create
This also works for review environments: each new review namespace gets its own vault-auth automatically, so no manual Vault changes are needed. When the review environment is stopped, the namespace and its Secret are removed.
Step 2 — Configure your pipeline
Include the Platon ArgoCD component in your .gitlab-ci.yml and define the two stages it uses. The component adds all the jobs for you:
include:
- component: $CI_SERVER_FQDN/platon/ci-components/argocd-deploy/deploy@main
stages:
- generate-manifests
- deploy
If you also build an image in the same pipeline, put your build stage before generate-manifests.
The component supports three environments:
| Environment | Runs on | Enabled by default | ArgoCD sync |
|---|---|---|---|
| review | every push to a branch other than the default branch | yes | automatic |
| staging | every push to the default branch | no | manual |
| production | every push to the default branch | yes | manual |
To turn environments on or off, use the component inputs. For example, to add staging:
include:
- component: $CI_SERVER_FQDN/platon/ci-components/argocd-deploy/deploy@main
inputs:
with-staging: true
| Input | Default | Description |
|---|---|---|
with-review | true | Review environment per branch, plus a manual stop-review job |
with-staging | false | Staging environment from the default branch |
with-production | true | Production environment from the default branch |
templates-dir | manifests | Directory containing your templates |
Bootstrapping reads these inputs from your .gitlab-ci.yml to decide which ArgoCD Applications to create. Commit the include with the environments you want before your project is bootstrapped. If you enable staging later, you can bootstrap the project again so that the staging Application is created.
To change a single job, declare a job with the same name. GitLab merges your keywords over the component's. For example, to require a manual click before deploying to production:
deploy-production:
when: manual
Review environments are stopped automatically after 14 days. You can also stop one earlier with the manual stop-review job, or by deleting the branch.
If you need a review environment that lasts longer, override the auto-stop setting in the same way:
deploy-review:
environment:
auto_stop_in: 30 days
Step 3 — Get your project bootstrapped
Bootstrapping connects your project to ArgoCD. It:
- creates your deploy repository,
argocd-apps/gl-proj-<id> - sets the
DEPLOY_REPOSITORY_PATHCI/CD variable on your source project, so the pipeline knows which repository to trigger - creates the AppProject, Applications and ApplicationSet for the environments enabled in your
.gitlab-ci.yml
While ArgoCD on Platon is being tested, the Platon team bootstraps projects for you. Ask on #platon on Slack and include the path to your GitLab project.
After the testing phase, you will bootstrap your project yourself in PaaS Console: find your GitLab project, select the ArgoCD cluster and click the bootstrap button. You need the Maintainer or Owner role on the GitLab project to do this.
Step 4 — What the pipeline does
When you push, the pipeline runs two stages:
Stage 1 — generate-manifests
The job runs envsubst on every .yaml and .yml file in manifests/, replacing each placeholder with the value of the variable it names. These can be built-in CI variables (such as $CI_COMMIT_SHA), variables defined in your .gitlab-ci.yml, or CI/CD variables from your project settings. The result is saved to manifests-generated/ as a pipeline artifact.
The job then checks the result and fails if:
- no manifests were generated, because an empty environment would make ArgoCD delete everything in it
- a file is not valid YAML after substitution
- a file contains a
kind: Secret
Stage 2 — deploy
The deploy job triggers the pipeline in your deploy repository, which replaces the environment's directory with the new manifests and commits them:
| Environment | Directory in deploy repo | ArgoCD Application | Namespace |
|---|---|---|---|
| production | prod/ | <project>-prod | gl-proj-<id>-prod |
| staging | staging/ | <project>-staging | gl-proj-<id>-staging |
| review | rev-<branch-slug>/ | <project>-review-<branch-slug> | gl-proj-<id>-review-<branch-slug> |
<project> is the last part of your GitLab project's URL, in lowercase. For gitlab.sikt.no/platon/example/hello-world it is hello-world. <id> is the gitlab project ID.
Step 5 — Verify the deployment
Open the ArgoCD UI once the pipeline has finished. To find your applications, filter by the gitlab-project-name label or search for your project name. Click an application to see a live graph of all its Kubernetes resources. Each application and resource shows two statuses:
- Sync status:
Syncedmeans everything in your manifests has been applied to the cluster.OutOfSyncmeans the cluster differs from what is in the deploy repository, for example because a new version has not been synced yet. - Health status:
Healthy(green heart) means the resources are running as expected, for example all pods of a Deployment are up and ready.Progressingmeans they are still starting, andDegradedmeans something is wrong, such as a pod that keeps crashing.
Your deployment succeeded when the application is both Synced and Healthy.
- Review environments are synced automatically. The new review application appears within a few minutes of the pipeline finishing.
- Production and staging are not synced automatically. After the pipeline finishes, the application shows
OutOfSync. Click Sync → Synchronize to deploy. Only maintainers of the GitLab group can sync production (see Permissions).
You can also check from the command line:
kubectl get pods -n gl-proj-<id>-<environment>
Step 6 — Make a change
The full loop looks like this:
- Edit your code or a manifest template in your source repository.
- Commit and push.
- GitLab CI renders the templates and commits them to the deploy repository.
- ArgoCD detects the new commit (it checks every 3 minutes by default, or click Refresh to check now).
- Review environments sync on their own. For staging and production, click Sync.
Next steps
- Applications: sync policies, permissions, rollbacks and the ArgoCD CLI
- Troubleshooting: common issues and how to resolve them