Bootstrapping ArgoCD with Nyl
This guide demonstrates how to bootstrap ArgoCD using Nyl with a self-hosting pattern, where ArgoCD manages itself and all applications through the ApplicationGenerator resource.
Overview
Section titled “Overview”The bootstrap pattern works as follows:
- Manually apply a bootstrap manifest to install ArgoCD
- The bootstrap includes an ArgoCD Application pointing to
apps.yaml - ArgoCD syncs the “apps” Application, running
nyl render apps.yaml - Nyl sees ApplicationGenerator in
apps.yamland scans for NylRelease files - Nyl generates ArgoCD Applications for each found NylRelease
- ArgoCD receives and creates all child Applications
- ArgoCD now manages all applications (including itself) declaratively
Prerequisites
Section titled “Prerequisites”kubectlconfigured with cluster access- Git repository for storing manifests
- Basic understanding of ArgoCD concepts
Directory Structure
Section titled “Directory Structure”Organize your repository as follows:
gitops-repo/├── bootstrap.yaml # Initial bootstrap (apply once manually)├── apps.yaml # ApplicationGenerator definition├── argocd/ # ArgoCD installation manifests│ └── argocd.yaml # HelmChart for ArgoCD├── clusters/│ └── default/ # Applications for default cluster│ ├── app1.yaml # Application 1 with NylRelease│ ├── app2.yaml # Application 2 with NylRelease│ └── app3.yaml # Application 3 with NylRelease├── nyl.toml # Nyl project + profile configuration└── nyl-secrets.yaml # Secrets configurationStep 1: Create Configuration Files
Section titled “Step 1: Create Configuration Files”nyl.toml
Section titled “nyl.toml”[project]components_search_paths = ["components"]helm_chart_search_paths = ["."]
[profile.default.values]# default profile valuesnyl-secrets.yaml
Section titled “nyl-secrets.yaml”type: nullStep 2: Create ArgoCD Installation Manifest
Section titled “Step 2: Create ArgoCD Installation Manifest”Create argocd/argocd.yaml:
apiVersion: nyl.niklasrosenstein.github.com/v1kind: NylReleasemetadata: name: argocd namespace: argocd---apiVersion: v1kind: Namespacemetadata: name: argocd---apiVersion: nyl.niklasrosenstein.github.com/v1kind: HelmChartmetadata: name: argocd namespace: argocdspec: chart: repository: https://argoproj.github.io/argo-helm name: argo-cd version: "5.51.6" values: # ArgoCD configuration server: extraArgs: - --insecure # For testing; use TLS in production
# Configure the Nyl plugin repoServer: volumes: - name: plugins emptyDir: {}
initContainers: - name: install-nyl image: alpine:3.18 command: [sh, -c] args: - | apk add --no-cache curl curl -L https://github.com/NiklasRosenstein/nyl/releases/latest/download/nyl-linux-amd64 \ -o /plugins/nyl chmod +x /plugins/nyl volumeMounts: - name: plugins mountPath: /plugins
volumeMounts: - name: plugins mountPath: /usr/local/bin/nyl subPath: nyl
# Plugin configuration configs: cm: configManagementPlugins: | - name: nyl-v2 generate: command: ["/bin/sh", "-c"] args: - | TEMPLATE_INPUT="${ARGOCD_ENV_NYL_CMP_TEMPLATE_INPUT:-${NYL_CMP_TEMPLATE_INPUT:-}}" test -n "$TEMPLATE_INPUT" || { echo "NYL_CMP_TEMPLATE_INPUT is required" >&2; exit 1; } nyl render "$TEMPLATE_INPUT"NYL_CMP_TEMPLATE_INPUT should usually be source-path-relative (for example apps.yaml when spec.source.path points at that directory). A leading / marks a repository-root-relative path.
Step 3: Create ApplicationGenerator
Section titled “Step 3: Create ApplicationGenerator”Create apps.yaml with the ApplicationGenerator resource:
apiVersion: argocd.nyl.niklasrosenstein.github.com/v1kind: ApplicationGeneratormetadata: name: cluster-apps namespace: argocdspec: # Where to create generated Applications destination: server: https://kubernetes.default.svc namespace: argocd
# Source repository configuration source: repoURL: https://github.com/your-org/gitops-repo.git targetRevision: HEAD path: clusters/default
# Optional: file filtering include: - "*.yaml" - "*.yml" exclude: - ".*" # Skip hidden files - "_*" # Skip files starting with underscore - "apps.yaml" # Avoid recursion
# ArgoCD project for generated Applications project: default
# Default sync policy for all generated Applications syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true
# Labels added to all generated Applications labels: managed-by: nyl generator: cluster-apps
# Annotations added to all generated Applications annotations: docs-url: https://wiki.example.com/cluster-appsStep 4: Create Sample Applications
Section titled “Step 4: Create Sample Applications”Create clusters/default/nginx.yaml:
apiVersion: nyl.niklasrosenstein.github.com/v1kind: NylReleasemetadata: name: nginx namespace: default---apiVersion: nyl.niklasrosenstein.github.com/v1kind: HelmChartmetadata: name: nginx namespace: defaultspec: chart: repository: https://charts.bitnami.com/bitnami name: nginx version: "15.4.4" values: replicaCount: 2 service: type: ClusterIPCreate clusters/default/redis.yaml:
apiVersion: nyl.niklasrosenstein.github.com/v1kind: NylReleasemetadata: name: redis namespace: default---apiVersion: nyl.niklasrosenstein.github.com/v1kind: HelmChartmetadata: name: redis namespace: defaultspec: chart: repository: https://charts.bitnami.com/bitnami name: redis version: "18.4.0" values: architecture: standalone auth: enabled: falseStep 5: Create Bootstrap Manifest
Section titled “Step 5: Create Bootstrap Manifest”Create bootstrap.yaml:
# Namespace for ArgoCDapiVersion: v1kind: Namespacemetadata: name: argocd---# Application to install ArgoCD itselfapiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: argocd namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.iospec: project: default source: repoURL: https://github.com/your-org/gitops-repo.git targetRevision: HEAD path: argocd plugin: name: nyl-v2 destination: server: https://kubernetes.default.svc namespace: argocd syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true---# Application generator that creates all other ApplicationsapiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: apps namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.iospec: project: default source: repoURL: https://github.com/your-org/gitops-repo.git targetRevision: HEAD path: . plugin: name: nyl-v2 destination: server: https://kubernetes.default.svc namespace: argocd syncPolicy: automated: prune: true selfHeal: trueImportant: In the apps Application, the path is . (repository root) because apps.yaml contains the ApplicationGenerator which will scan clusters/default.
Step 6: Bootstrap the Cluster
Section titled “Step 6: Bootstrap the Cluster”- Commit all files to your Git repository:
git add .git commit -m "Initial Nyl + ArgoCD bootstrap"git push origin main- Apply the bootstrap manifest to your cluster:
kubectl apply -f bootstrap.yaml- Wait for ArgoCD to install:
kubectl wait --for=condition=available --timeout=5m \ deployment/argocd-server -n argocd- Access ArgoCD UI:
# Port forward to access UIkubectl port-forward svc/argocd-server -n argocd 8080:443
# Get admin passwordkubectl get secret argocd-initial-admin-secret -n argocd \ -o jsonpath='{.data.password}' | base64 -d- Verify Applications were created:
kubectl get applications -n argocdExpected output:
NAME SYNC STATUS HEALTH STATUSargocd Synced Healthyapps Synced Healthynginx Synced Healthyredis Synced HealthyHow It Works
Section titled “How It Works”When you apply bootstrap.yaml:
- ArgoCD Namespace Created: The
argocdnamespace is created - ArgoCD Application Syncs: ArgoCD installs itself via the Nyl plugin
- Apps Application Syncs: The “apps” Application runs
nyl render "$NYL_CMP_TEMPLATE_INPUT"(for exampleapps.yaml) - ApplicationGenerator Processes: Nyl finds
apps.yaml, sees ApplicationGenerator - Directory Scanned: Nyl scans
clusters/default/for YAML files - Applications Generated: For each NylRelease found (nginx, redis), Nyl generates an ArgoCD Application
- Applications Created: ArgoCD receives the generated Applications and creates them
- Child Applications Sync: Each generated Application syncs its resources to the cluster
Verification
Section titled “Verification”Check Application Status
Section titled “Check Application Status”# View all applicationsargocd app list
# Get details of a specific applicationargocd app get nginx
# View application treeargocd app get nginx --show-operation
# View rendered manifestsargocd app manifests nginxVerify Nyl Plugin
Section titled “Verify Nyl Plugin”# Check if Nyl is available in repo-serverkubectl exec -it deployment/argocd-repo-server -n argocd -- nyl --version
# View plugin configurationkubectl get configmap argocd-cm -n argocd -o yaml | grep -A10 configManagementPluginsView Generated Applications
Section titled “View Generated Applications”# See what ApplicationGenerator producedkubectl exec -it deployment/argocd-repo-server -n argocd -- \ sh -c 'cd /tmp && git clone https://github.com/your-org/gitops-repo.git && \ cd gitops-repo && nyl render apps.yaml'Adding New Applications
Section titled “Adding New Applications”To add a new application to be managed by ArgoCD:
- Create a new YAML file in
clusters/default/:
apiVersion: nyl.niklasrosenstein.github.com/v1kind: NylReleasemetadata: name: postgres namespace: database---apiVersion: v1kind: Namespacemetadata: name: database---apiVersion: nyl.niklasrosenstein.github.com/v1kind: HelmChartmetadata: name: postgres namespace: databasespec: chart: repository: https://charts.bitnami.com/bitnami name: postgresql version: "13.2.24" values: auth: username: myuser database: mydb- Commit and push to Git:
git add clusters/default/postgres.yamlgit commit -m "Add PostgreSQL application"git push origin main- ArgoCD automatically detects the change and creates the
postgresApplication
No manual intervention needed! The ApplicationGenerator pattern discovers new applications automatically.
Troubleshooting
Section titled “Troubleshooting”Applications Not Created
Section titled “Applications Not Created”If generated Applications don’t appear:
-
Check the “apps” Application status:
Terminal window argocd app get apps -
View the rendered manifests:
Terminal window argocd app manifests apps -
Check if ApplicationGenerator is processing correctly:
Terminal window # Should show ArgoCD Applications, not the ApplicationGeneratorargocd app manifests apps | grep "kind: Application"
Plugin Failures
Section titled “Plugin Failures”If the Nyl plugin fails:
-
Check repo-server logs:
Terminal window kubectl logs deployment/argocd-repo-server -n argocd -f -
Verify Nyl installation:
Terminal window kubectl exec deployment/argocd-repo-server -n argocd -- which nylkubectl exec deployment/argocd-repo-server -n argocd -- nyl --version -
Test Nyl render manually:
Terminal window kubectl exec -it deployment/argocd-repo-server -n argocd -- sh# Inside the pod:cd /tmpgit clone <your-repo>cd <repo-name>nyl render apps.yaml
Sync Issues
Section titled “Sync Issues”If Applications fail to sync:
-
Check Application health:
Terminal window argocd app get <app-name> -
View sync operation details:
Terminal window argocd app get <app-name> --show-operation -
Force refresh and sync:
Terminal window argocd app sync <app-name> --force
Next Steps
Section titled “Next Steps”- ApplicationGenerator Reference - Detailed field documentation
- Best Practices - Production recommendations
- Multi-Cluster Setup - Managing multiple clusters