Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b86b660
feat(generic): migration from bitnami scripts
leiicamundi Dec 17, 2025
c7db1a4
test
leiicamundi Dec 17, 2025
b497d67
fix
leiicamundi Dec 17, 2025
10d2c02
fix
leiicamundi Dec 17, 2025
c0f88ca
fix
leiicamundi Dec 19, 2025
e1f8db5
fix
leiicamundi Dec 19, 2025
14b0f34
update
leiicamundi Feb 13, 2026
76cae07
fix
leiicamundi Feb 13, 2026
e545beb
renamed file to match filename limit
leiicamundi Feb 17, 2026
b27569f
fix: identity secret keys + use debug-failed-pods action
leiicamundi Feb 17, 2026
9ec7e06
fix: add global.secrets.autoGenerated + remove existingSecret for web…
leiicamundi Feb 18, 2026
fce6fb7
fix: restore webModelerPostgresql existingSecret + secretKeys for res…
leiicamundi Feb 18, 2026
18cb7ab
extract
leiicamundi Feb 18, 2026
eef188e
fixes
leiicamundi Feb 18, 2026
2602c54
fix
leiicamundi Feb 18, 2026
0358efc
tmate detached modefix
leiicamundi Feb 18, 2026
0a7701f
fix
leiicamundi Feb 18, 2026
0cd6f4b
fix
leiicamundi Feb 18, 2026
77ffe74
fix
leiicamundi Feb 18, 2026
a501505
fix
leiicamundi Feb 18, 2026
46ce44d
fix
leiicamundi Feb 18, 2026
976a628
fix
leiicamundi Feb 18, 2026
96acb99
fix
leiicamundi Feb 18, 2026
60cf04e
fix
leiicamundi Feb 18, 2026
ba879c3
fix
leiicamundi Feb 19, 2026
fe76992
debug
leiicamundi Feb 19, 2026
5e857d7
fix
leiicamundi Feb 19, 2026
830e939
fix
leiicamundi Feb 19, 2026
3faa23f
fix
leiicamundi Feb 19, 2026
43bf105
improve
leiicamundi Feb 20, 2026
27d9243
revert updates
leiicamundi Feb 20, 2026
4796756
fix
leiicamundi Feb 20, 2026
cef7353
fix
leiicamundi Feb 20, 2026
1717a18
fix(migration): add curl timeouts and fix search result parsing
leiicamundi Feb 25, 2026
3e59d87
fix: revert keycloak image tag from 26.5.0 to 26.3.2
leiicamundi Feb 25, 2026
0ee8c21
WIP
leiicamundi Feb 25, 2026
0f3a1aa
fix
leiicamundi Feb 25, 2026
a30edf3
fix
leiicamundi Feb 26, 2026
77e5768
fix
leiicamundi Feb 26, 2026
0cad6de
fix
leiicamundi Feb 26, 2026
52c3bdb
fix
leiicamundi Feb 26, 2026
0ad6bee
fix
leiicamundi Feb 27, 2026
112a376
fix
leiicamundi Mar 2, 2026
2c9cd65
fix
leiicamundi Mar 2, 2026
4519d30
fix
leiicamundi Mar 2, 2026
ba28560
fix(migration): skip empty ES indices in reindex restore
leiicamundi Mar 2, 2026
ba14332
fix(migration): auto-detect installed chart version for helm upgrade
leiicamundi Mar 2, 2026
5bea33c
fix: disable Bitnami sub-charts in operator values to avoid mutual ex…
leiicamundi Mar 2, 2026
9f0915f
fix
leiicamundi Mar 3, 2026
90189e9
Merge branch 'main' into feature/bitnami-to-alt-migration
leiicamundi Mar 3, 2026
603a7ab
fix(migration): add camunda- prefix to ES index patterns and explicit…
leiicamundi Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ self-hosted-runner:
# Labels of self-hosted runner in array of string
labels:
- aws-core-8-default
- aws-core-16-default
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
# Test matrix configuration for Migration from Bitnami tests
# This matrix defines the test scenarios for migrating from Bitnami sub-charts
# to Kubernetes operators (ECK, CNPG, Keycloak Operator)

