<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tom</title>
    <description>The latest articles on DEV Community by Tom (@toddyholiday).</description>
    <link>https://dev.to/toddyholiday</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4087630%2Fae5695ed-6f93-4de6-ac01-4ff5a4d167ce.png</url>
      <title>DEV Community: Tom</title>
      <link>https://dev.to/toddyholiday</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/toddyholiday"/>
    <language>en</language>
    <item>
      <title>Fakecloud vs Spinifex: AWS Emulator vs Production Platform</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Thu, 10 Sep 2026 06:59:32 +0000</pubDate>
      <link>https://dev.to/toddyholiday/fakecloud-vs-spinifex-aws-emulator-vs-production-platform-5367</link>
      <guid>https://dev.to/toddyholiday/fakecloud-vs-spinifex-aws-emulator-vs-production-platform-5367</guid>
      <description>&lt;p&gt;&lt;a href="https://fakecloud.dev" rel="noopener noreferrer"&gt;Fakecloud&lt;/a&gt; and &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; both answer to the AWS API, which is enough to land them in the same search results. They are not alternatives to each other. Fakecloud covers local development and CI. Spinifex covers production when that environment is hardware you own. Knowing which is which keeps a dev tool out of production and a production platform out of your CI pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Fakecloud is
&lt;/h2&gt;

&lt;p&gt;Fakecloud is a free, MIT-licensed AWS emulator built around the AWS Smithy service models. Instead of hand-writing each service, it generates its API surface from the same models AWS publishes, and that is how it reaches 105 services and 7,396 operations. The breadth is the point: model-driven coverage rather than hand-tuned depth.&lt;/p&gt;

&lt;p&gt;The runtime is a single binary of around 19 MB that idles near 10 MiB, so it fits into a CI job or a laptop without much overhead. Covered services include S3, DynamoDB, SQS, Lambda, IAM, STS, ECS, ECR, EC2, and Bedrock, plus RDS backed by six real database engines and 80 more beyond those. The project is younger and smaller by star count than Floci or LocalStack, and it targets a wider slice of the API than either.&lt;/p&gt;

&lt;p&gt;Fakecloud does not run real infrastructure. Call &lt;code&gt;ec2 run-instances&lt;/code&gt; and you get a well-formed response that matches the model, but no virtual machine boots. Call &lt;code&gt;s3 put-object&lt;/code&gt; and the bytes land somewhere convenient for the test, with no erasure-coded storage engine enforcing durability. For an emulator that trade-off is correct, because a developer's inner loop and a CI job need fast, faithful responses rather than production behaviour under load.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spinifex is
&lt;/h2&gt;

&lt;p&gt;Spinifex is an AWS-compatible cloud platform for hardware you own. It implements EC2, S3, IAM, EKS, and the rest of the common AWS service surface on standard Linux bare metal, and the implementation is real. An &lt;code&gt;aws ec2 run-instances&lt;/code&gt; call provisions a virtual machine through QEMU. S3 objects go to Spinifex's built-in object store, which spreads them across nodes with Reed-Solomon erasure coding. IAM policies evaluate against real principals and enforce across real network boundaries.&lt;/p&gt;

&lt;p&gt;Spinifex is built for production where AWS itself is unavailable: disconnected field deployments, air-gapped secure facilities, and data sovereignty rules that forbid sending data to infrastructure outside your control. It runs with no external control plane, makes no phone-home call, and installs from a release tarball with no internet access. The AWS CLI, Terraform with the AWS provider, eksctl, and any AWS SDK work against it with a single endpoint override.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why these two get compared
&lt;/h2&gt;

&lt;p&gt;Both tools answer &lt;code&gt;aws s3 ls&lt;/code&gt; correctly, and Fakecloud's model-driven conformance means it answers a long list of other calls too. That breadth is what surfaces it next to Spinifex when a team searches for a way to run the AWS API off Amazon. The choice comes up whenever a team replacing LocalStack is also weighing where production will run.&lt;/p&gt;

&lt;p&gt;Conforming to the API model and provisioning real infrastructure are different jobs. Fakecloud checks that your requests are well-formed and that your code handles the responses. Spinifex runs the workload. A suite that passes against Fakecloud tells you the integration code is correct. It does not tell you the VM will boot, the volume will survive a lost node, or the policy will deny the call it should deny.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they fit together
&lt;/h2&gt;

&lt;p&gt;Plenty of teams run both, at different stages of one pipeline. Fakecloud sits in development and CI, giving engineers a broad, quick AWS surface to build against with no account and no bill. Spinifex sits in production when that production is hardware the team controls, serving the same AWS API the application was written against.&lt;/p&gt;

&lt;p&gt;The endpoint changes between stages. The application code does not. Teams whose production target is AWS finish with a validation pass on real AWS. Teams whose production target is their own hardware finish on Spinifex: the same API, running on the machines that are the production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Fakecloud is at &lt;a href="https://github.com/faiscadev/fakecloud" rel="noopener noreferrer"&gt;github.com/faiscadev/fakecloud&lt;/a&gt;, MIT-licensed and needing no account to run. Spinifex documentation, including the air-gapped installation guide for disconnected deployments, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The source is on &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, written in Go and AGPL-3.0 licensed. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for the free sandbox&lt;/a&gt; to explore the AWS-compatible API surface before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>testing</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>MiniStack vs Spinifex: AWS Emulator vs Production Platform</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Thu, 10 Sep 2026 06:58:48 +0000</pubDate>
      <link>https://dev.to/toddyholiday/ministack-vs-spinifex-aws-emulator-vs-production-platform-4m93</link>
      <guid>https://dev.to/toddyholiday/ministack-vs-spinifex-aws-emulator-vs-production-platform-4m93</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/ministackorg/ministack" rel="noopener noreferrer"&gt;MiniStack&lt;/a&gt; and &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; both speak the AWS API. That surface similarity is what puts them in the same search results, but they're built for different stages of the software lifecycle. MiniStack is a development and CI testing tool. Spinifex is a production cloud platform. Teams that run both aren't hedging; they're using the right tool at each stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MiniStack is
&lt;/h2&gt;

&lt;p&gt;MiniStack is a free, MIT-licensed AWS emulator that emerged after LocalStack archived its Community Edition in March 2026. It runs on port 4566, covers 60+ AWS services, and requires no account or auth token. The Docker image is around 270 MB with roughly 30 MB idle memory, and startup is under two seconds.&lt;/p&gt;

&lt;p&gt;The design choice that distinguishes MiniStack from other emulators is that it backs some services with real infrastructure. When your test code calls its RDS endpoint, a real PostgreSQL instance is handling the storage. ElastiCache maps to a real Redis instance. That backing means test behaviour for database-heavy workloads more closely mirrors what the production database will do, including edge cases in query behaviour that a pure mock might smooth over.&lt;/p&gt;

&lt;p&gt;For teams whose biggest CI risk is database logic rather than AWS API surface coverage, MiniStack's real-infrastructure approach is a meaningful improvement over in-memory emulators.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spinifex is
&lt;/h2&gt;

&lt;p&gt;Spinifex is an AWS-compatible cloud platform that runs on standard Linux bare metal hardware. It implements EC2, S3, IAM, EKS, and the rest of the common AWS service surface against real underlying infrastructure. When you call &lt;code&gt;aws ec2 run-instances&lt;/code&gt;, it boots a real virtual machine using QEMU. EBS volumes are real block storage with real persistence. IAM policies are enforced across actual network boundaries. S3 is served by Predastore, which uses Reed-Solomon erasure coding to distribute objects across nodes so data survives hardware failures.&lt;/p&gt;

&lt;p&gt;Spinifex runs fully offline, with no external control plane and no phone-home dependency. It installs from a release tarball on any x86_64 or ARM64 Linux server. The AWS CLI, Terraform with the AWS provider, eksctl, and any AWS SDK work against it with a single endpoint override.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where they each fit
&lt;/h2&gt;

&lt;p&gt;MiniStack belongs in your dev environment and CI pipeline. It gives your application code a realistic AWS surface to run against without cloud costs or credentials, and the real database backing means your ORM queries and migration code get a more honest workout than they would against a pure in-memory mock.&lt;/p&gt;

&lt;p&gt;Spinifex belongs in production when that production environment is hardware you own. It's built for teams deploying to disconnected edge hardware, air-gapped secure facilities, and sovereign environments where data cannot leave infrastructure under direct control. The goal is that Terraform configs, IAM policies, and application code written for AWS run unchanged on your own hardware, because the API they're calling is the same API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What emulators can't catch
&lt;/h2&gt;

&lt;p&gt;MiniStack's real-database backing improves test fidelity for a specific class of problem, but the emulator model has structural limits that matter when correctness at the margins is the requirement.&lt;/p&gt;

&lt;p&gt;An emulator intercepts API calls and returns plausible responses. What it doesn't do is enforce real IAM policy evaluation against real principals, manage real VM lifecycle state, or replicate the durability and concurrency behaviour of a production storage system under load. These aren't gaps in MiniStack specifically; they're inherent to the emulator category. Emulators are optimised for development speed, not production parity.&lt;/p&gt;

&lt;p&gt;For teams whose production target is AWS, this gap is bridged by deploying to real AWS for final validation. For teams whose production target is hardware they own, there is no "real AWS" step in the pipeline. Spinifex is what fills that position: the same API, on the hardware that is the production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;MiniStack documentation and installation instructions are at &lt;a href="https://ministack.org" rel="noopener noreferrer"&gt;ministack.org&lt;/a&gt;. Spinifex documentation, including the air-gapped installation guide and Terraform workbooks, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The source is on &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, written in Go and AGPL-3.0 licensed. The &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;free sandbox&lt;/a&gt; lets you test the API against a live Spinifex instance before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>testing</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Floci vs Spinifex: AWS Emulator vs Production Platform</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Wed, 09 Sep 2026 01:59:32 +0000</pubDate>
      <link>https://dev.to/toddyholiday/floci-vs-spinifex-aws-emulator-vs-production-platform-5160</link>
      <guid>https://dev.to/toddyholiday/floci-vs-spinifex-aws-emulator-vs-production-platform-5160</guid>
      <description>&lt;p&gt;&lt;a href="https://floci.dev/" rel="noopener noreferrer"&gt;Floci&lt;/a&gt; and &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; both implement the AWS API surface, and that surface-level similarity puts them in the same search results. They're not alternatives to each other. Floci covers local development and CI. Spinifex covers production when that environment is hardware you own. Understanding why helps you use both without expecting either to do the other's job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Floci is
