This folder provides all required scripts and instructions for the full provisioning of the cluster(s) required for enabling a cloud-native way of work in OSM:
Management Cluster.First, you should load the environment variables with the key folders and configuration parameters. By default, in case some of them where still undefined, you may load sensible defaults by doing:
source 00-base-config.rc
Then, you should select the appropriate kubeconfig to point to the cluster where you want to install the auxiliary services. For instance:
export KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" # Alternatively: # kubectl config use-context osm-aux-svc-admin
Then run the all-in-one installer and, optionally, add the local Git user for more a more convenient setup to commit changes to the repos:
./01-provision-aux-svc.sh # (optional) ./02-provision-local-git-user.sh
First retrieve service's credentials and endpoints as environment variables:
# Load Gitea environment source "${CREDENTIALS_DIR}/gitea_environment.rc" source "${CREDENTIALS_DIR}/gitea_tokens.rc" # Load Minio environment source "${CREDENTIALS_DIR}/minio_environment.rc"
# Get URL and credentials to go with browser echo "Gitea HTTP URL: ${GITEA_HTTP_URL}" echo "Gitea admin user:" echo -e "- \tUser name: ${GITEA_ADMINISTRATOR_USERNAME}" echo -e "- \tPassword: ${GITEA_ADMINISTRATOR_PASSWORD}" echo "Gitea regular user:" echo -e "- \tUser name: ${GITEA_STD_USERNAME}" echo -e "- \tPassword: ${GITEA_STD_USER_PASS}" # SSH URL echo "Gitea SSH URL: ${GITEA_SSH_URL}"
Get the URL and the JWT token to access the Minio Operator Console with the browser:
# Open URL in browser using the JWT as access token echo "Console URL: ${MINIO_CONSOLE_URL}" echo -e "JWT token:\n${MINIO_SA_TOKEN}"
Then test the tenant:
# Add alias to connect to the tenant ALIAS=osm echo "Minio Tenant URL: ${MINIO_TENANT_URL}" minioc alias set ${ALIAS} ${MINIO_TENANT_URL} ${MINIO_OSM_USERNAME} ${MINIO_OSM_PASSWORD} --insecure # Test minioc admin info ${ALIAS} --insecure # (optional) Delete the alias minioc alias remove ${ALIAS}
First, you should load the environment variables with the key folders and configuration parameters (in case your had not done it before). By default, in case some of them where still undefined, you may load sensible defaults by doing:
source 00-base-config.rc
Then, you should select the appropriate kubeconfig to point to the cluster that you want to make a management cluster for OSM. For instance:
export KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-mgmt.yaml" # Alternatively: # kubectl config use-context osm-mgmt-admin
Depending on your situation, you can choose among these three procedures:
age key pair, reusing a set of pre-created manifests so that the process is simplified.age key pair).age key pair.age key pair.NOTE: Before proceeding, please ensure the appropriate kubeconfig and make sure to source the required base configuration at 00-base-config.rc.
./03-provision-mgmt-cluster.sh
(optional) Watch sync progress:
./flux/scripts/watch-mgmt-cluster.sh
# Sources helper functions source ./flux/scripts/helper-functions.rc # Creates a secret and encrypts it with age SECRET_NAME="test-secret" PROJECT_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}" PROFILE_NAME="_management" RESOURCES_DIR="${PROJECT_DIR}/managed-resources/${PROFILE_NAME}" kubectl create secret generic "${SECRET_NAME}" \ --namespace managed-resources \ --from-literal=foo=bar \ -o yaml --dry-run=client | tee "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml" # Encrypt in-place encrypt_secret_inplace "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml" # (Optional) View the secret manifest once encrypted cat "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
Push the new manifest:
pushd "${FLEET_REPO_DIR}" git status git add -A git commit -m "Test of encrypted secret" git push popd
Check that the secret was successfully decrypted by Flux and created properly:
kubectl get secret ${SECRET_NAME} -n managed-resources -o yaml kubectl get secret ${SECRET_NAME} -n managed-resources -o jsonpath='{.data.foo}' | base64 -d
Cleanup:
rm "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml" pushd "${FLEET_REPO_DIR}" git status git add -A git commit -m "Cleanup: Remove test secret" git push popd
After a while it should be deleted:
watch kubectl get secret ${SECRET_NAME} -n managed-resources
# Check the health of Crossplane providers kubectl get providers.pkg.crossplane.io kubectl get crd | grep upbound # kubectl get crd | grep azure # kubectl get crd | grep gcp # Check the availability of Argo WorkFlows kubectl port-forward deployment/argo-server -n argo 2746:2746 # Open <https://localhost:2746>
age key pairTODO:
Load the environment:
source 00-base-config.rc source "${CREDENTIALS_DIR}/gitea_environment.rc" source "${CREDENTIALS_DIR}/gitea_tokens.rc"
For convenience, create in Gitea a local user's profile, add public SSH key, and add as collaborator to the repo of the standard Gitea user (NOTE: We have to force the kubeconfig profile for the cluster for auxiliary services):
# Create new user export USER_NAME=$(git config --get user.name) export USER_MAIL=$(git config --get user.email) export USER_PASS="${GITEA_STD_USER_PASS}" # Same as standard user KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/create-user.sh" \ "${USER_NAME}" \ "${USER_PASS}" \ "${USER_MAIL}" # Create token export USER_TOKEN_NAME=user_token_name export USER_TOKEN=$( \ KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/create-cmd-access-token.sh" "${USER_NAME}" "${USER_TOKEN_NAME}" | \ grep 'Access token was successfully created' | \ cut -d ' ' -f 6 \ )
Add public SSH key:
# PARAMETERS: # ========== # 1) Server URL # 2) Username # 3) Token # 4) SSH key content # 5) SSH key name in Gitea's user profile # 6) Read only? KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/create-user-ssh-key.sh" \ "${GITEA_HTTP_URL}" \ "${USER_NAME}" \ "${USER_TOKEN}" \ "$(<${HOME}/.ssh/id_rsa.pub)" \ "local_user_ssh_key" \ false
Add user as collaborator of the relevant repos:
# Fleet repo KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/add-collaborator-to-user-repo.sh" \ "${GITEA_HTTP_URL}" \ "${GITEA_STD_USERNAME}" \ "${GITEA_STD_TOKEN}" \ "fleet-osm" \ "${USER_NAME}" \ "write" # SW-Catalogs repo KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/add-collaborator-to-user-repo.sh" \ "${GITEA_HTTP_URL}" \ "${GITEA_STD_USERNAME}" \ "${GITEA_STD_TOKEN}" \ "sw-catalogs-osm" \ "${USER_NAME}" \ "write"
Finally, clone both repos in a well-known location:
mkdir -p "${WORK_REPOS_DIR}" export FLEET_REPO_DIR="${WORK_REPOS_DIR}/fleet-osm" export SW_CATALOGS_REPO_DIR="${WORK_REPOS_DIR}/sw-catalogs-osm" # git@<GITEA_SSH_URL>:osm-developer/fleet-osm.git git clone ${GITEA_SSH_URL}/${GITEA_STD_USERNAME}/fleet-osm.git "${FLEET_REPO_DIR}" # git@<GITEA_SSH_URL>:osm-developer/sw-catalogs-osm.git git clone ${GITEA_SSH_URL}/${GITEA_STD_USERNAME}/sw-catalogs-osm.git "${SW_CATALOGS_REPO_DIR}" # Forces main instead of master pushd "${SW_CATALOGS_REPO_DIR}" # git branch -m master main git symbolic-ref HEAD refs/heads/main popd
Now we can run a regular Flux bootstrap (without encryption):
# Regular bootstrap REPO=fleet-osm GIT_PATH=./clusters/_management GIT_BRANCH=main GIT_HTTP_URL=${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/${REPO}.git flux bootstrap git \ --url=${GIT_HTTP_URL} \ --allow-insecure-http=true \ --username=${GITEA_STD_USERNAME} \ --password="${GITEA_STD_USER_PASS}" \ --token-auth=true \ --branch=${GIT_BRANCH} \ --path=${GIT_PATH} # (optional) Check if successful flux check
Once completed the bootstrap, we will pull the latest changes from the fleet repo so that we can work conveniently:
git -C "${FLEET_REPO_DIR}" pull
Create a new age key pair for the management cluster:
# Create private key and extract public key export AGE_KEY_NAME_MGMT=age.mgmt rm "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub" age-keygen -o "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" age-keygen -y "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" > "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub" # Save the contents in environment variables for easier consumption export PRIVATE_KEY_MGMT=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key") export PUBLIC_KEY_MGMT=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub") echo "${PRIVATE_KEY_MGMT}" echo "${PUBLIC_KEY_MGMT}"
Add the age private key to the cluster as secret:
cat "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" | kubectl create secret generic sops-age \ --namespace=flux-system \ --from-file=age.agekey=/dev/stdin
Create SOPS configuration at the root folder of the management cluster:
cat <<EOF > "${FLEET_REPO_DIR}/clusters/_management/.sops.yaml" creation_rules: - encrypted_regex: ^(data|stringData)$ age: ${PUBLIC_KEY_MGMT} # - path_regex: .*.yaml # encrypted_regex: ^(data|stringData)$ # age: ${PUBLIC_KEY_MGMT} EOF
(optional) Add also the public key to the repository so that others who clone the repo can encrypt new files:
cp "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub" "${FLEET_REPO_DIR}/clusters/_management/.sops.pub.asc"
Create the base folder structure + all profile folders for the management cluster:
# Name of the project for the OSM administrator export MGMT_PROJECT_NAME="osm_admin" # Creates all possible profile folders (as well as env var aliases) export MGMT_ADDON_CTRL_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/infra-controller-profiles/_management" export MGMT_ADDON_CONFIG_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/infra-config-profiles/_management" export MGMT_RESOURCES_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/_management" export MGMT_APPS_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/app-profiles/_management" mkdir -p "${MGMT_ADDON_CTRL_DIR}" mkdir -p "${MGMT_ADDON_CONFIG_DIR}" mkdir -p "${MGMT_RESOURCES_DIR}" mkdir -p "${MGMT_APPS_DIR}" # Copies the templates for management cluster setup export TEMPLATES_DIR="flux/templates" export TEMPLATES_DIR=$(readlink -f "${TEMPLATES_DIR}") export MGMT_CLUSTER_DIR="${FLEET_REPO_DIR}/clusters/_management" cp "${TEMPLATES_DIR}/fleet/clusters/_management"/* "${MGMT_CLUSTER_DIR}/"
Overrides the Git repo references and adds their secrets as needed (NOTE: these are the last secrets to be added imperatively):
# Repo URLs export FLEET_REPO_URL="${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/fleet-osm.git" export SW_CATALOGS_REPO_URL="${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/sw-catalogs-osm.git" export INFRA_CONTROLLERS_PATH="./${MGMT_PROJECT_NAME}/infra-controller-profiles/_management" export INFRA_CONFIGS_PATH="./${MGMT_PROJECT_NAME}/infra-config-profiles/_management" export MANAGED_RESOURCES_PATH="./${MGMT_PROJECT_NAME}/managed-resources/_management" export APPS_PATH="./${MGMT_PROJECT_NAME}/app-profiles/_management" # Fleet repo envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/fleet-repo.yaml" > "${MGMT_CLUSTER_DIR}/fleet-repo.yaml" # SW-Catalogs repo envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/sw-catalogs-repo.yaml" > "${MGMT_CLUSTER_DIR}/sw-catalogs-repo.yaml" # Secrets to access both Git repos kubectl create secret generic fleet-repo \ --namespace flux-system \ --from-literal=username="${GITEA_STD_USERNAME}" \ --from-literal=password="${GITEA_STD_USER_PASS}" kubectl create secret generic sw-catalogs \ --namespace flux-system \ --from-literal=username="${GITEA_STD_USERNAME}" \ --from-literal=password="${GITEA_STD_USER_PASS}" # Kustomization to sync infra controllers profile envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/infra-controllers.yaml" > "${MGMT_CLUSTER_DIR}/infra-controllers.yaml" # Kustomization to sync infra configs profile envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/infra-configs.yaml" > "${MGMT_CLUSTER_DIR}/infra-configs.yaml" # Kustomization to sync managed resources profile envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/managed-resources.yaml" > "${MGMT_CLUSTER_DIR}/managed-resources.yaml" # Kustomization to sync apps profile envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/apps.yaml" > "${MGMT_CLUSTER_DIR}/apps.yaml"
Create ConfigMap into profiles (and Namespace specs when needed) to avoid sync errors:
# Helper functions to create the profile ConfigMaps function safe_name() { echo "$1" | \ sed '/\.\// s|./||' | \ sed 's|\.|-|g' | \ sed 's|/|-|g' | \ sed 's|_|-|g' | \ sed 's| |-|g' } function create_profile_configmap() { local CONFIGMAP_NAME=$(safe_name "$1") local PROFILE_REPO_URL="$2" local PROFILE_PATH="$3" kubectl create configmap ${CONFIGMAP_NAME} \ --namespace flux-system \ --from-literal=repo="${PROFILE_REPO_URL}" \ --from-literal=path="${PROFILE_PATH}" \ -o yaml \ --dry-run=client } # Infra controllers ConfigMap # Same name as the corresponding kustomization name CONFIGMAP_NAME="infra-controllers" PROFILE_REPO_URL="${FLEET_REPO_URL}" PROFILE_PATH="${INFRA_CONTROLLERS_PATH}" create_profile_configmap \ "${CONFIGMAP_NAME}" \ "${PROFILE_REPO_URL}" \ "${PROFILE_PATH}" \ > "${MGMT_ADDON_CTRL_DIR}/profile-configmap.yaml" # Infra configurations ConfigMap CONFIGMAP_NAME="infra-configs" PROFILE_REPO_URL="${FLEET_REPO_URL}" PROFILE_PATH="${INFRA_CONFIGS_PATH}" create_profile_configmap \ "${CONFIGMAP_NAME}" \ "${PROFILE_REPO_URL}" \ "${PROFILE_PATH}" \ > "${MGMT_ADDON_CONFIG_DIR}/profile-configmap.yaml" # Managed resources ConfigMap CONFIGMAP_NAME="managed-resources" PROFILE_REPO_URL="${FLEET_REPO_URL}" PROFILE_PATH="${MANAGED_RESOURCES_PATH}" create_profile_configmap \ "${CONFIGMAP_NAME}" \ "${PROFILE_REPO_URL}" \ "${PROFILE_PATH}" \ > "${MGMT_RESOURCES_DIR}/profile-configmap.yaml" # Managed resources namespace kubectl create ns ${CONFIGMAP_NAME} \ -o yaml --dry-run=client \ > "${MGMT_RESOURCES_DIR}/namespace.yaml" # Apps ConfigMap CONFIGMAP_NAME="apps" PROFILE_REPO_URL="${FLEET_REPO_URL}" PROFILE_PATH="${APPS_PATH}" create_profile_configmap \ "${CONFIGMAP_NAME}" \ "${PROFILE_REPO_URL}" \ "${PROFILE_PATH}" \ > "${MGMT_APPS_DIR}/profile-configmap.yaml"
Push to Git all new manifests:
pushd "${FLEET_REPO_DIR}" git status git add -A git commit -m "Full profile structure after bootstrap + SOPS config" git push popd
(optional) Watch sync progress:
./flux/scripts/watch-mgmt-cluster.sh
# Helper function to in-place encrypt secrets in manifest function encrypt_secret_inplace() { local FILE="$1" sops \ --age=${PUBLIC_KEY_MGMT} \ --encrypt \ --encrypted-regex '^(data|stringData)$' \ --in-place "${FILE}" } # Creates a secret and encrypts it with age SECRET_NAME="prueba" kubectl create secret generic "${SECRET_NAME}" \ --namespace managed-resources \ --from-literal=foo=bar \ -o yaml --dry-run=client | tee "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml" encrypt_secret_inplace "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml" # (Optional) View the secret manifest once encrypted cat "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
Push the new manifest:
pushd "${FLEET_REPO_DIR}" git status git add -A git commit -m "Test of encrypted secret" git push popd
Check that the secret was successfully decrypted by Flux and created properly:
kubectl get secret ${SECRET_NAME} -n managed-resources -o yaml kubectl get secret ${SECRET_NAME} -n managed-resources -o jsonpath='{.data.foo}' | base64 -d
Cleanup:
rm "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml" pushd "${FLEET_REPO_DIR}" git status git add -A git commit -m "Cleanup: Remove test secret" git push popd
After a while it should be deleted:
watch kubectl get secret ${SECRET_NAME} -n managed-resources
First, we populate the SW-Catalogs repo:
rsync -varhP "${TEMPLATES_DIR}/sw-catalogs/" "${SW_CATALOGS_REPO_DIR}/" pushd "${SW_CATALOGS_REPO_DIR}" git status git add -A git commit -m "Sync from sw-catalogs template" git push -u origin main popd
Add the CrossPlane controller:
PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/controller" cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/"
Add the CrossPlane providers:
# Azure providers PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/azure" cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/" # GCP providers PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/gcp" cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/" # TODO: AWS providers
Add the Argo WorkFlows controller:
PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/argo-workflows" cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/"
Push all changes to the fleet repo:
pushd "${FLEET_REPO_DIR}" git status git add -A git commit -m "Install base controllers and CRDs into mgmt cluster" git push -u origin main popd
(optional) Checks:
# Check the health of Crossplane providers kubectl get providers.pkg.crossplane.io kubectl get crd | grep upbound # kubectl get crd | grep azure # kubectl get crd | grep gcp # Check the availability of Argo WorkFlows kubectl port-forward deployment/argo-server -n argo 2746:2746 # <https://localhost:2746>