From 5cec310cc3c7710d1e7502a01076ee69ce9453be Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Tue, 5 Mar 2024 16:57:21 -0600 Subject: [PATCH] feat: craft a gitops focused installation Write up a GitOps focused installation of Understack along with some helper scripts to assist the user with crafting their secrets and their initial layout of their data. --- apps/app-of-apps.yaml | 23 ++++++ docs/gitops-install.md | 138 ++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + scripts/gitops-deploy.sh | 41 ++++++++++ scripts/gitops-secrets-gen.sh | 45 +++++++++++ 5 files changed, 248 insertions(+) create mode 100644 apps/app-of-apps.yaml create mode 100644 docs/gitops-install.md create mode 100755 scripts/gitops-deploy.sh create mode 100755 scripts/gitops-secrets-gen.sh diff --git a/apps/app-of-apps.yaml b/apps/app-of-apps.yaml new file mode 100644 index 000000000..ca3fd388f --- /dev/null +++ b/apps/app-of-apps.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: app-of-apps + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + destination: + namespace: argocd + server: https://kubernetes.default.svc + project: default + source: + path: clusters/${DEPLOY_NAME} + repoURL: ${GIT_URL} + targetRevision: main + directory: + recurse: true + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/docs/gitops-install.md b/docs/gitops-install.md new file mode 100644 index 000000000..6fb0087ea --- /dev/null +++ b/docs/gitops-install.md @@ -0,0 +1,138 @@ +# GitOps based Install + +This guide is not meant to be a definitive guide to [GitOps][gitops] and +how it can be used with UnderStack or even a best practices example +but instead focused on an example development oriented installation. +It will make a few assumptions and some opinionated choices that may +not align with a production best practices installation. +Most notable assumptions are: + +- [GitOps][gitops] tooling runs on the same cluster as the deploy +- AIO (All-in-One) configuration +- Your cluster is a blank slate and can be entirely consumed + +You will have the source to your deployment and all the pre-deployment +work will occur on your local machine and not on any of the target +machines. + +## Getting the source + +You must fetch the source to this repo and since we will be using +[GitOps][gitops], you must also have a deployment repo. These +operations can all happen locally on your development machine. + +```bash +git clone https://github.com/rackerlabs/understack +# then either +git init uc-deploy +# or +git clone https://path/to/my/uc-deploy +``` + +## Pre-deployment + +Embracing GitOps and declarative configuration, we will define three +distinct pieces of information for your deployment. + +- Infrastructure: Where the software will live (TODO: this defines the cluster) +- Secrets: What are all the credentials, passwords, etc needed by the software +- Cluster: The actual software that will be deployed + +To properly scope this you'll need an environment name. For the +purposes of this document we'll call it `my-k3s`. + +### Environment Variables + +To avoid defining many environment variables we'll simplify by creating an +`.env` file for our deployment. In this case we'll call it `my-k3s.env` and +place it where we've cloned understack. + +```bash title="/path/to/understack/my-k3s.env" +UC_REPO="/path/to/understack" +UC_DEPLOY="/path/to/uc-deploy" +DEPLOY_NAME="my-k3s" +``` + +### Remaining pre-deployment config + +ArgoCD will need to know where it can access your deployment config +repo. This can be over SSH with a key or over HTTPS. Add to your +`my-k3s.env` the following: + +```bash title="/path/to/understack/my-k3s.env" +UC_DEPLOY_GIT_URL="git@github.com:my-org/uc-deploy.git" +UC_DEPLOY_SSH_FILE="/path/to/ssh.private" +``` + +All services will utilize unique DNS names. The facilitate this, UnderStack +will take a domain and add sub-domains for them. Add to your `my-k3s.env` +the following: + +```bash title="/path/to/understack/my-k3s.env" +DNS_ZONE="some.domain.corp" +``` + +### Populating the infrastructure + +TODO: some examples and documentation on how to build out a cluster + +### Generating secrets + +Secrets in their very nature are sensitive pieces of data. The ultimate +storage and injection of these in a production environment needs to be +carefully considered. For the purposes of this document no specific +choice has been made but tools like Vault, Sealed Secrets, SOPS, etc +should be considered. This will only generate the necessary secrets +using random data to sucessfully continue the installation. + +TODO: probably give at least one secure example + +```bash +./scripts/gitops-secrets-gen.sh ./my-k3s.env +cd /path/to/uc-deploy +git add secrets/my-k3s +git commit -m "my-k3s: secrets generation" +``` + +### Defining the app deployment + +In this section we will use the [App of Apps][app-of-apps] pattern to define +the deployment of all the components of UnderStack. + +```bash +./scripts/gitops-deploy.sh ./my-k3s.env +cd /path/to/uc-deploy +git add clusters/my-k3s +git commit -m "my-k3s: initial cluster config" +``` + +## Final modifications of your deployment + +This is point you can make changes to the [ArgoCD][argocd] configs before +you do the deployment. + +## Doing the Deployment + +At this point we will use our configs to make the actual deployment. +Make sure everything you've committed to your deployment repo is pushed +to your git server so that ArgoCD can access it. + +If you do not have ArgoCD deployed then you can use the following: + +```bash +kubectl kustomize --enable-helm \ + https://github.com/rackerlabs/understack//bootstrap/argocd/ \ + | kubectl apply -f - +``` + +Then run the following: + +```bash +kubectl apply -f "/path/to/uc-deploy/clusters/my-k3s/app-of-apps.yaml" +``` + +At this point ArgoCD will work to deploy Understack. + +[gitops]: +[app-of-apps]: +[argocd]: diff --git a/mkdocs.yml b/mkdocs.yml index ed0f68e10..3b70f9aa1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -53,3 +53,4 @@ nav: - openstack-helm.md - secrets.md - install-understack-ubuntu-k3s.md + - gitops-install.md diff --git a/scripts/gitops-deploy.sh b/scripts/gitops-deploy.sh new file mode 100755 index 000000000..d35787276 --- /dev/null +++ b/scripts/gitops-deploy.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +usage() { + echo "$(basename "$0") " >&2 + echo "" >&2 + echo "dns-zone: DNS zone where all the ingress endpoints will be hooked to" >&2 + echo "deploy-git-repo: URL to your deploy repo" >&2 + echo "local-clone: path to the local clone of your repo" >&2 + echo "deploy-name: name you are giving your deployment" >&2 + exit 1 +} + +template() { + local subvars + subvars="\$DNS_ZONE \$GIT_URL \$DEPLOY_NAME" + cat "$1" | envsubst "${subvars}" > "$2" +} + +if [ $# -ne 4 ]; then + usage +fi + +SCRIPTS_DIR="$(dirname "$0")" + +OUTPUT_DIR="$3" + +export DNS_ZONE="$1" +export GIT_URL="$2" +export DEPLOY_NAME="$4" + +for part in operators components; do + echo "Creating ${part} configs" + mkdir -p "${OUTPUT_DIR}/clusters/${DEPLOY_NAME}/${part}" + for tmpl in $(find "${SCRIPTS_DIR}/../apps/${part}" -type f); do + outfile=$(basename "${tmpl}") + template "${tmpl}" "${OUTPUT_DIR}/clusters/${DEPLOY_NAME}/${part}/${outfile}" + done + rm -rf "${OUTPUT_DIR}/clusters/${DEPLOY_NAME}/${part}/kustomization.yaml" +done +echo "Creating app-of-apps config" +template "${SCRIPTS_DIR}/../apps/app-of-apps.yaml" "${OUTPUT_DIR}/clusters/${DEPLOY_NAME}/app-of-apps.yaml" diff --git a/scripts/gitops-secrets-gen.sh b/scripts/gitops-secrets-gen.sh new file mode 100755 index 000000000..f3bda3d54 --- /dev/null +++ b/scripts/gitops-secrets-gen.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +function usage() { + echo "$(basename "$0") " >&2 + echo "" >&2 + echo "Generates random secrets needed by the apps in this repo" >&2 + exit 1 +} + +if [ $# -ne 1 ]; then + usage +fi + +SCRIPTS_DIR=$(dirname "$0") + +if [ ! -f "$1"]; then + echo "Did not get a file with environment variables." >&2 + usage +fi + +kubectl --namespace openstack \ + create secret generic mariadb \ + --dry-run=client -o yaml \ + --type Opaque \ + --from-literal=root-password="$(${SCRIPTS_DIR}/pwgen.sh)" \ + --from-literal=password="$(${SCRIPTS_DIR}/pwgen.sh)" \ + > "$1/secret-mariadb.yaml" + +kubectl --namespace nautobot \ + create secret generic nautobot-env \ + --dry-run=client -o yaml \ + --type Opaque \ + --from-literal=NAUTOBOT_SECRET_KEY="$(${SCRIPTS_DIR}/pwgen.sh)" \ + --from-literal=NAUTOBOT_SUPERUSER_API_TOKEN="$(${SCRIPTS_DIR}/pwgen.sh)" \ + --from-literal=NAUTOBOT_SUPERUSER_PASSWORD="$(${SCRIPTS_DIR}/pwgen.sh)" \ + > "$1/secret-nautobot-env.yaml" + +kubectl --namespace nautobot \ + create secret generic nautobot-redis \ + --dry-run=client -o yaml \ + --type Opaque \ + --from-literal=redis-password="$(${SCRIPTS_DIR}/pwgen.sh)" \ + > "$1/secret-nautobot-redis.yaml" + +"${SCRIPTS_DIR}/gen-os-secrets.sh" "$1/secret-openstack.yaml"