{"id":19299866,"url":"https://github.com/cloudogu/gitops-playground","last_synced_at":"2025-11-20T13:03:30.151Z","repository":{"id":38244006,"uuid":"303955221","full_name":"cloudogu/gitops-playground","owner":"cloudogu","description":"Creates a complete GitOps-based operational stack / IDP on your Kubernetes clusters","archived":false,"fork":false,"pushed_at":"2025-11-18T09:57:42.000Z","size":22388,"stargazers_count":240,"open_issues_count":1,"forks_count":52,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-11-18T10:07:26.217Z","etag":null,"topics":["argo","argocd","gcr","gitops","gitops-playground","gke","gke-cluster","grafana","hashicorp-vault","helm","idp","internal-developer-platform","jenkins","k3d","k3s","k8s","kubernetes","prometheus","scm-manager","vault"],"latest_commit_sha":null,"homepage":"","language":"Groovy","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudogu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-10-14T08:45:46.000Z","updated_at":"2025-11-14T07:07:27.000Z","dependencies_parsed_at":"2023-11-13T14:29:20.275Z","dependency_job_id":null,"html_url":"https://github.com/cloudogu/gitops-playground","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/cloudogu/gitops-playground","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fgitops-playground","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fgitops-playground/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fgitops-playground/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fgitops-playground/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudogu","download_url":"https://codeload.github.com/cloudogu/gitops-playground/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fgitops-playground/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285439531,"owners_count":27171997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-20T02:00:05.334Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argo","argocd","gcr","gitops","gitops-playground","gke","gke-cluster","grafana","hashicorp-vault","helm","idp","internal-developer-platform","jenkins","k3d","k3s","k8s","kubernetes","prometheus","scm-manager","vault"],"created_at":"2024-11-09T23:13:00.872Z","updated_at":"2025-11-20T13:03:30.137Z","avatar_url":"https://github.com/cloudogu.png","language":"Groovy","funding_links":[],"categories":["Groovy"],"sub_categories":[],"readme":"# gitops-playground\n\nCreates a complete GitOps-based operational stack that can be used as an internal developer platform (IDP) on your \nKubernetes clusters:\n\n* Deployment: GitOps via Argo CD with a ready-to-use [repo structure](#argo-cd)\n* Monitoring: [Prometheus and Grafana](#monitoring-tools)\n* Secrets Management:  [Vault and External Secrets Operator](#secrets-management-tools)\n* Notifications/Alerts: Grafana and ArgoCD can be predefined with either an external mailserver or [MailHog](https://github.com/mailhog/MailHog) for demo purposes.\n* Pipelines: Example applications using [Jenkins](#jenkins) with the [gitops-build-lib](https://github.com/cloudogu/gitops-build-lib) and [SCM-Manager](#scm-manager)\n* Ingress Controller: [ingress-nginx](https://github.com/kubernetes/ingress-nginx/)\n* Certificate Management: [cert-manager](#certificate-management)\n* [Content Loader](docs/content-loader/content-loader.md): Completely customize what is pushed to Git during installation.\n  This allows for adding your own end-user or IDP apps, creating repos, adding Argo CD tenants, etc.\n* Runs on: \n  * local cluster (try it [with only one command](#tldr)), \n  * in the public cloud, \n  * and even air-gapped environments.\n\nThe gitops-playground is derived from our experiences in [consulting](https://platform.cloudogu.com/consulting/kubernetes-und-gitops/?mtm_campaign=gitops-playground\u0026mtm_kwd=consulting\u0026mtm_source=github\u0026mtm_medium=link),\noperating our internal developer platform (IDP) at [Cloudogu](https://cloudogu.com/?mtm_campaign=gitops-playground\u0026mtm_kwd=cloudogu\u0026mtm_source=github\u0026mtm_medium=link) and is used in our [GitOps trainings](https://platform.cloudogu.com/en/trainings/gitops-continuous-operations/?mtm_campaign=gitops-playground\u0026mtm_kwd=training\u0026mtm_source=github\u0026mtm_medium=link).  \n\n[![Playground features](docs/gitops-playground-features.drawio.svg)](https://cdn.jsdelivr.net/gh/cloudogu/gitops-playground@main/docs/gitops-playground-features.drawio.svg \"View full size\")\n\n## TL;DR\n\nYou can try the GitOps Playground on a local Kubernetes cluster by running a single command:\n\n```shell\nbash \u003c(curl -s \\\n  https://raw.githubusercontent.com/cloudogu/gitops-playground/main/scripts/init-cluster.sh) \\\n  \u0026\u0026 docker run --rm -t --pull=always -u $(id -u) \\\n    -v ~/.config/k3d/kubeconfig-gitops-playground.yaml:/home/.kube/config \\\n    --net=host \\\n    ghcr.io/cloudogu/gitops-playground --yes --argocd --ingress-nginx --base-url=http://localhost\n# More IDP-features: --mailhog --monitoring --vault=dev --cert-manager\n# More features for developers: --jenkins --registry --content-examples\n```\n\nNote that on some linux distros like debian do not support subdomains of localhost.\nThere you might have to use `--base-url=http://local.gd` (see [local ingresses](#local-ingresses)).\n\nSee the list of [applications](#applications) to get started.\n\nWe recommend running this command as an unprivileged user, that is inside the [docker group](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).\n\n## Table of contents\n\n\u003c!-- Update with `doctoc --notitle README.md --maxlevel 5`. See https://github.com/thlorenz/doctoc --\u003e\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [What is the GitOps Playground?](#what-is-the-gitops-playground)\n- [Installation](#installation)\n  - [Overview](#overview)\n  - [Create Cluster](#create-cluster)\n  - [Apply playground](#apply-playground)\n    - [Apply via Docker (local cluster)](#apply-via-docker-local-cluster)\n    - [Apply via kubectl (remote cluster)](#apply-via-kubectl-remote-cluster)\n    - [Configuration](#configuration)\n      - [Overview of all CLI and config options](#overview-of-all-cli-and-config-options)\n      - [Configuration file](#configuration-file)\n      - [Print all CLI parameters](#print-all-cli-parameters)\n      - [Deploy Ingress Controller](#deploy-ingress-controller)\n      - [Deploy Ingresses](#deploy-ingresses)\n      - [Deploy GitOps operators](#deploy-gitops-operators)\n      - [Deploy with local Cloudogu Ecosystem](#deploy-with-local-cloudogu-ecosystem)\n      - [Deploy with productive Cloudogu Ecosystem and GCR](#deploy-with-productive-cloudogu-ecosystem-and-gcr)\n      - [Override default images](#override-default-images)\n      - [Argo CD-Notifications](#argo-cd-notifications)\n      - [Monitoring](#monitoring)\n      - [Mail server](#mail-server)\n      - [MailHog](#mailhog)\n      - [External Mailserver](#external-mailserver)\n      - [Secrets Management](#secrets-management)\n      - [Certificate Management](#certificate-management)\n  - [Remove playground](#remove-playground)\n  - [Running on Windows or Mac](#running-on-windows-or-mac)\n    - [Mac and Windows WSL](#mac-and-windows-wsl)\n    - [Windows Docker Desktop](#windows-docker-desktop)\n- [Stack](#stack)\n  - [Credentials](#credentials)\n  - [Argo CD](#argo-cd)\n    - [Why not use argocd-autopilot?](#why-not-use-argocd-autopilot)\n    - [cluster-resources](#cluster-resources)\n  - [Jenkins](#jenkins)\n  - [SCMs](#scms)\n    - [SCM-Manager](#scm-manager)\n    - [Gitlab](#gitlab)\n  - [Monitoring tools](#monitoring-tools)\n  - [Secrets Management Tools](#secrets-management-tools)\n    - [dev mode](#dev-mode)\n    - [prod mode](#prod-mode)\n    - [Example app](#example-app)\n  - [Example Applications](#example-applications)\n    - [PetClinic with plain k8s resources](#petclinic-with-plain-k8s-resources)\n    - [PetClinic with helm](#petclinic-with-helm)\n    - [3rd Party app (NGINX) with helm, templated in Jenkins](#3rd-party-app-nginx-with-helm-templated-in-jenkins)\n    - [3rd Party app (NGINX) with helm, using Helm dependency mechanism](#3rd-party-app-nginx-with-helm-using-helm-dependency-mechanism)\n- [Development](#development)\n- [License](#license)\n- [Written Offer](#written-offer)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## What is the GitOps Playground?\n\nThe GitOps Playground provides a reproducible environment for setting up a complete GitOps-based operational stack \nthat can be used as an internal developer platform (IDP) on your Kubernetes clusters.\nIt provides an image for automatically setting up a Kubernetes Cluster including CI-server (Jenkins),\nsource code management (SCM-Manager), Monitoring and Alerting (Prometheus, Grafana, MailHog), Secrets Management (Hashicorp\nVault and External Secrets Operator) and of course, Argo CD as GitOps operator.\n\nThe playground also deploys a number of [example applications](#example-applications).\n\nThe GitOps Playground lowers the barriers for operating your application on Kubernetes using GitOps.\nIt creates a complete GitOps-based operational stack on your Kubernetes clusters.\nNo need to read lots of books and operator\ndocs, getting familiar with CLIs, ponder about GitOps Repository folder structures and promotion to different environments, etc.  \nThe GitOps Playground is a pre-configured environment to see GitOps in motion, including more advanced use cases like\nnotifications, monitoring and secret management.\n\nIn addition to creating an operational stack in production, you can run the playground locally, for learning and developing new features. \n\nWe aim to be compatible with various environments, we even run in an air-gapped networks.\n\n## Installation\n\nThere a several options for running the GitOps playground\n\n* on a local k3d cluster\n  Works best on Linux, but is possible on [Windows and Mac](#windows-or-mac). \n* on a remote k8s cluster\n* each with the option\n    * to use an external Jenkins, SCM-Manager and registry\n      (this can be run in production, e.g. with a [Cloudogu Ecosystem](https://cloudogu.com/en/ecosystem/?mtm_campaign=gitops-playground\u0026mtm_kwd=ces\u0026mtm_source=github\u0026mtm_medium=link)) or\n    * to run everything inside the cluster (for demo only)\n\nThe diagrams below show an overview of the playground's architecture and three scenarios for running the playground.\nFor a simpler overview including all optional features such as monitoring and secrets management see intro at the very top.\n\nNote that running Jenkins inside the cluster is meant for demo purposes only. The third graphic shows our production\nscenario with the Cloudogu EcoSystem (CES). Here better security and build performance is achieved using ephemeral\nJenkins build agents spawned in the cloud.\n\n### Overview\n| Playground on local machine                                                | Production environment with Cloudogu EcoSystem                                       |\n|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------|\n| [![Playground on local machine](docs/gitops-playground-local.drawio.svg)](https://cdn.jsdelivr.net/gh/cloudogu/gitops-playground@main/docs/gitops-playground-local.drawio.svg \"View full size\") | [![A possible production environment](docs/gitops-playground-production.drawio.svg)](https://cdn.jsdelivr.net/gh/cloudogu/gitops-playground@main/docs/gitops-playground-production.drawio.svg \"View full size\") |\n\n### Create Cluster\n\nYou can apply the GitOps playground to \n\n* a local k3d cluster (see [docs](docs/k3d.md) or [script](scripts/init-cluster.sh) for more details):\n  ```shell\n  bash \u003c(curl -s \\\n    https://raw.githubusercontent.com/cloudogu/gitops-playground/main/scripts/init-cluster.sh)\n  ```\n* a remote k8s cluster on Google Kubernetes Engine (e.g. via Terraform, see our [docs](docs/gke.md)),\n* or almost any k8s cluster.  \n  Note that if you want to deploy Jenkins inside the cluster, you either need Docker as container runtime or set Jenkins up to run its build on an agent that provides Docker.\n\nFor the local cluster, you can avoid hitting DockerHub's rate limiting by using a mirror via the `--docker-io-registry-mirror` parameter.\n\nFor example:\n\n```bash\nbash \u003c(curl -s \\\n    https://raw.githubusercontent.com/cloudogu/gitops-playground/main/scripts/init-cluster.sh) --docker-io-registry-mirror https://mirror.gcr.io\n```\n\nThis parameter is passed on the containerd used by k3d. \n\nIn addition, the Jobs run by Jenkins are using the host's Docker daemon.  \nTo avoid rate limits there, you might have to configure a mirror there as well.\nThis can be done in the `/etc/docker/daemon.json` or in the config of Docker Desktop.\n\nFor example:\n```json\n{\n  \"registry-mirrors\": [\"https://mirror.gcr.io\"]\n}\n```\n\n### Apply playground\n\nYou can apply the playground to your cluster using our container image `ghcr.io/cloudogu/gitops-playground`.  \nOn success, the container prints a little intro on how to get started with the GitOps playground.\n\nThere are several options for running the container:\n\n* For local k3d cluster, we recommend running the image as a local container via `docker`\n* For remote clusters (e.g. on GKE) you can run the image inside a pod of the target cluster via `kubectl`.\n\nAll options offer the same parameters, see [below](#overview-of-all-cli-and-config-options).\n\n#### Apply via Docker (local cluster)\n\nWhen connecting to k3d it is easiest to apply the playground via a local container in the host network and pass\nk3d's kubeconfig.\n\n```shell\nCLUSTER_NAME=gitops-playground\ndocker pull ghcr.io/cloudogu/gitops-playground\ndocker run --rm -t -u $(id -u) \\\n  -v ~/.config/k3d/kubeconfig-${CLUSTER_NAME}.yaml:/home/.kube/config \\\n  --net=host \\\n  ghcr.io/cloudogu/gitops-playground # additional parameters go here\n``` \n\nNote:\n* `docker pull` in advance makes sure you have the newest image, even if you ran this command before.  \n  Of course, you could also specify a specific [version of the image](https://github.com/cloudogu/gitops-playground/pkgs/container/gitops-playground/versions).\n* Using the host network makes it possible to determine `localhost` and to use k3d's kubeconfig without altering, as it\n  access the API server via a port bound to localhost.\n* We run as the local user in order to avoid file permission issues with the `kubeconfig-${CLUSTER_NAME}.yaml.`\n* If you experience issues and want to access the full log files, use the following command while the container is running:\n\n```bash\ndocker exec -it \\\n  $(docker ps -q  --filter ancestor=ghcr.io/cloudogu/gitops-playground) \\\n  bash -c -- 'tail -f  -n +1 /tmp/playground-log-*'\n```\n\n#### Apply via kubectl (remote cluster)\n\nFor remote clusters it is easiest to apply the playground via kubectl.\nYou can find info on how to install kubectl [here](https://v1-25.docs.kubernetes.io/docs/tasks/tools/#kubectl).\n\n```shell\n# Create a temporary ServiceAccount and authorize via RBAC.\n# This is needed to install CRDs, etc.\nkubectl create serviceaccount gitops-playground-job-executer -n default\nkubectl create clusterrolebinding gitops-playground-job-executer \\\n  --clusterrole=cluster-admin \\\n  --serviceaccount=default:gitops-playground-job-executer\n\n# Then start apply the playground with the following command:\n# To access services on remote clusters, add either --remote or --ingress-nginx --base-url=$yourdomain\nkubectl run gitops-playground -i --tty --restart=Never \\\n  --overrides='{ \"spec\": { \"serviceAccount\": \"gitops-playground-job-executer\" } }' \\\n  --image ghcr.io/cloudogu/gitops-playground \\\n  -- --yes --argocd # additional parameters go here. \n\n# If everything succeeded, remove the objects\nkubectl delete clusterrolebinding/gitops-playground-job-executer \\\n  sa/gitops-playground-job-executer pods/gitops-playground -n default  \n```\n\nIn general `docker run` should work here as well. But GKE, for example, uses gcloud and python in their kubeconfig.\nRunning inside the cluster avoids these kinds of issues.\n\n#### Configuration\n\nThe following describes how to configure GOP.\n\nYou can configure GOP using CLI params, config file and/or config map.\nConfig file and map have the same format and offer a [schema file](https://raw.githubusercontent.com/cloudogu/gitops-playground/main/docs/configuration.schema.json). \nSee [here](#configuration-file).\nYou can also find a list of all CLI/config options [here](#overview-of-all-cli-and-config-options).\n\n**Configuration precedence (highest to lowest):**\n1. Command-line parameters\n2. Configuration files (`--config-file`)\n3. Config maps (`--config-map`)\n\nThat is, if you pass a param via CLI, for example, it will overwrite the corresponding value in the configuration.\n\n##### Overview of all CLI and config options\n- [Application](#application)\n- [Registry](#registry)\n- [Jenkins](#jenkins)\n- [SCM](#scmtenant)\n  - [SCMM](#scmmtenant)\n  - [GITLAB](#gitlabtenant)\n- [Images](#images)\n- [Features](#argocd)\n    - [ArgoCD](#argocd)\n    - [Mail](#mail)\n    - [Monitoring](#monitoring)\n    - [Secrets](#secrets)\n    - [Ingress Nginx](#ingress-nginx)\n    - [Cert Manager](#cert-manager)\n- [Content](#content)\n- [Multitenant](#multitenant)\n  - [SCMM](#scm-managercentral)\n  - [GITLAB](#gitlabcentral)\n\n###### Application\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--config-file` | - | `''` | String | Config file path |\n| `--config-map` | - | `''` | String | Config map name |\n| `-d, --debug` | `application.debug` | - | Boolean | Enable debug mode |\n| `-x, --trace` | `application.trace` | - | Boolean | Enable trace mode |\n| `--output-config-file` | `application.outputConfigFile` | `false` | Boolean | Output configuration file |\n| `-v, --version` | `application.versionInfoRequested` | `false` | Boolean | Display version and license info |\n| `-h, --help` | `application.usageHelpRequested` | `false` | Boolean | Display help message |\n| `--remote` | `application.remote` | `false` | Boolean | Expose services as LoadBalancers |\n| `--insecure` | `application.insecure` | `false` | Boolean | Sets insecure-mode in cURL which skips cert validation |\n| `--openshift` | `application.openshift` | `false` | Boolean | When set, openshift specific resources and configurations are applied |\n| `--username` | `application.username` | `'admin'` | String | Set initial admin username |\n| `--password` | `application.password` | `'admin'` | String | Set initial admin passwords |\n| `-y, --yes` | `application.yes` | `false` | Boolean | Skip confirmation |\n| `--name-prefix` | `application.namePrefix` | `''` | String | Set name-prefix for repos, jobs, namespaces |\n| `--destroy` | `application.destroy` | `false` | Boolean | Unroll playground |\n| `--pod-resources` | `application.podResources` | `false` | Boolean | Write kubernetes resource requests and limits on each pod |\n| `--git-name` | `application.gitName` | `'Cloudogu'` | String | Sets git author and committer name used for initial commits |\n| `--git-email` | `application.gitEmail` | `'hello@cloudogu.com'` | String | Sets git author and committer email used for initial commits |\n| `--base-url` | `application.baseUrl` | `''` | String | The external base url (TLD) for all tools |\n| `--url-separator-hyphen` | `application.urlSeparatorHyphen` | `false` | Boolean | Use hyphens instead of dots to separate application name from base-url |\n| `--mirror-repos` | `application.mirrorRepos` | `false` | Boolean | Changes the sources of deployed tools so they work in air-gapped environments |\n| `--skip-crds` | `application.skipCrds` | `false` | Boolean | Skip installation of CRDs |\n| `--namespace-isolation` | `application.namespaceIsolation` | `false` | Boolean | Configure tools to work with given namespaces only |\n| `--netpols` | `application.netpols` | `false` | Boolean | Sets Network Policies |\n\n\n###### Registry\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--registry` | `registry.active` | `false` | Boolean | Installs a simple cluster-local registry for demonstration purposes. Warning: Registry does not provide authentication! |\n| `--internal-registry-port` | `registry.internalPort` | `30000` | Integer | Port of registry registry. Ignored when a registry*url params are set |\n| `--registry-url` | `registry.url` | `''` | String | The url of your external registry, used for pushing images |\n| `--registry-path` | `registry.path` | `''` | String | Optional when registry-url is set |\n| `--registry-username` | `registry.username` | `''` | String | Optional when registry-url is set |\n| `--registry-password` | `registry.password` | `''` | String | Optional when registry-url is set |\n| `--registry-proxy-url` | `registry.proxyUrl` | `''` | String | The url of your proxy-registry. Used in pipelines to authorize pull base images |\n| `--registry-proxy-username` | `registry.proxyUsername` | `''` | String | Use with registry-proxy-url, added to Jenkins as credentials and created as pull secrets |\n| `--registry-proxy-password` | `registry.proxyPassword` | `''` | String | Use with registry-proxy-url, added to Jenkins as credentials and created as pull secrets |\n| `--registry-username-read-only` | `registry.readOnlyUsername` | `''` | String | Optional alternative username for registry-url with read-only permissions |\n| `--registry-password-read-only` | `registry.readOnlyPassword` | `''` | String | Optional alternative password for registry-url with read-only permissions |\n| `--create-image-pull-secrets` | `registry.createImagePullSecrets` | `false` | Boolean | Create image pull secrets for registry and proxy-registry for all GOP namespaces |\n| - | `registry.helm.chart` | `'docker-registry'` | String | Name of the Helm chart |\n| - | `registry.helm.repoURL` | `'https://helm.twun.io'` | String | Repository url from which the Helm chart should be obtained |\n| - | `registry.helm.version` | `'2.2.3'` | String | The version of the Helm chart to be installed |\n| - | `registry.helm.values` | `[:]` | Map | Helm values of the chart |\n\n###### Jenkins\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--jenkins` | `jenkins.active` | `false` | Boolean | Installs Jenkins as CI server |\n| `--jenkins-skip-restart` | `jenkins.skipRestart` | `false` | Boolean | Skips restarting Jenkins after plugin installation |\n| `--jenkins-skip-plugins` | `jenkins.skipPlugins` | `false` | Boolean | Skips plugin installation |\n| `--jenkins-url` | `jenkins.url` | `''` | String | The url of your external jenkins |\n| `--jenkins-username` | `jenkins.username` | `'admin'` | String | Mandatory when jenkins-url is set |\n| `--jenkins-password` | `jenkins.password` | `'admin'` | String | Mandatory when jenkins-url is set |\n| `--jenkins-metrics-username` | `jenkins.metricsUsername` | `'metrics'` | String | Mandatory when jenkins-url is set and monitoring enabled |\n| `--jenkins-metrics-password` | `jenkins.metricsPassword` | `'metrics'` | String | Mandatory when jenkins-url is set and monitoring enabled |\n| `--maven-central-mirror` | `jenkins.mavenCentralMirror` | `''` | String | URL for maven mirror, used by applications built in Jenkins |\n| `--jenkins-additional-envs` | `jenkins.additionalEnvs` | `[:]` | Map | Set additional environments to Jenkins |\n| - | `jenkins.helm.chart` | `'jenkins'` | String | Name of the Helm chart |\n| - | `jenkins.helm.repoURL` | `'https://charts.jenkins.io'` | String | Repository url from which the Helm chart should be obtained |\n| - | `jenkins.helm.version` | `'5.8.43'` | String | The version of the Helm chart to be installed |\n| - | `jenkins.helm.values` | `[:]` | Map | Helm values of the chart |\n\n###### Scm(Tenant)\n\n| CLI              | Config                          | Default      | Type                    | Description                                                           |\n|------------------|---------------------------------|--------------|-------------------------|-----------------------------------------------------------------------|\n| `--scm-provider` | `scmTenant.scmProviderType`     | `SCM_MANAGER` | ScmProviderType         | Specifies the SCM provider type. Possible values: `SCM_MANAGER`, `GITLAB`. |\n|                  | `scmTenant.gitOpsUsername`      | `''`         | String                  | The username for the GitOps user.                                      |\n|                  | `scmTenant.gitlab`              | `''`         | GitlabTenantConfig      | Configuration for GitLab, including URL, username, token, and parent group ID. |\n|                  | `scmTenant.scmManager`          | `''`         | ScmManagerTenantConfig  | Configuration for SCM Manager, such as internal setup or plugin handling. |\n\n###### SCMM(Tenant)\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--scmm-skip-restart` | `scmm.skipRestart` | `false` | Boolean | Skips restarting SCM-Manager after plugin installation |\n| `--scmm-skip-plugins` | `scmm.skipPlugins` | `false` | Boolean | Skips plugin installation |\n| `--scmm-url` | `scmm.url` | `''` | String | The host of your external scm-manager |\n| `--scmm-username` | `scmm.username` | `'admin'` | String | Mandatory when scmm-url is set |\n| `--scmm-password` | `scmm.password` | `'admin'` | String | Mandatory when scmm-url is set |\n| `--scm-root-path` | `scmm.rootPath` | `'repo'` | String | Sets the root path for the Git Repositories |\n| - | `scmm.helm.chart` | `'scm-manager'` | String | Name of the Helm chart |\n| - | `scmm.helm.repoURL` | `'https://packages.scm-manager.org/repository/helm-v2-releases/'` | String | Repository url from which the Helm chart should be obtained |\n| - | `scmm.helm.version` | `'3.10.2'` | String | The version of the Helm chart to be installed |\n| - | `scmm.helm.values` | `[:]` | Map | Helm values of the chart |\n\n\n###### Gitlab(Tenant)\n\n| CLI               | Config             | Default   | Type   | Description                                                                                                |\n|-------------------|--------------------|-----------|--------|------------------------------------------------------------------------------------------------------------|\n| `--gitlab-url`    | `gitlabTenant.url` | `''`      | String | Base URL for the GitLab instance.                                                                          |\n| `--gitlab-username` | `gitlabTenant.username` | `'oauth2.0'` | String | Defaults to: `oauth2.0` when a PAT token is provided.                                                      |\n| `--gitlab-token`  | `gitlabTenant.password` | `''`      | String | PAT token for the account.                                                                                 |\n| `--gitlab-parent-id` | `gitlabTenant.parentGroupId` | `''`  | String | The numeric ID for the GitLab Group where repositories and subgroups should be created.                    |\n|                   | `gitlabTenant.internal` | `false`  | Boolean | Indicates if GitLab is running in the same Kubernetes cluster. Currently only external URLs are supported. |\n\n\n###### Images\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--kubectl-image` | `images.kubectl` | `\"bitnamilegacy/kubectl:1.29\"` | String | Sets image for kubectl |\n| `--helm-image` | `images.helm` | `\"ghcr.io/cloudogu/helm:3.16.4-1\"` | String | Sets image for helm |\n| `--kubeval-image` | `images.kubeval` | `\"ghcr.io/cloudogu/helm:3.16.4-1\"` | String | Sets image for kubeval |\n| `--helmkubeval-image` | `images.helmKubeval` | `\"ghcr.io/cloudogu/helm:3.16.4-1\"` | String | Sets image for helmkubeval |\n| `--yamllint-image` | `images.yamllint` | `\"cytopia/yamllint:1.25-0.7\"` | String | Sets image for yamllint |\n| `--nginx-image` | `images.nginx` | `''` | String | Sets image for nginx |\n| `--petclinic-image` | `images.petclinic` | `'eclipse-temurin:17-jre-alpine'` | String | Sets image for petclinic |\n| `--maven-image` | `images.maven` | `''` | String | Sets image for maven |\n\n###### ArgoCD\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--argocd` | `features.argocd.active` | `false` | Boolean | Installs ArgoCD as GitOps CD tool |\n| `--argocd-operator` | `features.argocd.operator` | `false` | Boolean | Install ArgoCD operator |\n| `--argocd-url` | `features.argocd.url` | `''` | String | The url of your external argocd |\n| `--argocd-email-from` | `features.argocd.emailFrom` | `'argocd@example.org'` | String | Email from address for ArgoCD notifications |\n| `--argocd-email-to-user` | `features.argocd.emailToUser` | `'app-team@example.org'` | String | Email to address for user notifications |\n| `--argocd-email-to-admin` | `features.argocd.emailToAdmin` | `'infra@example.org'` | String | Email to address for admin notifications |\n| `--argocd-resource-inclusions-cluster` | `features.argocd.resourceInclusionsCluster` | `''` | String | ArgoCD resource inclusions for cluster |\n| `--argocd-namespace` | `features.argocd.namespace` | `'argocd'` | String | ArgoCD namespace |\n| - | `features.argocd.env` | - | List | Environment variables for ArgoCD |\n\n###### Mail\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--mailhog, --mail` | `features.mail.mailhog` | `false` | Boolean | Installs Mailhog as email testing tool |\n| `--mailhog-url` | `features.mail.mailhogUrl` | `''` | String | The url of your external mailhog |\n| `--smtp-address` | `features.mail.smtpAddress` | `''` | String | SMTP server address |\n| `--smtp-port` | `features.mail.smtpPort` | `null` | Integer | SMTP server port |\n| `--smtp-user` | `features.mail.smtpUser` | `''` | String | SMTP username |\n| `--smtp-password` | `features.mail.smtpPassword` | `''` | String | SMTP password |\n| `--mailhog-image` | `features.mail.helm.image` | `'ghcr.io/cloudogu/mailhog:v1.0.1'` | String | Mailhog container image |\n| - | `features.mail.helm.chart` | `'mailhog'` | String | Name of the Helm chart |\n| - | `features.mail.helm.repoURL` | `'https://codecentric.github.io/helm-charts'` | String | Repository url from which the Helm chart should be obtained |\n| - | `features.mail.helm.version` | `'5.0.1'` | String | The version of the Helm chart to be installed |\n| - | `features.mail.helm.values` | `[:]` | Map | Helm values of the chart |\n\n###### Monitoring\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--metrics, --monitoring` | `features.monitoring.active` | `false` | Boolean | Installs monitoring stack (Prometheus, Grafana) |\n| `--grafana-url` | `features.monitoring.grafanaUrl` | `''` | String | The url of your external grafana |\n| `--grafana-email-from` | `features.monitoring.grafanaEmailFrom` | `'grafana@example.org'` | String | Email from address for Grafana notifications |\n| `--grafana-email-to` | `features.monitoring.grafanaEmailTo` | `'infra@example.org'` | String | Email to address for Grafana notifications |\n| `--grafana-image` | `features.monitoring.helm.grafanaImage` | `''` | String | Grafana container image |\n| `--grafana-sidecar-image` | `features.monitoring.helm.grafanaSidecarImage` | `''` | String | Grafana sidecar container image |\n| `--prometheus-image` | `features.monitoring.helm.prometheusImage` | `''` | String | Prometheus container image |\n| `--prometheus-operator-image` | `features.monitoring.helm.prometheusOperatorImage` | `''` | String | Prometheus operator container image |\n| `--prometheus-config-reloader-image` | `features.monitoring.helm.prometheusConfigReloaderImage` | `''` | String | Prometheus config reloader container image |\n| - | `features.monitoring.helm.chart` | `'kube-prometheus-stack'` | String | Name of the Helm chart |\n| - | `features.monitoring.helm.repoURL` | `'https://prometheus-community.github.io/helm-charts'` | String | Repository url from which the Helm chart should be obtained |\n| - | `features.monitoring.helm.version` | `'69.7.4'` | String | The version of the Helm chart to be installed |\n| - | `features.monitoring.helm.values` | `[:]` | Map | Helm values of the chart |\n\n###### Secrets\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--vault` | `features.secrets.vault.mode` | - | VaultMode | Install Vault for secrets management |\n| `--vault-url` | `features.secrets.vault.url` | `''` | String | The url of your external vault |\n| `--vault-image` | `features.secrets.vault.helm.image` | `''` | String | Vault container image |\n| `--external-secrets-image` | `features.secrets.externalSecrets.helm.image` | `''` | String | External secrets operator image |\n| `--external-secrets-certcontroller-image` | `features.secrets.externalSecrets.helm.certControllerImage` | `''` | String | External secrets cert controller image |\n| `--external-secrets-webhook-image` | `features.secrets.externalSecrets.helm.webhookImage` | `''` | String | External secrets webhook image |\n| - | `features.secrets.vault.helm.chart` | `'vault'` | String | Name of the Helm chart |\n| - | `features.secrets.vault.helm.repoURL` | `'https://helm.releases.hashicorp.com'` | String | Repository url from which the Helm chart should be obtained |\n| - | `features.secrets.vault.helm.version` | `'0.25.0'` | String | The version of the Helm chart to be installed |\n| - | `features.secrets.externalSecrets.helm.chart` | `'external-secrets'` | String | Name of the Helm chart |\n| - | `features.secrets.externalSecrets.helm.repoURL` | `'https://charts.external-secrets.io'` | String | Repository url from which the Helm chart should be obtained |\n| - | `features.secrets.externalSecrets.helm.version` | `'0.9.16'` | String | The version of the Helm chart to be installed |\n\n###### Ingress Nginx\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--ingress-nginx` | `features.ingressNginx.active` | `false` | Boolean | Install Ingress Nginx controller |\n| `--ingress-nginx-image` | `features.ingressNginx.helm.image` | `''` | String | Ingress Nginx controller image |\n| - | `features.ingressNginx.helm.chart` | `'ingress-nginx'` | String | Name of the Helm chart |\n| - | `features.ingressNginx.helm.repoURL` | `'https://kubernetes.github.io/ingress-nginx'` | String | Repository url from which the Helm chart should be obtained |\n| - | `features.ingressNginx.helm.version` | `'4.12.1'` | String | The version of the Helm chart to be installed |\n| - | `features.ingressNginx.helm.values` | `[:]` | Map | Helm values of the chart |\n\n###### Cert Manager\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--cert-manager` | `features.certManager.active` | `false` | Boolean | Install cert-manager for TLS certificate management |\n| `--cert-manager-image` | `features.certManager.helm.image` | `''` | String | Cert-manager controller image |\n| `--cert-manager-webhook-image` | `features.certManager.helm.webhookImage` | `''` | String | Cert-manager webhook image |\n| `--cert-manager-cainjector-image` | `features.certManager.helm.cainjectorImage` | `''` | String | Cert-manager CA injector image |\n| `--cert-manager-acme-solver-image` | `features.certManager.helm.acmeSolverImage` | `''` | String | Cert-manager ACME solver image |\n| `--cert-manager-startup-api-check-image` | `features.certManager.helm.startupAPICheckImage` | `''` | String | Cert-manager startup API check image |\n| - | `features.certManager.helm.chart` | `'cert-manager'` | String | Name of the Helm chart |\n| - | `features.certManager.helm.repoURL` | `'https://charts.jetstack.io'` | String | Repository url from which the Helm chart should be obtained |\n| - | `features.certManager.helm.version` | `'1.16.1'` | String | The version of the Helm chart to be installed |\n| - | `features.certManager.helm.values` | `[:]` | Map | Helm values of the chart |\n\n###### Content\n\n| CLI | Config | Default | Type | Description |\n|-----|--------|---------|------|-------------|\n| `--content-examples` | `content.examples` | `false` | Boolean | Deploy example content: source repos, GitOps repos, Jenkins Job, Argo CD apps/project |\n| - | `content.namespaces` | `[]` | List | Additional kubernetes namespaces |\n| - | `content.repos` | `[]` | List | Content repos to push into target environment |\n| - | `content.variables` | `[:]` | Map | Additional variables to use in custom templates |\n| - | `content.repos[].url` | `''` | String | URL of the content repo. Mandatory for each type |\n| - | `content.repos[].path` | `'.'` | String | Path within the content repo to process |\n| - | `content.repos[].ref` | `''` | String | Reference for a specific branch, tag, or commit |\n| - | `content.repos[].targetRef` | `''` | String | Reference for a specific branch or tag in the target repo |\n| - | `content.repos[].username` | `''` | String | Username to authenticate against content repo |\n| - | `content.repos[].password` | `''` | String | Password to authenticate against content repo |\n| - | `content.repos[].templating` | `false` | Boolean | When true, template all files ending in .ftl within the repo |\n| - | `content.repos[].type` | `MIRROR` | ContentRepoType | Content repo type (FOLDER_BASED, COPY, MIRROR) |\n| - | `content.repos[].target` | `''` | String | Target repo for the repository in the form of namespace/name |\n| - | `content.repos[].overwriteMode` | `INIT` | OverwriteMode | How customer repos will be updated (INIT, RESET, UPGRADE) |\n| - | `content.repos[].createJenkinsJob` | `false` | Boolean | If true, creates a Jenkins job |\n\n###### MultiTenant\n\n| CLI                          | Config                              | Default       | Type                     | Description                                                    |\n|------------------------------|-------------------------------------|---------------|--------------------------|----------------------------------------------------------------|\n| `--dedicated-instance`       | `multiTenant.useDedicatedInstance`  | `false`       | Boolean                  | Toggles the Dedicated Instances Mode. See docs for more info   |\n| `--central-argocd-namespace` | `multiTenant.centralArgocdNamespace`| `'argocd'`    | String                   | Namespace for the centralized Argocd                           |\n| `--central-scm-provider`     | `multiTenant.scmProviderType`       | `SCM_MANAGER` | ScmProviderType          | The SCM provider type. Possible values: `SCM_MANAGER`, `GITLAB`|\n|                              | `multiTenant.gitlab`                | ``        | GitlabCentralConfig      | Config for GITLAB                                              |\n|                              | `multiTenant.scmManager`            | ``        | ScmManagerCentralConfig  | Config for SCM Manager                                         |\n\n###### Gitlab(Central)\n\n| CLI                          | Config                         | Default     | Type    | Description                                                      |\n|------------------------------|--------------------------------|-------------|---------|------------------------------------------------------------------|\n| `--central-gitlab-url`       | `multiTenant.gitlab.url`       | `''`        | String  | URL for external Gitlab                                          |\n| `--central-gitlab-username`  | `multiTenant.gitlab.username`  | `'oauth2.0'`| String  | Username for GitLab authentication                               |\n| `--central-gitlab-token`     | `multiTenant.gitlab.password`  | `''`        | String  | Password for SCM Manager authentication                          |\n| `--central-gitlab-group-id`  | `multiTenant.gitlab.parentGroupId` | `''`    | String  | Main Group for Gitlab where the GOP creates it's groups/repos    |\n|                              | `multiTenant.gitlab.internal`  | `false`     | Boolean | SCM is running on the same cluster (only external supported now) |\n\n###### Scm-Manager(Central)\n\n| CLI                          | Config                              | Default         | Type    | Description                                                                          |\n|------------------------------|-------------------------------------|-----------------|---------|--------------------------------------------------------------------------------------|\n| `--central-scmm-internal`    | `multiTenant.scmManager.internal`   | `false`         | Boolean | SCM for Central Management is running on the same cluster, so k8s internal URLs can be used for access |\n| `--central-scmm-url`         | `multiTenant.scmManager.url`        | `''`            | String  | URL for the centralized Management Repo                                              |\n| `--central-scmm-username`    | `multiTenant.scmManager.username`   | `''`            | String  | CENTRAL SCMM USERNAME                                                                |\n| `--central-scmm-password`    | `multiTenant.scmManager.password`   | `''`            | String  | CENTRAL SCMM Password                                                                |\n| `--central-scmm-root-path`   | `multiTenant.scmManager.rootPath`   | `'repo'`        | String  | Root path for SCM Manager                                                            |\n| `--central-scmm-namespace`   | `multiTenant.scmManager.namespace`  | `'scm-manager'` | String  | Namespace where to find the Central SCMM                                             |\n\n##### Configuration file\n\nYou can also use a configuration file to specify the parameters (`--config-file` or `--config-map`).\nThat file must be a YAML file. \n\nNote that the config file is not yet a complete replacement for CLI parameters.\n\nYou can use `--output-config-file` to output the current config as set by defaults and CLI parameters.\n\nIn addition, For easier validation and auto-completion, we provide a [schema file](https://raw.githubusercontent.com/cloudogu/gitops-playground/main/docs/configuration.schema.json).\n\nFor example in Jetbrains IntelliJ IDEA, you can use the schema for autocompletion and validation when you put the following at the beginning of your config file:\n\n```yaml\n# $schema: https://raw.githubusercontent.com/cloudogu/gitops-playground/main/docs/configuration.schema.json\n```\n\nIf you work with an older version, you can use a specific git commit ID instead of `main` in the schema URL.\n\nThen use the context assistant to enable coding assistance or fill in all available properties.\nSee [here](https://www.jetbrains.com/help/ruby/yaml.html#use-schema-keyword) for the full manual.\n\n![example of a config file inside Jetbrains IntelliJ IDEA](docs/config-file-assistant.png)\n\n###### Apply via Docker\n\n```bash\ndocker run --rm -t --pull=always -u $(id -u) \\\n    -v ~/.config/k3d/kubeconfig-gitops-playground.yaml:/home/.kube/config \\\n    -v $(pwd)/gitops-playground.yaml:/config/gitops-playground.yaml \\\n    --net=host \\\n    ghcr.io/cloudogu/gitops-playground --yes --argocd --config-file=/config/gitops-playground.yaml\n```\n\n###### Apply via kubectl\n\n[Create the serviceaccount and clusterrolebinding](#apply-via-kubectl-remote-cluster)\n\n```bash\n$ cat config.yaml # for example\nfeatures: \n  monitoring:\n    active: true\n\n# Convention:\n# Find the ConfigMap inside the current namespace for the config map\n# From the config map, pick the key \"config.yaml\"\nkubectl create configmap gitops-config --from-file=config.yaml\n\nkubectl run gitops-playground -i --tty --restart=Never \\\n  --overrides='{ \"spec\": { \"serviceAccount\": \"gitops-playground-job-executer\" } }' \\\n  --image ghcr.io/cloudogu/gitops-playground \\\n  -- --yes --argocd --config-map=gitops-config\n```\n\nAfterwards, you might want to do a [clean up](#apply-via-kubectl-remote-cluster).\nIn addition, you might want to delete the config-map as well.\n\n``` bash\nkubectl delete cm gitops-config \n```\n\n\n##### Print all CLI parameters\n\nYou can get a full list of all CLI options like so:\n\n```shell\ndocker run -t --rm ghcr.io/cloudogu/gitops-playground --help\n```\n\n##### Deploy Ingress Controller\n\nIn the default installation the GitOps-Playground comes without an Ingress-Controller.  \n\nWe use Nginx as default Ingress-Controller.\nIt can be enabled via the configfile or parameter `--ingress-nginx`.\n\nIn order to make use of the ingress controller, it is recommended to use it in conjunction with [`--base-url`](#deploy-ingresses), which will create `Ingress` objects for all components of the GitOps playground.\n\nThe ingress controller is based on the helm chart [`ingress-nginx`](https://kubernetes.github.io/ingress-nginx).\n\nAdditional parameters from this chart's values.yaml file can be added to the installation through the gitops-playground [configuration file](#configuration-file).\n\nExample:\n```yaml\nfeatures:\n  ingressNginx:\n    active: true\n    helm:\n      values:\n        controller:\n          replicaCount: 4\n```\nIn this Example we override the default `controller.replicaCount` (GOP's default is 2).\n\nThis config file is merged with precedence over the defaults set by \n* [the GOP](applications/cluster-resources/ingress-nginx-helm-values.ftl.yaml) and\n* [the charts itself](https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/values.yaml).\n\n##### Deploy Ingresses\n\nIt is possible to deploy `Ingress` objects for all components. You can either\n\n* set a common base url (`--base-url=https://example.com`) or\n* individual URLS:\n```\n--argocd-url https://argocd.example.com \n--grafana-url https://grafana.example.com \n--vault-url https://vault.example.com \n--mailhog-url https://mailhog.example.com \n--petclinic-base-domain petclinic.example.com \n--nginx-base-domain nginx.example.com\n```\n* or both, where the individual URLs take precedence.\n\nNote: \n* `jenkins-url` and `scmm-url` are for external services and do not lead to ingresses, but you can set them via `--base-url` for now.\n* In order to make use of the `Ingress` you need an ingress controller.\n  If your cluster does not provide one, the Playground can deploy one for you, via the [`--ingress-nginx` parameter](#deploy-ingress-controller).\n* For this to work, you need to set an `*.example.com` DNS record to the externalIP of the ingress controller.\n\nAlternatively, [hyphen-separated ingresses](#subdomains-vs-hyphen-separated-ingresses) can be created,\nlike http://argocd-example.com\n\n###### Subdomains vs hyphen-separated ingresses\n\n* By default, the ingresses are built as subdomains of `--base-url`.  \n* You can change this behavior using the parameter `--url-separator-hyphen`.  \n* With this, hyphens are used instead of dots to separate application name from base URL.\n* Examples: \n  * `--base-url=https://xyz.example.org`: `argocd.xyz.example.org` (default)  \n  * `--base-url=https://xyz.example.org`: `argocd-xyz.example.org` (`--url-separator-hyphen`)\n* This is useful when you have a wildcard certificate for the TLD, but use a subdomain as base URL.  \n  Here, browsers accept the validity only for the first level of subdomains.\n\n###### Local ingresses\n\nThe ingresses can also be used when running the playground on your local machine:\n\n* Ingresses might be easier to remember than arbitrary port numbers and look better in demos \n* With ingresses, we can execute our [local clusters](docs/k3d.md) in higher isolation or multiple playgrounds concurrently\n* Ingresses are required [for running on Windows/Mac](#windows-or-mac).\n\nTo use them locally, \n* init your cluster (`init-cluster.sh`).\n* apply your playground with the following parameters  \n  * `--base-url=http://localhost` \n    * this is possible on Windows (tested on 11), Mac (tested on Ventura) or when using Linux with [systemd-resolved](https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html) (default in Ubuntu, not Debian)  \n      As an alternative, you could add all `*.localhost` entries to your `hosts` file.  \n      Use `kubectl get ingress -A` to get a full list \n    * Then, you can reach argocd on `http://argocd.localhost`, for example\n  * `--base-url=http://local.gd` (or `127.0.0.1.nip.io`, `127.0.0.1.sslip.io`, or others)\n    * This should work for all other machines that have access to the internet without further config \n    * Then, you can reach argocd on `http://argocd.local.gd`, for example\n* Note that when using port 80, the URLs are shorter, but you run into issues because port 80 is regarded as a privileged port. \n  Java applications seem not to be able to reach `localhost:80` or even `127.0.0.1:80` (`NoRouteToHostException`)\n* You can change the port using `init-cluster.sh --bind-ingress-port=8080`.  \n  When you do, make sure to append the same port when applying the playground: `--base-url=http://localhost:8080`\n* If your setup requires you to bind to a specific interface, you can just pass it with e.g. `--bind-ingress-port=127.0.0.1:80`\n\n##### Deploy GitOps operators\n\n* `--argocd` - deploy Argo CD GitOps operator\n\n\u003e ⚠️ **Note** that switching between operators is not supported.  \n\u003e That is, expect errors (for example with cluster-resources) if you apply the playground once with Argo CD and the next\n\u003e time without it. We recommend resetting the cluster with `init-cluster.sh` beforehand.\n\n##### Deploy with local Cloudogu Ecosystem\n\nSee our [Quickstart Guide](https://cloudogu.com/en/ecosystem/quick-start-guide/?mtm_campaign=gitops-playground\u0026mtm_kwd=ces\u0026mtm_source=github\u0026mtm_medium=link) on how to set up the instance.  \nThen set the following parameters.\n\n```shell\n# Note: \n# * In this case --password only sets the Argo CD admin password (Jenkins and \n#    SCMM are external)\n# * Insecure is needed, because the local instance will not have a valid cert\n--jenkins-url=https://192.168.56.2/jenkins \\ \n--scmm-url=https://192.168.56.2/scm \\\n--jenkins-username=admin \\\n--jenkins-password=yourpassword \\\n--scmm-username=admin \\\n--scmm-password=yourpassword \\\n--password=yourpassword \\\n--insecure\n```\n\n##### Deploy with productive Cloudogu Ecosystem and GCR\n\nUsing Google Container Registry (GCR) fits well with our cluster creation example via Terraform on Google Kubernetes Engine\n(GKE), see our [docs](docs/gke.md).\n\nNote that you can get a free CES demo instance set up with a Kubernetes Cluster as GitOps Playground\n[here](https://cloudogu.com/en/ecosystem/demo-appointment/?mtm_campaign=gitops-playground\u0026mtm_kwd=ces\u0026mtm_source=github\u0026mtm_medium=link).\n\n```shell\n# Note: In this case --password only sets the Argo CD admin password (Jenkins \n# and SCMM are external) \n--jenkins-url=https://your-ecosystem.cloudogu.net/jenkins \\ \n--scmm-url=https://your-ecosystem.cloudogu.net/scm \\\n--jenkins-username=admin \\\n--jenkins-password=yourpassword \\\n--scmm-username=admin \\\n--scmm-password=yourpassword \\\n--password=yourpassword \\\n--registry-url=eu.gcr.io \\\n--registry-path=yourproject \\\n--registry-username=_json_key \\ \n--registry-password=\"$( cat account.json | sed 's/\"/\\\\\"/g' )\" \n```\n\n##### Override default images\n\n###### gitops-build-lib\n\nImages used by the gitops-build-lib are set in the `gitopsConfig` in each `Jenkinsfile` of an application like that:\n\n```\ndef gitopsConfig = [\n    ...\n    buildImages          : [\n            helm: 'ghcr.io/cloudogu/helm:3.10.3-1',\n            kubectl: 'bitnamilegacy/kubectl:1.29',\n            kubeval: 'ghcr.io/cloudogu/helm:3.10.3-1',\n            helmKubeval: 'ghcr.io/cloudogu/helm:3.10.3-1',\n            yamllint: 'cytopia/yamllint:1.25-0.7'\n    ],...\n```\n\nTo override each image in all the applications you can use following parameters:\n\n* `--kubectl-image someRegistry/someImage:1.0.0`\n* `--helm-image someRegistry/someImage:1.0.0`\n* `--kubeval-image someRegistry/someImage:1.0.0`\n* `--helmkubeval-image someRegistry/someImage:1.0.0`\n* `--yamllint-image someRegistry/someImage:1.0.0`\n\n###### Tools and Exercises\n\nImages used by various tools and exercises can be configured using the following parameters:\n\n* `--grafana-image someRegistry/someImage:1.0.0`\n* `--external-secrets-image someRegistry/someImage:1.0.0`\n* `--external-secrets-certcontroller-image someRegistry/someImage:1.0.0`\n* `--external-secrets-webhook-image someRegistry/someImage:1.0.0`\n* `--vault-image someRegistry/someImage:1.0.0`\n* `--nginx-image someRegistry/someImage:1.0.0`\n* `--maven-image someRegistry/someImage:1.0.0`\n\nNote that specifying a tag is mandatory.  \n  \n  \n  \n##### Argo CD-Notifications\n\nIf you are using a remote cluster, you can set the `--argocd-url` parameter so that argocd-notification messages have a\nlink to the corresponding application.\nOtherwise, `argocd.$base-url` is used.\n\nYou can specify email addresses for notifications (note that by default, MailHog will not actually send emails)\n\n* `--argocd-email-from`: Sender E-Mail address. Default is `argocd@example.org`)\n* `--argocd-email-to-admin`: Alerts send to admin. Default is `infra@example.org`)\n* `--argocd-email-to-user`: Alerts send to user. Default is `app-team@example.org`)\n\n\n##### Monitoring\n\nSet the parameter `--monitoring` to enable deployment of monitoring and alerting tools like prometheus, grafana and mailhog.\n\nSee [Monitoring tools](#monitoring-tools) for details.\n\nYou can specify email addresses for notifications (note that by default, MailHog will not actually send emails)\n\n* `--grafana-email-from`: Sender E-Mail address. Default is `grafana@example.org`\n* `--grafana-email-to`: Recipient E-Mail address. Default is `infra@example.org`\n\n##### Mail server\n\nThe gitops-playground uses MailHog to showcase notifications.  \nAlternatively, you can configure an external mailserver.\n\nNote that you can't use both at the same time.   \nIf you set either `--mailhog` or `--mail` parameter, MailHog will be installed  \nIf you set `--smtp-*` parameters, a external Mailserver will be used and MailHog will not be deployed.\n\n##### MailHog\nSet the parameter `--mailhog` to enable MailHog.\n\nThis will deploy MailHog and configure Argo CD and Grafana to send mails to MailHog.  \nSender and recipient email addresses can be set via parameters in some applications, e.g. `--grafana-email-from` or `--argocd-email-to-user`.\n\nParameters:\n* `--mailhog`: Activate MailHog as internal Mailserver\n* `--mailhog-url`: Specify domain name (ingress) under which MailHog will be served\n\n##### External Mailserver\nIf you want to use an external Mailserver you can set it with these parameters\n\n* `--smtp-address`: External Mailserver SMTP address or IP\n* `--smtp-port`: External Mailserver SMTP port\n* `--smtp-user`: External Mailserver login username\n* `--smtp-password`: External Mailservers login password. Make sure to put your password in single quotes.\n\nThis will configure Argo CD and Grafana to send mails using your external mailserver.  \nIn addition you should set matching sender and recipient email addresses, e.g. `--grafana-email-from` or `--argocd-email-to-user`.\n\n##### Secrets Management\n\nSet the parameter `--vault=[dev|prod]` to enable deployment of secret management tools hashicorp vault and external\nsecrets operator.\n\n`--vault-url` specifies domain name, Otherwise, `vault.$base-url` is used.\n\n\n\nSee [Secrets management tools](#secrets-management-tools) for details.\n\n##### Certificate Management\nIs implemented by cert-manager. \nSet the parameter `--cert-manager` to enable cert-manager.\nFor custom images use this parameters to override defaults:\n- --cert-manager-image \n- --cert-manager-webhook-image \n- --cert-manager-cainjector-image \n- --cert-manager-acme-solver-image\n- --cert-manager-startup-api-check-image\n\ni.e.\n```\n--cert-manager-image someRegistry/cert-manager-controller:latest\n``` \n### Remove playground\n\nFor k3d, you can just `k3d cluster delete gitops-playground`. This will delete the whole cluster.\nIf you want to delete k3d use `rm .local/bin/k3d`.\n\nTo remove the playground without deleting the cluster, use the option `--destroy`.\nYou need to pass the same parameters when deploying the playground to ensure that the destroy script \ncan authenticate with all tools.\nNote that this option has limitations. It does not remove CRDs, namespaces, locally deployed SCM-Manager, Jenkins and registry, plugins for SCM-Manager and Jenkins \n\n### Running on Windows or Mac\n\n* In general: We cannot use the `host` network, so it's easiest to access via [ingress controller](#deploy-ingress-controller) and [ingresses](#local-ingresses).\n* `--base-url=http://localhost --ingress-nginx` should work on both Windows and Mac.\n* In case of problems resolving e.g. `jenkins.localhost`, you could try using `--base-url=http://local.gd` or similar, as described in [local ingresses](#local-ingresses).\n\n#### Mac and Windows WSL\n\nOn macOS and when using the Windows Subsystem Linux on Windows (WSL), you can just run our [TL;DR command](#tldr) after installing Docker.\n\nFor Windows, we recommend using [Windows Subsystem for Linux version 2](https://learn.microsoft.com/en-us/windows/wsl/install#install-wsl-command) (WSL2) with a [native installation of Docker Engine](https://docs.docker.com/engine/install/), because it's easier to set up and less prone to errors.\n\nFor macOS, please increase the Memory limit in Docker Desktop (for your DockerVM) to be \u003e 10 GB.\nRecommendation: 16GB.\n\n```bash\nbash \u003c(curl -s \\\n  https://raw.githubusercontent.com/cloudogu/gitops-playground/main/scripts/init-cluster.sh) \\\n  \u0026\u0026 docker run --rm -t --pull=always -u $(id -u) \\\n    -v ~/.config/k3d/kubeconfig-gitops-playground.yaml:/home/.kube/config \\\n    --net=host \\\n    ghcr.io/cloudogu/gitops-playground --yes --argocd --ingress-nginx --base-url=http://localhost\n# If you want to try all features, you might want to add these params: --mail --monitoring --vault=dev\n```\n\nWhen you encounter errors with port 80 you might want to use e.g. \n* `init-cluster.sh) --bind-ingress-port=8080` and \n* `--base-url=http://localhost:8080` instead.\n\n#### Windows Docker Desktop\n\n* As mentioned in the previous section, we recommend using WSL2 with a native Docker Engine.\n* If you must, you can also run using Docker Desktop from native Windows console (see bellow)\n* However, there seems to be a problem when the Jenkins Jobs running the playground access docker, e.g.   \n```\n$ docker run -t -d -u 0:133 -v ... -e ******** bitnamilegacy/kubectl:1.25.4 cat\ndocker top e69b92070acf3c1d242f4341eb1fa225cc40b98733b0335f7237a01b4425aff3 -eo pid,comm\nprocess apparently never started in /tmp/gitops-playground-jenkins-agent/workspace/xample-apps_petclinic-plain_main/.configRepoTempDir@tmp/durable-7f109066\n(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)\nCannot contact default-1bg7f: java.nio.file.NoSuchFileException: /tmp/gitops-playground-jenkins-agent/workspace/xample-apps_petclinic-plain_main/.configRepoTempDir@tmp/durable-7f109066/output.txt\n```\n* In Docker Desktop, it's recommended to use WSL2 as backend. \n* Using the Hyper-V backend should also work, but we experienced random `CrashLoopBackoff`s of running pods due to liveness probe timeouts.  \n  Same as for macOS, increasing the Memory limit in Docker Desktop (for your DockerVM) to be \u003e 10 GB might help.  \n  Recommendation: 16GB.\n\nHere is how you can start the playground from a Windows-native PowerShell console:\n\n* [Install k3d](https://k3d.io/#installation), see [init-cluster.sh](scripts/init-cluster.sh) for `K3D_VERSION`, e.g. using `winget`\n```powershell\nwinget install k3d --version x.y.z\n```\n* Create k3d cluster.\n  See `K3S_VERSION` in [init-cluster.sh](scripts/init-cluster.sh) for `$image`, then execute  \n```powershell\n$ingress_port = \"80\"\n$registry_port = \"30000\"\n$image = \"rancher/k3s:v1.25.5-k3s2\"\n# Note that ou can query the image version used by playground like so: \n# (Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/cloudogu/gitops-playground/main/scripts/init-cluster.sh').Content -split \"`r?`n\" | Select-String -Pattern 'K8S_VERSION=|K3S_VERSION='\n\nk3d cluster create gitops-playground `\n    --k3s-arg=--kube-apiserver-arg=service-node-port-range=8010-65535@server:0 `\n    -p ${ingress_port}:80@server:0:direct `\n    -v /var/run/docker.sock:/var/run/docker.sock@server:0 `\n    --image=${image} `\n    -p ${registry_port}:30000@server:0:direct\n\n# Write $HOME/.config/k3d/kubeconfig-gitops-playground.yaml\nk3d kubeconfig write gitops-playground\n```\n* Note that\n  * You can ignore the warning about docker.sock\n  * We're mounting the docker socket, so it can be used by the Jenkins Agents for the docker-plugin.\n  * Windows seems not to provide a group id for the docker socket. So the Jenkins Agents run as root user.\n  * If you prefer running with an unprivileged user, consider running on WSL2, Mac or Linux\n  * You could also add `-v gitops-playground-build-cache:/tmp@server:0 ` to persist the Cache of the Jenkins agent between restarts of k3d containers.\n* Apply playground:  \n  Note that when using a `$registry_port` other than `30000` append the command `--internal-registry-port=$registry_port` bellow\n  \n```powershell\ndocker run --rm -t --pull=always `\n    -v $HOME/.config/k3d/kubeconfig-gitops-playground.yaml:/home/.kube/config `\n    --net=host `\n    ghcr.io/cloudogu/gitops-playground --yes --argocd --ingress-nginx --base-url=http://localhost:$ingress_port # more params go here\n```\n\n## Stack\n\nAs described [above](#what-is-the-gitops-playground) the GitOps playground creates a complete GitOps-based operational\nstack that can be used as an internal developer platform (IDP) on your Kubernetes cluster.\n\nThe stack is composed of multiple applications, where some of them can be accessed via a web UI.\n* Argo CD\n* Prometheus/Grafana\n* Jenkins\n* SCM-Manager\n* Vault\n* Ingress-nginx\n* Cert-Manager\n\nIn addition, there are example applications that provide a turnkey solution for GitOps-Pipelines from a developer's\npoint of view.\nSee [Example Applications](#example-applications).\n\nWe recommend using the `--ingress-nginx` and `--base-url` Parameters.\nWith these, the applications are made available as subdomains of `base-url`.\n\nFor example, `--base-url=http://localhost` leads to `\n* http://argocd.localhost\n* http://grafana.localhost\n* http://jenkins.localhost\n* http://scmm.localhost\n* http://vault.localhost\n\nOf course, this would also work for production instances with proper domains, see [Deploy Ingresses](#deploy-ingresses).\n\nAll applications are deployed via GitOps and can be found in the `cluster-resources` repository.\nSee [Argo CD](#argo-cd) for more details on the repository structure.\n\n### Credentials\n\nIf deployed within the cluster, all applications can be accessed via: `admin/admin`\n\nNote that you can change (and should for a remote cluster!) the password with the `--password` argument.\nThere also is a `--username` parameter, which is ignored for argocd. That is, for now Argo CD's username always is `admin`.\n\n### Argo CD\n\nArgo CD is installed in a production-ready way that allows for operating Argo CD with Argo CD, using GitOps and\nproviding a [repo per team pattern](https://github.com/cloudogu/gitops-patterns/tree/8e1056f#repo-per-team).\n\nWhen installing the GitOps playground, the following steps are performed to bootstrap Argo CD:\n\n* The following repos are created and initialized:\n    * `argocd` (management and config of Argo CD itself),\n    * `example-apps` (example for a developer/application team's GitOps repo) and\n    * `cluster-resources` (example for a cluster admin or infra/platform team's repo; see below for details)\n* Argo CD is installed imperatively via a helm chart.\n* Two resources are applied imperatively to the cluster: an `AppProject` called `argocd` and an `Application` called\n  `bootstrap`. These are also contained within the `argocd` repository.\n\nFrom there, everything is managed via GitOps. This diagram shows how it works.\n\n[![](docs/argocd-repos.svg)](https://cdn.jsdelivr.net/gh/cloudogu/gitops-playground@main/docs/argocd-repos.svg \"View full size\")\n\n1. The `bootstrap` application manages the folder `applications`, which also contains `bootstrap` itself.  \n   With this, changes to the `bootstrap` application can be done via GitOps. The `bootstrap` application also deploys\n   other apps ([App Of Apps pattern](https://github.com/argoproj/argo-cd/blob/v2.7.1/docs/operator-manual/cluster-bootstrapping.md?plain=1))\n2. The `argocd` application manages the folder `argocd` which contains Argo CD's resources as an umbrella helm chart.  \n   The [umbrella chart pattern](https://github.com/helm/helm-www/blob/d2543/content/en/docs/howto/charts_tips_and_tricks.md#complex-charts-with-many-dependencies)\n   allows describing the actual values in `values.yaml` and deploying additional resources (such as secrets and\n   ingresses) via the `templates` folder. The actual ArgoCD chart is declared in the `Chart.yaml`\n3. The `Chart.yaml` contains the Argo CD helm chart as `dependency`. It points to a deterministic version of the Chart\n   (pinned via `Chart.lock`) that is pulled from the Chart repository on the internet.  \n   This mechanism can be used to upgrade Argo CD via GitOps. See the [Readme of the argocd repository](argocd/argocd/README.md)\n   for details.\n4. The `projects` application manages the `projects` folder, that contains the following `AppProjects`:\n    * the `argocd` project, used for bootstrapping\n    * the built-in `default` project (which is restricted to [eliminate threats to security](https://github.com/argoproj/argo-cd/blob/ce8825ad569bf961178606acc5f3842532148093/docs/threat_model.pdf))\n    * one project per team (to implement least privilege and also notifications per team):\n        * `cluster-resources` (for platform admin, needs more access to cluster) and\n        * `example-apps` (for developers, needs less access to cluster)\n5. The `cluster-resources` application points to the `cluster-resources` git repository (`argocd` folder), which\n   has the typical folder structure of a GitOps repository (explained in the next step). This way, the platform admins\n   use GitOps in the same way as their \"customers\" (the developers) and can provide better support.\n6. The `example-apps` application points to the `example-apps` git repository (`argocd` folder again). Like the\n   `cluster-resources`, it also has the typical folder structure of a GitOps repository:\n    * `apps` - contains the kubernetes resources of all applications (the actual YAML)\n    * `argocd` - contains Argo CD `Applications` that point to subfolders of `apps` (App Of Apps pattern, again)\n    * `misc` - contains kubernetes resources, that do not belong to specific applications (namespaces, RBAC,\n      resources used by multiple apps, etc.)\n7. The `misc` application points to the `misc` folder\n8. The `my-app-staging` application points to the `apps/my-app/staging` folder within the same repo. This provides a\n   folder structure for release promotion. The `my-app-*` applications implement the [Environment per App Pattern](https://github.com/cloudogu/gitops-patterns/tree/8e1056f#global-vs-env-per-app).\n   This pattern allows each application to have its own environments, e.g. production and staging or none at all.\n   Note that the actual YAML here could either be pushed manually or using the CI server.\n   The [applications](#example-applications) contain examples that push config changes from the app repo to the GitOps\n   repo using the CI server. This implementation mixes the [Repo per Team and Repo per App patterns](https://github.com/cloudogu/gitops-patterns/tree/8e1056f#repository-structure)\n9. The corresponding production environment is realizing using the `my-app-production` application, that points to the\n   `apps/my-app/production` folder within the same repo.  \n   Note that it is recommended to protect the `production` folders from manual access, if supported by the SCM of your choice.  \n   Alternatively, instead of different YAMLs files as used in the diagram, these applications could be realized as\n    * Two applications in the same YAML (implemented in the playground, see e.g. [`petclinic-plain.yaml`](argocd/example-apps/argocd/petclinic-plain.ftl.yaml))\n    * Two application with the same name in different namespaces, when ArgoCD is enabled to search for applications\n      within different namespaces (implemented in the playground, see\n      [Argo CD's values.yaml](argocd/argocd/argocd/values.ftl.yaml) - `application.namespaces` setting)\n    * One `ApplicationSet`, using the [`git` generator for directories](https://github.com/argoproj/argo-cd/blob/v2.7.1/docs/operator-manual/applicationset/Generators-Git.md#git-generator-directories)\n      (not used in GitOps playground, yet)\n\nTo keep things simpler, the GitOps playground only uses one kubernetes cluster, effectively implementing the [Standalone](https://github.com/cloudogu/gitops-patterns/tree/8e1056f#standalone)\npattern. However, the repo structure could also be used to serve multiple clusters, in a [Hub and Spoke](https://github.com/cloudogu/gitops-patterns/tree/8e1056f#hub-and-spoke) pattern:\nAdditional clusters could either be defined in the `vaules.yaml` or as secrets via the `templates` folder.\n\nWe're also working on an optional implementation of the [namespaced](https://github.com/cloudogu/gitops-patterns/tree/8e1056f#namespaced) pattern, using the [Argo CD operator](https://github.com/argoproj-labs/argocd-operator).\n\n#### Why not use argocd-autopilot?\n\nAnd advanced question: Why does the GitOps playground not use the [**argocd-autopilot**](https://github.com/argoproj-labs/argocd-autopilot)?\n\nThe short answer is: As of 2023-05, version 0.4.15 it looks far from ready for production.\n\nHere is a diagram that shows how the repo structure created by autopilot looks like:\n\n[![](docs/autopilot-repo.svg)](https://cdn.jsdelivr.net/gh/cloudogu/gitops-playground@main/docs/autopilot-repo.svg \"View full size\")\n\nHere are some thoughts why we deem it not a good fit for production:\n\n* The version of ArgoCD is not pinned.\n    * Instead, the `kustomization.yaml` (3️ in the diagram) points to a `base` within the autopilot repo, which in turn\n      points to the `stable` branch of the Argo CD repo.\n    * While it might be possible to pin the version using Kustomize, this is not the default and looks complicated.\n    * A non-deterministic version calls for trouble. Upgrades of Argo CD might happen unnoticed.\n    * What about breaking changes? What about disaster recovery?\n* The repository structure autopilot creates is more complicated (i.e. difficult to understand and maintain) than\n  the one used in the playground\n    * Why is the `autopilot-bootstrap` application (1️ in the diagram) not within the GitOps repo and lives only in the\n      cluster?\n    * The approach of an `ApplicationSet` within the `AppProject`'s yaml pointing to a `config.json` (more difficult to\n      write than YAML) is difficult to grasp (4️ and 6️ in the diagram)\n    * The `cluster-resources` `ApplicationSet` is a good approach to multi-cluster but again, requires writing JSON\n      (4️ in the diagram).\n* Projects are used to realize environments (6️ and 7️ in the diagram).  \n  How would we separate teams in this [monorepo structure](https://github.com/cloudogu/gitops-patterns/tree/789d300#repository-structure)?  \n  One idea would be to use multiple Argo CD instances, realising a [Standalone pattern](https://github.com/cloudogu/gitops-patterns/tree/789d30055443b6096d9018ca13cbd4234a24cc3d#operator-deployment).\n  This would mean that every team would have to manage its own ArgoCD instance.  \n  How could this task be delegated to a dedicated platform team? These are the questions that lead to the structure\n  realized in the GitOps playground.\n\n#### cluster-resources\n\nThe playground installs cluster-resources (like prometheus, grafana, vault, external secrets operator, etc.) via the repo  \n`argocd/cluster-resources`. See [ADR](docs/architecture-decision-records.md#deploying-cluster-resources-with-argo-cd-using-inline-yaml) for more details.\n\nWhen installing without Argo CD, the tools are installed using helm imperatively.\nWe fall back to using imperative helm installation as a kind of neutral ground.\n\n### Jenkins\n\nYou can set an external jenkins server via the following parameters when applying the playground.\nSee [parameters](#overview-of-all-cli-and-config-options) for examples.\n\n* `--jenkins-url`,\n* `--jenkins-username`,\n* `--jenkins-password`\n\nThe user has to have the following privileges:\n* install plugins\n* set credentials\n* create jobs\n* restarting\n\nTo apply additional global environments for jenkins you can use `--jenkins-additional-envs \"KEY1=value1,KEY2=value2\"` parameter.\n\nNote that the [example applications](#example-applications) pipelines will only run on a Jenkins that uses agents that provide\na docker host. That is, Jenkins must be able to run e.g. `docker ps` successfully on the agent.\n\n## SCMs\n\nYou can choose between the following Git providers:\n\n- SCM-Manager\n- GitLab\n\nFor configuration details, see the CLI or configuration parameters above ([SCM](#scmtenant)).\n\n### GitLab\n\nWhen using GitLab, you must provide a valid **parent group ID**.\nThis group will serve as the main group for the GOP to create and manage all required repositories.\n\n[![gitlab ParentID](docs/gitlab-parentid.png)](https://docs.gitlab.com/user/group/#find-the-group-id)\n\nTo authenticate with Gitlab provide a token token as password. More information can be found [here](https://docs.gitlab.com/api/rest/authentication/)  or [here](https://docs.gitlab.com/user/profile/personal_access_tokens/)\nThe username should remain 'oauth2.0' to access the API, unless stated otherwise by GitLab documentation.\n### SCM-Manager\n\nYou can set an external SCM-Manager via the following parameters when applying the playground.\nSee [parameters](#overview-of-all-cli-and-config-options) for examples.\n\n* `--scmm-url`,\n* `--scmm-username`,\n* `--scmm-password`\n\nThe user on the scm has to have privileges to:\n* add / edit users\n* add / edit permissions\n* add / edit repositories\n* add / edit proxy\n* install plugins\n\n### Monitoring tools\n\nSet the parameter `--monitoring` so the [kube-prometheus-stack](https://github.com/prometheus-operator/kube-prometheus)\nvia its [helm-chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)\nis being deployed including dashboards for \n- ArgoCD\n- Ingress Nginx Controller\n- Prometheus\n- SCMManager\n- Jenkins.\n\n\nGrafana can be used to query and visualize metrics via prometheus.\nIt is exposed via ingress, e.g. http://grafana.localhost.\nPrometheus is not exposed by default.\n\nIn addition, argocd-notifications is set up. Applications deployed with Argo CD now will alert via email to mailhog\nthe sync status failed, for example.\n\n**Note that this only works with Argo CD so far**\n\n### Secrets Management Tools\n\nVia the `vault` parameter, you can deploy Hashicorp Vault and the External Secrets Operator into your GitOps playground.\n\nWith this, the whole flow from secret value in Vault to kubernetes `Secret` via External Secrets Operator can be seen in\naction:\n\n![External Secret Operator \u003c-\u003e Vault - flow](https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/cloudogu/gitops-playground/main/docs/plantuml-src/External-Secret-Operator-Flow.puml\u0026fmt=svg)\n\nFor this to work, the GitOps playground configures the whole chain in Kubernetes and vault (when [dev mode](#dev-mode) is used):\n\n![External Secret Operator Custom Resources](https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/cloudogu/gitops-playground/main/docs/plantuml-src/External-Secret-Operator-CRs.puml\u0026fmt=svg)\n\n* In k8s `namespaces` `argocd-staging` and `argocd-production`:\n    * Creates `SecretStore` and `ServiceAccount` (used to authenticate with vault)\n    * Creates `ExternalSecrets`\n* In Vault:\n    * Create secrets for staging and prod\n    * Create a human user for changing the secrets\n    * Authorizes the service accounts on those secrets\n* Creates an [example app](#example-app) that uses the `secrets`\n\n#### dev mode\n\nFor testing you can set the parameter `--vault=dev` to deploy vault in development mode. This will lead to\n* vault being transient, i.e. all changes during runtime are not persisted. Meaning a restart will reset to default.\n* Vault is initialized with some fixed secrets that are used in the example app, see below.\n* Vault authorization is initialized with service accounts used in example `SecretStore`s for external secrets operator\n* Vault is initialized with the usual `admin/admin` account (can be overriden with `--username` and `--password`)\n\nThe secrets are then picked up by the `vault-backend` `SecretStore`s (connects External Secrets Operator with Vault) in\nthe namespace `argocd-staging` and `argocd-production` namespaces\n\n#### prod mode\n\nWhen using `vault=prod` you'll have to initialize vault manually but on the other hand it will persist changes.\n\nIf you want the example app to work, you'll have to manually\n* set up vault, unseal it and\n* authorize the `vault` service accounts in `argocd-production` and `argocd-staging` namspaces. See `SecretStore`s and\n  [dev-post-start.sh](system/secrets/vault/dev-post-start.sh) for an example.\n\n\n#### Example app\n\nWith vault in `dev` mode and ArgoCD enabled, the example app `applications/nginx/argocd/helm-jenkins` will be deployed\nin a way that exposes the vault secrets `secret/\u003cenvironment\u003e/nginx-secret` via HTTP on the URL `http://\u003chost\u003e/secret`,\nfor example `http://staging.nginx-helm.nginx.localhost/secret`.\n\nWhile exposing secrets on the web is a bad practice, it's good for demoing auto reload of a secret changed in\nvault.\n\nTo demo this, you could\n* change the [staging secret](http://vault.localhost/ui/vault/secrets/secret/edit/staging/nginx-helm-jenkins)\n* Wait for the change to show on the web, e.g. like so\n```shell\nwhile ; do echo -n \"$(date '+%Y-%m-%d %H:%M:%S'): \" ; \\\n  curl http://staging.nginx-helm.nginx.localhost/secret/ ; echo; sleep 1; done\n```\n\nThis usually takes between a couple of seconds and 1-2 minutes.  \nThis time consists of `ExternalSecret`'s `refreshInterval`, as well as the [kubelet sync period](https://v1-25.docs.kubernetes.io/docs/concepts/configuration/configmap/#mounted-configmaps-are-updated-automatically)\n(defaults to [1 Minute](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/#kubelet-config-k8s-io-v1beta1-KubeletConfiguration))\n+ cache propagation delay\n\nThe following video shows this demo in time-lapse:\n\n[secrets-demo-video](https://user-images.githubusercontent.com/1824962/215204174-eadf180b-2a82-4273-8cbb-6e7c187267c6.mp4)\n\n### Example Applications\n\nThe playground comes with example applications that provide a turnkey solution for GitOps-Pipelines  \nfrom a developer's point of view.\n\nThese can be enabled using `--content-examples`.  \nThey require a registry, so locally use `--registry` or pass in an existing instance using `registry-url`.  \nThe examples very much rely on jenkins. So it is recommended to enable it using `--jenkins` or pass in an existing \ninstance using `--jenkins-url`.  \n\nThe examples include staging and production environments, providing a ready-to-use solution for promotion.\n\nAll applications are deployed via separated application and GitOps repos:\n\n![](https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/cloudogu/k8s-diagrams/cdd6bb77/diagrams/gitops-with-app-repo.puml\u0026fmt=png)\n\n* Separation of app repo (e.g. `petclinic-plain`) and GitOps repo (e.g. `argocd/example-app`)\n* Config is maintained in app repo,\n* CI Server writes to GitOps repo and creates PullRequests.\n\nThe applications implement a simple staging mechanism:\n\n* After a successful Jenkins build, the staging application will be deployed into the cluster by the GitOps operator.\n* Deployment of production applications can be triggered by accepting pull requests.\n* For some applications working without CI Server and committing directly to the GitOps repo is pragmatic  \n  (e.g. 3rd-party-application like NGINX, like [`argocd/nginx-helm-umbrella`](argocd/example-apps/argocd/nginx-helm-umbrella.ftl.yaml))\n\n[![app-repo-vs-gitops-repo](docs/app-repo-vs-gitops-repo.svg)](https://cdn.jsdelivr.net/gh/cloudogu/gitops-playground@main/docs/app-repo-vs-gitops-repo.svg \"View full size\")\n\nNote that the GitOps-related logic is implemented in the\n[gitops-build-lib](https://github.com/cloudogu/gitops-build-lib) for Jenkins. See the README there for more options like\n* staging,\n* resource creation,\n* validation (fail early / shift left). \n\nFor further understanding, also take a look at our GitOps pattern repository\n[cloudogu/gitops-patterns](https://github.com/cloudogu/gitops-patterns?tab=readme-ov-file#gitops-playground)\n\nPlease note that it might take about a minute after the pull request has been accepted for the GitOps operator to start\ndeploying.\nAlternatively, you can trigger the deployment via ArgoCD's UI or CLI.\n\n\nWe recommend using the `--ingress-nginx` and `--base-url` Parameters.\nWith these, the applications are made available as subdomains of `base-url`.\n\nFor example, `--base-url=http://localhost` leads to \nhttp://staging.petclinic-plain.petclinic.localhost/.\n\nThe `.petlinic.` part can be overridden using\n`--petclinic-base-domain` (for the petlinic examples/exercises), or \n`--nginx-base-domain` (for the nginx examples/exercises).\n\n#### PetClinic with plain k8s resources\n\n[Jenkinsfile](applications/petclinic/argocd/plain-k8s/Jenkinsfile) for `plain` deployment\n\n* Staging: http://staging.petclinic-plain.petclinic.localhost/\n* Production: http://production.petclinic-plain.petclinic.localhost/  \n  Note that you have to accept a [pull request](http://scmm.localhost/scm/repo/argocd/example-apps/pull-requests/) for deployment\n\n#### PetClinic with helm\n\n[Jenkinsfile](applications/petclinic/argocd/helm/Jenkinsfile) for `helm` deployment\n\n* Staging: http://staging.petclinic-helm.petclinic.localhost/\n* Production: http://production.petclinic-helm.petclinic.localhost/  \n   Note that you have to accept a [pull request](http://scmm.localhost/scm/repo/argocd/example-apps/pull-requests/) for deployment\n\n#### 3rd Party app (NGINX) with helm, templated in Jenkins\n\n[Jenkinsfile](applications/nginx/argocd/helm-jenkins/Jenkinsfile)\n\n* Staging: http://staging.nginx-helm.nginx.localhost/\n* Production: http://production.nginx-helm.nginx.localhost/  \n  Note that you have to accept a [pull request](http://scmm.localhost/scm/repo/argocd/example-apps/pull-requests/) for deployment\n\n\n#### 3rd Party app (NGINX) with helm, using Helm dependency mechanism\n\n* http://production.nginx-helm-umbrella.nginx.localhost/\n\n## Development\n\nSee [docs/developers.md](docs/developers.md)\n\n## License\nCopyright © 2020 - present Cloudogu GmbH\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.  \n\nSee [LICENSE](LICENSE) for details.\n\nGitOps Playground© for use with  Argo™, Git™, Jenkins®, Kubernetes®, Grafana®, Prometheus®, Vault® and SCM-Manager \n\nArgo™ is an unregistered trademark of The Linux Foundation®  \nGit™ is an unregistered trademark of Software Freedom Conservancy Inc.  \nJenkins® is a registered trademark of LF Charities Inc.  \nKubernetes® and the Kubernetes logo® are registered trademarks of The Linux Foundation®  \nK8s® is a registered trademark of The Linux Foundation®  \nThe Grafana Labs Marks are trademarks of Grafana Labs, and are used with Grafana Labs’ permission. We are not affiliated with, endorsed or sponsored by Grafana Labs or its affiliates.  \nPrometheus® is a registered trademark of The Linux Foundation®  \nVault® and the Vault logo® are registered trademarks of HashiCorp® (http://www.hashicorp.com/)  \n\n## Written Offer\nWritten Offer for Source Code:\n\nInformation on the license conditions and - if required by the license - on the source code is available free of charge on request.  \nHowever, some licenses require providing physical copies of the source or object code. If this is the case, you can request a copy of the source code. A small fee is charged for these services to cover the cost of physical distribution.\n\nTo receive a copy of the source code, you can either submit a written request to\n\nCloudogu GmbH  \nGarküche 1  \n38100 Braunschweig\n\nor you may email hello@cloudogu.com.\n\nYour request must be sent within three years from the date you received the software from Cloudogu that is the subject of your request or, in the case of source code licensed under the AGPL/GPL/LGPL v3, for as long as Cloudogu offers spare parts or customer support\nfor the product, including the components or binaries that are the subject of your request.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudogu%2Fgitops-playground","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudogu%2Fgitops-playground","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudogu%2Fgitops-playground/lists"}