.png)
"Haul" a Portable Registry for Airgapped IrisClusters
Rancher Government Hauler streamlines deploying and maintaining InterSystems container workloads in air-gapped environments by simplifying how you package and move required assets. It treats container images, Helm charts, and other files as content and collections, letting you fetch, store, and distribute them declaratively or via CLI — without changing your existing workflows. Meaning your charts and what have yous, can have conditionals on your pull locations in Helm values, etc.
If you have been tracking how HealthShare is being deployed via IPM Packages, you can certainly appreciate the adoption of OCI compliance storage for the packages themselves using ORAS... which is core to the Hauler solution.
.png)
Goal
I booked a flight to Grand Rapids, MI (GRR) to Boston Logan (BOS) on Allegiant and will not have access to the internet in the friendly skies. The dog ate my homework and I am on deck for a proof of concept upon arrival that requires a simple IrisCluster and the InterSystems Kubernetes Operator doing amazing things, but I am essentially airgapped the majority of the time on my way to Boston. Let's create a haul so we can pull images from it while airgapped on the flight on a scramble to crush the demo.
.png)
Kind Cluster
Provision a quick kind cluster, but with an asterisk for understanding
cat <<EOF | kind create cluster --name ikohauler --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."172.17.0.1:31337"]
endpoint = ["http://172.17.0.1:31337"]
networking:
disableDefaultCNI: false
EOF
Kind’s containerd defaults to HTTPS-only. If your Hauler registry is HTTP on 31337, you need to tell containerd inside the Kind nodes that this host:port is an insecure (plain-HTTP) mirror. The containerConfigPatches is relevant later, but we need to allow it to talk to our Docker ip address on a specified port.
Create the Haul (GRR)
Go grab hauler for your system while you are sitting at the gate, remember to switch to airplane mode once boarded.
curl -sfL https:
Now, from experience I know the Operator needs a pair of containers and the IrisCluster I am creating is dead simple so Ill just need one of those, for the inventory of three images, lets create the Haul.
hauler store add image containers.intersystems.com/intersystems/irishealth-community:2025.1
hauler store add image containers.intersystems.com/intersystems/iris-operator-amd:3.8.42.100
hauler store add image appscode/kubectl:v1.14
hauler store info
You will see a folder created on the directory you are building your haul be created, `store`.

Lets load up the Haul (which is a collection of our images) so we can take the part of the internet with us.
hauler store save --filename ikoplus-haul.tar.zst
rf -rf store
Lets whack the store directory too for dramatics and get ready for takeoff.
In Flight
We are now at cruising altitude and the constant safety announcements are being tuned out by my airpods, lets provision an IrisCluster and IKO.
Airgap the Haul
We have the haul, represented as `ikoplus-haul.tar.zst` on your machine... Lets extract it for use and boot a registry.
sween @ fhirwatch-pop-os ~/Desktop/IKOPLUS/hauler
└─ $ ▶ hauler store load --filename ikoplus-haul.tar.zst
2025-10-21 13:56:43 INF loading haul [ikoplus-haul.tar.zst] to [/home/sween/Desktop/IKOPLUS/hauler/store]
2025-10-21 13:56:47 INF unarchiving completed successfully
Looks like we got our `store` folder back, so we should be in business.
Now, boot the registry:
hauler store serve registry --port 31337
.png)
Use of port 31337 in celebration of the great Back Orifice and Netbus from the 90's.
Lets peak now at the local registry with a quick curl:
curl http://172.17.0.1:31337/v2/_catalog
{"repositories":["appscode/kubectl","intersystems/iris-operator-amd","intersystems/irishealth-community"]}
Airgapped IKO and IrisCluster
So now we need to adjust our Chart for IKO, and our IrisCluster accordingly to point to our Hauler endpoint.
values.yaml
replicaCount: 1
operator:
registry: 172.17.0.1:31337
repository: intersystems/iris-operator-amd
tag: 3.8.42.100
useFQDN: true
webserverPort: 52773
useIrisFsGroup: false
numThreads: 2
resyncPeriod: "10m"
webGatewayStartupTimeout: 0
cleaner:
registry: 172.17.0.1:31337
repository: kubectl
tag: v1.14
IrisCluster.yaml
apiVersion: intersystems.com/v1alpha1
kind: IrisCluster
metadata:
name: airgapped-iris
namespace: default
spec:
topology:
data:
image: 172.17.0.1:31337/intersystems/irishealth-community:2025.1
serviceTemplate:
spec:
type: LoadBalancer
externalTrafficPolicy: Local
How we install IKO and the IrisCluster!
helm install iko . -f values.yaml
kubectl apply -f iriscluster.yaml
💥 We pulled from 10,000 feet people.

Demo
Here we prove we have a running IrisCluster and Operator that were provisioned from a local Hauler registry, airgapped!
kubectl get pods -n default -o jsonpath='{range .items[*]}{.metadata.name}{" => "}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}'
airgapped-iris-data-0 => 172.17.0.1:31337/intersystems/irishealth-community:2025.1
iko-iris-operator-amd-5d679956db-pkbmg => 172.17.0.1:31337/intersystems/iris-operator-amd:3.8.42.100
🙌