Skip to content

Commit

Permalink
Merge pull request #391 from Gregory-Pereira/umami-metrics-deployment
Browse files Browse the repository at this point in the history
Metrics deployment
  • Loading branch information
vishnoianil authored Dec 11, 2024
2 parents 438617a + ac980b2 commit aa65db0
Show file tree
Hide file tree
Showing 20 changed files with 570 additions and 26 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/lint-jobs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: "-e SC1091" # ignores using .env for source as issue

markdown-lint:
runs-on: ubuntu-latest
steps:
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ pathservice.pid
/playwright-report/
/blob-report/
/playwright/.cache/

playwright/.auth
# dont track secrets in git
deploy/k8s/overlays/kind/umami/umami-secret.yaml
deploy/k8s/overlays/openshift/umami/umami-secret.yaml
146 changes: 122 additions & 24 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ else
PIPE_DEV_NULL=
endif

#add an alias between kubectl and oc
OC := $(shell command -v oc 2>/dev/null || echo kubectl)
ILAB_KUBE_CONTEXT?=kind-instructlab-ui
ILAB_KUBE_NAMESPACE?=instructlab
ILAB_KUBE_CLUSTER_NAME?=instructlab-ui
CONTAINER_ENGINE?=docker
DEVCONTAINER_BINARY_EXISTS ?= $(shell command -v devcontainer)
TAG=$(shell git rev-parse HEAD)
UMAMI_KUBE_NAMESPACE?=umami
SEALED_SECRETS_CONTROLLER_NAMESPACE=kube-system
SEALED_SECRETS_CONTROLLER_NAME=sealed-secrets-controller
##@ Development - Helper commands for development
.PHONY: md-lint
md-lint: ## Lint markdown files
Expand Down Expand Up @@ -89,7 +94,6 @@ start-dev-podman: ## Start UI development stack in podman
echo "Please create a .env file in the root of the project." ; \
exit 1 ; \
fi

$(CMD_PREFIX) yes | cp -rf .env ./deploy/compose/.env
$(CMD_PREFIX) podman-compose -f ./deploy/compose/ui-compose.yml up -d
$(CMD_PREFIX) echo "Development environment started."
Expand All @@ -111,9 +115,37 @@ check-kubectl:
exit 1 ; \
fi

.PHONY: check-kubeseal
check-kubeseal:
$(CMD_PREFIX) if [ -z "$(shell which kubeseal)" ]; then \
echo "Please install kubeseal" ; \
echo "https://github.com/bitnami-labs/sealed-secrets?tab=readme-ov-file#kubeseal" ; \
exit 1 ; \
fi

.PHONY: check-sealed-secrets-controller
check-sealed-secrets-controller:
$(CMD_PREFIX) kubectl get deployment ${SEALED_SECRETS_CONTROLLER_NAME} -n ${SEALED_SECRETS_CONTROLLER_NAMESPACE} > /dev/null 2>&1 || { \
echo "Error: Could not find the Sealed Secrets controller deployment named '${SEALED_SECRETS_CONTROLLER_NAME}' in namespace '${SEALED_SECRETS_CONTROLLER_NAMESPACE}'."; \
echo "Please update SEALED_SECRETS_CONTROLLER_NAME and SEALED_SECRETS_CONTROLLER_NAMESPACE at the top of the Makefile"; \
echo "to match your deployment, or see https://github.com/bitnami-labs/sealed-secrets#controller for information on installing it."; \
exit 1; \
}

.PHONY: check-yq
check-yq:
$(CMD_PREFIX) if ! command -v yq >/dev/null 2>&1; then \
echo "Error: 'yq' is not installed."; \
echo "Please visit https://github.com/mikefarah/yq#install for installation instructions."; \
exit 1; \
fi

.PHONY: load-images
load-images: ## Load images onto Kind cluster
$(CMD_PREFIX) docker pull ghcr.io/instructlab/ui/ui:main
$(CMD_PREFIX) kind load --name $(ILAB_KUBE_CLUSTER_NAME) docker-image ghcr.io/instructlab/ui/ui:main
$(CMD_PREFIX) docker pull postgres:15-alpine
$(CMD_PREFIX) kind load --name $(ILAB_KUBE_CLUSTER_NAME) docker-image postgres:15-alpine

