Files
spinifex/docs/exoscale-integration/README.md
T
Ben Duncan 14ba518186 feat: source=exoscale external pool allocating Elastic IPs through the exo CLI (#1140)
* docs: add work-in-progress Exoscale integration guide with stack diagrams

* feat: source=exoscale external pool allocating Elastic IPs through the exo CLI

* docs: rewrite the Exoscale guide as a short end-user install, and test the exo fake, store and wiring
2026-09-30 15:08:26 -05:00

10 KiB

title, seoTitle, description, category, tags, resources
title seoTitle description category tags resources
Spinifex on Exoscale Run Spinifex on Exoscale with Elastic IPs — Spinifex Docs Install Spinifex on one Exoscale instance and run EC2, load balancers and EKS on real Exoscale Elastic IPs. Install
install
exoscale
cloud
elastic ip
title url
Single-Node Install /docs/install
title url
Spinifex on Oracle Cloud /docs/oci-integration
title url
VPC Networking /docs/vpc-networking
title url
Spinifex Repository https://github.com/mulgadc/spinifex

Running Spinifex on Exoscale

Warning

Work in progress. This page is not yet published on docs.mulgadc.com. Do not add it to scripts/docs-config.json in mulga-docs until the Limits section is settled.

One Exoscale instance, the AWS APIs on its address, and guests reachable on real Exoscale Elastic IPs that Spinifex creates and deletes for you.

Table of Contents


What you get

A single Exoscale instance runs the whole Spinifex stack: EC2, EBS, S3, VPC, load balancers and EKS, behind an endpoint the ordinary AWS CLI, SDKs and Terraform provider talk to unmodified.

Whenever something needs a public address, such as an instance in a public subnet, an Elastic IP, an internet-facing load balancer or a NAT gateway, Spinifex creates an Exoscale Elastic IP, attaches it to your instance, and deletes it again when the resource goes away. You never manage the addresses by hand.

Single node on Exoscale — the instance on the zone's public network with one interface, Elastic IPs routed into OVN through the routed-NAT transit veth, the control plane, tenant VPCs and the block storage volume


Before you start

You need:

  • An Exoscale organisation and an API key that can create, attach, detach and delete Elastic IPs.
  • An SSH key pair.
  • The AWS CLI on your laptop.

Then create these in one zone, from the Exoscale console or the exo CLI. This guide uses de-fra-1.

Resource Setting
Compute instance standard.huge (8 vCPU / 32 GiB) or larger, template Linux Ubuntu 26.04 LTS 64-bit, 100 GiB disk, your SSH key
Block storage volume 256 GiB or more, attached to the instance
Security group Allow all inbound TCP, UDP and ICMP from 0.0.0.0/0, attached to the instance

Note the instance's ID (a UUID, shown on its page in the console) and the volume's ID. You do not need to create any Elastic IPs.

Note

The security group is open on purpose. Guests are filtered by their own Spinifex security groups, and the node by the Spinifex host firewall you turn on in step 5.


Install

Everything below runs on the instance, over SSH as ubuntu.

1. Check that the instance can run VMs

ls -l /dev/kvm && cat /sys/module/kvm_intel/parameters/nested

/dev/kvm must exist and the second line must print Y. If either fails, pick a different instance type before going further.

2. Put the data volume at /var/lib/spinifex

Every guest disk and S3 object lives here, so it belongs on the volume and not on the 100 GiB root disk.

VOL_ID=<volume ID>
DEV=/dev/disk/by-id/virtio-${VOL_ID:0:20}

sudo mkfs.ext4 -L spinifex-data "$DEV"          # only on a new, empty volume
sudo mkdir -p /var/lib/spinifex
echo "UUID=$(sudo blkid -o value -s UUID "$DEV") /var/lib/spinifex ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
sudo mount /var/lib/spinifex
findmnt /var/lib/spinifex                       # must print a line

3. Install the exo CLI and give it your key

Spinifex manages Elastic IPs by running exo, so it needs the CLI and a key file.

curl -fsSLO https://github.com/exoscale/cli/releases/download/v1.101.0/exoscale-cli_1.101.0_linux_amd64.deb
sudo dpkg -i exoscale-cli_1.101.0_linux_amd64.deb

sudo mkdir -p /etc/spinifex/exoscale
sudo tee /etc/spinifex/exoscale/exoscale.toml >/dev/null <<'EOF'
defaultaccount = "spinifex"

[[accounts]]
  name        = "spinifex"
  key         = "EXO..."
  secret      = "..."
  defaultZone = "de-fra-1"
EOF
sudo chmod 700 /etc/spinifex/exoscale && sudo chmod 600 /etc/spinifex/exoscale/exoscale.toml

Check the key works: sudo exo --config /etc/spinifex/exoscale/exoscale.toml compute elastic-ip list -z de-fra-1.

4. Install Spinifex

curl -sfL https://install.mulgadc.com | sudo bash
sudo /usr/local/share/spinifex/setup-ovn.sh --management --nat-uplink

sudo spx admin init --node node1 --nodes 1 --region eu-central-1 --az eu-central-1a \
  --ipsec=false --external-mode=nat
sudo chown -R spinifex-daemon: /etc/spinifex/exoscale

Now tell Spinifex where to get public addresses. Add this to the end of /etc/spinifex/spinifex.toml, just above the [bootstrap] section, using your instance ID:

[[network.external_pools]]
name                 = "exo"
source               = "exoscale"
exoscale_zone        = "de-fra-1"
exoscale_instance_id = "<instance ID>"

Leave the nat-transit pool that init wrote where it is.

Note

eu-central-1 is the region name your AWS tools will see. It is your choice and does not have to match the Exoscale zone.

5. Turn on the firewall, then start

sudo env SETUP_STAGES=firewall /usr/local/share/spinifex/setup.sh --firewall on
sudo systemctl start spinifex.target
systemctl list-units 'spinifex-*' --no-pager

Every spinifex-* unit should be active. The daemon log confirms the Elastic IP integration is working:

sudo journalctl -u spinifex-daemon | grep -E 'exo CLI|Exoscale allocator ready'

6. Import an image

sudo spx admin images import --name ubuntu-26.04-x86_64 --config /etc/spinifex/spinifex.toml

For EKS, also import spinifex-eks-node. sudo spx admin images list --config /etc/spinifex/spinifex.toml shows the full catalogue.


Use it from your laptop

Copy the cluster's CA and the admin credentials from the instance:

NODE=<instance public IP>
mkdir -p ~/.spinifex
ssh ubuntu@$NODE 'sudo cat /etc/spinifex/ca.pem' > ~/.spinifex/exo-ca.pem

Copy the [spinifex] section of ~/.aws/credentials on the instance into your own ~/.aws/credentials as [spinifex-exo], then:

aws configure set --profile spinifex-exo region eu-central-1
export AWS_PROFILE=spinifex-exo AWS_CA_BUNDLE=~/.spinifex/exo-ca.pem
export AWS_ENDPOINT_URL=https://$NODE:9999

aws ec2 describe-regions        # proves the connection

Launch an instance

aws ec2 import-key-pair --key-name demo --public-key-material fileb://~/.ssh/id_ed25519.pub
SG=$(aws ec2 describe-security-groups --filters Name=group-name,Values=default --query 'SecurityGroups[0].GroupId' --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr 0.0.0.0/0

AMI=$(aws ec2 describe-images --filters Name=name,Values='*ubuntu-26.04*' --query 'Images[0].ImageId' --output text)
aws ec2 run-instances --image-id "$AMI" --instance-type t3.small --key-name demo \
  --query 'Instances[0].InstanceId' --output text

After about a minute, describe-instances shows a public IP. That is a new Exoscale Elastic IP, and it appears in the Exoscale console with a description beginning spinifex:.

ssh ubuntu@<public IP> 'curl -s ifconfig.me'    # prints the same address

Terminating the instance deletes the Elastic IP at Exoscale.

Load balancers and EKS

The Terraform workbooks run unchanged. Pass the region and endpoint:

cd nginx-alb
terraform init
terraform apply -var region=eu-central-1 -var spinifex_endpoint=https://$NODE:9999

nginx-alb builds two web servers behind an internet-facing load balancer. eks-quickstart builds a Kubernetes cluster with one worker. Run terraform destroy before starting the next one, because of the quota below.

Important

Exoscale allows five Elastic IPs per organisation by default, and every public address Spinifex hands out uses one. An instance with a public IP uses one, an internet-facing load balancer one, a NAT gateway one, and eks-quickstart three. Past the quota, allocate-address returns AddressLimitExceeded and a launch returns InsufficientAddressCapacity. Ask Exoscale support to raise it.

Exoscale keeps counting a deleted Elastic IP for a while. After a terraform destroy, exo limits still shows the old usage even though exo compute elastic-ip list no longer shows the addresses, so an apply straight afterwards can hit the quota. Wait until exo limits agrees with the list before starting the next workbook.


Troubleshooting

A guest's public IP does not answer from the instance itself. That is expected: traffic from the host to a guest's Elastic IP is dropped. Test from your laptop.

SSH or HTTP is refused straight after launch. Guests take 30 to 60 seconds to boot. Wait and retry.

An EKS cluster goes to FAILED within seconds, or a load balancer never becomes active. Run exo limits. If Elastic IP usage is at the maximum, the cluster could not get its public endpoint; destroy it, wait for usage to drop, and apply again.

The daemon logs an exo error at start. Run the check at the end of step 3. A wrong key, secret or zone is the usual cause.

An Elastic IP you created yourself. Spinifex only ever touches Elastic IPs whose description starts with spinifex:<instance ID>:. Anything else in the organisation is left alone, but it still counts against the quota.


Limits

Proven on one standard.huge instance in de-fra-1 on 2026-09-30: EC2 with a public IP, Elastic IP allocate and release, the nginx-alb workbook and the eks-quickstart workbook with one worker. Each was reached from the internet and left no Elastic IP behind at Exoscale.

Not yet tested:

  • More than one node. Each node would carry its own guests' Elastic IPs, with cluster traffic over an Exoscale private network.
  • Moving an Elastic IP between nodes with its guest.
  • A narrowly scoped API key. The proof used an unrestricted key.
  • Other zones, bare metal and GPU instances.
  • Guest disk performance on Exoscale block storage.