Airgap deployment
Use this guide when remote Control Plane hosts or Edgelet node hosts cannot reach the public internet or container registries. potctl runs on a connected operator machine. It pulls or caches artifacts locally, then transfers them over SSH.
This page covers SSH deploy paths only (remote ControlPlane and fleet Agent). Kubernetes and Helm installs are out of scope here.
End-to-end workflow
- Prepare remote hosts (SSH and sudo).
- Deploy a remote
ControlPlanewithspec.airgap: trueand pinned image tags. - Deploy fleet
Agentdocuments withspec.airgap: true(recommended: native +package.version). - Apply
OfflineImagemanifests so microservice images load on nodes before application deploy. - Deploy applications that reference offline catalog entries (Offline images in Learn).
Set spec.airgap: true on the YAML kind, or controllers[].airgap per host when only some Controller hosts are disconnected. Field rules: Remote ControlPlane schema and Multi-controller HA.
Native vs container on edge hosts
Native + package.version (recommended) | Container + package.container.image | |
|---|---|---|
| Edge host engine | Embedded edgelet engine (default) | docker or podman must exist on the host |
| What potctl stages | Edgelet binary from operator cache (~/.iofog/v3/airgap-binaries/) | Container images loaded on the host |
| Typical use | Production air-gapped edges | Standardize on containerized Edgelet |
For deploymentType: container, remote hosts need a working docker or podman before deploy. Native airgap does not require a separate container engine on the edge host.
Remote ControlPlane
---
apiVersion: datasance.com/v3
kind: ControlPlane
metadata:
name: remote
spec:
airgap: true
iofogUser:
name: Foo
surname: Bar
controller:
publicUrl: https://controller.example.com:51121
consoleUrl: https://console.example.com:8008
package:
image: ghcr.io/datasance/controller:v3.9.0
auth:
mode: embedded
bootstrap:
username: admin
password: "LocalTest12!"
systemMicroservices:
router:
amd64: ghcr.io/datasance/router:3.9.0
arm64: ghcr.io/datasance/router:3.9.0
riscv64: ghcr.io/datasance/router:3.9.0
arm: ghcr.io/datasance/router:3.9.0
nats:
amd64: ghcr.io/datasance/nats:2.14.3
arm64: ghcr.io/datasance/nats:2.14.3
riscv64: ghcr.io/datasance/nats:2.14.3
arm: ghcr.io/datasance/nats:2.14.3
nats:
enabled: true
controllers:
- name: remote-1
host: 10.0.23.66
ssh:
user: admin
keyFile: ~/.ssh/id_rsa
systemAgent:
package:
version: "1.1.0"
config:
deploymentType: native
containerEngine: edgelet
arch: amd64
host: 192.168.139.148
potctl deploy -f controlplane.yaml
With spec.airgap: true, potctl downloads Controller, Router, NATS, debugger, and system Edgelet artifacts on the operator machine and transfers them over SSH.
Requirements:
- Set
controllers[].systemAgent.config.archon every controller when airgap is enabled (global or per-host). - List all four architecture keys under
systemMicroserviceswhen the fleet mixes CPU types. - Pin
controller.package.imageand router tags to your v3.9.0 train.
Custom bootstrap scripts: controllers[].systemAgent.scripts (same merge rules as fleet Agent). Embedded layers live in the CLI repo: assets/edgelet.
Full ControlPlane field reference: Remote deploy guide.
Remote Edgelet nodes (recommended: native airgap)
---
apiVersion: datasance.com/v3
kind: Agent
metadata:
name: edge-airgap-1
spec:
host: 10.0.0.51
ssh:
user: ubuntu
keyFile: ~/.ssh/id_rsa
airgap: true
package:
version: "1.1.0"
config:
arch: amd64
deploymentType: native
containerEngine: edgelet
upstreamRouters:
- default-router
routerConfig:
routerMode: edge
messagingPort: 5671
upstreamNatsServers:
- default-nats-hub
natsConfig:
natsMode: leaf
natsServerPort: 4222
Set spec.airgap: true, pin spec.package.version, and set spec.config.arch. potctl stages the Edgelet binary and runs the default bootstrap on the host.
First-time remote install steps: Setup Edgelet nodes.
Container airgap (alternative)
When Edgelet runs as a container on the edge host, pre-install docker or podman, then use:
---
apiVersion: datasance.com/v3
kind: Agent
metadata:
name: edge-container-airgap
spec:
host: 192.168.139.148
ssh:
user: foo
keyFile: ~/.ssh/id_rsa
port: 22
airgap: true
package:
container:
image: ghcr.io/datasance/edgelet:1.1.0
config:
deploymentType: container
containerEngine: docker
arch: arm64
potctl pulls Edgelet, Router, NATS, and debugger images on the operator machine, transfers them over SSH, and loads them into the host engine.
OfflineImage for microservices
Edgelet nodes still cannot pull application images at runtime in an air-gapped site. Use kind: OfflineImage after agents exist in the namespace.
Offline images in Learn is the reference for multi-arch keys (amd64, arm64, riscv64, arm), spec.auth, and CLI flags (--no-cache, --transfer-pool).
Steps:
- Define
OfflineImageYAML with image tags per architecture andspec.agentnames (remoteAgentonly). - Run
potctl deploy -f offline-image.yaml. potctl pulls on the operator machine, transfers over SSH, and loads images on each node. Catalog items use registryfrom_cache(ID2). - Deploy microservices that reference the offline catalog name.
Example:
---
apiVersion: datasance.com/v3
kind: OfflineImage
metadata:
name: my-app-offline
spec:
amd64: ghcr.io/datasance/my-app:1.0
arm64: ghcr.io/datasance/my-app:1.0
agent:
- edge-airgap-1
- edge-airgap-2
Deploy order: Control Plane → fleet Agents → OfflineImage → applications.
For the full platform path, see Platform deployment introduction.