&lt;/h2&gt;

&lt;p&gt;Floci is a free, open-source AWS emulator built to replace LocalStack Community Edition after LocalStack archived its free tier in March 2026. It's built on Quarkus and compiled to a native binary via GraalVM, which produces its headline numbers: startup time around 24ms and idle memory around 13 MiB. It covers 47 AWS services, requires no account or auth token, and is MIT-licensed.&lt;/p&gt;

&lt;p&gt;The design intention is explicit drop-in compatibility. Floci listens on port 4566 and accepts the same credential pattern as LocalStack, so existing SDK configurations, Docker Compose setups, and CI scripts work without changes. It also translates LocalStack environment variables automatically for teams migrating from older configurations. Beyond AWS, it supports Azure and GCP endpoints, which is useful for codebases that target more than one cloud provider.&lt;/p&gt;

&lt;p&gt;What Floci doesn't do is run real infrastructure. When your code calls &lt;code&gt;s3.put_object&lt;/code&gt;, Floci intercepts that call and stores the data somewhere convenient for the test. There's no actual storage engine enforcing durability guarantees, no real IAM policy evaluation against a real principal, and no hypervisor managing virtual machine state. That's the correct trade-off for a development tool: speed and breadth of service coverage matter more than production-grade correctness when you're running a developer's inner loop or a CI job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spinifex is
&lt;/h2&gt;

&lt;p&gt;Spinifex is an AWS-compatible cloud platform for hardware you own. It implements EC2, S3, IAM, EKS, and the rest of the common AWS service surface on standard Linux bare metal, and the implementation is real: an &lt;code&gt;aws ec2 run-instances&lt;/code&gt; call provisions an actual virtual machine using QEMU. S3 objects go to Predastore, which distributes them across nodes using Reed-Solomon erasure coding. IAM policies are evaluated against real callers and enforced across real network boundaries.&lt;/p&gt;

&lt;p&gt;The use cases are production environments where AWS itself isn't available: disconnected field deployments, air-gapped secure facilities, and data sovereignty requirements that prohibit sending data to infrastructure outside your direct control. Spinifex runs without any external control plane, has no phone-home requirement, and installs from a release tarball with no internet access needed. The AWS CLI, Terraform with the AWS provider, eksctl, and boto3 all work against it with a single endpoint override.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why these two get compared
&lt;/h2&gt;

&lt;p&gt;Both tools answer &lt;code&gt;aws s3 ls&lt;/code&gt; correctly. That's enough to surface both in the same search, and the question "should I use Floci or Spinifex?" comes up whenever a team with existing LocalStack infrastructure is evaluating on-premise options at the same time.&lt;/p&gt;

&lt;p&gt;The architecture underneath is completely different, and the appropriate contexts don't overlap. Floci is optimised for startup time, low resource footprint, and broad service coverage in a container, because those are the properties that matter in a developer's inner loop. Spinifex is optimised for production reliability, real hardware management, and disconnected operation, because those are the properties that matter when bare metal is the production environment.&lt;/p&gt;

&lt;p&gt;A benchmark between them would measure the wrong things. Floci starts in 24ms; Spinifex starts VMs on real hardware. Floci fits in a Docker container; Spinifex manages your infrastructure. Neither is trying to do what the other does.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they fit together
&lt;/h2&gt;

&lt;p&gt;Many teams use both across different stages of the same pipeline. Floci runs in the development environment and CI so that engineers can write and test code against AWS APIs without a cloud account or a cloud bill. Spinifex runs in the production environment when that environment is hardware the team controls, and provides the same AWS API surface that the application was developed against.&lt;/p&gt;

&lt;p&gt;The endpoint changes between stages. The application code doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Floci is at &lt;a href="https://github.com/floci-io/floci" rel="noopener noreferrer"&gt;github.com/floci-io/floci&lt;/a&gt;, MIT-licensed and requiring no account to run. Documentation for Spinifex is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;, including the air-gapped installation guide for disconnected deployments. The source is on &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, written in Go and AGPL-3.0 licensed. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for the free sandbox&lt;/a&gt; to explore the AWS-compatible API surface before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>testing</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Equinix Metal Shut Down: What Bare Metal Cloud Users Can Do Now</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Mon, 07 Sep 2026 04:40:11 +0000</pubDate>
      <link>https://dev.to/toddyholiday/equinix-metal-shut-down-what-bare-metal-cloud-users-can-do-now-2b5a</link>
      <guid>https://dev.to/toddyholiday/equinix-metal-shut-down-what-bare-metal-cloud-users-can-do-now-2b5a</guid>
      <description>&lt;p&gt;Equinix Metal went offline on June 30, 2026. If your infrastructure ran on it, you already know that: the API is gone, servers provisioned on the platform were wiped at the cutoff, and what was once an on-demand bare metal cloud with ten-minute provisioning times is now a 404. Equinix announced the shutdown in November 2024, which gave customers eighteen months to plan a migration, but knowing it was coming and knowing what to do next are two different things.&lt;/p&gt;

&lt;p&gt;This post covers the options, what each one involves, and where each one makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Equinix Metal was
&lt;/h2&gt;

&lt;p&gt;Equinix &lt;a href="https://www.equinix.com/newsroom/press-releases/2020/03/equinix-completes-acquisition-of-packet-to-accelerate-equinix-digital-edge" rel="noopener noreferrer"&gt;acquired Packet in March 2020 for $335 million&lt;/a&gt; and rebranded the service as Equinix Metal. The value proposition was simple: dedicated physical servers, no hypervisor overhead, API-first provisioning in under ten minutes, and native integration to Equinix's Fabric interconnection network so you could reach cloud providers and private networks with low latency without building your own cross-connects. It sat in a gap that very few services filled: genuine bare metal performance with the kind of developer experience people expected from cloud VMs.&lt;/p&gt;

&lt;p&gt;The shutdown came because Metal represented only around 1.25% of Equinix's revenue, and the company decided its future was in colocation, interconnection, and hyperscale rather than competing with AWS on compute. That's a reasonable business decision, but it leaves a real gap for the teams who built on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest options
&lt;/h2&gt;

&lt;p&gt;There is no single direct replacement for what Equinix Metal was, because what made it valuable was the combination of physical performance, API-first control, and Equinix's interconnection fabric in a single product. Each migration path recovers some of that but not all of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move to a managed bare metal provider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most direct substitution is another bare metal cloud, and several have been actively courting Equinix Metal refugees. Latitude.sh markets itself specifically as an Equinix Metal replacement and offers a developer-friendly API, Terraform provider, and fast provisioning across a smaller number of locations. Hetzner offers bare metal dedicated servers with decent API support and competitive pricing, especially in Europe. OVHcloud covers a wider range of locations and has API-driven provisioning, though the experience is more configuration-heavy than either of the others.&lt;/p&gt;

&lt;p&gt;The main trade-off with any of these is that you're still in someone else's data centre, on someone else's hardware, subject to their pricing changes and service decisions. You solve the immediate migration problem without changing the underlying dependency structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move to a hyperscaler&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS, GCP, and Azure all offer bare metal instance types, and if your workload was on Equinix Metal for performance reasons rather than cost or data residency reasons, moving to an AWS &lt;code&gt;i4i.metal&lt;/code&gt; or a GCP bare metal option is technically straightforward. The existing AWS SDK and Terraform tooling transfers directly and you gain the full breadth of managed services around your compute.&lt;/p&gt;

&lt;p&gt;The obvious cost is that bare metal in a hyperscaler is expensive relative to dedicated servers elsewhere, and egress costs compound quickly. For teams that chose Equinix Metal partly because hyperscaler economics didn't work for their workload, moving to AWS metal is probably not the answer, but for teams that valued the Equinix Fabric interconnection to those same hyperscalers, it removes an indirection layer entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Own the hardware and bring your own cloud API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A smaller subset of Equinix Metal customers chose it not just for managed convenience but because they wanted hardware performance with a cloud-compatible API surface, and for some of them the managed nature of the service was a compromise rather than a requirement. For those teams, the migration path is colocation plus software that gives them the API layer back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; is an open-source, AGPL-3.0 licensed cloud platform written in Go that implements the AWS API surface on hardware you own and operate. It covers EC2, S3, IAM, EKS, and more of the common AWS API surface, which means the same Terraform configs, AWS CLI scripts, and SDK integrations that worked against your Equinix Metal infrastructure or against AWS can be pointed at a Spinifex node in a colocation facility with a provider override:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;endpoints&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spinifex_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;iam&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spinifex_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;sts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spinifex_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;eks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spinifex_endpoint&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spinifex is not a managed service, and it is not a drop-in Equinix Metal replacement in the sense that Latitude.sh is. You take on the operational responsibility for the hardware: firmware, failure, and physical network uplinks. In return you get full control over the platform, no per-hour billing, and an AWS-compatible API surface your existing tooling already talks to. For teams with the operational appetite for it, and for teams with data sovereignty or security requirements that constrain which managed providers they can use, this is the migration path that preserves the most control.&lt;/p&gt;

&lt;p&gt;The Equinix colocation business is still open, so one option is keeping your hardware in an Equinix facility and running Spinifex on it. You lose the API-driven bare metal provisioning that Metal provided, but you keep the Equinix Fabric interconnection that many teams valued for reaching cloud providers and private peers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to think about when choosing
&lt;/h2&gt;

&lt;p&gt;The right path depends on a few things that are specific to each team's situation.&lt;/p&gt;

&lt;p&gt;If the main value of Equinix Metal was the interconnection fabric, look at whether that can be reproduced in the new environment. Equinix's colocation and Fabric products are separate from Metal and still exist, and some managed bare metal providers have their own interconnection partnerships.&lt;/p&gt;

&lt;p&gt;If the main value was the API-first provisioning and developer experience rather than the physical hardware specifically, moving to a hyperscaler or a well-provisioned managed bare metal provider is probably the cleanest migration.&lt;/p&gt;

