Skip to main content
Version: v3.9.0

Multi-controller HA

This page is how potctl deploys kind: ControlPlane across multiple hosts: shared configuration, the database rule, parallel Edgelet rollout, global certificate upload, and system Edgelet nodes in list order.

The deploy command and single-host example are on Remote. Adding one host later is the Controller add-on.

What each host runs​

Each spec.controllers[] entry is a physical or virtual machine that runs:

  1. Edgelet.
  2. A Controller container from the translated Edgelet ControlPlane manifest. Every host gets the same global auth, database, and image spec.
  3. A system Edgelet node (isSystem: true). That node deploys Router and, when enabled, NATS as system microservices from spec.systemMicroservices.

This is a multi-node Edgelet layout: one Controller process per host. It is not the Kubernetes model of one custom resource and several pod replicas. When you run more than one controller host, those processes share an external database.

Database​

controllers[] lengthDatabase
1spec.database is optional. A single Controller may use embedded SQLite on Edgelet.
2 or morespec.database.provider is required, with host, port, user, password, and databaseName.

Validation rejects multiple controllers without an external database. The same rule applies when you add a host with kind: Controller and the stored control plane still has one controller and no external database.

Supported providers: postgres and mysql.

Every Controller container uses the same spec.database settings. Failover behavior depends on how you run the Controller and the database, outside this CLI.

Endpoint and URLs​

FieldRole
spec.endpointPrimary address potctl waits on for the Controller API
spec.controller.publicUrlPublic URL written into Edgelet environment. When both are set, they match.
Per-controller endpointMay be recorded after deploy for that host's API address

Use HTTPS URLs that match spec.tls and spec.ca. See Securing a remote control plane.

Phase 1: parallel, per host​

For each spec.controllers[] entry, at the same time:

  1. SSH preflight (reachable host, key, user).
  2. Edgelet install (native or container, from the system Edgelet node config).
  3. Airgap checks when spec.airgap or controllers[].airgap is set. That controller needs systemAgent.config.arch.
  4. Private Edgelet registry manifest when spec.controller.package has registry, username, and password.
  5. Translate the global spec plus this controller row into Edgelet YAML.
  6. edgelet deploy -f on that host. potctl polls until the Controller is running.

No Controller API login happens until every host completes this phase, or one fails.

Phase 2: once per namespace​

After every host succeeds and namespace config is saved:

  1. Wait for the Controller API at the global endpoint or public URL.
  2. When auth.mode is embedded, bootstrap and create iofogUser if it is missing.
  3. Register a pull registry on the Controller when private controller.package credentials were used.
  4. Upload global certificates when any of routerSiteCA, routerLocalCA, natsSiteCA, or natsLocalCA is set. The Controller stores TLS secrets and CA catalog entries under the operator-aligned names. See Securing a remote control plane. This step is skipped when every block is empty.
  5. Fill console URL on the stored control plane when it is still empty.

Phase 3: system Edgelet nodes, in order​

System Edgelet nodes are deployed in controllers[] order, not in parallel.

Index 0​

  • isSystem: true
  • upstreamRouters: empty (default router on this node)
  • upstreamNatsServers: empty (NATS hub on this node when NATS is enabled)

This host anchors default-router and default-nats-hub.

Index 1 and later​

  • isSystem: true
  • upstreamRouters includes default-router (appended if you supply a partial list)
  • upstreamNatsServers includes default-nats-hub

Interior Edgelet nodes connect messaging to the resources registered on the first host.

Each index​

  1. Deploy the Edgelet node config to the Controller API.
  2. Edgelet on that host is already installed from phase 1.
  3. Point Edgelet at the controller URL and provision it with the system key.
  4. Save the Edgelet node UUID and SSH metadata in namespace config.

When systemAgent is {}, deployment type is native, isSystem is true, and arch may default to auto on remote when config is omitted. Airgap still requires arch.

NATS​

When spec.nats.enabled is true, images under systemMicroservices.nats must be set. potctl fills defaults from the build tags when you omit them. The first host runs NATS. Later hosts reference default-nats-hub.

Airgap​

When airgap is enabled globally or on a controller:

  • systemAgent.config.arch is required for that controller.
  • Images and the Edgelet binary are staged from the CLI cache before the SSH transfer.

See Airgap deployment.

When a step fails​

SituationWhat happens
A host fails during Edgelet deployThe parallel phase fails. Global auth, CA upload, and system Edgelet nodes do not run.
The index 0 system Edgelet node failsLater indexes are not provisioned.
A second controller is added without an external databaseValidation rejects the file.
Duplicate controller name or hostValidation rejects the file.

Compared with Kubernetes​

TopicKubernetesControlPlaneRemote ControlPlane
Unit of scalereplicas.controller, NATS StatefulSet replicascontrollers[] hosts
Databasespec.database on the user file, translated to the custom resourceGlobal spec.database
Router and NATS TLSOperator Secrets in the namespaceCA names created through the Controller API, plus system microservices on Edgelet
Messaging topologyOperator registers the default router and NATS hubFirst and later system Edgelet nodes, with upstream lists

Day-2​

Status after deploy is on Overview, under Cluster controllers (Active, Standby, or Stale). That block does not open a detail panel.

potctl describe controlplane
potctl describe controller CONTROLLER_NAME

Image and Edgelet pins move with Upgrade the platform train. Deploy the full ControlPlane file again after you edit it. Plan index 0 as the primary router and NATS host. Adding a controller does not reorder that host. Use the Controller add-on when the global spec is already stored.

Group 3See anything wrong with the document? Help us improve it!