.PHONY: stop-dev-kind
stop-dev-kind: check-kind ## Stop the Kind cluster to destroy the development environment
Expand Down Expand Up @@ -152,8 +184,30 @@ undeploy: ## Undeploy the InstructLab UI stack from a kubernetes cluster
fi
$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) delete namespace $(ILAB_KUBE_NAMESPACE)

.PHONY: deploy-umami-kind
deploy-umami-kind: wait-for-readiness load-images
$(CMD_PREFIX) if [ ! -f .env ]; then \
echo "Please create a .env file in the root of the project." ; \
exit 1 ; \
fi
$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) create namespace $(UMAMI_KUBE_NAMESPACE) --dry-run=client -o yaml | kubectl apply -f -
$(CMD_PREFIX) bash -c "source .env && \
deploy/k8s/base/umami/deploy-umami-openshift-env-secret-conversion.sh KIND $(UMAMI_KUBE_NAMESPACE)"
$(CMD_PREFIX) kubectl create -f ./deploy/k8s/overlays/kind/umami/umami-secret.yaml
$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) apply -k ./deploy/k8s/overlays/kind/umami
$(CMD_PREFIX) echo "Waiting for Umami Deployment (pods: postgresql and umami) ..."
$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) wait --for=condition=Ready pods -n $(UMAMI_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=umami --timeout=15m
$(CMD_PREFIX) umami_ingress=$$(kubectl get ingress umami-ingress -n umami -o jsonpath='{.spec.rules[*].host}') ; \
echo "Umami ingress deployed to: $$umami_ingress"

.PHONY: undeploy-umami-kind
undeploy-umami-kind:
-$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) scale --replicas=0 deployment/umami -n $(UMAMI_KUBE_NAMESPACE)
-$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) delete -f ./deploy/k8s/overlays/kind/umami/umami-secret.yaml
-$(CMD_PREFIX) kubectl --context=$(ILAB_KUBE_CONTEXT) delete -k ./deploy/k8s/overlays/kind/umami

.PHONY: start-dev-kind ## Run the development environment on Kind cluster
start-dev-kind: setup-kind deploy ## Setup a Kind cluster and deploy InstructLab UI on it
start-dev-kind: setup-kind load-images deploy ## Setup a Kind cluster and deploy InstructLab UI on it

##@ OpenShift - UI prod and qa deployment on OpenShift
.PHONY: deploy-qa-openshift
Expand All @@ -162,53 +216,97 @@ deploy-qa-openshift: ## Deploy QA stack of the InstructLab UI on OpenShift
echo "Please create a .env file in the root of the project." ; \
exit 1 ; \
fi

$(CMD_PREFIX) yes | cp -rf .env ./deploy/k8s/overlays/openshift/qa/.env
$(CMD_PREFIX) oc apply -k ./deploy/k8s/overlays/openshift/qa
$(CMD_PREFIX) oc wait --for=condition=Ready pods -n $(ILAB_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=ui --timeout=15m
$(CMD_PREFIX) $(OC) apply -k ./deploy/k8s/overlays/openshift/qa
$(CMD_PREFIX) $(OC) wait --for=condition=Ready pods -n $(ILAB_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=ui --timeout=15m

.PHONY: redeploy-qa-openshift
redeploy-qa-openshift: ## Redeploy QA stack of the InstructLab UI on OpenShift
$(CMD_PREFIX) oc -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/ui
$(CMD_PREFIX) oc -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/pathservice

$(CMD_PREFIX) $(OC) -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/ui
$(CMD_PREFIX) $(OC) -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/pathservice

.PHONY: undeploy-qa-openshift
undeploy-qa-openshift: ## Undeploy QA stack of the InstructLab UI on OpenShift
$(CMD_PREFIX) oc delete -k ./deploy/k8s/overlays/openshift/qa
$(CMD_PREFIX) $(OC) delete -k ./deploy/k8s/overlays/openshift/qa
$(CMD_PREFIX) if [ -f ./deploy/k8s/overlays/openshift/qa/.env ]; then \
rm ./deploy/k8s/overlays/openshift/qa/.env ; \
fi

.PHONY: deploy-umami-qa-openshift
deploy-umami-qa-openshift:
$(CMD_PREFIX) if [ ! -f .env ]; then \
echo "Please create a .env file in the root of the project." ; \
exit 1 ; \
fi
$(CMD_PREFIX) $(OC) create namespace $(UMAMI_KUBE_NAMESPACE) --dry-run=client -o yaml | $(OC) apply -f -
$(CMD_PREFIX) source .env && \
deploy/k8s/base/umami/deploy-umami-openshift-env-secret-conversion.sh OPENSHIFT $(UMAMI_KUBE_NAMESPACE)
$(CMD_PREFIX) $(OC) apply -f ./deploy/k8s/overlays/openshift/umami/umami-secret.yaml
$(CMD_PREFIX) $(OC) apply -k ./deploy/k8s/overlays/openshift/umami
$(CMD_PREFIX) echo "Waiting for Umami Deployment (pods: postgresql and umami) ..."
$(CMD_PREFIX) $(OC) wait --for=condition=Ready pods -n $(UMAMI_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=umami --timeout=15m
$(CMD_PREFIX) umami_route=$$($(OC) get route umami -n $(UMAMI_KUBE_NAMESPACE) | tail -n 1 | awk '{print $$2}') ; \
echo "Umami route deployed to: $$umami_route"

.PHONY: undeploy-umami-qa-openshift
undeploy-umami-qa-openshift:
-$(CMD_PREFIX) $(OC) scale --replicas=0 deployment/umami -n $(UMAMI_KUBE_NAMESPACE)
-$(CMD_PREFIX) $(OC) delete -f ./deploy/k8s/overlays/openshift/umami/umami-secret.yaml
-$(CMD_PREFIX) $(OC) delete -k ./deploy/k8s/overlays/openshift/umami

.PHONY: deploy-prod-openshift
deploy-prod-openshift: ## Deploy production stack of the InstructLab UI on OpenShift
$(CMD_PREFIX) if [ ! -f .env ]; then \
echo "Please create a .env file in the root of the project." ; \
exit 1 ; \
fi

$(CMD_PREFIX) yes | cp -rf .env ./deploy/k8s/overlays/openshift/prod/.env
$(CMD_PREFIX) oc apply -k ./deploy/k8s/overlays/openshift/prod
$(CMD_PREFIX) oc wait --for=condition=Ready pods -n $(ILAB_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=ui --timeout=15m
$(CMD_PREFIX) $(OC) apply -k ./deploy/k8s/overlays/openshift/prod
$(CMD_PREFIX) $(OC) wait --for=condition=Ready pods -n $(ILAB_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=ui --timeout=15m

.PHONY: redeploy-prod-openshift
redeploy-prod-openshift: ## Redeploy production stack of the InstructLab UI on OpenShift
$(CMD_PREFIX) oc -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/ui
$(CMD_PREFIX) oc -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/pathservice

$(CMD_PREFIX) $(OC) -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/ui
$(CMD_PREFIX) $(OC) -n $(ILAB_KUBE_NAMESPACE) rollout restart deploy/pathservice

.PHONY: undeploy-prod-openshift
undeploy-prod-openshift: ## Undeploy production stack of the InstructLab UI on OpenShift
$(CMD_PREFIX) oc delete -k ./deploy/k8s/overlays/openshift/prod
$(CMD_PREFIX) $(OC) delete -k ./deploy/k8s/overlays/openshift/prod
$(CMD_PREFIX) if [ -f ./deploy/k8s/overlays/openshift/prod/.env ]; then \
rm ./deploy/k8s/overlays/openshift/prod/.env ; \
fi

.PHONY: deploy-umami-prod-openshift
deploy-umami-prod-openshift: check-kubeseal check-sealed-secrets-controller
$(CMD_PREFIX) if [ ! -f .env ]; then \
echo "Please create a .env file in the root of the project." ; \
exit 1 ; \
fi
$(CMD_PREFIX) $(OC) create namespace $(UMAMI_KUBE_NAMESPACE) --dry-run=client -o yaml | $(OC) apply -f -
$(CMD_PREFIX) source .env && \
deploy/k8s/base/umami/deploy-umami-openshift-env-secret-conversion.sh "OPENSHIFT" $(UMAMI_KUBE_NAMESPACE)
$(CMD_PREFIX) cat deploy/k8s/overlays/openshift/umami/umami-secret.yaml | kubeseal \
--controller-name=${SEALED_SECRETS_CONTROLLER_NAME} \
--controller-namespace=${SEALED_SECRETS_CONTROLLER_NAMESPACE} \
--format yaml > ./deploy/k8s/overlays/openshift/umami/umami-secret.sealedsecret.yaml
$(CMD_PREFIX) $(OC) apply -f deploy/k8s/overlays/openshift/umami/umami-secret.sealedsecret.yaml
$(CMD_PREFIX) $(OC) apply -k deploy/k8s/overlays/openshift/umami
$(CMD_PREFIX) echo "Waiting for Umami Deployment (pods: postgresql and umami) ..."
$(CMD_PREFIX) $(OC) wait --for=condition=Ready pods -n $(UMAMI_KUBE_NAMESPACE) --all -l app.kubernetes.io/part-of=umami --timeout=15m
$(CMD_PREFIX) umami_route=$$($(OC) get route umami -n $(UMAMI_KUBE_NAMESPACE) | tail -n 1 | awk '{print $$2}') ; \
echo "Umami route deployed to: $$umami_route"

.PHONY: undeploy-umami-prod-openshift
undeploy-umami-prod-openshift:
-$(CMD_PREFIX) $(OC) scale --replicas=0 deployment/umami -n $(UMAMI_KUBE_NAMESPACE)
-$(CMD_PREFIX) $(OC) delete -f ./deploy/k8s/overlays/openshift/umami/umami-secret.sealedsecret.yaml
-$(CMD_PREFIX) $(OC) delete -k ./deploy/k8s/overlays/openshift/umami

.PHONY: check-dev-container-installed
check-dev-container-installed:
@if [ -z "${DEVCONTAINER_BINARY_EXISTS}" ]; then \
echo "You do not have devcontainer installed, please isntall it!"; \
exit 1; \
echo "You do not have devcontainer installed, please isntall it!" ; \
exit 1 ; \
fi;

.PHONY: build-dev-container
Expand All @@ -233,12 +331,12 @@ cycle-dev-container:
CONTAINER_IDS=$(shell ${CONTAINER_ENGINE} ps -a | grep "quay.io/instructlab-ui/devcontainer" | awk '{print $$1}') && \
if [ -n "$$CONTAINER_IDS" ]; then \
for CONTAINER_ID in "$$CONTAINER_IDS"; do \
echo "Stopping and removing container $$CONTAINER_ID of imageid $$image_id..."; \
${CONTAINER_ENGINE} rm "$$CONTAINER_ID" -f; \
done; \
fi; \
echo "removing image with id $$image_id and all containers using that image ..."; \
${CONTAINER_ENGINE} rmi $$image_id -f; \
echo "Stopping and removing container $$CONTAINER_ID of imageid $$image_id..." ; \
${CONTAINER_ENGINE} rm "$$CONTAINER_ID" -f ; \
done ; \
fi ; \
echo "removing image with id $$image_id and all containers using that image ..." ; \
${CONTAINER_ENGINE} rmi $$image_id -f ; \
fi;
$(MAKE) build-dev-container
$(MAKE) start-dev-container
19 changes: 19 additions & 0 deletions argocd/overlays/applicaitons/app-of-apps.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app-of-apps-ilab
spec:
destination:
namespace: openshift-gitpos
name: in-cluster
project: default
source:
path: argocd/overlays/applicaitons
repoURL: https://github.com/instructlab/ui.git
targetRevision: HEAD
syncPolicy:
syncOptions:
- Validate=false
- ApplyOutOfSyncOnly=true
# automated:
# selfHeal: true
7 changes: 7 additions & 0 deletions argocd/overlays/applicaitons/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: openshift-gitops
resources:
# - prod.yaml # currently not deployed via argo
- qa.yaml
- umami.yaml
2 changes: 1 addition & 1 deletion argocd/overlays/applicaitons/prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
name: ilab-ui-stack-production
spec:
destination:
name: in-cluster
name: in-cluster # THIS NEEDS TO CHANGE once we get prod on ARGO
namespace: instructlab
project: default
source:
Expand Down
17 changes: 17 additions & 0 deletions argocd/overlays/applicaitons/umami.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: umami
spec:
project: default
source:
repoURL: https://github.com/instructlab/ui.git
path: deploy/k8s/overlays/openshift/umami
targetRevision: main
destination:
namespace: umami
name: in-cluster
syncPolicy:
automated:
selfHeal: true

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/bin/bash
# -*- indent-tabs-mode: nil; tab-width: 2; sh-indentation: 2; -*-

# Helper script to filter out `.env`` values related to umami deployment, and generate the secret manifest from that

# Requires: kubectl, yq

if [ -f ".env" ]; then
source .env
fi

if [ "$#" -ne 2 ]; then
echo "USAGE: $0 TARGET NAMESPACE
TARGET: The deployment target. Options: [\"OPENSHIFT\", \"KIND\"]
NAMESPACE: The namespace where you want to deploy the umami-secret." 1>&2
exit 1
fi

TARGET="$1"
NAMESPACE="$2"

if [ "${TARGET}" == "OPENSHIFT" ]; then
UMAMI_SECRET_FILE_PATH="deploy/k8s/overlays/openshift/umami/umami-secret.yaml"
UMAMI_DATABASE_NAME_KEY_NAME=POSTGRESQL_DATABASE
UMAMI_DATABASE_USER_KEY_NAME=POSTGRESQL_USER
UMAMI_DATABASE_PASSWORD_KEY_NAME=POSTGRESQL_PASSWORD
elif [ "${TARGET}" == "KIND" ]; then
UMAMI_SECRET_FILE_PATH="deploy/k8s/overlays/kind/umami/umami-secret.yaml"
UMAMI_DATABASE_NAME_KEY_NAME=POSTGRES_DB
UMAMI_DATABASE_USER_KEY_NAME=POSTGRES_USER
UMAMI_DATABASE_PASSWORD_KEY_NAME=POSTGRES_PASSWORD
else
echo "Error, \$TARGET ${TARGET} not recongnized.
TARGET options: [\"OPENSHIFT\", \"KIND\"]"
exit 1
fi

required_vars=("DATABASE_TYPE" "UMAMI_DATABASE_NAME" "UMAMI_DATABASE_USER" "UMAMI_DATABASE_PASSWORD" "UMAMI_APP_SECRET" "DATABASE_URL")

missing_vars=()

for var in "${required_vars[@]}"; do
if [[ -z "${!var}" ]]; then
missing_vars+=("$var")
fi
done

if [[ ${#missing_vars[@]} -gt 0 ]]; then
echo "The following environment variables are missing:"
for var in "${missing_vars[@]}"; do
echo " - $var"
done
echo "Please add these variables to your .env file."
exit 1
fi

cluster_domain=$(kubectl cluster-info | grep 'Kubernetes control plane' | awk -F// '{print $2}' | awk -F: '{print $1}')

# Note: `.env` values get rerouted to their correct image target
# Prod uses: `POSTGRESQL_DATABASE`,`POSTGRESQL_USER`, and `POSTGRESQL_PASSWORD`
# Stage uses: `POSTGRES_DB`, `POSTGRES_USER` and `POSTGRES_PASSWORD`
# This different is due to the differences in the `postgresql:15-alpine` image and the `registry.redhat.io/rhel9/postgresql-15:9.5-1733127512` image
# Both map `UMAMI_APP_SECRET` to `APP_SECRET`

kubectl create secret generic umami-secret \
--from-literal "DATABASE_TYPE=${DATABASE_TYPE}" \
--from-literal "${UMAMI_DATABASE_NAME_KEY_NAME}=${UMAMI_DATABASE_NAME}" \
--from-literal "${UMAMI_DATABASE_USER_KEY_NAME}=${UMAMI_DATABASE_USER}" \
--from-literal "${UMAMI_DATABASE_PASSWORD_KEY_NAME}=${UMAMI_DATABASE_PASSWORD}" \
--from-literal "APP_SECRET=${UMAMI_APP_SECRET}" \
--from-literal "DATABASE_URL=${DATABASE_URL}" \
--namespace "${NAMESPACE}" \
--dry-run=client \
-o yaml > ${UMAMI_SECRET_FILE_PATH}

yq eval ".metadata.labels.cluster_domain = \"${cluster_domain}\"" -i ${UMAMI_SECRET_FILE_PATH}

echo "Secret manifest has been created: ${UMAMI_SECRET_FILE_PATH}."
Loading

0 comments on commit aa65db0

Please sign in to comment.