&lt;p&gt;If the main value was the combination of physical performance and a cloud-compatible API surface, and the workload has data residency or sovereignty requirements that constrain which managed providers are acceptable, owning the hardware with Spinifex providing the API layer is the path to evaluate.&lt;/p&gt;

&lt;p&gt;If the deadline passed before a clean migration was in place, get workloads off any remaining dependencies on a service that no longer exists and onto something stable, even if that means a temporary home on a hyperscaler while the longer-term architecture is figured out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Full Spinifex documentation, including the installation guide and Terraform workbooks for common infrastructure patterns, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The source is on &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, written in Go and AGPL-3.0 licensed. If you're working through a migration from Equinix Metal and want to talk through what makes sense for your specific situation, &lt;a href="https://mulgadc.com/contact" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>selfhosted</category>
      <category>baremetal</category>
    </item>
    <item>
      <title>OpenStack vs Spinifex: Why AWS API Compatibility Changes the On-Prem Equation</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Fri, 04 Sep 2026 00:25:20 +0000</pubDate>
      <link>https://dev.to/toddyholiday/openstack-vs-spinifex-why-aws-api-compatibility-changes-the-on-prem-equation-1g</link>
      <guid>https://dev.to/toddyholiday/openstack-vs-spinifex-why-aws-api-compatibility-changes-the-on-prem-equation-1g</guid>
      <description>&lt;p&gt;The decision to move workloads off public cloud onto hardware you control usually comes with a secondary question that gets answered too late: what happens to the tooling? Terraform configs, CLI automation, IAM role structures, Kubernetes clusters provisioned with eksctl, all of that was written against the AWS API, and the answer to "does it work on our private cloud?" depends almost entirely on which private cloud platform you choose. OpenStack and Spinifex give different answers to that question, so let's dive into what they both are and where you'd pick either one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What OpenStack actually is
&lt;/h2&gt;

&lt;p&gt;OpenStack is the incumbent open source private cloud platform, governed by the &lt;a href="https://openinfra.org/" rel="noopener noreferrer"&gt;OpenInfra Foundation&lt;/a&gt; and running at serious scale. According to the OpenInfra Foundation, &lt;a href="https://openinfra.org/annual-report" rel="noopener noreferrer"&gt;OpenStack deployments now exceed 55 million cores&lt;/a&gt; in production worldwide, with organisations including Walmart, Workday, and CERN among the large-scale operators. Telecoms have leaned heavily on it for 5G and Open RAN backbone infrastructure through the StarlingX project. It is a mature platform with over fifteen years of production hardening behind it.&lt;/p&gt;

&lt;p&gt;The core services cover the same ground as any cloud platform: Nova for compute, Neutron for networking, Cinder for block storage, Swift for object storage, Keystone for identity and authentication, Glance for image management, and Heat for orchestration. Each is a full project in its own right, with its own API, documentation, and upgrade lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The operational reality
&lt;/h2&gt;

&lt;p&gt;Deploying OpenStack for production use is not a weekend project. The most accessible deployment path today is Kolla-Ansible, which containerises OpenStack services and uses Ansible to orchestrate the install, and it has simplified what used to be an extremely manual process. The official documentation acknowledges that Kolla "permits operators with little experience to deploy OpenStack quickly," which is true in the sense that a motivated team can get a cluster running, but running it at production quality and knowing how to troubleshoot failures across distributed containerised services still requires operational expertise. OpenStack networking in particular, built on Neutron with OVN or OVS, has a learning curve that most teams underestimate.&lt;/p&gt;

&lt;p&gt;For organisations with a dedicated cloud operations team, this is a reasonable trade. Engineering teams whose core expertise is software development rather than infrastructure operations will carry the operational overhead with less to absorb it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AWS API question
&lt;/h2&gt;

&lt;p&gt;The challenge for teams moving from AWS tooling is that OpenStack has its own API surface. Nova is not EC2, Cinder is not EBS, and Keystone is not IAM. Terraform resources written for AWS use the &lt;code&gt;aws&lt;/code&gt; provider and EC2/EBS/S3 resource types, and those don't translate to OpenStack without a rewrite using the OpenStack provider.&lt;/p&gt;

&lt;p&gt;There was an OpenStack project called ec2-api that provided an AWS EC2 compatibility wrapper for OpenStack, but &lt;a href="https://opendev.org/openstack/ec2-api" rel="noopener noreferrer"&gt;that project is retired and no longer maintained&lt;/a&gt;. An organisation moving workloads from AWS to OpenStack is taking on a migration project at the Terraform and automation layer, not just at the infrastructure layer. Every &lt;code&gt;aws_instance&lt;/code&gt;, &lt;code&gt;aws_security_group&lt;/code&gt;, and &lt;code&gt;aws_eks_cluster&lt;/code&gt; resource in your configurations needs to be rewritten for the OpenStack equivalents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your existing AWS tooling transfers to Spinifex without modification. It does not transfer to OpenStack without rewriting it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Spinifex does differently
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; takes the opposite approach to the API question. Rather than building a new cloud platform with its own API surface, it implements the AWS API on hardware you own, covering EC2, S3, IAM, EKS, and the rest of the common AWS service surface. The endpoint changes; the API does not. A Terraform config that targets AWS today can target a Spinifex node with a single provider block override, and the resource definitions, modules, variable files, and state management stay exactly as they are.&lt;/p&gt;

&lt;p&gt;The operational profile is also different. Spinifex runs as a single platform on standard Linux hardware, coordinated by NATS and managed by systemd, with no separate etcd cluster and no external control plane components. It also installs and runs in fully air-gapped environments with no internet connectivity, which is a requirement OpenStack can satisfy in principle but which requires additional planning and configuration to achieve.&lt;/p&gt;

&lt;p&gt;Spinifex is AGPL-3.0 licensed and written in Go, with the source at &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When OpenStack is the right choice
&lt;/h2&gt;

&lt;p&gt;OpenStack is the right choice when the scale and multi-tenancy requirements of the deployment justify its operational complexity. Service providers running public or community cloud infrastructure, telecoms deploying 5G core, and large enterprises with dedicated cloud operations teams are the natural users of OpenStack, and it serves them well. If you need a platform that hundreds of teams can share with strong tenant isolation and a mature ecosystem of plugins, integrations, and management tooling built up over fifteen years, OpenStack is where you start looking.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Spinifex is the right choice
&lt;/h2&gt;

&lt;p&gt;Spinifex is the right choice when your team has existing AWS tooling and the requirement is to run that tooling on hardware you own, without a migration project at the automation layer. Disconnected environments, data sovereignty requirements, and edge deployments are where the AWS API compatibility matters most. Teams that can't justify a dedicated cloud ops function benefit from Spinifex's simpler operational profile.&lt;/p&gt;

&lt;p&gt;Before choosing between them, ask what your team needs to operate the platform and whether you have it. For teams whose existing capability is AWS, that question often determines the outcome before the feature list does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Platform documentation for Spinifex, including the air-gapped installation guide and Terraform workbooks for common infrastructure patterns, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The source is on &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. OpenStack documentation and deployment guides are at &lt;a href="https://docs.openstack.org" rel="noopener noreferrer"&gt;docs.openstack.org&lt;/a&gt;, and the OpenInfra Foundation can be found at &lt;a href="https://openinfra.org" rel="noopener noreferrer"&gt;openinfra.org&lt;/a&gt;. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for the Spinifex free sandbox&lt;/a&gt; to explore the AWS-compatible API surface before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>openstack</category>
      <category>aws</category>
      <category>devops</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>VMware Alternatives in 2026: Where Teams Are Landing After the Broadcom Pricing Shock</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Thu, 03 Sep 2026 00:02:54 +0000</pubDate>
      <link>https://dev.to/toddyholiday/vmware-alternatives-in-2026-where-teams-are-landing-after-the-broadcom-pricing-shock-1gip</link>
      <guid>https://dev.to/toddyholiday/vmware-alternatives-in-2026-where-teams-are-landing-after-the-broadcom-pricing-shock-1gip</guid>
      <description>&lt;p&gt;Broadcom completed its $69 billion VMware acquisition in November 2023 and within weeks eliminated every perpetual license. Customers moved to subscription-only terms, forcing small deployments into bundles sized for enterprise. Standalone vSphere customers reported price increases of 800 to 1,500%. &lt;a href="https://www.ciodive.com/news/att-broadcom-vmware-price-hikes-court-battle/728603/" rel="noopener noreferrer"&gt;AT&amp;amp;T sued&lt;/a&gt; after receiving a quote representing a 1,050% increase. Customers already running the full VMware Cloud Foundation bundle — vSphere plus vSAN plus NSX — saw prices hold roughly flat or fall around 50%, but anyone running vSphere on its own absorbed the full shock.&lt;/p&gt;

&lt;p&gt;A CloudBolt survey published in early 2026 found that 86% of respondents were reducing their VMware footprints, with just over half planning phased transitions rather than full replacements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where teams are landing
&lt;/h2&gt;

&lt;p&gt;Proxmox is the clearest beneficiary. Community subscriptions and forum traffic grew substantially after the Broadcom announcement, and it is consistently the first alternative named in VMware migration threads across r/sysadmin, r/homelab, and enterprise IT forums. Proxmox is open source, runs on the same x86 hardware VMware ran on, and manages VMs and containers through a familiar web interface with no licensing floor.&lt;/p&gt;

&lt;p&gt;Other destinations include Nutanix, which has been pointed in its VMware-refugee marketing, OpenStack for teams already familiar with it, and public cloud for workloads where on-premise was never a compliance requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap Proxmox does not fill
&lt;/h2&gt;

&lt;p&gt;Proxmox replaces the hypervisor and gives you a working KVM environment. It does not give you the AWS API surface.&lt;/p&gt;

&lt;p&gt;Teams that spent years building Terraform modules against the AWS provider, writing IAM policies, running eksctl for Kubernetes cluster provisioning, and scripting against the AWS CLI now face a choice: learn a new operational model on Proxmox from scratch, or find something that brings the API surface they already know to the hardware they are migrating to.&lt;/p&gt;

&lt;p&gt;Spinifex (&lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;github.com/mulgadc/spinifex&lt;/a&gt;, AGPL-3.0, Go) runs on standard Linux bare metal, which means it runs on the same hardware you are already evaluating for your post-VMware migration. It implements EC2, S3, IAM, EKS, ECS, ECR, VPC, and EBS through the AWS API that your existing tooling already speaks. A Terraform config that provisions infrastructure on AWS provisions the same infrastructure on Spinifex with a single provider endpoint override. The eksctl and kubectl workflows, the IAM role structures, the AWS CLI scripts all run unchanged.&lt;/p&gt;

