IKO Plus: Database Management, Migration, or Day 1 Seeding your Mirrored IrisCluster
.png)
Mirror Your Database Across the Galaxy with Seeding
Hello cpf fans! This walkthrough explores using the “seed” capability in IRIS to provision an entire IrisCluster mirror, 4 maps wide, with compute starting from an IRIS.DAT in a galaxy far, far away.
This is incredibly powerful if you have a successful monolithic implementation and want to scale it to the outer rim using Kubernetes and the InterSystems Kubernetes Operator (IKO). Even though my midichlorian count is admittedly low, I’ve seen hardcore Caché hackers shovel around DATs, compact/shrink them, and update ZROUTINES. This same approach can help shrink and secure your containerized workloads too.
The Mission
I’ll show you how I built an IrisCluster that pulls an IRIS.DAT file from an arbitrary location via an initContainer and uses it to “seed” a mirrored database throughout its topology.
I used a repository I visit annually: @Guillaume Rongier’s InstallSamples, which features a committed IRIS.DAT.
🌱 This will be the seed for our IrisCluster.
Provisioning the Cluster
First, I provision a quick Kind cluster with 5 worker nodes, install Cilium as the CNI, and deploy the IKO. Then, I label the nodes with Star Wars planet names.
ikoseedcluster.sh
cat <<EOF | kind create cluster --name ikoseed --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
- role: worker
- role: worker
networking:
disableDefaultCNI: true
EOF
kind get kubeconfig --name ikoseed > ikoseed.kubeconfig
cilium install --version v1.18.0 --kubeconfig ikoseed.kubeconfig
cilium status --wait --kubeconfig ikoseed.kubeconfig
helm install iko iris-operator/ --kubeconfig ikoseed.kubeconfig
# Label the planets
planets=(tatooine coruscant hoth naboo endor)
i=0
for node in $(kubectl get nodes --no-headers --kubeconfig ikoseed.kubeconfig | awk '/worker/{print $1}'); do
planet=${planets[$i]}
kubectl label node "$node" topology.kubernetes.io/zone="$planet" --overwrite --kubeconfig ikoseed.kubeconfig
echo "$node → zone=$planet"
i=$(( (i+1) % ${#planets[@]} ))
done
I now have a happy Kubernetes cluster, nodes labelled as tatooine, coruscant, hoth, naboo, and endor.
.png)
IrisCluster Topology
Here is the topology declaration, including the critical initContainer and seed configuration.
iriscluster.yaml
apiVersion: intersystems.com/v1alpha1
kind: IrisCluster
metadata:
name: ikoplus-seed-sweenx12
namespace: ikoplus
spec:
imagePullSecrets:
- name: containers-pull-secret
licenseKeySecret:
name: license-key-secret
volumes:
- name: airgapdir
emptyDir: {}
topology:
data:
image: containers.intersystems.com/intersystems/irishealth:2025.1
mirrorMap: primary,backup,drasync,rwrasync
mirrored: true
volumeMounts:
- name: airgapdir
mountPath: /airgapdir
irisDatabases:
- name: SAMPLES
directory: /irissys/data/IRIS/mgr/SAMPLES
mirrored: true
ecp: true
seed: /airgapdir/
logicalOnly: false
preferredZones:
- tatooine
- coruscant
- hoth
- naboo
initContainers:
- name: init-grongierisc-samples
image: debian:bookworm-slim
command:
- sh
- -c
- |
echo "Retrieving Samples from @grongierisc's repository..."
apt-get update && apt-get install -y curl
cd /airgapdir
curl -L https://media.githubusercontent.com/media/grongierisc/InstallSamples/refs/heads/master/samples/IRIS.DAT --output IRIS.DAT
chmod -R 777 /airgapdir
chown -R 51773:51773 /airgapdir
volumeMounts:
- name: airgapdir
mountPath: /airgapdir
securityContext:
runAsUser: 0
compute:
image: containers.intersystems.com/intersystems/irishealth:2025.1
replicas: 1
preferredZones:
- endor
How Seeding Works
The init-container retrieves the database from GitHub and places it in /airgapdir/IRIS.DAT. In the IrisCluster spec, we tell the operator to use this as a seed:
irisDatabases:
- name: SAMPLES
directory: /irissys/data/IRIS/mgr/SAMPLES
seed: /airgapdir/
Under the hood, IKO generates a cpf merge with an Actions directive to handle the heavy seeding:
[Actions]
CreateDatabase:Name=SAMPLES,Directory=/irissys/data/IRIS/mgr,Seed=/airgapdir
CreateNamespace:Name=ENSDEMO,Globals=SAMPLES,Routines=SAMPLES,Interop=1
Deployment & Attestation
Applying the configuration:
kubectl apply -f iriscluster.yaml -n ikoplus
.png)
After a few minutes, the cluster comes to life. I pulled up the Mirroring Monitor to see if our seeded database “SAMPLES” made it to the party.

🎉 It DID!
I also verified the filesystem on the pods to ensure the DAT is in all the right places.
.png)
And the ECP client (compute node) is successfully connected:
.png)
Testing Replication Across the Galaxy
I wrote a global on the Primary mirror and then looped over the topology to ensure it mirrored correctly.
seedmirrorcheck.sh
#!/bin/bash
export KUBECONFIG=ikoseed.kubeconfig
NAMESPACE=${1:-ikoplus}
CMD='iris session IRIS -U ENSDEMO -B <<EOF
ZWRITE ^MayTheForce
HALT
EOF'
for pod in $(kubectl get pods -n "$NAMESPACE" -o jsonpath='{.items[*].metadata.name}'); do
echo "---- Pod: $pod ----"
kubectl -n "$NAMESPACE" exec "$pod" -- /bin/sh -c "$CMD"
done
.png)
The results are solid:
- ✅ Primary (Persisted)
- ✅ Backup (Persisted)
- ✅ DRAsync (Persisted)
- ✅ RWRAsync (Persisted)
- ✅ Compute (Accessible via ECP)
🎉 The Force is with us!
Related Reading: