Skip to content

Migration Steps: To Fully GitOps

Imported from Confluence

Content may be outdated. Verify before following any procedures. View original | Last updated: January 2026

Introduction

This wiki documents the process of migrating from local application deployment with Helmfile to a GitOps approach. 

The GKE Infra cluster in DTGrowth Dev serves as the proof of concept for the migration and now manages all infrastructure applications using GitOps. See the ArgoCD Apps UI. You can follow the epic's tickets in AGPTR-299 to track the progress of Berlin infrastructure Helm deployments migrating to ArgoCD.

What's important to note

The hyperlinks in this wiki points directly to code examples in the DTGrowth Dev ArgoCD migration, and serves as a guide for migration in other projects. See migration checklist for step-by-step migration procedure

  • We use one (1) ArgoCD instance per product and environment. For example, ArgoCD Core Dev deploys into both the GKE Infra and Core Dev clusters. Therefore, you must register the GKE Infra and Core clusters in the GKE Core Argocd. To do this, you need to enable cross-cluster connectivity.
  • One (1) ApplicationSet centrally manages all infrastructure apps. We use a list generator to set up infrastructure apps in the GKE Infra cluster. Use this structure to define app paths under ArgoCD management, and easily extend the list generator to add apps.
  • One (1) ArgoCD Application manages all secrets related to the infrastructure applications in: external-secrets-config.
  • To begin migration, identify which apps to migrate. List existing Helm releases in the cluster with:
❯ kubectx
Switched to context "gke_agp-growth-dev-fm_us-east1_gke-infra-growth-dev-useast1".
❯ helm list --all-namespaces -q
ccc-config
cert-manager
cert-manager-letsencrypt
dns-validation
gatekeeper
gatekeeper-rules
gateway-api-prv
gcpvm-metrics
gitlab-runner
gitlab-runner-terraform
gke-notification
gke-rbac
grafana
prometheus
prometheus-blackbox-exporter
thanos

ArgoCD Migration Checklist

793 4067c5fb-c51d-4f15-80fe-19e85f6f2b43 complete Configure cross-cluster connectivity. 794 8d31b75f-c8e9-4778-b0db-95ea8b5e2b28 complete Identify applications to be migrated. 795 85f949b2-9544-41a9-84b0-8cb4603a5fbd complete Set up External Secrets Infrastructure. 796 89974aa6-e7a3-4000-99ca-8a636b32faa6 complete Add the application to the ApplicationSet list, configure sync options, and set ignoreDifferences as required. 797 f2522f9d-009b-4cb9-ab5d-d778244f20dc complete Verify the status in ArgoCD, check pod health, confirm secret availability, and ensure application functionality after migration. 798 29824e5a-2c08-41ab-a965-ed8ca9909df0 complete Delete old Helm releases, set up notifications for status updates, and update related documentation to reflect changes. 799 d4d7422c-41f5-4bfb-85ae-04d5e3902acd complete Create ArgoCD Monitoring: Grafana + Alertmanager.


1. Cross-Cluster Connectivity

Ensure RBAC permissions and network access are in place.
controller:
  serviceAccount:
    create: true
    name: "argocd-application-controller"
    annotations:
      iam.gke.io/gcp-service-account: sa-gke-argocd-application-cont@agp-growth-dev-fm.iam.gserviceaccount.com
sa-gke-argocd-repo-server = {
  namespace   = "argo-cd"
  roles       = ["roles/container.developer", "roles/cloudkms.cryptoKeyDecrypter"]
  k8s_sa_name = "argocd-repo-server"
}
sa-gke-argocd-image-updater = {
  namespace   = "argo-cd"
  roles       = ["roles/artifactregistry.reader"]
  k8s_sa_name = "argocd-image-updater"
}
sa-gke-argocd-application-controller = {
  namespace   = "argo-cd"
  roles       = ["roles/container.admin", "roles/cloudkms.cryptoKeyDecrypter"]
  k8s_sa_name = "argocd-application-controller"
}
- clusterRoleName: argocd-manager
  users:
    - sa-gke-argocd-application-cont@agp-growth-dev-fm.iam.gserviceaccount.com
  rules:
    - apiGroups:
        - "*"
      resources:
        - "*"
      verbs:
        - get
        - list
        - watch
        - create
        - update
        - patch
        - delete
        - deletecollection
    - nonResourceURLs:
        - "*"
      verbs:
        - get
- clusterRoleName: external-secrets-cert-controller-extra
  serviceaccount: external-secrets-cert-controller
  sa_namespace: external-secrets
  rules:
    - apiGroups:
        - "discovery.k8s.io"
      resources:
        - "endpointslices"
      verbs:
        - get
        - list
        - watch
    - apiGroups:
        - ""
      resources:
        - endpoints
        - services
        - pods
      verbs:
        - get
        - list
        - watch