&lt;p&gt;Teams rebuilding private cloud after VMware need a hypervisor to replace vSphere and an operational model to replace the management layer they had built around it. Proxmox answers the first question. For teams whose operational model was built on AWS tooling, Spinifex answers the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  The licensing parallel
&lt;/h2&gt;

&lt;p&gt;Broadcom's move from perpetual licences to subscription minimums is worth noting because it shapes how teams evaluate everything that comes after VMware. Spinifex is AGPL-3.0, meaning the source is available, auditable, and free to use with no minimum core count and no subscription floor. Documentation including the multi-node setup guide and hardware reference architectures is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For teams that watched a perpetual VMware licence turn into an 800% price increase, the AGPL licence and open source development model is not a footnote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Spinifex documentation, including the multi-node setup guide and hardware reference architectures, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The source is at &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, AGPL-3.0 licensed and written in Go. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for the free sandbox&lt;/a&gt; to explore the AWS-compatible API surface before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>vmware</category>
      <category>devops</category>
      <category>opensource</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Every Tool That Implements the AWS API in 2026</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Tue, 01 Sep 2026 23:55:02 +0000</pubDate>
      <link>https://dev.to/toddyholiday/every-tool-that-implements-the-aws-api-in-2026-3oba</link>
      <guid>https://dev.to/toddyholiday/every-tool-that-implements-the-aws-api-in-2026-3oba</guid>
      <description>&lt;p&gt;The AWS API has become infrastructure's common language, and a whole ecosystem has grown up around running it somewhere other than AWS. Some tools mock it for testing. Others implement it for real. Knowing which is which saves you from deploying a dev tool to production or wiring a production platform into your CI pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two categories
&lt;/h2&gt;

&lt;p&gt;The tools split into emulators and real cloud platforms. Emulators intercept AWS API calls and return plausible responses without provisioning real infrastructure, where state is usually ephemeral, VMs never boot, and the goal is behavioural approximation fast enough for a developer's inner loop. Real cloud platforms provision actual infrastructure where EC2 calls boot real virtual machines and block storage carries real persistence guarantees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emulators
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Moto
&lt;/h3&gt;

&lt;p&gt;Moto (&lt;a href="https://github.com/getmoto/moto" rel="noopener noreferrer"&gt;github.com/getmoto/moto&lt;/a&gt;, Apache 2.0, 8,400+ stars) has been around since 2013, making it the oldest option here. It works differently from the rest because rather than running a local server, it patches boto3 calls in-process through a test decorator. A function wrapped in &lt;code&gt;@mock_aws&lt;/code&gt; intercepts all AWS SDK calls and returns mock responses without any network traffic. This makes it fast and easy to drop into Python test suites, but it only works for Python. Teams using the AWS CLI, Terraform, or Go SDKs need a server-based option.&lt;/p&gt;

&lt;h3&gt;
  
  
  LocalStack
&lt;/h3&gt;

&lt;p&gt;LocalStack (&lt;a href="https://github.com/localstack/localstack" rel="noopener noreferrer"&gt;github.com/localstack/localstack&lt;/a&gt;, 64,000+ stars) is the dominant name in local AWS development. It runs as a Docker container exposing the AWS API on &lt;code&gt;localhost:4566&lt;/code&gt; and covers over 120 services. In March 2026, LocalStack archived its Community Edition repository and moved core services behind a paid plan. A free tier remains for non-commercial use and open source projects, but the Base plan covering Cloud Pods persistent state costs $39 per month and the Ultimate plan runs $89 per month. Teams that depended on CE for commercial CI pipelines are now evaluating alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Floci
&lt;/h3&gt;

&lt;p&gt;Floci (&lt;a href="https://floci.dev" rel="noopener noreferrer"&gt;floci.dev&lt;/a&gt;, &lt;a href="https://github.com/floci-io/floci" rel="noopener noreferrer"&gt;github.com/floci-io/floci&lt;/a&gt;, MIT, 22,800+ stars) launched in March 2026 as a direct response to the LocalStack CE archival. It covers 84 AWS services on &lt;code&gt;localhost:4566&lt;/code&gt;, requires no account, collects no telemetry, and ships as a single Docker image built on Quarkus and GraalVM native. The result is a 24ms startup time and a 13 MiB idle memory footprint. The star count reflects genuine demand from teams who wanted a zero-friction replacement and found one fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fakecloud
&lt;/h3&gt;

&lt;p&gt;Fakecloud (&lt;a href="https://fakecloud.dev" rel="noopener noreferrer"&gt;fakecloud.dev&lt;/a&gt;, &lt;a href="https://github.com/faiscadev/fakecloud" rel="noopener noreferrer"&gt;github.com/faiscadev/fakecloud&lt;/a&gt;, MIT, ~500 stars) covers 105 services and 7,396 operations, claiming full Smithy conformance against the AWS service model. The binary is around 19 MB and idles at roughly 10 MiB. Services include S3, DynamoDB, SQS, Lambda, IAM, STS, ECS, ECR, EC2, RDS with six real database engines, Bedrock, and 80+ more. It is a newer and smaller project than Floci but more ambitious in scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  MiniStack
&lt;/h3&gt;

&lt;p&gt;MiniStack (&lt;a href="https://github.com/ministackorg/ministack" rel="noopener noreferrer"&gt;github.com/ministackorg/ministack&lt;/a&gt;, MIT, 4,300 stars) covers 60+ services including S3, SQS, DynamoDB, Lambda, SNS, IAM, STS, Kinesis, EventBridge, Secrets Manager, SSM, CloudWatch, and SES. It supports Terraform, boto3, the AWS CLI, and CDK, and handles multi-account and multi-region configurations. The multi-region support puts it ahead of simpler options for teams testing region-aware workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real cloud platforms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ubicloud
&lt;/h3&gt;

&lt;p&gt;Ubicloud (&lt;a href="https://github.com/ubicloud/ubicloud" rel="noopener noreferrer"&gt;github.com/ubicloud/ubicloud&lt;/a&gt;, AGPL-3.0, Ruby, 12,300 stars) is a managed cloud service running on Hetzner and Leaseweb hardware. It offers elastic compute, block storage, firewall, load balancer, managed Postgres, Kubernetes, AI inference endpoints, and IAM, at prices running 3 to 10x lower than equivalent AWS services. Teams evaluating it should understand that Ubicloud is a hosted service accessed over the internet rather than software you deploy on your own hardware. Moving to Ubicloud means moving from one cloud to a cheaper cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spinifex
&lt;/h3&gt;

&lt;p&gt;Spinifex (&lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;github.com/mulgadc/spinifex&lt;/a&gt;, AGPL-3.0, Go) implements EC2, EBS, S3, VPC, IAM, EKS, ECS, ECR, and RDS on hardware you own, with no external control plane and no internet requirement. An &lt;code&gt;aws ec2 run-instances&lt;/code&gt; call boots a real VM via QEMU. S3 calls go to an erasure-coded object store. IAM policies enforce against real network boundaries. The same Terraform configs, eksctl workflows, and AWS CLI scripts that run against AWS run against Spinifex with a single provider endpoint override.&lt;/p&gt;

&lt;p&gt;Spinifex targets environments where data cannot leave hardware under direct control and where the infrastructure needs to operate with no external dependencies, covering air-gapped facilities, edge deployments, and sovereign environments. Full documentation including air-gapped install and reference architectures for specific hardware is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to use when
&lt;/h2&gt;

&lt;p&gt;For Python test suites, Moto is the natural choice because it is in-process, fast, and has been maintained for over a decade. For local dev or CI in any language, Floci offers the smallest footprint with zero account requirements, LocalStack offers the widest service coverage for teams already on a paid plan, and MiniStack or Fakecloud fill the gap for multi-region needs or specific services those two cover. For a cheaper cloud alternative where connectivity is not a concern, Ubicloud cuts the bill without changing the operational model. For hardware you own, Spinifex runs the AWS tooling you have already built on infrastructure that never calls home.&lt;/p&gt;

&lt;p&gt;Most teams end up using something from both categories because an emulator covers dev and CI while a real platform handles production or sovereign workloads. The endpoint changes; the code does not.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>opensource</category>
      <category>localstack</category>
    </item>
    <item>
      <title>Ubicloud vs Spinifex: Two Approaches to Open Source Cloud</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Tue, 01 Sep 2026 23:30:41 +0000</pubDate>
      <link>https://dev.to/toddyholiday/ubicloud-vs-spinifex-two-approaches-to-open-source-cloud-3n37</link>
      <guid>https://dev.to/toddyholiday/ubicloud-vs-spinifex-two-approaches-to-open-source-cloud-3n37</guid>
      <description>&lt;p&gt;The phrase "open source alternative to AWS" covers a lot of ground. It can mean a dev-time emulator, a managed service that runs on someone else's hardware, or software you install on bare metal you own and operate entirely within your own network. Ubicloud and Spinifex are both open source, both AGPL-3.0 licensed, and both designed to give teams cloud-like compute without the AWS bill. But they are built for different problems, and picking the wrong one for your context costs real time to undo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Ubicloud is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ubicloud/ubicloud" rel="noopener noreferrer"&gt;Ubicloud&lt;/a&gt; is a YC-backed open source cloud platform written in Ruby. It provides elastic compute via virtual machines, block storage (non-replicated), virtual networking with firewalls and load balancers, managed Postgres with automatic backups and point-in-time restore, Kubernetes, GitHub Actions runner integration, AI inference, and attribute-based access control. You can self-host it on bare metal from providers like Hetzner or Leaseweb, or use their managed service which runs on the same bare metal providers and handles the operational overhead for you.&lt;/p&gt;

&lt;p&gt;Ubicloud gives you cloud convenience at a cost closer to bare metal pricing, with the option to avoid the operational burden of managing it yourself. For teams whose primary motivation is reducing their AWS bill rather than taking infrastructure fully in-house, this is a practical path.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spinifex is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; is an open source AWS-compatible cloud platform, written in Go and AGPL-3.0 licensed, that runs on standard Linux bare metal hardware you own and operate. Rather than defining a new cloud API, it implements the AWS API itself, covering EC2, S3, IAM, EKS, and the rest of the common AWS service surface, so the Terraform configs, CLI scripts, IAM roles, and SDK integrations your team has already written work against it without modification. The endpoint changes; the tooling doesn't.&lt;/p&gt;

