This repo demonstrates managing multiple OpenShift clusters with ACM and GitOps. Useful for demonstrating cluster-level multitenancy.
├── bootstrap
│ ├── base
│ ├── namespaces
│ │ └── clusters
│ │ ├── team-1
│ │ ├── team-2
│ │ └── team-3
│ └── secrets
│ └── clusters
│ ├── team-1
│ ├── team-2
│ └── team-3
├── cluster_types
│ ├── type_a
│ ├── type_b
│ └── type_c
├── components
│ ├── application
│ ├── applicationset
│ ├── managedcluster
│ │ └── aws
│ ├── namespace
│ ├── operators
│ │ ├── _base
│ │ ├── cert-manager
│ │ └── web-terminal
│ └── secrets
│ ├── _examples
│ │ ├── cloud_credentials
│ │ │ └── aws
│ │ ├── installconfig
│ │ │ └── aws
│ │ └── pull_secret
│ ├── cloud_credentials # <-- NOT COMMITTED TO GIT!
│ │ └── aws
│ ├── installconfig # <-- NOT COMMITTED TO GIT!
│ │ ├── aws
│ │ └── templates
│ └── pull_secret # <-- NOT COMMITTED TO GIT!
└── hubs
└── primary
├── managed_clusters
│ └── team-1
│ ├── gitops
│ ├── managedcluster
│ └── secrets
└── operators
bootstrap: Resources used to kickstart GitOps on ACM hubs.bootstrap/namespace: Namespaces that are applied onto ACM hubs manually before applying GitOps resources.bootstrap/secrets: Secrets that are applied onto ACM hubs manually before applying GitOps resources.bootstrap/base: The resource that kickstarts GitOps.
cluster_types: A portfolio of different "flavors" of clusters that your platform teams support. This is useful for ensuring consistent cluster configuration for multiple teams.components: Resources deployed into ACM hubs or managed clusters, like namespaces, ArgoCD configurations, operators, and so on.hubs: ACM hubs. The bootstrap process creates an ArgoCD application that synchronizes these subdirectories with hub clusters.hubs/$HUB_NAME/managed_clusters: Clusters managed by an ACM hub.hubs/$HUB_NAME/operators: Operators installed into the hub.
- An OpenShift cluster with ACM and Multicluster Engine installed.
ocorkubectl- A GitHub or GitLab Account (any Git repo will work as long as your ACM hub can access it)
NOTE: While we are generating the secrets "by hand" here, in a real-world scenario, you would use a secrets manager like HashiCorp Vault to store these secrets securely elsewhere or an encryption tool like sops to store them securely in a Git repository.
Copy the example secrets into the secrets top-level directory:
find components/secrets/_examples -type f |
while read -r secret
do
target="${secret//_examples\//}"
mkdir -p "$(dirname "$target")"
test -f "$target" || cp "$secret" "$target"
doneNOTE: These are NOT committed to Git!
Next, copy the example Installer config in components/secrets/installconfigs/templates/
to your /tmp directory, then open it in an editor and replace the keys set to
replace-me with real values.
Finally, use the command below to update the Secret that will hold your Installer Config with a base64 representation:
yq -ir '.data."install-config.yaml" = "'$(base64 -w=0 < /tmp/install-config.yaml)'"' \
components/secrets/installconfig/aws/installconfig.yamlOpen components/secrets/cloud_credentials/aws/credential.yaml and replace the
keys set to replace-me with real values.
-
Retrieve the pull secret for the Red Hat registry or your company's private registry. It should look something like the below:
{"auths":{"cloud.openshift.com":{"email":"example@email.address","auth":"long-string"}}} -
Run the command below to update the pull secret credential at
components/secrets/pull_secret/credential.yamlwith a base64-encoded representation:yq -r '.data.".dockerconfigjson" = "'$(echo "$YOUR_PULL_SECRET"| base64 -w=0)'"' ] components/secrets/pull_secret/credential.yaml
Render the Kustomize template that will apply secrets to your cluster:
oc kustomize bootstrap/secretsYou should see a YAML like shown below:
apiVersion: v1
data:
aws_access_key_id: some key
aws_secret_access_key: some value
kind: Secret
metadata:
labels:
cluster.open-cluster-management.io/backup: ""
cluster.open-cluster-management.io/credentials: ""
cluster.open-cluster-management.io/type: aws
name: cloud-creds
namespace: cluster-team-1
---
apiVersion: v1
data:
install-config.yaml: some-install-config
kind: Secret
metadata:
labels:
Verify that replace-me is not in the output:
oc kustomize bootstrap/secrets | grep -i replace
# should be emptyRender the Kustomize template that ArgoCD will apply onto your primary ACM hub:
oc kustomize hubs/primaryThis should render a YAML similar to this:
apiVersion: operators.coreos.com/v1alpha1
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-operator
---
apiVersion: v1
kind: Namespace
metadata:
name: cluster-team-1
---
apiVersion: v1
kind: Namespace
metadata:
name: web-terminal-operator
---
apiVersion: agent.open-cluster-management.io/v1
kind: KlusterletAddonConfig
metadata:
name: cluster-team-1
namespace: cluster-team-1
spec:
applicationManager:
enabled: true
# ...omitted for brevityVerify that replace-me is not in the output:
$: kubectl kustomize hubs/primary | grep replace-me
# should be emptyRender the Kustomize templates in the bootstrap directory:
oc kustomize bootstrap/baseThis should produce a YAML like the one shown below:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: primary-hub
namespace: openshift-gitops
spec:
destination:
namespace: primary-hub-bootstrap
server: https://kubernetes.default.svc
ignoreDifferences:
- group: cluster.open-cluster-management.io
jsonPointers:
- /metadata/labels/cloud
- /metadata/labels/name
- /metadata/labels/vendor
kind: ManagedCluster
- group: operator.open-cluster-management.io
jsonPointers:
- /spec/overrides/components
kind: MultiClusterHub
- group: multicluster.openshift.io
jsonPointers:
- /spec/overrides/components
kind: MultiClusterEngine
project: default
source:
path: ./hubs/primary
repoURL: https://github.com/redhat-na-ssa/acm-gitops-demo
targetRevision: main
syncPolicy:
automated: {}
syncOptions:
- CreateNamespace=true
- SkipDryRunOnMissingResource=true
- RespectIgnoreDifferences=trueIf everything checks out, bootstrap your ACM hub and watch it go!
oc apply -k bootstrap/baseWait about an hour for the three managed clusters to finish provisioning.
You should see something like the below:
#WIP
Run the commands below to change the repo URL and branch that your clusters will sync against:
url="your-repo-url"
branch="your-branch"
grep -lr repoURL |
grep -v README.md |
xargs sed -Ei "s;repoURL:.*;repoURL: $url;g"
grep -lr targetRevision |
grep -v README.md |
xargs sed -Ei "s;targetRevision:.*;targetRevision: $branch;g"Commit and push your changes then re-bootstrap your hubs as documented in the Deploy section.
Do the following if you'd like to synchronize your cluster with a private repository:
-
Update the
sshPrivateKeyproperty incomponents/secrets/argocd_repository/credentials.yamlwith the SSH private key for your repository. -
Replace the
replace-mevalues inbootstrap/secrets/argocd-private-repository/kustomization.yamlwith actual values. -
Add the below under
resourcesin thebootstrap/secrets/kustomization.yaml:- argocd-private-repository
-
Replace all references to repositories in this codebase with the URL to your private repo:
url="your-repo-url" # <--------- replace this grep -lr repoURL | grep -v README.md | xargs sed -Ei "s;repoURL:.*;repoURL: $url;g"
GitOps enables you to customize any of your clusters to your liking! Here are some examples of tasks you can perform after you begin managing your clusters with GitOps.
You might want to create an ACM hub for testing new clusters, policies and/or configurations. This is straightforward to do with GitOps.
- Create a new copy of
hubs/primary:cp hubs/primary hubs/staging - Create a new bootstrap base for your new hub:
cp bootstrap/base bootstrap/staging - Remove (or add!) any managed clusters in
hubs/staging. - Commit and push your changes.
- Bootstrap the new ACM hub:
oc login api.$STAGING_CLUSTER && oc apply -k bootstrap/staging
- Create a new branch off of
main. - Create a new copy of
hubs/primary/managed_clusters/team-1. - Modify the patches in the managed cluster kustomization that you copied.
- Commit and push your changes into your branch.
- Create a pull request to merge your branch into
main. - Hold a review session to verify your changes with the team (or other stakeholders).
- Approve the request. The new cluster will get created within a minute or two
of
mainbeing updated.
NOTE: This approach works well with a "staging" ACM hub, especially if teams will be requesting new clusters in a self-service model.