mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
392 lines
12 KiB
Bash
Executable File
392 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# usage: etc/final_deployment.sh [-e|--docker-export] [-c|--helm-chart] [-k|--kustomize] [-p|--prepare-k3s-pipeline] [-o|--output-dir DIR]
|
|
#
|
|
# This script handles post-installation deployment tasks for Knoe.
|
|
# 1st use case: -e|--docker-export
|
|
# Runs docker image export for each image required to deploy Knoe.
|
|
# Artifacts are written to DOCKER_IMPORT_DIR.
|
|
# 2nd use case: -c|--helm-chart
|
|
# Creates a Helm chart from the current k8s manifests.
|
|
# Artifacts are written to HELM_CHART_DIR.
|
|
# 3rd use case: -k|--kustomize
|
|
# Creates kustomize deployments (one per component).
|
|
# Artifacts are written to KUSTOMIZE_DIR.
|
|
# 4th use case: -p|--prepare-k3s-pipeline
|
|
# Stages all artifacts for k3s delivery via OpenTofu + ArgoCD.
|
|
# Copies manifests, generates tfvars, and creates ArgoCD Application manifests.
|
|
|
|
usage() {
|
|
echo "Usage: $0 [options]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -e, --docker-export Export required docker images to DOCKER_IMPORT_DIR"
|
|
echo " -c, --helm-chart Create Helm chart from k8s manifests"
|
|
echo " -k, --kustomize Create kustomize deployments from k8s manifests"
|
|
echo " -p, --prepare-k3s-pipeline Stage artifacts for k3s delivery (OpenTofu + ArgoCD)"
|
|
echo " -o, --output-dir DIR Base directory for docker-import/, helm-chart/, and kustomize/"
|
|
echo ""
|
|
}
|
|
|
|
do_docker_export=0
|
|
do_helm_chart=0
|
|
do_kustomize=0
|
|
do_k3s_pipeline=0
|
|
export_dir=""
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-e|--docker-export)
|
|
do_docker_export=1
|
|
shift
|
|
;;
|
|
-c|--helm-chart)
|
|
do_helm_chart=1
|
|
shift
|
|
;;
|
|
-k|--kustomize)
|
|
do_kustomize=1
|
|
shift
|
|
;;
|
|
-p|--prepare-k3s-pipeline)
|
|
do_k3s_pipeline=1
|
|
shift
|
|
;;
|
|
-o|--output-dir)
|
|
if [[ -z "${2:-}" ]]; then
|
|
echo "Missing value for $1"
|
|
usage
|
|
exit 1
|
|
fi
|
|
export_dir="$2"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ $do_docker_export -eq 0 && $do_helm_chart -eq 0 && $do_kustomize -eq 0 && $do_k3s_pipeline -eq 0 ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
export PROJECT_ROOT
|
|
|
|
# Load environment if env.sh exists
|
|
if [[ -f "${PROJECT_ROOT}/env.sh" ]]; then
|
|
source "${PROJECT_ROOT}/env.sh"
|
|
fi
|
|
|
|
default_owner="$(id -un 2>/dev/null || echo knoe)"
|
|
knoe_data="${PROLE_DATA:-/opt/knoe/data/${default_owner}}"
|
|
knoe_data="${knoe_data%/}"
|
|
|
|
if [[ -n "$export_dir" ]]; then
|
|
export_dir="${export_dir%/}"
|
|
DOCKER_IMPORT_DIR="${export_dir}/docker-import"
|
|
HELM_CHART_DIR="${export_dir}/helm-chart"
|
|
KUSTOMIZE_DIR="${export_dir}/kustomize"
|
|
fi
|
|
|
|
DOCKER_IMPORT_DIR="${DOCKER_IMPORT_DIR:-${knoe_data}/docker-import}"
|
|
HELM_CHART_DIR="${HELM_CHART_DIR:-${knoe_data}/helm-chart}"
|
|
KUSTOMIZE_DIR="${KUSTOMIZE_DIR:-${knoe_data}/kustomize}"
|
|
|
|
export_docker_images() {
|
|
echo "Exporting Docker images to: ${DOCKER_IMPORT_DIR}"
|
|
mkdir -p "${DOCKER_IMPORT_DIR}"
|
|
|
|
# Collect images from K8s manifests
|
|
# Robust extraction of image names from YAML files
|
|
find "${PROJECT_ROOT}/k8s/knoe" "${PROJECT_ROOT}/k8s/openbao" "${PROJECT_ROOT}/k8s/opentofu" -name "*.yaml" -exec grep -h "image:" {} + | awk -F'image:' '{print $2}' | awk '{print $1}' | sed "s/['\"]//g" > /tmp/knoe_images.txt
|
|
|
|
# Also check Supabase compose if it exists
|
|
if [[ -f "${PROJECT_ROOT}/supabase/docker/docker-compose.yml" ]]; then
|
|
grep -h "image:" "${PROJECT_ROOT}/supabase/docker/docker-compose.yml" | awk -F'image:' '{print $2}' | awk '{print $1}' | sed "s/['\"]//g" >> /tmp/knoe_images.txt
|
|
fi
|
|
|
|
# Add Kerberos proxy image if defined
|
|
KRB_IMG="${KRB5_AD_PROXY_IMAGE:-alpine/socat}"
|
|
if [[ -n "$KRB_IMG" ]]; then
|
|
echo "$KRB_IMG" >> /tmp/knoe_images.txt
|
|
fi
|
|
|
|
# Add Kerberos test image (used by init_kerberos_test.sh)
|
|
KRB_TEST_IMG="${KRB5_TEST_IMAGE:-${PROLE_KRB_TEST_IMAGE:-ubuntu:24.04}}"
|
|
if [[ -n "$KRB_TEST_IMG" ]]; then
|
|
echo "$KRB_TEST_IMG" >> /tmp/knoe_images.txt
|
|
fi
|
|
|
|
# Unique images
|
|
sort -u /tmp/knoe_images.txt > /tmp/knoe_images_unique.txt
|
|
|
|
while read -r image; do
|
|
if [[ -z "$image" ]]; then continue; fi
|
|
|
|
# Ensure we have the image locally
|
|
echo "Checking image: $image"
|
|
if ! docker image inspect "$image" >/dev/null 2>&1; then
|
|
echo "Pulling $image (platform linux/arm64)..."
|
|
docker pull --platform linux/arm64 "$image"
|
|
fi
|
|
|
|
safe_name=$(echo "$image" | sed 's/\//_/g' | sed 's/:/_/g')
|
|
tar_path="${DOCKER_IMPORT_DIR}/${safe_name}.tar"
|
|
|
|
echo "Exporting $image to $tar_path..."
|
|
docker save "$image" -o "$tar_path"
|
|
if [[ $? -eq 0 ]]; then
|
|
echo "[OK] Exported $image"
|
|
else
|
|
echo "[ERROR] Failed to export $image"
|
|
fi
|
|
done < /tmp/knoe_images_unique.txt
|
|
|
|
rm -f /tmp/knoe_images.txt /tmp/knoe_images_unique.txt
|
|
echo "Docker export complete."
|
|
}
|
|
|
|
create_helm_chart() {
|
|
local chart_dir="${HELM_CHART_DIR}"
|
|
local chart_name="knoe"
|
|
local chart_version="0.1.0"
|
|
local app_version
|
|
app_version="$(date -u +%Y.%m.%d)"
|
|
|
|
echo "Creating Helm chart in: ${chart_dir}"
|
|
mkdir -p "${chart_dir}/templates"
|
|
|
|
# Clean managed template subdirs to avoid stale manifests.
|
|
rm -rf "${chart_dir}/templates/knoe" "${chart_dir}/templates/openbao" "${chart_dir}/templates/opentofu"
|
|
|
|
cat > "${chart_dir}/Chart.yaml" <<EOF
|
|
apiVersion: v2
|
|
name: ${chart_name}
|
|
description: Knoe deployment manifests
|
|
type: application
|
|
version: ${chart_version}
|
|
appVersion: "${app_version}"
|
|
EOF
|
|
|
|
cat > "${chart_dir}/values.yaml" <<'EOF'
|
|
# Values are unused by default. Manifests are installed as-is.
|
|
EOF
|
|
|
|
copy_manifests() {
|
|
local src_dir="$1"
|
|
local dest_subdir="$2"
|
|
if [[ ! -d "$src_dir" ]]; then
|
|
echo "Skipping missing manifest dir: $src_dir"
|
|
return
|
|
fi
|
|
local dest_dir="${chart_dir}/templates/${dest_subdir}"
|
|
mkdir -p "${dest_dir}"
|
|
local found=0
|
|
while IFS= read -r -d '' file; do
|
|
if [[ "$(basename "$file")" == "kustomization.yaml" ]]; then
|
|
continue
|
|
fi
|
|
cp "$file" "${dest_dir}/"
|
|
found=1
|
|
done < <(find "$src_dir" -maxdepth 1 -type f -name "*.yaml" -print0)
|
|
if [[ $found -eq 0 ]]; then
|
|
echo "No manifests found in $src_dir"
|
|
fi
|
|
}
|
|
|
|
copy_manifests "${PROJECT_ROOT}/k8s/knoe" "knoe"
|
|
copy_manifests "${PROJECT_ROOT}/k8s/openbao" "openbao"
|
|
copy_manifests "${PROJECT_ROOT}/k8s/opentofu" "opentofu"
|
|
|
|
echo "Helm chart creation complete."
|
|
}
|
|
|
|
create_kustomize_deployments() {
|
|
local base_dir="${KUSTOMIZE_DIR}"
|
|
echo "Creating kustomize deployments in: ${base_dir}"
|
|
mkdir -p "${base_dir}"
|
|
|
|
create_kustomize_package() {
|
|
local name="$1"
|
|
local src_dir="$2"
|
|
if [[ ! -d "$src_dir" ]]; then
|
|
echo "Skipping missing manifest dir: $src_dir"
|
|
return
|
|
fi
|
|
|
|
local dest_dir="${base_dir}/${name}"
|
|
mkdir -p "${dest_dir}"
|
|
|
|
# Copy manifests except kustomization.yaml
|
|
local files=()
|
|
while IFS= read -r -d '' file; do
|
|
if [[ "$(basename "$file")" == "kustomization.yaml" ]]; then
|
|
continue
|
|
fi
|
|
cp "$file" "${dest_dir}/"
|
|
files+=("$(basename "$file")")
|
|
done < <(find "$src_dir" -maxdepth 1 -type f -name "*.yaml" -print0)
|
|
|
|
if [[ ${#files[@]} -eq 0 ]]; then
|
|
echo "No manifests found in $src_dir"
|
|
return
|
|
fi
|
|
|
|
{
|
|
echo "apiVersion: kustomize.config.k8s.io/v1beta1"
|
|
echo "kind: Kustomization"
|
|
echo "resources:"
|
|
for f in "${files[@]}"; do
|
|
echo " - ${f}"
|
|
done
|
|
} > "${dest_dir}/kustomization.yaml"
|
|
}
|
|
|
|
create_kustomize_package "knoe" "${PROJECT_ROOT}/k8s/knoe"
|
|
create_kustomize_package "openbao" "${PROJECT_ROOT}/k8s/openbao"
|
|
create_kustomize_package "opentofu" "${PROJECT_ROOT}/k8s/opentofu"
|
|
|
|
echo "Kustomize deployments creation complete."
|
|
}
|
|
|
|
if [[ $do_docker_export -eq 1 ]]; then
|
|
export_docker_images
|
|
fi
|
|
|
|
if [[ $do_helm_chart -eq 1 ]]; then
|
|
create_helm_chart
|
|
fi
|
|
|
|
if [[ $do_kustomize -eq 1 ]]; then
|
|
create_kustomize_deployments
|
|
fi
|
|
|
|
prepare_k3s_pipeline() {
|
|
echo "========================================"
|
|
echo "Preparing k3s pipeline (OpenTofu + ArgoCD)"
|
|
echo "========================================"
|
|
echo ""
|
|
|
|
local pipeline_dir="${PROJECT_ROOT}/deploy/opentofu/k3s"
|
|
local manifest_root="${pipeline_dir}/manifests"
|
|
local argocd_dir="${pipeline_dir}/argocd"
|
|
mkdir -p "${manifest_root}" "${argocd_dir}"
|
|
|
|
echo "==> Staging k8s manifests to ${manifest_root}"
|
|
local total=0
|
|
for component in knoe openbao opentofu; do
|
|
local src="${PROJECT_ROOT}/k8s/${component}"
|
|
if [[ ! -d "$src" ]]; then
|
|
echo " [SKIP] ${component}/ (not found)"
|
|
continue
|
|
fi
|
|
local dst="${manifest_root}/${component}"
|
|
mkdir -p "$dst"
|
|
local count=0
|
|
for f in "${src}"/*.yaml; do
|
|
[[ -f "$f" ]] || continue
|
|
cp "$f" "$dst/"
|
|
count=$((count + 1))
|
|
done
|
|
total=$((total + count))
|
|
echo " [OK] ${component}/ -> manifests/${component}/ (${count} files)"
|
|
done
|
|
echo " Total manifests staged: ${total}"
|
|
|
|
# Stage Supabase manifests if present
|
|
local supabase_k8s="${PROJECT_ROOT}/supabase/k8s"
|
|
if [[ -d "$supabase_k8s" ]]; then
|
|
local dst="${manifest_root}/supabase"
|
|
mkdir -p "$dst"
|
|
local count=0
|
|
for f in "${supabase_k8s}"/*.yaml; do
|
|
[[ -f "$f" ]] || continue
|
|
cp "$f" "$dst/"
|
|
count=$((count + 1))
|
|
done
|
|
if [[ $count -gt 0 ]]; then
|
|
echo " [OK] supabase/k8s/ -> manifests/supabase/ (${count} files)"
|
|
fi
|
|
fi
|
|
|
|
# Write tfvars
|
|
local k3s_server="${K3S_SERVER_URL:-}"
|
|
local k3s_token="${K3S_TOKEN:-}"
|
|
local namespace="${PROLE_NAMESPACE:-default}"
|
|
|
|
echo ""
|
|
echo "==> Writing opentofu.auto.tfvars"
|
|
echo " k3s_server_url = ${k3s_server:-(not set)}"
|
|
echo " namespace = ${namespace}"
|
|
|
|
cat > "${pipeline_dir}/opentofu.auto.tfvars" <<EOF
|
|
k3s_server_url = "${k3s_server}"
|
|
k3s_token = "${k3s_token}"
|
|
namespace = "${namespace}"
|
|
EOF
|
|
|
|
# Generate ArgoCD Application manifests
|
|
echo ""
|
|
echo "==> Generating ArgoCD Application manifests in argocd/"
|
|
|
|
local repo_url="${PROLE_GIT_REPO:-}"
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url=$(cd "${PROJECT_ROOT}" && git remote get-url origin 2>/dev/null || true)
|
|
fi
|
|
repo_url="${repo_url:-https://github.com/knoe-dev/knoe.git}"
|
|
local target_revision="${PROLE_GIT_BRANCH:-main}"
|
|
|
|
for component in knoe openbao opentofu; do
|
|
cat > "${argocd_dir}/application-${component}.yaml" <<EOF
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: knoe-${component}
|
|
namespace: argocd
|
|
spec:
|
|
project: default
|
|
source:
|
|
repoURL: ${repo_url}
|
|
targetRevision: ${target_revision}
|
|
path: deploy/opentofu/k3s/manifests/${component}
|
|
destination:
|
|
server: ${k3s_server:-https://kubernetes.default.svc}
|
|
namespace: ${namespace}
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
syncOptions:
|
|
- CreateNamespace=true
|
|
EOF
|
|
echo " [OK] application-${component}.yaml"
|
|
done
|
|
|
|
echo ""
|
|
echo "==> k3s pipeline preparation complete."
|
|
echo " Pipeline dir: ${pipeline_dir}"
|
|
echo " ArgoCD apps: ${argocd_dir}"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " cd ${pipeline_dir} && tofu init && tofu plan && tofu apply"
|
|
echo " kubectl apply -f ${argocd_dir}/"
|
|
}
|
|
|
|
if [[ $do_k3s_pipeline -eq 1 ]]; then
|
|
prepare_k3s_pipeline
|
|
fi
|