&lt;p&gt;Spinifex imposes one hard constraint: no external control plane, no phone-home, no dependency on any infrastructure outside the boundary you define. It runs air-gapped, in classified facilities, at the tactical edge, and in any environment where traffic to a US-headquartered cloud provider is either technically impossible or operationally prohibited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the two products diverge
&lt;/h2&gt;

&lt;p&gt;The key difference is not the feature list but the deployment model and what it implies about your operational context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting model.&lt;/strong&gt; Ubicloud runs on provider hardware, either managed by Ubicloud or self-managed by you on Hetzner or similar. Your data and compute still live on a third party's physical infrastructure. Spinifex runs on hardware you own, in a facility you control, with no third party in the stack below the OS. For most cost-reduction use cases this distinction doesn't matter. For organisations with data sovereignty obligations, regulatory constraints, or contractual requirements around physical infrastructure ownership, it is the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS API compatibility depth.&lt;/strong&gt; Ubicloud provides cloud-like services but does not expose the AWS API surface directly. Your Terraform configs written for AWS, your eksctl commands, and your &lt;code&gt;aws ecr get-login-password&lt;/code&gt; calls won't work against Ubicloud without changes because Ubicloud has its own interface layer rather than the AWS API. Spinifex implements the AWS API itself, so existing tooling and automation work against it without modification. The endpoint changes; nothing else does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disconnected operation.&lt;/strong&gt; Ubicloud is designed for connected infrastructure, either cloud-hosted or hosted on a connected bare metal provider. There is no air-gap installation path and no documented support for fully disconnected operation. Spinifex installs from a tarball with no internet dependency and runs with no ongoing external connectivity required, which makes it the appropriate choice for edge deployments, industrial sites, and environments where network egress is restricted or prohibited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S3 and block storage.&lt;/strong&gt; Ubicloud's block storage is non-replicated by design. Predastore, Spinifex's S3 implementation, uses Reed-Solomon erasure coding to distribute objects across nodes so that a node failure doesn't result in data loss. Teams that need the durability model AWS S3 provides should factor this in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Managed database.&lt;/strong&gt; Ubicloud has an advantage here. Its managed Postgres offering includes automatic backups, point-in-time restore, and high availability, comparable to RDS in terms of operational convenience. Spinifex exposes an RDS-compatible API for database connectivity, but the database management layer is your responsibility. For teams that want managed Postgres without the AWS bill, Ubicloud is the stronger choice for that service specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one is right for a given situation
&lt;/h2&gt;

&lt;p&gt;For teams whose goal is reducing cloud costs while remaining on hosted infrastructure and who want a managed service option, Ubicloud is a reasonable choice. The Ruby codebase has an active community, the managed service option lowers the operational entry bar, and the managed Postgres offering covers a gap that Spinifex doesn't fill at the same level.&lt;/p&gt;

&lt;p&gt;For teams whose requirements include hardware ownership, disconnected operation, air-gapped installation, or AWS API compatibility so that existing Terraform and CLI tooling transfers without changes, Spinifex is the appropriate platform. It's also the more natural choice for defence, government, and regulated industry contexts where the deployment environment may be a Pelican case at a forward operating position or a classified facility with no external network routes at all.&lt;/p&gt;

&lt;p&gt;The two products share a broad category label but address different operational contexts. Evaluate each against the environment you're actually deploying into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Spinifex documentation, including reference architectures and the air-gapped install guide, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The source is at &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, AGPL-3.0 licensed and written in Go. Ubicloud's source and documentation are at &lt;a href="https://github.com/ubicloud/ubicloud" rel="noopener noreferrer"&gt;github.com/ubicloud/ubicloud&lt;/a&gt;. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for the Spinifex free sandbox&lt;/a&gt; to explore the AWS API surface before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>opensource</category>
      <category>devops</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>LocalStack vs Spinifex: the Right Tool for Dev, the Right Tool for Production</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Tue, 01 Sep 2026 00:57:06 +0000</pubDate>
      <link>https://dev.to/toddyholiday/localstack-vs-spinifex-the-right-tool-for-dev-the-right-tool-for-production-2c42</link>
      <guid>https://dev.to/toddyholiday/localstack-vs-spinifex-the-right-tool-for-dev-the-right-tool-for-production-2c42</guid>
      <description>&lt;p&gt;LocalStack versus Spinifex comes up often enough to address directly. They don't compete because they solve different problems at different points in the software lifecycle. Conflating the two leads to reaching for the wrong tool and being frustrated when it doesn't fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What LocalStack is for
&lt;/h2&gt;

&lt;p&gt;LocalStack is an AWS emulator. You run it locally in a Docker container and it intercepts calls to AWS API endpoints, returning responses that closely approximate what the real AWS would return. It covers over 120 services and understands the same SDKs, CLI commands, and Terraform provider that you use against real AWS. For local development and CI testing, it's excellent: you can write a Lambda that reads from S3, test it locally against a LocalStack instance, and be confident the code will behave the same way in AWS without incurring API costs or requiring a real AWS account to be wired into your local dev loop.&lt;/p&gt;

&lt;p&gt;The emulation is not perfect at the edges, and LocalStack itself is clear that it's a development tool rather than a production platform. State is ephemeral by default, meaning a container restart loses everything. There are no real virtual machines being managed, no actual block storage with persistence guarantees, and no genuine network enforcement between services. The goal is behavioural approximation fast enough to run in a developer's inner loop, not correctness guarantees at the margins.&lt;/p&gt;

&lt;p&gt;In March 2026, LocalStack archived its Community Edition GitHub repository and moved core services behind a paid plan, which drew a strong reaction from the developer community given the project had accumulated over 64,000 GitHub stars. A permanent free tier remains available for non-commercial use, and students and open-source projects can access the full suite without charge, but the Base plan covering persistent state via Cloud Pods costs &lt;a href="https://localstack.cloud/pricing" rel="noopener noreferrer"&gt;$45 per month&lt;/a&gt;. That change is largely why "LocalStack alternative" has become a high-volume search query, and it's a reasonable frustration for teams that relied on CE for commercial CI pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spinifex is for
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;Spinifex&lt;/a&gt; is not a development tool and not an emulator. It implements the AWS API surface on real bare metal hardware so that the hardware you own becomes the production environment, while preserving every piece of AWS tooling you've already built competency around. EC2 calls provision actual virtual machines with real CPU and memory allocation. EBS volumes are actual block storage with real persistence guarantees. IAM policies are enforced across real network boundaries. The S3-compatible object storage layer, Predastore, distributes objects across nodes using Reed-Solomon erasure coding so data survives node failures.&lt;/p&gt;

&lt;p&gt;The use case is environments where AWS itself isn't available or appropriate: disconnected field deployments, air-gapped secure facilities, data sovereignty requirements that prohibit data leaving infrastructure under your direct control, and workloads where owning the hardware is more economical than cloud compute and egress costs. Spinifex runs without any external control plane or cloud dependency and installs from a release tarball with no internet access required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the comparison comes up and what it gets wrong
&lt;/h2&gt;

&lt;p&gt;These two tools get compared because they both speak the AWS API. If you run &lt;code&gt;aws s3 ls&lt;/code&gt; against a LocalStack instance or against a Spinifex instance, you get the same command syntax and a similar response format. The surface-level similarity creates the impression they're doing similar things, but the underlying architecture is completely different and the appropriate use cases don't overlap.&lt;/p&gt;

&lt;p&gt;LocalStack is optimised for speed and breadth of service coverage in a single Docker container, because those are the properties that matter for a dev inner loop. Spinifex is optimised for production reliability, real hardware management, and disconnected operation, because those are the properties that matter when the hardware you're running on is the production environment. Neither tool is trying to do what the other does.&lt;/p&gt;

&lt;p&gt;The analogy is SQLite versus PostgreSQL. SQLite is an excellent embedded database and the right choice for a huge range of applications. PostgreSQL is a production database server designed for concurrent multi-user workloads with real persistence and replication. They both speak SQL. Choosing between them isn't really a comparison because the contexts in which each is correct don't overlap, and a benchmark between them would be measuring the wrong things.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use each
&lt;/h2&gt;

&lt;p&gt;LocalStack is the right answer if you're writing application code against AWS APIs and you want a fast, cheap, offline-capable way to run that code in your local dev environment or CI pipeline without hitting real AWS. The free tier covers non-commercial use, and even the paid plans are inexpensive relative to the time and API cost savings for a team running hundreds of CI builds a day. If you've moved from the Community Edition and want a free alternative, &lt;a href="https://floci.dev/" rel="noopener noreferrer"&gt;Floci&lt;/a&gt; and MiniStack are MIT-licensed emulators that appeared in early 2026 and cover similar territory.&lt;/p&gt;

&lt;p&gt;Spinifex is the right answer if the hardware you're running on is the production environment and you want that hardware to behave like AWS, rather than approximating AWS behaviour in a dev mock. The Terraform configs, IAM policies, CLI scripts, and SDK integrations you've written for AWS work against Spinifex without modification because the API is identical, not approximated. Spinifex is driven by operational requirements: a disconnected edge deployment, a data sovereignty obligation, or a cost calculation at scale.&lt;/p&gt;

&lt;p&gt;Many teams run both: LocalStack or an equivalent in their dev and CI environments for the same reasons they've always used it, and Spinifex for the production edge or sovereign deployment that the real workload targets. The endpoint your application points at changes; the code doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Full Spinifex documentation is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;, including the air-gapped installation guide for disconnected deployments. The source is on &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, written in Go and AGPL-3.0 licensed. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for our free sandbox&lt;/a&gt; to explore the API surface against a live instance before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Self-Hosted IAM: Roles, Policies, and Instance Profiles Without AWS</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Mon, 31 Aug 2026 01:32:57 +0000</pubDate>
      <link>https://dev.to/toddyholiday/self-hosted-iam-roles-policies-and-instance-profiles-without-aws-1c5g</link>
      <guid>https://dev.to/toddyholiday/self-hosted-iam-roles-policies-and-instance-profiles-without-aws-1c5g</guid>
      <description>&lt;p&gt;Self-hosted IAM is the part of the AWS stack that most bare-metal alternatives leave out. They'll give you virtual machines and maybe object storage, but they hand-wave the access control layer, which means engineers fall back to baking credentials into images, rotating static access keys manually, or running without meaningful multi-tenancy at all. Spinifex implements the full surface, including users, groups, policies, roles, instance profiles, and STS credential delivery, and your existing tooling works against it without modification.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spinifex IAM actually covers