matrix:
distro:
# Kind is used for migration tests — no cloud infra needed
- name: Kind
schedule_only: false
type: kind

scenario:
# Test the full migration workflow
- name: migration-from-bitnami
shortName: mfb

declination:
- name: no-domain
use_tls: false
desc: Test migration from Bitnami to operators without domain configuration.
- name: domain
use_tls: true
desc: Test migration from Bitnami to operators with Ingress and TLS (camunda.example.com).

# Components to test migration for
# Each component can be tested independently
component:
- name: full
desc: Run full migration (all components)
orchestration: true
identity: true
keycloak: true
webmodeler: true
436 changes: 436 additions & 0 deletions .github/workflows/generic_kubernetes_migration_test.yml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,5 @@ terraform.tfstate.backup
trivyreport.txt

camunda-docs/
debug/
camunda-platform-helm/
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,6 @@ repos:
rev: 0.2.3
hooks:
- id: yamlfmt
exclude: (generic/kubernetes/operator-based/elasticsearch/elasticsearch-cluster.yml|local/kubernetes/kind-single-region/configs/elasticsearch-cluster.yml)
# yamlfmt removes quotes around YAML values like "OFF" which breaks ES config
# yamllint disable-line rule:line-length
exclude: (generic/kubernetes/operator-based/elasticsearch/elasticsearch-cluster.yml|generic/kubernetes/migration/manifests/eck-cluster.yml|local/kubernetes/kind-single-region/configs/elasticsearch-cluster.yml)
1 change: 1 addition & 0 deletions generic/kubernetes/migration/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.state
147 changes: 147 additions & 0 deletions generic/kubernetes/migration/1-deploy-targets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/bin/bash
# =============================================================================
# Phase 1: Deploy target operators and clusters (NO DOWNTIME)
# =============================================================================
# This phase installs the target infrastructure alongside the existing Bitnami
# components. It runs while the application is fully operational.
#
# Delegates to the operator-based reference architecture scripts:
# ../operator-based/postgresql/deploy.sh — CNPG operator + PG clusters
# ../operator-based/elasticsearch/deploy.sh — ECK operator + ES cluster
# ../operator-based/keycloak/deploy.sh — Keycloak operator + CR
#
# The Elasticsearch cluster uses a migration-specific manifest that adds
# reindex.remote.whitelist support for data migration via the _reindex API.
#
# Prerequisites:
# - source env.sh
# - kubectl configured and pointing to the right cluster
# - helm repo add camunda https://helm.camunda.io
# - yq installed (for CNPG CLUSTER_FILTER support)
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC2034 # Used by lib.sh after sourcing
CURRENT_SCRIPT="1-deploy-targets.sh"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib.sh"
parse_common_args "$@"

check_env

timer_start

section "Phase 1: Deploy Target Infrastructure (no downtime)"

show_plan 1
run_hooks "pre-phase-1"

if is_external_pg || is_external_es; then
echo "External target mode is active:"
is_external_pg && echo " • PostgreSQL → external managed service (CNPG will NOT be deployed)"
is_external_es && echo " • Elasticsearch → external managed service (ECK will NOT be deployed)"
echo ""
fi

# ─────────────────────────────────────────────────────────────────────────────
# Customization warning
# ─────────────────────────────────────────────────────────────────────────────
warn_customization

confirm "Have you reviewed and customized the operator-based manifests?"

# ─────────────────────────────────────────────────────────────────────────────
# Resource validation
# ─────────────────────────────────────────────────────────────────────────────
validate_target_resources

# ─────────────────────────────────────────────────────────────────────────────
# 1. PostgreSQL (CNPG) — one cluster per component that needs PG
# ─────────────────────────────────────────────────────────────────────────────

needs_pg_migration() {
local component="$1"
detect_pg_sts "$component" >/dev/null 2>&1
}

if [[ "${MIGRATE_IDENTITY}" == "true" ]] || [[ "${MIGRATE_KEYCLOAK}" == "true" ]] || [[ "${MIGRATE_WEBMODELER}" == "true" ]]; then
section "1/3 — CloudNativePG (operator + clusters)"

if is_external_pg; then
log_info "PG_TARGET_MODE=external — CNPG deployment skipped"
save_state "PG_TARGET_IS_EXTERNAL" "true"
else
# Determine which clusters to deploy
PG_CLUSTERS_TO_DEPLOY=()

if [[ "${MIGRATE_IDENTITY}" == "true" ]] && needs_pg_migration identity; then
PG_CLUSTERS_TO_DEPLOY+=("${CNPG_IDENTITY_CLUSTER}")
fi
if [[ "${MIGRATE_KEYCLOAK}" == "true" ]] && needs_pg_migration keycloak; then
PG_CLUSTERS_TO_DEPLOY+=("${CNPG_KEYCLOAK_CLUSTER}")
fi
if [[ "${MIGRATE_WEBMODELER}" == "true" ]] && needs_pg_migration webmodeler; then
PG_CLUSTERS_TO_DEPLOY+=("${CNPG_WEBMODELER_CLUSTER}")
fi