gcloud container clusters describe gke-infra-growth-dev-useast1 --region=us-east1 --project=agp-growth-dev-fm --format="value(masterAuth.clusterCaCertificate)" 2>/dev/null
Expected outcome:

Clusters are registered in ArgoCD

Screenshot 2025-11-25 at 14.23.44.png


2. Identify Apps to be migrated

List Helm releases, document dependencies, and define a strategy for handling secrets.

808 e82543f0-1361-456d-9a64-09bd2bf7d2f1 incomplete

List all current Helm releases: helm list --all-namespaces -q

809 28bd56eb-9acb-430d-9ab8-58dba28c17f1 incomplete Check each app's details: App name, namespace, chart version, dependencies.  810 45bdf1ba-2f8a-4c7d-bdfd-d0253013d487 incomplete Check which apps use secrets in secrets.yaml (e.g Prometheus, Grafana, etc.)


3. Setup External Secrets Infrastructure

811 6211d72e-652c-4fac-bdb9-3815a2623925 incomplete Deploy the external-secrets-operator. 812 incomplete Create a Service Account (SA) for the External Secrets Operator. 813 incomplete Update the ESO configuration. 814 incomplete Update Infra Apps ApplicationSet to deploy ESO. 815 73939876-d0bd-4c5d-8154-d4702059a00c incomplete Create secrets in GCP Secrets Manager.
816 incomplete Create Secrets in GCP Secrets Manager.

    • 817 incomplete Note: When creating secrets for the secrets manager, add them to secrets.yaml in JSON format. For example: -
              grafana:
                  secret_data: |
                      {
                          "admin-user": "xxxxxxxx",
                          "admin-password": "xxxxxxxxx",
                          "gf_sql_password": "xxxxxxxxx",
                      }
      

    818 526b93cd-c76c-4ade-9c12-8920127a31ca incomplete Create a Sync Notification Topic. Create it and reference it in the secret creation, like here and here.

819 5ddb7f61-eeba-4c45-9227-dc352c27486c incomplete Set up ClusterSecretStore for gcpsm (supports GCP Secret Manager, Infisical, etc.). 820 incomplete Update External Secrets Configuration. 821 incomplete Update ArgoCD Application for external-secrets-config to deploy ClusterSecretStore and external secrets.

Expected outcome:

4. Start migrating apps

822 8000d523-e369-48a5-9fb1-f023435714e8 incomplete Gradually add apps to the ApplicationSet elements list: like here.   823 cf00f678-cffb-43d3-9f08-0ecb47208f19 incomplete  Recommended: You can switch the target revision in argocd-init-app to a feature branch when migration of apps is ongoing: argocd-init-app. This means you don't need to merge to main/master for every app you migrate. 824 b00174f2-d83b-4b5c-8fae-7fa5b9326c0a incomplete Informed the team about the migration? 825 cf3dfb03-e5b9-442a-a1d2-9520f92ae013 incomplete

Start with simple, non-critical apps (no secrets, dev, etc.), e.g. ccc-config, dns-validation

826 3d517e11-63e1-4cc4-a479-7a8349524b1d incomplete

For apps that mount secrets, such as GitLab Runner or Grafana.

827 6fdf0074-4b3d-46e8-873c-77872101efb7 incomplete

Mount the secrets like here

828 b88114df-77b9-42bf-ae05-30b32b3b6f12 incomplete

Update the app config to consume the secrets like here.

829 ae7aaac2-d1ac-405c-8dc3-785aa587071b incomplete

Tip: find /etc/secrets in the config file to understand points where change is required

830 b88114df-77b9-42bf-ae05-30b32b3b6f12 incomplete  ApplicationSets synchronise independently; Expect initial volume mount failures, which should self-heal as secrets become available to the application.

Expected outcome:
  • Apps should be added to the ApplicationSet elements list
- name: <app-name>
  chartRepo: <helm-chart-repo>
  chartPath: charts/<chart-name>/<version>
  namespace: <namespace>
  valueFile: helm/config/<app-name>/gke-infra-<env>-<region>/values.yaml
  • Verified status of pods in ArgoCD shows OK: checked pod health, confirmed secret availability, and ensured application functionality after migration.


5. Validate Deployment

  • Checked ArgoCD app status?
  • UI shows "Healthy" and "Synced", review logs
  • Verified pods are running

kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
- Checked secrets were created (if using external secrets)?

kubectl get externalsecret -n <namespace>
kubectl get secret <secret-name> -n <namespace>
kubectl describe externalsecret <name> -n <namespace>
Expected outcome:
  • Application functionality is tested. No Diffs
  • Service endpoints, logs, metrics

6. Post-Migration Tasks

  • Deleted old Helm release?
helm uninstall <release-name> -n <namespace>
  • Configured Slack notifications?
  • additionalAnnotations in ApplicationSet with notifications.argoproj.io/subscribe

  • Configure monitoring for ArgoCD:

  • Alerts in Alertmanager, like here
  • Grafana: Argocd-operational-overview Dashboard. Import using ID from here