&lt;/h2&gt;

&lt;p&gt;The IAM implementation in Spinifex covers the primitives you'd reach for in AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Users and access keys&lt;/strong&gt; for human operators and service accounts, with the same key pair format the CLI and SDKs expect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed and inline policies&lt;/strong&gt; in the same JSON format as AWS, with &lt;code&gt;Allow&lt;/code&gt; and &lt;code&gt;Deny&lt;/code&gt; effects, action patterns, and resource ARNs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Groups&lt;/strong&gt; for bundling shared permissions across users without per-user policy management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roles&lt;/strong&gt; with trust policies that specify which principals are allowed to assume them, either AWS principals like specific users or service principals like &lt;code&gt;ec2.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance profiles&lt;/strong&gt; that bind a role to an EC2 instance so the instance itself can call AWS APIs without any static credentials in the guest environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STS AssumeRole&lt;/strong&gt; for programmatic role assumption, returning short-lived credentials that expire and auto-rotate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All IAM resources are scoped to the account they're created in, matching AWS account isolation semantics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles and trust policies
&lt;/h2&gt;

&lt;p&gt;A role is an IAM identity that has no long-lived credentials. Instead of an access key pair, it has a trust policy that declares who may assume it, and whoever assumes it receives short-lived credentials from STS. No static secret is ever distributed to the service that needs access, which makes this the right model for service-to-service auth.&lt;/p&gt;

&lt;p&gt;Creating a role requires writing a trust policy first. For a role that EC2 instances will use, trust the &lt;code&gt;ec2.amazonaws.com&lt;/code&gt; service principal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/ec2-trust.json &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "ec2.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;aws iam create-role &lt;span class="nt"&gt;--role-name&lt;/span&gt; app-server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--assume-role-policy-document&lt;/span&gt; file:///tmp/ec2-trust.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Role for app servers"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To trust a specific user principal instead, swap &lt;code&gt;Service&lt;/code&gt; for &lt;code&gt;AWS&lt;/code&gt; and supply the user ARN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::000000000001:user/deploy-bot"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spinifex validates trust policies at write time, rejecting &lt;code&gt;NotPrincipal&lt;/code&gt;, &lt;code&gt;NotAction&lt;/code&gt;, empty &lt;code&gt;Principal&lt;/code&gt; blocks, and empty-string &lt;code&gt;Action&lt;/code&gt; values with &lt;code&gt;MalformedPolicyDocument&lt;/code&gt;. &lt;code&gt;Condition&lt;/code&gt; blocks are accepted only in the &lt;code&gt;StringEquals&lt;/code&gt; form used for web identity federation, so the validation surface is deliberately narrower than full AWS IAM while still covering the common patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attaching permissions to a role
&lt;/h2&gt;

&lt;p&gt;A freshly created role can do nothing. Grant it permissions by attaching a managed policy, exactly as you would with a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam attach-role-policy &lt;span class="nt"&gt;--role-name&lt;/span&gt; app-server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy-arn&lt;/span&gt; arn:aws:iam::000000000001:policy/S3ReadOnly

aws iam list-attached-role-policies &lt;span class="nt"&gt;--role-name&lt;/span&gt; app-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or embed an inline policy directly on the role, which travels with it and is deleted when the role is deleted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam put-role-policy &lt;span class="nt"&gt;--role-name&lt;/span&gt; app-server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy-name&lt;/span&gt; ec2-describe &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy-document&lt;/span&gt; &lt;span class="s1"&gt;'{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ec2:DescribeInstances"],"Resource":"*"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both approaches produce the same evaluation result. Managed policies are useful when the same permission set applies to multiple roles or users; inline policies are useful when the permission is specific to that one role and you want it to go away if the role does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instance profiles and IMDS
&lt;/h2&gt;

&lt;p&gt;The instance profile is what gets role credentials into a running EC2 instance. A profile is a container that binds exactly one role to a set of EC2 instances, and the instances get their credentials delivered through the Instance Metadata Service at &lt;code&gt;169.254.169.254&lt;/code&gt;, the same address AWS uses. The AWS CLI and every AWS SDK check IMDS for credentials automatically, so an instance launched with a profile needs no credentials configured inside the guest at all.&lt;/p&gt;

&lt;p&gt;Creating a profile and adding the role to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam create-instance-profile &lt;span class="nt"&gt;--instance-profile-name&lt;/span&gt; app-server-profile
aws iam add-role-to-instance-profile &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instance-profile-name&lt;/span&gt; app-server-profile &lt;span class="nt"&gt;--role-name&lt;/span&gt; app-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then launch an instance with the profile attached:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 run-instances &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image-id&lt;/span&gt; ami-0dd52c90440ff4150 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instance-type&lt;/span&gt; t3.micro &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subnet-id&lt;/span&gt; subnet-a0e5fc381376d82a1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--iam-instance-profile&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app-server-profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside that instance, any code running with the AWS CLI or an AWS SDK will pick up the role's credentials from IMDS without any configuration. The credentials rotate automatically and are never written to disk.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No static keys baked into images, no manual rotation, no credentials files inside the guest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Assuming a role programmatically
&lt;/h2&gt;

&lt;p&gt;Services and CI systems can also assume a role directly using STS, provided the trust policy allows their principal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws sts assume-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-arn&lt;/span&gt; arn:aws:iam::000000000001:role/deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-session-name&lt;/span&gt; release-42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STS returns a temporary credential set with an expiry; the caller exports it as environment variables for the duration of the operation. The same call works from inside a guest using the instance role, from a CI runner with its own user credentials, or from any other principal allowed by the trust policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for air-gapped and on-premise deployments
&lt;/h2&gt;

&lt;p&gt;IAM solves the same problem whether you're on AWS or on your own hardware: services need to call APIs, and those calls need to be authorised without distributing long-lived secrets. On AWS, IAM and instance profiles handle this automatically. On bare metal without Spinifex, the typical answer is a static access key that lives in the environment, gets committed to config files, and has no expiry.&lt;/p&gt;

&lt;p&gt;Spinifex brings the same credential delivery model to hardware you own. Instances get roles, roles have policies, and credentials arrive through IMDS, expire after the session duration, and rotate without operator involvement. Engineers who already understand IAM don't need to learn a different access control system when the compute moves to on-premise hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;IAM configuration is covered in the &lt;a href="https://docs.mulgadc.com/docs/iam-roles-and-instance-profiles" rel="noopener noreferrer"&gt;IAM roles and instance profiles guide&lt;/a&gt; and the &lt;a href="https://docs.mulgadc.com/docs/iam-users-and-policies" rel="noopener noreferrer"&gt;IAM users and policies guide&lt;/a&gt; in the Spinifex documentation. Source is at &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, AGPL-3.0 licensed and written in Go. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for our free sandbox&lt;/a&gt; to explore the IAM surface before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>iam</category>
      <category>security</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Running ECS Workloads on Bare Metal with Spinifex</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Fri, 28 Aug 2026 05:21:27 +0000</pubDate>
      <link>https://dev.to/toddyholiday/running-ecs-workloads-on-bare-metal-with-spinifex-4k9o</link>
      <guid>https://dev.to/toddyholiday/running-ecs-workloads-on-bare-metal-with-spinifex-4k9o</guid>
      <description>&lt;p&gt;ECS is the part of the AWS stack that teams reach for when they want container orchestration without the complexity surface of Kubernetes. A cluster, some task definitions, a service, and a load balancer, and the scheduler handles placement and restarts. The problem is that ECS is deeply tied to AWS. The scheduler is a managed service, the container instances are EC2 instances, and the whole thing assumes a live connection to &lt;code&gt;amazonaws.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Spinifex implements ECS on the EC2 launch type so the same model runs on bare metal, in disconnected environments, and behind whatever network boundaries your operational context requires.&lt;/p&gt;

&lt;h2&gt;
  
  
  How ECS on Spinifex works
&lt;/h2&gt;

&lt;p&gt;Spinifex follows the AWS EC2 launch type model directly: you supply the compute. A cluster is a logical grouping. The capacity behind it is container instances, which are ordinary EC2 instances booted from Spinifex's &lt;code&gt;spinifex-ecs-node&lt;/code&gt; image, each running the Spinifex ECS agent. The agent registers the instance with the cluster, reports its available CPU and memory, and runs the containers the scheduler places on it.&lt;/p&gt;

&lt;p&gt;There is no serverless capacity equivalent and no Fargate-style launch type. &lt;code&gt;RequiresCompatibilities&lt;/code&gt; of &lt;code&gt;FARGATE&lt;/code&gt; is accepted in a task definition but not honoured. If you're used to Fargate, the shift is that you manage the container instance count yourself rather than letting AWS provision capacity on demand, but the task definition format and service configuration remain the same.&lt;/p&gt;

&lt;p&gt;A task definition describes one or more containers with image, CPU and memory limits, port mappings, environment variables, and an optional task IAM role. A task is a running instantiation of that definition, and the scheduler places tasks on instances with sufficient free capacity. A service keeps a desired count of tasks running, replaces any that fail, and registers each task's IP with an ALB target group when load balancer configuration is present.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;p&gt;Container instances must boot Spinifex's &lt;code&gt;spinifex-ecs-node&lt;/code&gt; image, which ships with the ECS agent pre-installed. Confirm the image is imported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 describe-images &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--filters&lt;/span&gt; &lt;span class="s1"&gt;'Name=tag:spinifex:managed-by,Values=ecs'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Images[].[ImageId,Name]'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no rows come back, the image is not imported and needs to be registered before you can provision capacity.&lt;/p&gt;