if [[ ${#PG_CLUSTERS_TO_DEPLOY[@]} -eq 3 ]]; then
# All 3 clusters needed — deploy without filter (more efficient)
deploy_postgresql ""
elif [[ ${#PG_CLUSTERS_TO_DEPLOY[@]} -gt 0 ]]; then
# Deploy individual clusters
for cluster in "${PG_CLUSTERS_TO_DEPLOY[@]}"; do
deploy_postgresql "$cluster"
done
else
log_info "No PostgreSQL components need migration — skipping CNPG"
fi
fi
fi

# ─────────────────────────────────────────────────────────────────────────────
# 2. Elasticsearch (ECK)
# ─────────────────────────────────────────────────────────────────────────────

if [[ "${MIGRATE_ELASTICSEARCH}" == "true" ]]; then
section "2/3 — ECK Elasticsearch"

if is_external_es; then
log_info "ES_TARGET_MODE=external — ECK deployment skipped"
save_state "ES_TARGET_IS_EXTERNAL" "true"
elif kubectl get elasticsearch "${ECK_CLUSTER_NAME}" -n "${NAMESPACE}" &>/dev/null; then
log_success "ECK cluster ${ECK_CLUSTER_NAME} already exists — skipping"
else
deploy_elasticsearch
save_state "ECK_DEPLOYED" "true"
fi
fi

# ─────────────────────────────────────────────────────────────────────────────
# 3. Keycloak Operator
# ─────────────────────────────────────────────────────────────────────────────

if [[ "${MIGRATE_KEYCLOAK}" == "true" ]]; then
section "3/3 — Keycloak Operator"

if kubectl get keycloak keycloak -n "${NAMESPACE}" &>/dev/null; then
log_success "Keycloak CR already exists — skipping"
else
deploy_keycloak
save_state "KEYCLOAK_OPERATOR_DEPLOYED" "true"
fi
fi

section "Phase 1 Complete ($(timer_elapsed))"
if is_external_pg || is_external_es; then
echo "Target infrastructure configured (external targets will be used for data restore)."
else
echo "All target infrastructure is deployed and running alongside existing Bitnami."
fi
echo "The application is still fully operational — no downtime has occurred."
echo ""
echo "Next: ./2-backup.sh"

run_hooks "post-phase-1"
complete_phase 1
118 changes: 118 additions & 0 deletions generic/kubernetes/migration/2-backup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/bash
# =============================================================================
# Phase 2: Initial Backup (NO DOWNTIME)
# =============================================================================
# Takes a backup of all data sources while the application is still running.
# This is a "warm" backup — final consistency is ensured in Phase 3 after
# freezing the application.
#
# What it does:
# 1. Introspect source Bitnami StatefulSets (PG + ES)
# 2. Create backup PVC
# 3. Run PG backup jobs for identity, keycloak, webmodeler
# 4. Run ES backup verification for orchestration data
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC2034 # Used by lib.sh after sourcing
CURRENT_SCRIPT="2-backup.sh"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib.sh"
parse_common_args "$@"
load_state

check_env
require_phase 1 "Phase 1 (deploy targets)"

timer_start

section "Phase 2: Initial Backup (no downtime)"

show_plan 2
run_hooks "pre-phase-2"

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
export TIMESTAMP

ensure_backup_pvc

# ─────────────────────────────────────────────────────────────────────────────
# PostgreSQL backups (one per component)
# ─────────────────────────────────────────────────────────────────────────────

do_pg_backup() {
local component="$1"
local db_name="$2"
local db_user="$3"

local sts_name
sts_name=$(detect_pg_sts "$component") || {
log_warn "${component}: Bitnami PG not found — skipping"
return 0
}

section " Backup: ${component} PostgreSQL (${sts_name})"
introspect_pg "$sts_name"

export COMPONENT="$component"
export PG_HOST="${sts_name}.${NAMESPACE}.svc.cluster.local"
export PG_PORT="5432"
export PG_DATABASE="$db_name"
export PG_USERNAME="$db_user"
# PG_SECRET_NAME and PG_SECRET_KEY are auto-detected by introspect_pg

backup_pg

# Save state for Phase 3
save_state "${component^^}_PG_STS" "$sts_name"
save_state "${component^^}_PG_IMAGE" "$PG_IMAGE"
save_state "${component^^}_BACKUP_FILE" "${component}-db-${TIMESTAMP}.dump"
save_state "${component^^}_BACKUP_TIMESTAMP" "$TIMESTAMP"
}

if [[ "${MIGRATE_IDENTITY}" == "true" ]]; then
do_pg_backup identity "${IDENTITY_DB_NAME}" "${IDENTITY_DB_USER}"
fi

if [[ "${MIGRATE_KEYCLOAK}" == "true" ]]; then
do_pg_backup keycloak "${KEYCLOAK_DB_NAME}" "${KEYCLOAK_DB_USER}"
fi

if [[ "${MIGRATE_WEBMODELER}" == "true" ]]; then
do_pg_backup webmodeler "${WEBMODELER_DB_NAME}" "${WEBMODELER_DB_USER}"
fi

# ─────────────────────────────────────────────────────────────────────────────
# Elasticsearch backup verification
# ─────────────────────────────────────────────────────────────────────────────

if [[ "${MIGRATE_ELASTICSEARCH}" == "true" ]]; then
section " Backup: Elasticsearch"

introspect_es

# Use the ClusterIP service name for ES API access (not the StatefulSet name).
export ES_HOST="${ES_SERVICE}.${NAMESPACE}.svc.cluster.local"
export ES_PORT="9200"
export ES_SECRET_NAME="${CAMUNDA_RELEASE_NAME}-elasticsearch"

backup_es

save_state "ES_STS" "$ES_STS_NAME"
save_state "ES_SERVICE" "$ES_SERVICE"
save_state "ES_IMAGE" "$ES_IMAGE"
fi

section "Phase 2 Complete ($(timer_elapsed))"
echo "All initial backups are done. The application is still fully operational."
echo ""
echo "IMPORTANT: The next phase (3-cutover.sh) will cause a brief downtime"
echo "while it freezes the application, takes a final consistent backup,"
echo "restores data to the new targets, and switches over."
echo ""
echo "Next: ./3-cutover.sh"

run_hooks "post-phase-2"
complete_phase 2
Loading
Loading