&lt;p&gt;Container instances also need the &lt;code&gt;ecsInstanceRole&lt;/code&gt; instance profile, which is a role trusted by &lt;code&gt;ec2.amazonaws.com&lt;/code&gt; with an &lt;code&gt;ecs:*&lt;/code&gt; policy, exposed through a profile of the same name. The Spinifex console's provision-capacity action creates it on first use, and the ECS Quickstart Terraform workbook creates it automatically unless you opt out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a cluster and registering a task definition
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;spinifex-&amp;lt;nodename&amp;gt;

aws ecs create-cluster &lt;span class="nt"&gt;--cluster-name&lt;/span&gt; demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then register a task definition. This example uses &lt;code&gt;awsvpc&lt;/code&gt; network mode, EC2 launch type, and one nginx container on port 80:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecs register-task-definition &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--family&lt;/span&gt; web &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--network-mode&lt;/span&gt; awsvpc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--requires-compatibilities&lt;/span&gt; EC2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cpu&lt;/span&gt; 256 &lt;span class="nt"&gt;--memory&lt;/span&gt; 512 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--container-definitions&lt;/span&gt; &lt;span class="s1"&gt;'[{
    "name":"web",
    "image":"docker.io/library/nginx:1.27-alpine",
    "portMappings":[{"containerPort":80,"protocol":"tcp"}],
    "essential":true
  }]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;awsvpc&lt;/code&gt; network mode means each task gets its own ENI and private IP in your subnet, matching the AWS behaviour. If you're fronting tasks with an ALB target group, it must use &lt;code&gt;target_type = "ip"&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provisioning container instances
&lt;/h2&gt;

&lt;p&gt;Once the cluster exists, add capacity by launching EC2 instances from the ECS node image with the &lt;code&gt;ecsInstanceRole&lt;/code&gt; profile attached. The cloud-init user data needs to point the agent at the cluster name. The ECS Quickstart Terraform workbook generates this user data for you, and the Spinifex console wraps the same call in a Provision capacity action.&lt;/p&gt;

&lt;p&gt;Once instances boot and the agent registers, verify they appear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecs list-container-instances &lt;span class="nt"&gt;--cluster&lt;/span&gt; demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running tasks and creating services
&lt;/h2&gt;

&lt;p&gt;Run a one-off task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecs run-task &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; demo &lt;span class="nt"&gt;--task-definition&lt;/span&gt; web &lt;span class="nt"&gt;--count&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--network-configuration&lt;/span&gt; &lt;span class="s1"&gt;'awsvpcConfiguration={subnets=[subnet-aaaa]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or create a service to keep a desired count running behind a target group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecs create-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; demo &lt;span class="nt"&gt;--service-name&lt;/span&gt; web &lt;span class="nt"&gt;--task-definition&lt;/span&gt; web &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--desired-count&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--network-configuration&lt;/span&gt; &lt;span class="s1"&gt;'awsvpcConfiguration={subnets=[subnet-aaaa]}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--load-balancers&lt;/span&gt; &lt;span class="s1"&gt;'targetGroupArn=&amp;lt;tg-arn&amp;gt;,containerName=web,containerPort=80'&lt;/span&gt;

aws ecs describe-services &lt;span class="nt"&gt;--cluster&lt;/span&gt; demo &lt;span class="nt"&gt;--services&lt;/span&gt; web &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'services[0].[runningCount,desiredCount]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Task IAM roles and credential delivery
&lt;/h2&gt;

&lt;p&gt;If your containers need to call AWS APIs, give the task definition a &lt;code&gt;taskRoleArn&lt;/code&gt;. The role must be trusted by &lt;code&gt;ecs-tasks.amazonaws.com&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-tasks.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a task has a &lt;code&gt;taskRoleArn&lt;/code&gt;, the ECS agent injects &lt;code&gt;AWS_CONTAINER_CREDENTIALS_RELATIVE_URI&lt;/code&gt; into the container environment and serves short-lived credentials for that role at &lt;code&gt;169.254.170.2&lt;/code&gt;. Any AWS SDK in the container picks these up automatically without static keys. If &lt;code&gt;executionRoleArn&lt;/code&gt; is set, the agent uses it to authorise ECR image pulls instead of falling back to the container instance role.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging
&lt;/h2&gt;

&lt;p&gt;Spinifex honours the &lt;code&gt;json-file&lt;/code&gt; log driver, which is the containerd default. Container stdout and stderr are written on the container instance and are accessible there. There is no CloudWatch Logs path.&lt;/p&gt;

&lt;p&gt;To read a task's logs, find the container instance running it and inspect the containerd output on that host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On the container instance:&lt;/span&gt;
ctr &lt;span class="nt"&gt;-n&lt;/span&gt; default containers &lt;span class="nb"&gt;ls&lt;/span&gt;                &lt;span class="c"&gt;# find {taskId}-{containerName}&lt;/span&gt;
ctr &lt;span class="nt"&gt;-n&lt;/span&gt; default tasks &lt;span class="nb"&gt;ls
&lt;/span&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; containerd | &lt;span class="nb"&gt;grep&lt;/span&gt; &amp;lt;taskId&amp;gt;    &lt;span class="c"&gt;# container stdout/stderr via the host journal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Task definitions that declare &lt;code&gt;awslogs&lt;/code&gt; or another log driver are accepted without error, and Spinifex logs a warning at registration naming the container, so the fallback is not silent. Containers are named &lt;code&gt;{taskId}-{containerName}&lt;/code&gt; and carry &lt;code&gt;mulga.ecs.*&lt;/code&gt; labels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment circuit breaker
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;UpdateService&lt;/code&gt; to a new task-definition revision performs a rolling update that honours &lt;code&gt;deploymentConfiguration&lt;/code&gt;: &lt;code&gt;minimumHealthyPercent&lt;/code&gt; keeps that fraction of the desired count running while &lt;code&gt;maximumPercent&lt;/code&gt; bounds how many extra tasks can launch during the roll. Enabling the deployment circuit breaker causes a rollout to fail if its tasks repeatedly fail to start, and with &lt;code&gt;rollback&lt;/code&gt; enabled it automatically reverts to the last-good task definition revision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current limitations
&lt;/h2&gt;

&lt;p&gt;ECS v1 in Spinifex is deliberately minimal. Known gaps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No service discovery.&lt;/strong&gt; &lt;code&gt;serviceRegistries&lt;/code&gt; and Cloud Map integration are not implemented. Reach a service through its load balancer rather than a DNS name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No capacity providers or managed scaling.&lt;/strong&gt; Capacity is the static total of your registered instances and there is no ASG binding or scale-out. You manage the instance count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;secrets[]&lt;/code&gt; are rejected.&lt;/strong&gt; A task definition that declares container &lt;code&gt;secrets[]&lt;/code&gt; fails &lt;code&gt;RegisterTaskDefinition&lt;/code&gt; with &lt;code&gt;InvalidParameterException&lt;/code&gt; rather than running without the secrets it expects. Use environment variables or fetch secrets at startup instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags via &lt;code&gt;TagResource&lt;/code&gt; are not persisted.&lt;/strong&gt; Tag the resources at creation time rather than updating tags after the fact.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When this is the right model
&lt;/h2&gt;

&lt;p&gt;ECS on Spinifex fits the same scenarios as ECS on AWS, applied to environments where AWS isn't available or appropriate: disconnected field deployments, regulated environments that require workloads on hardware under direct control, and on-premise data centres where teams have already built tooling around ECS task definitions.&lt;/p&gt;

&lt;p&gt;The task definitions and service configuration that work in AWS ECS work in Spinifex without modification, so teams moving workloads from cloud to on-premise hardware don't need to rewrite their container infrastructure to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;The full ECS walkthrough, including the Terraform workbook for provisioning clusters and container instances end-to-end, is in the &lt;a href="https://docs.mulgadc.com/docs/ecs" rel="noopener noreferrer"&gt;ECS documentation&lt;/a&gt;. Source is at &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, AGPL-3.0 licensed and written in Go. Or &lt;a href="https://mulgadc.com/signup" rel="noopener noreferrer"&gt;sign up for our free sandbox&lt;/a&gt; to explore ECS on Spinifex before deploying on your own hardware.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ecs</category>
      <category>containers</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Running Kubernetes in an Air-Gapped Environment With Spinifex</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Thu, 27 Aug 2026 23:52:36 +0000</pubDate>
      <link>https://dev.to/toddyholiday/running-kubernetes-in-an-air-gapped-environment-with-spinifex-5f14</link>
      <guid>https://dev.to/toddyholiday/running-kubernetes-in-an-air-gapped-environment-with-spinifex-5f14</guid>
      <description>&lt;p&gt;Running Kubernetes in an air-gapped environment is harder than it looks. Kubernetes pulls container images from registries. Control plane components phone home during bootstrap. Node configuration tooling assumes it can reach package repositories. The ecosystem is built around internet connectivity, and peeling that assumption out of a real deployment is tedious enough that most teams avoid it or work around it with expensive and brittle proxy setups.&lt;/p&gt;

&lt;p&gt;Spinifex installs without internet access, using a release tarball and pre-staged packages transferred on USB media, and it provides an AWS-compatible EKS implementation so you get managed Kubernetes on hardware that never leaves your network.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "air-gapped" actually means here
&lt;/h2&gt;

&lt;p&gt;There are different degrees of disconnection, so here is what Spinifex supports and where the constraints are.&lt;/p&gt;

&lt;p&gt;The Spinifex platform, covering the AWS gateway, compute, block storage, object storage, networking, and IAM, installs and runs with no internet connectivity at all. Nothing in the install process reaches out to the internet once you've transferred the release tarball and dependencies to the target machine. The &lt;code&gt;--no-telemetry&lt;/code&gt; flag on &lt;code&gt;spx admin init&lt;/code&gt; prevents the one-shot install telemetry beacon, suppressing even that initial call.&lt;/p&gt;

&lt;p&gt;EKS clusters have one constraint: the control plane needs egress during bootstrap. The EKS guide's troubleshooting notes document this as expected behaviour for the current release. Once the cluster is active, your workloads can run in a LAN with no external routes as long as container images are available locally, either pre-pulled or served from a Spinifex ECR instance on the same network. The platform itself doesn't require connectivity for ongoing operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the offline installer
&lt;/h2&gt;

&lt;p&gt;The air-gapped install process works in two phases: prepare everything you need on a connected machine, then transfer and install on the target.&lt;/p&gt;

&lt;p&gt;On a machine with internet access, download the Spinifex release tarball, the install script, and the SHA-256 checksum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64   &lt;span class="c"&gt;# or arm64&lt;/span&gt;
&lt;span class="nv"&gt;TAG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://api.github.com/repos/mulgadc/spinifex/releases/latest &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'"tag_name"'&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;'"'&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/mulgadc/spinifex/releases/download/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TAG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSLO&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/spinifex-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TAG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-linux-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSLO&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/spinifex-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TAG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-linux-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz.sha256"&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSLO&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/setup.sh"&lt;/span&gt;

&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"spinifex-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TAG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-linux-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz.sha256"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pre-download the APT packages the installer needs. Using &lt;code&gt;--download-only&lt;/code&gt; writes the &lt;code&gt;.deb&lt;/code&gt; files to the apt cache without installing them, so the connected machine is unaffected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--download-only&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  nbdkit nbdkit-plugin-dev pkg-config &lt;span class="se"&gt;\&lt;/span&gt;
  qemu-system-x86 qemu-utils &lt;span class="se"&gt;\&lt;/span&gt;
  ovmf qemu-efi-aarch64 &lt;span class="se"&gt;\&lt;/span&gt;
  libvirt-daemon-system libvirt-clients libvirt-dev &lt;span class="se"&gt;\&lt;/span&gt;
  ovn-central ovn-host openvswitch-switch &lt;span class="se"&gt;\&lt;/span&gt;
  dhcpcd-base make gcc jq curl iproute2 netcat-openbsd &lt;span class="se"&gt;\&lt;/span&gt;
  wget unzip xz-utils file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download the AWS CLI v2 installer and the cloud image you'll use as the guest OS for virtual machines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="s2"&gt;"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; awscliv2.zip

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; images
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="s2"&gt;"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; images/debian-13-amd64.qcow2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stage everything onto the transfer media:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /media/spinifex-deploy/&lt;span class="o"&gt;{&lt;/span&gt;tarball,apt-packages,aws,images&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;spinifex-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TAG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-linux-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz /media/spinifex-deploy/tarball/
&lt;span class="nb"&gt;cp &lt;/span&gt;setup.sh /media/spinifex-deploy/
&lt;span class="nb"&gt;cp&lt;/span&gt; /var/cache/apt/archives/&lt;span class="k"&gt;*&lt;/span&gt;.deb /media/spinifex-deploy/apt-packages/
&lt;span class="nb"&gt;cp &lt;/span&gt;awscliv2.zip /media/spinifex-deploy/aws/
&lt;span class="nb"&gt;cp &lt;/span&gt;images/&lt;span class="k"&gt;*&lt;/span&gt;.qcow2 /media/spinifex-deploy/images/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing on the air-gapped target
&lt;/h2&gt;

&lt;p&gt;On the target server, with no internet connection, mount the transfer media and work through the install sequence.&lt;/p&gt;

&lt;p&gt;Install the APT packages from the local cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount /dev/sdb1 /mnt/usb

&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; /mnt/usb/apt-packages/&lt;span class="k"&gt;*&lt;/span&gt;.deb
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;--no-download&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--no-download&lt;/code&gt; flag tells apt to resolve any outstanding dependencies using only what's already in the local cache. If a dependency is missing, you'll need to add it to the &lt;code&gt;--download-only&lt;/code&gt; step on the connected machine and re-stage.&lt;/p&gt;

&lt;p&gt;Install the AWS CLI and run the Spinifex installer, pointing it at the local tarball and suppressing the package and AWS download steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; unzip /mnt/usb/aws/awscliv2.zip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo&lt;/span&gt; ./aws/install

&lt;span class="nv"&gt;INSTALL_SPINIFEX_TARBALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/mnt/usb/tarball/spinifex-&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nt"&gt;-linux-&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.tar.gz &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_SPINIFEX_SKIP_APT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_SPINIFEX_SKIP_AWS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
bash /mnt/usb/setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;setup.sh&lt;/code&gt; without &lt;code&gt;sudo&lt;/code&gt;. The script handles privilege escalation internally and ends by launching a &lt;code&gt;newgrp spinifex&lt;/code&gt; subshell so your current shell picks up the &lt;code&gt;spinifex&lt;/code&gt; group membership, which is required for the AWS CLI to read the TLS certificates in &lt;code&gt;/etc/spinifex/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Configure OVN networking, initialise without telemetry, and start the services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; /usr/local/share/spinifex/setup-ovn.sh &lt;span class="nt"&gt;--management&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;spx admin init &lt;span class="nt"&gt;--node&lt;/span&gt; node1 &lt;span class="nt"&gt;--nodes&lt;/span&gt; 1 &lt;span class="nt"&gt;--no-telemetry&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start spinifex.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import the cloud image from the USB media:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;spx admin images import &lt;span class="nt"&gt;--file&lt;/span&gt; /mnt/usb/images/debian-13-amd64.qcow2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--distro&lt;/span&gt; debian &lt;span class="nt"&gt;--version&lt;/span&gt; 13 &lt;span class="nt"&gt;--arch&lt;/span&gt; x86_64 &lt;span class="nt"&gt;--boot-mode&lt;/span&gt; uefi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the install worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;spinifex-&amp;lt;nodename&amp;gt;
aws ec2 describe-instance-types
aws ec2 describe-images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both calls returning data confirms the AWS gateway is up and the image is registered. At this point you have a fully functional AWS-compatible cloud platform running on isolated hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running EKS clusters on the disconnected platform
&lt;/h2&gt;

&lt;p&gt;With Spinifex running, you can create EKS clusters using the standard AWS CLI workflow. The &lt;code&gt;spx admin init&lt;/code&gt; command creates the &lt;code&gt;spinifex-&amp;lt;nodename&amp;gt;&lt;/code&gt; AWS profile automatically, pointing all API calls at the local Spinifex gateway on port 9999.&lt;/p&gt;

&lt;p&gt;Before creating a cluster, confirm the &lt;code&gt;eks-node&lt;/code&gt; image is registered, because Spinifex blocks cluster creation until it's present:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 describe-images &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--filters&lt;/span&gt; &lt;span class="s1"&gt;'Name=tag:spinifex:managed-by,Values=eks'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Images[].[ImageId,Name]'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the EKS node image isn't in your catalogue yet, you'll need to stage it on the transfer media along with the other cloud images and import it with &lt;code&gt;spx admin images import&lt;/code&gt; before proceeding.&lt;/p&gt;

&lt;p&gt;With the image in place, create the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;spinifex-&amp;lt;nodename&amp;gt;

aws eks create-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; demo &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-arn&lt;/span&gt; arn:aws:iam::000000000000:role/eks-cluster-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resources-vpc-config&lt;/span&gt; &lt;span class="nv"&gt;subnetIds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;subnet-aaaa,subnet-bbbb,endpointPublicAccess&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--access-config&lt;/span&gt; &lt;span class="nv"&gt;authenticationMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;API &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kubernetes-version&lt;/span&gt; 1.32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;authenticationMode=API&lt;/code&gt; flag is required because Spinifex implements the access-entry authentication model rather than the older &lt;code&gt;aws-auth&lt;/code&gt; ConfigMap approach.&lt;/p&gt;

&lt;p&gt;During cluster bootstrap the control plane needs egress, so ensure the subnet the control plane lands in has an internet gateway route, or confirm the route is in place temporarily. Once the cluster reaches the &lt;code&gt;ACTIVE&lt;/code&gt; state, the control plane doesn't need ongoing connectivity for its own operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks &lt;span class="nb"&gt;wait &lt;/span&gt;cluster-active &lt;span class="nt"&gt;--name&lt;/span&gt; demo

aws eks create-nodegroup &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster-name&lt;/span&gt; demo &lt;span class="nt"&gt;--nodegroup-name&lt;/span&gt; default &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node-role-arn&lt;/span&gt; arn:aws:iam::000000000000:role/eks-node-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subnets&lt;/span&gt; subnet-aaaa subnet-bbbb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scaling-config&lt;/span&gt; &lt;span class="nv"&gt;minSize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1,maxSize&lt;span class="o"&gt;=&lt;/span&gt;2,desiredSize&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instance-types&lt;/span&gt; t3.medium

aws eks update-kubeconfig &lt;span class="nt"&gt;--name&lt;/span&gt; demo
kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running workloads with no external connectivity
&lt;/h2&gt;

&lt;p&gt;Once the cluster is active, the blocking question for disconnected environments is image availability. Kubernetes pods pull images when they start, and without internet access the nodes need to reach a local image source.&lt;/p&gt;

&lt;p&gt;Spinifex includes an ECR-compatible container registry for hosting images on the same network as the cluster. Push images to a local Spinifex ECR instance, configure your pod specs to pull from it, and the entire workload lifecycle from image push through deployment stays within the local network, with no dependency on Docker Hub, GitHub Container Registry, or any external registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical benefit
&lt;/h2&gt;

&lt;p&gt;The reason to go through this process rather than using a simpler Kubernetes distribution is operational continuity. Engineers who know how to operate EKS on AWS know how to operate EKS on Spinifex, because the API surface, the CLI commands, the Terraform resource types, and the IAM model are identical. AWS tooling and operational knowledge transfers to the disconnected environment without a relearning curve.&lt;/p&gt;

&lt;p&gt;For defence, industrial, and classified environments where the security requirement is hardware you own and control, that means a production Kubernetes platform without a separate body of tooling knowledge or a reduced feature set.&lt;/p&gt;

&lt;p&gt;Full documentation, including Terraform workbooks for common EKS configurations, is at &lt;a href="https://docs.mulgadc.com" rel="noopener noreferrer"&gt;docs.mulgadc.com&lt;/a&gt;. The air-gapped install guide is at &lt;a href="https://docs.mulgadc.com/docs/install-airgapped" rel="noopener noreferrer"&gt;docs.mulgadc.com/docs/install-airgapped&lt;/a&gt;. Spinifex is open source, written in Go, and AGPL-3.0 licensed, with the full source at &lt;a href="https://github.com/mulgadc/spinifex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>airgap</category>
      <category>devops</category>
      <category>selfhosted</category>
    </item>
  </channel>
</rss>
