mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
docs: ECS service guide + register ecs-quickstart workbook (#434)
* docs: add ECS (Elastic Container Service) guide + register ecs-quickstart workbook Add a Container Services -> ECS doc mirroring the EKS/ECR shape: concepts (cluster, task definition, task, service, container instances via the ECS-AMI EC2 launch type), an aws ecs / console / Terraform quickstart, task IAM roles via the credential endpoint, awsvpc networking, and the honest v1 limitations (no service discovery, awslogs discarded, no rolling deployments, no capacity providers, no distinct execution role). Convert the ecs-quickstart workbook README to the doc-page format (frontmatter + overview/prerequisites/instructions/troubleshooting) so it renders as a Terraform Workbooks entry alongside the EKS workbooks. * docs: add node-image prerequisite banner + infra diagram to EKS and ECS pages Add a GitHub-style [!IMPORTANT] banner to the EKS and ECS prerequisites flagging the required node-image import (eks-node / spinifex-ecs-node), mirroring the install page's WAN-bridge banner, each with a describe-images verification command. Add a basic Spinifex topology diagram (SVG) to each Overview, in the tf-nginx-alb visual style: the EKS managed control plane + node-group workers, and the ECS ALB + container instances with the gateway/agent and task-credential path.
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="470" viewBox="0 0 900 470">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#0a0a0a"/>
|
||||
<stop offset="100%" style="stop-color:#0d1117"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="inet-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#3fb95022"/>
|
||||
<stop offset="100%" style="stop-color:#3fb95008"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="pub-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#3fb9501f"/>
|
||||
<stop offset="100%" style="stop-color:#3fb95008"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gw-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#DC26261f"/>
|
||||
<stop offset="100%" style="stop-color:#DC262608"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="900" height="470" fill="url(#bg)" rx="12"/>
|
||||
|
||||
<text x="24" y="30" font-family="'Segoe UI', system-ui, sans-serif" font-size="11" fill="#a1a1aa" letter-spacing="2.5" font-weight="600">ECS · EC2 LAUNCH TYPE ON SPINIFEX</text>
|
||||
<text x="876" y="30" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#71717a" text-anchor="end">container instances from spinifex-ecs-node AMI · awsvpc + ALB</text>
|
||||
|
||||
<!-- Internet -->
|
||||
<rect x="120" y="52" width="200" height="40" rx="8" fill="url(#inet-grad)" stroke="#3fb950" stroke-width="1.1" stroke-opacity="0.55"/>
|
||||
<text x="220" y="76" font-family="'SF Mono', ui-monospace, monospace" font-size="13" fill="#3fb950" text-anchor="middle" font-weight="700">Internet</text>
|
||||
|
||||
<!-- connector to ALB -->
|
||||
<line x1="220" y1="92" x2="220" y2="112" stroke="#71717a" stroke-width="1" opacity="0.5"/>
|
||||
<polygon points="216,108 224,108 220,116" fill="#71717a" opacity="0.7"/>
|
||||
|
||||
<!-- ALB -->
|
||||
<g transform="translate(90, 116)">
|
||||
<rect width="260" height="60" rx="8" fill="url(#pub-grad)" stroke="#3fb950" stroke-width="1.2" stroke-opacity="0.6"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12.5" fill="#3fb950" font-weight="700">Application Load Balancer</text>
|
||||
<line x1="16" y1="32" x2="244" y2="32" stroke="#3fb950" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<text x="20" y="50" font-family="'Segoe UI', sans-serif" font-size="10" fill="#7ee787">target group · target_type = ip</text>
|
||||
</g>
|
||||
|
||||
<!-- Spinifex Gateway (control plane) -->
|
||||
<g transform="translate(560, 110)">
|
||||
<rect width="316" height="72" rx="8" fill="url(#gw-grad)" stroke="#DC2626" stroke-width="1.2" stroke-opacity="0.65"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12.5" fill="#F87171" font-weight="700">Spinifex Gateway :9999</text>
|
||||
<text x="296" y="24" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#FCA5A5" text-anchor="end">control plane</text>
|
||||
<line x1="16" y1="32" x2="300" y2="32" stroke="#DC2626" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<text x="20" y="48" font-family="'Segoe UI', sans-serif" font-size="10" fill="#FCA5A5">ECS agent registers · TLS + SigV4 (IMDS creds)</text>
|
||||
<text x="20" y="63" font-family="'Segoe UI', sans-serif" font-size="10" fill="#FCA5A5">task role creds → container at 169.254.170.2</text>
|
||||
</g>
|
||||
|
||||
<!-- ALB fan-out to subnets (traffic) -->
|
||||
<line x1="220" y1="176" x2="220" y2="200" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<line x1="220" y1="200" x2="650" y2="200" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<line x1="220" y1="200" x2="220" y2="228" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<line x1="650" y1="200" x2="650" y2="228" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<text x="435" y="195" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#7ee787" text-anchor="middle">balances to each task's ENI</text>
|
||||
|
||||
<!-- agent path: subnets up to gateway -->
|
||||
<line x1="718" y1="228" x2="718" y2="182" stroke="#F87171" stroke-width="1.1" stroke-dasharray="3,3" opacity="0.6"/>
|
||||
<polygon points="714,186 722,186 718,178" fill="#F87171" opacity="0.8"/>
|
||||
|
||||
<!-- subnet_a -->
|
||||
<g transform="translate(60, 228)">
|
||||
<rect width="320" height="156" rx="8" fill="url(#pub-grad)" stroke="#3fb950" stroke-width="1.2" stroke-opacity="0.55"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12" fill="#3fb950" font-weight="700">subnet_a</text>
|
||||
<text x="300" y="24" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#7ee787" text-anchor="end">az-a</text>
|
||||
<line x1="16" y1="32" x2="304" y2="32" stroke="#3fb950" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<!-- container instance -->
|
||||
<rect x="20" y="42" width="280" height="98" rx="6" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.55" stroke-width="0.8"/>
|
||||
<text x="34" y="60" font-family="'SF Mono', ui-monospace, monospace" font-size="11" fill="#c084fc" font-weight="700">container instance</text>
|
||||
<text x="286" y="60" font-family="'Segoe UI', sans-serif" font-size="9" fill="#d8b4fe" text-anchor="end">AMI: spinifex-ecs-node</text>
|
||||
<text x="34" y="74" font-family="'Segoe UI', sans-serif" font-size="8.5" fill="#a1a1aa">ecsInstanceRole · ECS agent</text>
|
||||
<rect x="34" y="82" width="118" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="93" y="102" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">task (web)</text>
|
||||
<text x="93" y="116" font-family="'Segoe UI', sans-serif" font-size="8" fill="#a1a1aa" text-anchor="middle">awsvpc ENI</text>
|
||||
<rect x="166" y="82" width="118" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="225" y="102" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">task (web)</text>
|
||||
<text x="225" y="116" font-family="'Segoe UI', sans-serif" font-size="8" fill="#a1a1aa" text-anchor="middle">awsvpc ENI</text>
|
||||
</g>
|
||||
|
||||
<!-- subnet_b -->
|
||||
<g transform="translate(520, 228)">
|
||||
<rect width="320" height="156" rx="8" fill="url(#pub-grad)" stroke="#3fb950" stroke-width="1.2" stroke-opacity="0.55"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12" fill="#3fb950" font-weight="700">subnet_b</text>
|
||||
<text x="300" y="24" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#7ee787" text-anchor="end">az-b</text>
|
||||
<line x1="16" y1="32" x2="304" y2="32" stroke="#3fb950" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<rect x="20" y="42" width="280" height="98" rx="6" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.55" stroke-width="0.8"/>
|
||||
<text x="34" y="60" font-family="'SF Mono', ui-monospace, monospace" font-size="11" fill="#c084fc" font-weight="700">container instance</text>
|
||||
<text x="286" y="60" font-family="'Segoe UI', sans-serif" font-size="9" fill="#d8b4fe" text-anchor="end">AMI: spinifex-ecs-node</text>
|
||||
<text x="34" y="74" font-family="'Segoe UI', sans-serif" font-size="8.5" fill="#a1a1aa">ecsInstanceRole · ECS agent</text>
|
||||
<rect x="34" y="82" width="118" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="93" y="102" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">task (web)</text>
|
||||
<text x="93" y="116" font-family="'Segoe UI', sans-serif" font-size="8" fill="#a1a1aa" text-anchor="middle">awsvpc ENI</text>
|
||||
<rect x="166" y="82" width="118" height="50" rx="4" fill="#3fb9501a" stroke="#3fb950" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="225" y="103" font-family="'SF Mono', ui-monospace, monospace" font-size="9.5" fill="#7ee787" text-anchor="middle">image pull</text>
|
||||
<text x="225" y="117" font-family="'Segoe UI', sans-serif" font-size="8" fill="#7ee787" text-anchor="middle">registry / ECR</text>
|
||||
</g>
|
||||
|
||||
<!-- footer note -->
|
||||
<text x="450" y="410" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#71717a" text-anchor="middle">No ECS launch API — you add capacity by booting EC2 instances from the spinifex-ecs-node AMI (the console's "Provision capacity" wraps RunInstances)</text>
|
||||
<text x="450" y="426" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#71717a" text-anchor="middle">The service keeps the desired task count running and registers each task's ENI IP with the ALB target group</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,96 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="470" viewBox="0 0 900 470">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#0a0a0a"/>
|
||||
<stop offset="100%" style="stop-color:#0d1117"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="inet-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#3fb95022"/>
|
||||
<stop offset="100%" style="stop-color:#3fb95008"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="pub-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#3fb9501f"/>
|
||||
<stop offset="100%" style="stop-color:#3fb95008"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="cp-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#DC26261f"/>
|
||||
<stop offset="100%" style="stop-color:#DC262608"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="900" height="470" fill="url(#bg)" rx="12"/>
|
||||
|
||||
<text x="24" y="30" font-family="'Segoe UI', system-ui, sans-serif" font-size="11" fill="#a1a1aa" letter-spacing="2.5" font-weight="600">EKS · MANAGED KUBERNETES ON SPINIFEX</text>
|
||||
<text x="876" y="30" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#71717a" text-anchor="end">control plane VM + NLB · workers from eks-node AMI</text>
|
||||
|
||||
<!-- Internet / kubectl -->
|
||||
<rect x="330" y="52" width="240" height="40" rx="8" fill="url(#inet-grad)" stroke="#3fb950" stroke-width="1.1" stroke-opacity="0.55"/>
|
||||
<text x="450" y="76" font-family="'SF Mono', ui-monospace, monospace" font-size="13" fill="#3fb950" text-anchor="middle" font-weight="700">Internet · kubectl + aws eks</text>
|
||||
|
||||
<!-- connector to control plane -->
|
||||
<line x1="450" y1="92" x2="450" y2="112" stroke="#71717a" stroke-width="1" opacity="0.5"/>
|
||||
<polygon points="446,108 454,108 450,116" fill="#71717a" opacity="0.7"/>
|
||||
|
||||
<!-- Control plane (Spinifex-managed) -->
|
||||
<g transform="translate(290, 116)">
|
||||
<rect width="320" height="76" rx="8" fill="url(#cp-grad)" stroke="#DC2626" stroke-width="1.2" stroke-opacity="0.65"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12.5" fill="#F87171" font-weight="700">EKS Control Plane</text>
|
||||
<text x="300" y="24" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#FCA5A5" text-anchor="end">Spinifex-managed</text>
|
||||
<line x1="16" y1="32" x2="304" y2="32" stroke="#DC2626" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<rect x="20" y="42" width="135" height="22" rx="4" fill="#DC26261a" stroke="#DC2626" stroke-opacity="0.5" stroke-width="0.6"/>
|
||||
<text x="87" y="57" font-family="'SF Mono', ui-monospace, monospace" font-size="10.5" fill="#FCA5A5" text-anchor="middle" font-weight="600">API NLB (public)</text>
|
||||
<rect x="165" y="42" width="135" height="22" rx="4" fill="#DC26261a" stroke="#DC2626" stroke-opacity="0.5" stroke-width="0.6"/>
|
||||
<text x="232" y="57" font-family="'SF Mono', ui-monospace, monospace" font-size="10.5" fill="#FCA5A5" text-anchor="middle" font-weight="600">apiserver VM</text>
|
||||
</g>
|
||||
|
||||
<!-- authn note -->
|
||||
<rect x="624" y="138" width="172" height="32" rx="6" fill="#0a0a0a" stroke="#71717a" stroke-width="0.6" stroke-opacity="0.5"/>
|
||||
<text x="710" y="151" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#a1a1aa" text-anchor="middle">authn: API · access entries</text>
|
||||
<text x="710" y="163" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#a1a1aa" text-anchor="middle">aws eks get-token (IAM → RBAC)</text>
|
||||
|
||||
<!-- fan-out to node-group subnets -->
|
||||
<line x1="450" y1="192" x2="450" y2="210" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<line x1="230" y1="210" x2="670" y2="210" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<line x1="230" y1="210" x2="230" y2="228" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<line x1="670" y1="210" x2="670" y2="228" stroke="#3fb950" stroke-width="1" stroke-dasharray="3,3" opacity="0.55"/>
|
||||
<text x="450" y="206" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#7ee787" text-anchor="middle">managed node group · workers join the control plane</text>
|
||||
|
||||
<!-- subnet_a -->
|
||||
<g transform="translate(108, 228)">
|
||||
<rect width="320" height="150" rx="8" fill="url(#pub-grad)" stroke="#3fb950" stroke-width="1.2" stroke-opacity="0.55"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12" fill="#3fb950" font-weight="700">subnet_a</text>
|
||||
<text x="300" y="24" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#7ee787" text-anchor="end">az-a</text>
|
||||
<line x1="16" y1="32" x2="304" y2="32" stroke="#3fb950" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<!-- worker node -->
|
||||
<rect x="20" y="42" width="280" height="92" rx="6" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.55" stroke-width="0.8"/>
|
||||
<text x="34" y="60" font-family="'SF Mono', ui-monospace, monospace" font-size="11" fill="#c084fc" font-weight="700">worker node</text>
|
||||
<text x="286" y="60" font-family="'Segoe UI', sans-serif" font-size="9" fill="#d8b4fe" text-anchor="end">AMI: eks-node</text>
|
||||
<rect x="34" y="72" width="76" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="72" y="100" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">pod</text>
|
||||
<rect x="122" y="72" width="76" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="160" y="100" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">pod</text>
|
||||
<rect x="210" y="72" width="76" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="248" y="100" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">pod</text>
|
||||
</g>
|
||||
|
||||
<!-- subnet_b -->
|
||||
<g transform="translate(472, 228)">
|
||||
<rect width="320" height="150" rx="8" fill="url(#pub-grad)" stroke="#3fb950" stroke-width="1.2" stroke-opacity="0.55"/>
|
||||
<text x="20" y="24" font-family="'SF Mono', ui-monospace, monospace" font-size="12" fill="#3fb950" font-weight="700">subnet_b</text>
|
||||
<text x="300" y="24" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#7ee787" text-anchor="end">az-b</text>
|
||||
<line x1="16" y1="32" x2="304" y2="32" stroke="#3fb950" stroke-opacity="0.3" stroke-width="0.5"/>
|
||||
<rect x="20" y="42" width="280" height="92" rx="6" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.55" stroke-width="0.8"/>
|
||||
<text x="34" y="60" font-family="'SF Mono', ui-monospace, monospace" font-size="11" fill="#c084fc" font-weight="700">worker node</text>
|
||||
<text x="286" y="60" font-family="'Segoe UI', sans-serif" font-size="9" fill="#d8b4fe" text-anchor="end">AMI: eks-node</text>
|
||||
<rect x="34" y="72" width="76" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="72" y="100" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">pod</text>
|
||||
<rect x="122" y="72" width="76" height="50" rx="4" fill="#a855f71a" stroke="#a855f7" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="160" y="100" font-family="'SF Mono', ui-monospace, monospace" font-size="10" fill="#d8b4fe" text-anchor="middle">pod</text>
|
||||
<rect x="210" y="72" width="76" height="50" rx="4" fill="#3fb9501a" stroke="#3fb950" stroke-opacity="0.45" stroke-width="0.6"/>
|
||||
<text x="248" y="93" font-family="'SF Mono', ui-monospace, monospace" font-size="9.5" fill="#7ee787" text-anchor="middle">ECR</text>
|
||||
<text x="248" y="107" font-family="'Segoe UI', sans-serif" font-size="8" fill="#7ee787" text-anchor="middle">pull</text>
|
||||
</g>
|
||||
|
||||
<!-- footer note -->
|
||||
<text x="450" y="404" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#71717a" text-anchor="middle">You provide the VPC, subnets, and IAM roles · Spinifex provisions the control plane, node-group VMs, and security groups</text>
|
||||
<text x="450" y="420" font-family="'Segoe UI', sans-serif" font-size="9.5" fill="#71717a" text-anchor="middle">Node groups always boot the registered eks-node image · workers need egress (IGW / NAT) to pull images</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,270 @@
|
||||
---
|
||||
title: "ECS (Elastic Container Service)"
|
||||
description: "Run AWS-compatible ECS workloads on Spinifex — create a cluster, register a task definition, boot container instances from the ECS node image, run tasks, and front a long-running service with an Application Load Balancer, all via the AWS CLI, the Spinifex console, or Terraform."
|
||||
category: "Containers"
|
||||
tags:
|
||||
- ecs
|
||||
- containers
|
||||
- tasks
|
||||
- alb
|
||||
- iam
|
||||
sections:
|
||||
- overview
|
||||
- prerequisites
|
||||
- instructions
|
||||
- troubleshooting
|
||||
resources:
|
||||
- title: "ECS Quickstart Workbook"
|
||||
url: "https://github.com/mulgadc/spinifex/tree/main/docs/terraform-workbooks/ecs-quickstart"
|
||||
- title: "Terraform AWS Provider"
|
||||
url: "https://registry.terraform.io/providers/hashicorp/aws/latest"
|
||||
- title: "AWS ECS Task IAM Roles"
|
||||
url: "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html"
|
||||
---
|
||||
|
||||
# ECS (Elastic Container Service)
|
||||
|
||||
> Spinifex's ECS service gives you an AWS-compatible container orchestrator: you register task definitions and run them — one-off as tasks, or kept-running as a service behind a load balancer — on container instances you launch from the Spinifex ECS node image. Standard tools — `aws ecs`, the Terraform AWS provider — work unchanged.
|
||||
|
||||
## Overview
|
||||
|
||||
ECS on Spinifex follows the AWS **EC2 launch type**: you supply the compute. A cluster is a logical grouping; the capacity behind it is **container instances** — ordinary EC2 instances booted from Spinifex's `spinifex-ecs-node` image, each running the Spinifex ECS agent. The agent registers the instance with the cluster, reports its CPU/memory, and runs the containers the scheduler places on it.
|
||||
|
||||
There is **no ECS-specific launch API** — this is AWS-faithful. You add capacity by launching EC2 instances from the ECS node image (with the `ecsInstanceRole` instance profile), exactly as on AWS. The Spinifex console wraps this in a one-click **Provision capacity** action, but underneath it is just `RunInstances`.
|
||||
|
||||
A **task definition** describes one or more containers (image, CPU/memory, ports, environment, and an optional task IAM role). A **task** is a running instantiation of a task definition; the scheduler bin-packs tasks onto instances with free capacity. A **service** keeps a desired number of tasks running, replaces failed ones, and — when configured — registers each task's IP with an Application Load Balancer target group.
|
||||
|
||||
<p align="center">
|
||||
<img src="../../../.github/assets/diagrams/ecs-topology.svg" alt="ECS on Spinifex — an Application Load Balancer fronts awsvpc tasks running on container instances booted from the spinifex-ecs-node AMI; the ECS agent registers with the Spinifex gateway over TLS and SigV4 and serves task-role credentials to containers" width="900">
|
||||
</p>
|
||||
|
||||
**What you'll create:**
|
||||
|
||||
| Resource | Purpose |
|
||||
|---|---|
|
||||
| VPC + subnets | The network the cluster and tasks run in |
|
||||
| Internet Gateway | Egress so instances can pull container images |
|
||||
| `ecsInstanceRole` | Instance profile letting the agent reach the control plane |
|
||||
| ECS cluster | The logical grouping tasks and instances join |
|
||||
| Task definition | The container spec (image, CPU/memory, ports, task role) |
|
||||
| Container instance(s) | EC2 VMs from the ECS node image that run tasks |
|
||||
| Service + ALB target group | Keeps N tasks running and load-balances them |
|
||||
|
||||
**Spinifex specifics**
|
||||
|
||||
- **EC2 launch type only.** There is no Fargate-equivalent serverless capacity; you run and pay for the container instances. `RequiresCompatibilities` of `FARGATE` is not honoured.
|
||||
- **`awsvpc` network mode.** Each task gets its own ENI and private IP in your subnet. Target groups must use `target_type = "ip"`; the service's `network_configuration` selects the subnets and security groups.
|
||||
- **The container-instance image is fixed.** Instances must boot Spinifex's `spinifex-ecs-node` image (resolve it by the `spinifex:managed-by=ecs` tag) and carry the `ecsInstanceRole` instance profile.
|
||||
- **Task IAM roles via the credential endpoint.** A task with a `taskRoleArn` gets `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` injected; the agent serves short-lived credentials for that role at `169.254.170.2`, AWS-faithful — your container's SDK picks them up with no static keys.
|
||||
|
||||
### Limitations
|
||||
|
||||
ECS v1 is deliberately minimal. Keep these in mind:
|
||||
|
||||
- **No service discovery.** `serviceRegistries` / Cloud Map integration is not implemented — reach a service through its load balancer, not a DNS name.
|
||||
- **`awslogs` log driver is discarded.** Container stdout/stderr is not shipped to CloudWatch Logs; the log configuration is accepted but dropped.
|
||||
- **No rolling deployments.** The reconciler keeps the desired count running but ignores `deploymentConfiguration` (`minimumHealthyPercent` / `maximumPercent`); an `UpdateService` to a new revision replaces tasks without a health-gated rollout or circuit-breaker.
|
||||
- **No capacity providers or managed scaling.** Capacity is the static total of your registered instances; there is no scale-out/in or ASG binding — you manage the instance count.
|
||||
- **No distinct execution role.** ECR pulls use the instance role directly; `executionRoleArn` is not honoured separately.
|
||||
- **`secrets[]` are silently dropped**, and tags set via `TagResource` are not persisted. Health-check settings beyond the target group default are not forwarded.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Prerequisite — `spinifex-ecs-node` image required.**
|
||||
>
|
||||
> Container instances **must** boot Spinifex's **`spinifex-ecs-node`** image — it carries the ECS agent. Import it before provisioning capacity (during `spx admin init` or via the image catalogue); the console's provision-capacity action and the Terraform workbook both resolve it by tag.
|
||||
>
|
||||
> **Verify before continuing:**
|
||||
>
|
||||
> ```bash
|
||||
> aws ec2 describe-images \
|
||||
> --filters 'Name=tag:spinifex:managed-by,Values=ecs' \
|
||||
> --query 'Images[].[ImageId,Name]' --output text
|
||||
> ```
|
||||
>
|
||||
> No rows means the image is not imported — register it before continuing.
|
||||
|
||||
The Terraform workbook builds all of this for you. For the CLI or console paths, have it in place first.
|
||||
|
||||
- **Spinifex running**, with the AWS CLI configured for the `spinifex` profile (see [Installing Spinifex](/docs/install)).
|
||||
- **The `spinifex-ecs-node` image** imported. Confirm it resolves:
|
||||
|
||||
```bash
|
||||
aws ec2 describe-images \
|
||||
--filters 'Name=tag:spinifex:managed-by,Values=ecs' \
|
||||
--query 'Images[].[ImageId,Name]' --output text
|
||||
```
|
||||
|
||||
- **A VPC with at least one subnet** and an **Internet Gateway** with a default route (`0.0.0.0/0 → IGW`), so instances can pull container images.
|
||||
- **The `ecsInstanceRole` instance profile.** It is account-global: a role trusted by `ec2.amazonaws.com` with an `ecs:*` policy, exposed through an instance profile of the same name. The console's provision-capacity action creates it on first use; the Terraform workbook creates it unless you opt out.
|
||||
- **An optional task IAM role** trusted by `ecs-tasks.amazonaws.com`, if your containers call AWS APIs.
|
||||
|
||||
## Instructions
|
||||
|
||||
The same workload can be created three ways. Pick your tool — each path reaches the same running service.
|
||||
|
||||
:::tabs
|
||||
@tab AWS CLI
|
||||
|
||||
### 1. Create the cluster
|
||||
|
||||
```bash
|
||||
export AWS_PROFILE=spinifex
|
||||
|
||||
aws ecs create-cluster --cluster-name demo
|
||||
```
|
||||
|
||||
### 2. Register a task definition
|
||||
|
||||
`awsvpc` network mode, EC2 launch type, one nginx container on port 80:
|
||||
|
||||
```bash
|
||||
aws ecs register-task-definition \
|
||||
--family web \
|
||||
--network-mode awsvpc \
|
||||
--requires-compatibilities EC2 \
|
||||
--cpu 256 --memory 512 \
|
||||
--container-definitions '[{
|
||||
"name":"web",
|
||||
"image":"docker.io/library/nginx:1.27-alpine",
|
||||
"portMappings":[{"containerPort":80,"protocol":"tcp"}],
|
||||
"essential":true
|
||||
}]'
|
||||
```
|
||||
|
||||
### 3. Add capacity
|
||||
|
||||
Launch one or more EC2 instances from the ECS node image with the `ecsInstanceRole`
|
||||
instance profile and a cloud-init that points the agent at the cluster. The
|
||||
[ECS Quickstart workbook](https://github.com/mulgadc/spinifex/tree/main/docs/terraform-workbooks/ecs-quickstart)
|
||||
produces this user-data for you; the console **Provision capacity** action is the
|
||||
one-click equivalent. Once an instance boots and its agent registers, it appears here:
|
||||
|
||||
```bash
|
||||
aws ecs list-container-instances --cluster demo
|
||||
```
|
||||
|
||||
### 4. Run a task or create a service
|
||||
|
||||
Run a one-off task:
|
||||
|
||||
```bash
|
||||
aws ecs run-task \
|
||||
--cluster demo --task-definition web --count 1 \
|
||||
--network-configuration 'awsvpcConfiguration={subnets=[subnet-aaaa]}'
|
||||
```
|
||||
|
||||
Or keep it running behind an ALB target group (`target_type = ip`):
|
||||
|
||||
```bash
|
||||
aws ecs create-service \
|
||||
--cluster demo --service-name web --task-definition web \
|
||||
--desired-count 2 \
|
||||
--network-configuration 'awsvpcConfiguration={subnets=[subnet-aaaa]}' \
|
||||
--load-balancers 'targetGroupArn=<tg-arn>,containerName=web,containerPort=80'
|
||||
|
||||
aws ecs describe-services --cluster demo --services web \
|
||||
--query 'services[0].[runningCount,desiredCount]'
|
||||
```
|
||||
|
||||
@tab Spinifex UI
|
||||
|
||||
The Spinifex console drives the same workflow. From the left navigation open **ECS → Clusters**.
|
||||
|
||||
### 1. Create the cluster
|
||||
|
||||
Click **Create Cluster**, give it a name, and submit. It appears in the **Clusters** list.
|
||||
|
||||
### 2. Provision capacity
|
||||
|
||||
Open the cluster and use **Provision capacity** on the **Infrastructure** (container instances) tab. The console launches instances from the `spinifex-ecs-node` image, attaches the `ecsInstanceRole` instance profile (creating it if needed), and injects the gateway URL and CA into the instance's cloud-init — so the agent registers without any manual key handling. The instances appear under **Infrastructure** as they register.
|
||||
|
||||
### 3. Register a task definition and run it
|
||||
|
||||
- The **Task definitions** view lists families and revisions; register a new revision with the container image, CPU/memory, and ports.
|
||||
- From a task definition, **Run task** for a one-off, or create a **Service** to keep a desired count running.
|
||||
- A cluster's **Services** and **Tasks** tabs show what is running; open a task or service for its detail page (containers, networking, and public/private endpoints).
|
||||
|
||||
### 4. Attach a load balancer
|
||||
|
||||
When creating a service, select an ALB target group (`target_type = ip`) so each task's ENI is registered and traffic is balanced across tasks.
|
||||
|
||||
@tab Terraform
|
||||
|
||||
The [ECS Quickstart workbook](https://github.com/mulgadc/spinifex/tree/main/docs/terraform-workbooks/ecs-quickstart) builds the whole stack in one `apply`: VPC, IAM, cluster, task definition, container instances, and an ALB-fronted service. It is the Terraform-native equivalent of the console's provision-capacity action.
|
||||
|
||||
```bash
|
||||
git clone --depth 1 --filter=blob:none --sparse https://github.com/mulgadc/spinifex.git spinifex-tf
|
||||
cd spinifex-tf
|
||||
git sparse-checkout set docs/terraform-workbooks
|
||||
cd docs/terraform-workbooks/ecs-quickstart
|
||||
```
|
||||
|
||||
The core resources point the AWS provider at Spinifex's `ecs`, `ec2`, `iam`, `sts`, and `elasticloadbalancingv2` endpoints, then create the cluster, an `awsvpc` task definition with a task role, and a service wired to a target group:
|
||||
|
||||
```hcl
|
||||
resource "aws_ecs_cluster" "main" {
|
||||
name = "ecs-quickstart"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "web" {
|
||||
family = "ecs-quickstart-web"
|
||||
network_mode = "awsvpc"
|
||||
requires_compatibilities = ["EC2"]
|
||||
cpu = "256"
|
||||
memory = "512"
|
||||
task_role_arn = aws_iam_role.task.arn
|
||||
|
||||
container_definitions = jsonencode([{
|
||||
name = "web"
|
||||
image = "docker.io/library/nginx:1.27-alpine"
|
||||
essential = true
|
||||
portMappings = [{ containerPort = 80, protocol = "tcp" }]
|
||||
}])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "web" {
|
||||
name = "ecs-quickstart-web"
|
||||
cluster = aws_ecs_cluster.main.id
|
||||
task_definition = aws_ecs_task_definition.web.arn
|
||||
desired_count = 1
|
||||
|
||||
network_configuration {
|
||||
subnets = [aws_subnet.a.id, aws_subnet.b.id]
|
||||
security_groups = [aws_security_group.node.id]
|
||||
}
|
||||
|
||||
load_balancer {
|
||||
target_group_arn = aws_lb_target_group.web.arn
|
||||
container_name = "web"
|
||||
container_port = 80
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Because a container instance reaches the control plane over the gateway (TLS + SigV4) rather than a managed AWS endpoint, the workbook makes the two things the console injects explicit: a **LAN-reachable** `gateway_url` (the host's bridge IP, not `127.0.0.1`) and the gateway CA, both baked into the instance's cloud-init. Apply it:
|
||||
|
||||
```bash
|
||||
export AWS_PROFILE=spinifex
|
||||
tofu init
|
||||
tofu apply -var 'gateway_url=https://<host-lan-ip>:9999'
|
||||
```
|
||||
|
||||
`ecsInstanceRole` is account-global — if it already exists (from the console), pass `-var 'create_instance_role=false'`. See the workbook README for the full variable list and teardown.
|
||||
|
||||
:::
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**No container instances appear after launching them.** The agent registers over the gateway, not a managed endpoint, so check its cloud-init injected a correct **LAN-reachable** gateway URL (not `127.0.0.1` — a guest VM cannot reach the host loopback) and the gateway CA. `cloud-init write_files` runs once per instance, so fixing the user-data needs an instance **replacement**, not an in-place modify. Confirm the instance carries the `ecsInstanceRole` instance profile.
|
||||
|
||||
**Tasks stay `PENDING`.** No instance has free capacity for the task's CPU/memory reservation. Add capacity, or lower the task definition's reservations. `aws ecs list-container-instances` should show at least one `ACTIVE` instance.
|
||||
|
||||
**Service `runningCount` below `desiredCount`.** Either there is not enough capacity (see above), or tasks are failing to start — check the task's containers can pull their image (instances need an egress route) and that the image reference is valid.
|
||||
|
||||
**Load balancer target unhealthy / app unreachable.** The target group must be `target_type = ip` (tasks register their ENI IP, not an instance ID). The ALB DNS name ends in `.elb.spinifex.local` and does not resolve from outside; fetch its public IP with `aws elbv2 describe-load-balancers` and curl that. Note health-check settings beyond the target group default are not forwarded.
|
||||
|
||||
**Container cannot assume its task role.** Confirm the task definition sets `taskRoleArn` and the role is trusted by `ecs-tasks.amazonaws.com`. The agent injects `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`; a container that overrides this variable, or an SDK too old to honour it, will not pick up the credentials.
|
||||
|
||||
**Expected a feature that is missing.** ECS v1 omits service discovery, `awslogs` shipping, rolling deployments, capacity providers, and a distinct execution role. See the Limitations in the Overview.
|
||||
@@ -36,6 +36,10 @@ An EKS cluster on Spinifex has two parts: a **control plane** (the managed Kuber
|
||||
|
||||
Authentication uses **EKS access entries** (the API authentication mode) — IAM principals are mapped to Kubernetes RBAC groups, and `kubectl` authenticates with `aws eks get-token` exactly as it does on AWS.
|
||||
|
||||
<p align="center">
|
||||
<img src="../../../.github/assets/diagrams/eks-topology.svg" alt="EKS on Spinifex — a managed control plane (public API NLB plus apiserver VM) fronts a managed node group of eks-node worker VMs running pods across two subnets, pulling images from ECR" width="900">
|
||||
</p>
|
||||
|
||||
**What you'll create:**
|
||||
|
||||
| Resource | Purpose |
|
||||
@@ -57,6 +61,21 @@ Authentication uses **EKS access entries** (the API authentication mode) — IAM
|
||||
|
||||
## Prerequisites
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Prerequisite — `eks-node` image required.**
|
||||
>
|
||||
> Node groups always boot Spinifex's **`eks-node`** image, and it **must** be registered before you create a cluster — the console blocks cluster creation until it is present. Import it during `spx admin init` (or via the image catalogue) ahead of time.
|
||||
>
|
||||
> **Verify before continuing:**
|
||||
>
|
||||
> ```bash
|
||||
> aws ec2 describe-images \
|
||||
> --filters 'Name=tag:spinifex:managed-by,Values=eks' \
|
||||
> --query 'Images[].[ImageId,Name]' --output text
|
||||
> ```
|
||||
>
|
||||
> No rows means the image is not imported — register it before continuing.
|
||||
|
||||
Before creating a cluster you need the supporting infrastructure in place. The Terraform workbooks build all of this for you; if you are using the CLI or console, create it first.
|
||||
|
||||
- **Spinifex running**, with the AWS CLI configured for the `spinifex` profile (see [Installing Spinifex](/docs/install)) and `kubectl` installed.
|
||||
|
||||
@@ -1,48 +1,76 @@
|
||||
# ECS Quickstart
|
||||
---
|
||||
title: "ECS Quickstart"
|
||||
description: "Stand up a complete AWS-compatible ECS stack on Spinifex with Terraform — a VPC, IAM roles, a cluster, a task definition with a task role, container instances launched from the ECS node image, and an awsvpc service fronted by an Application Load Balancer."
|
||||
category: "Terraform Workbooks"
|
||||
tags:
|
||||
- terraform
|
||||
- ecs
|
||||
- containers
|
||||
- alb
|
||||
- iam
|
||||
- vpc
|
||||
- workbook
|
||||
sections:
|
||||
- overview
|
||||
- prerequisites
|
||||
- instructions
|
||||
- troubleshooting
|
||||
resources:
|
||||
- title: "ECS Service Documentation"
|
||||
url: "/docs/ecs"
|
||||
- title: "Terraform AWS Provider"
|
||||
url: "https://registry.terraform.io/providers/hashicorp/aws/latest"
|
||||
- title: "Spinifex Repository"
|
||||
url: "https://github.com/mulgadc/spinifex"
|
||||
- title: "OpenTofu"
|
||||
url: "https://opentofu.org/"
|
||||
---
|
||||
|
||||
An end-to-end ECS stack on Spinifex, provisioned with OpenTofu: a cluster, a
|
||||
task definition with a task role, container instances launched from the
|
||||
`spinifex-ecs-node` AMI, and an awsvpc service fronted by an Application Load
|
||||
Balancer target group.
|
||||
# Terraform: ECS Quickstart
|
||||
|
||||
This is the Terraform-native equivalent of the console's "provision capacity"
|
||||
action. Because a Spinifex container instance reaches the control plane over the
|
||||
gateway (TLS + SigV4) rather than a managed AWS endpoint, the workbook makes the
|
||||
two things the console injects for you explicit: a LAN-reachable gateway URL and
|
||||
the gateway CA, both baked into the instance's cloud-init user-data. The agent
|
||||
draws its credentials from IMDS via the `ecsInstanceRole` instance profile, so
|
||||
no static keys are written.
|
||||
> The smallest end-to-end ECS example on Spinifex: a VPC, the IAM roles ECS needs, a cluster, a task definition, container instances booted from the ECS node image, and an `awsvpc` service load-balanced behind an Application Load Balancer.
|
||||
|
||||
## Overview
|
||||
|
||||
This workbook is the Terraform-native equivalent of the console's **Provision capacity** action. It provisions a full ECS stack in one `apply`: a VPC with two public subnets, the `ecsInstanceRole` instance profile, a task IAM role, an ECS cluster, an `awsvpc` task definition running nginx, one or more container instances launched from the `spinifex-ecs-node` AMI, and an Application Load Balancer with a target group the service registers into.
|
||||
|
||||
Because a Spinifex container instance reaches the control plane over the **gateway** (TLS + SigV4) rather than a managed AWS endpoint, the workbook makes the two things the console injects for you explicit: a **LAN-reachable** gateway URL and the gateway CA, both baked into the instance's cloud-init user-data. The agent draws its credentials from IMDS via the `ecsInstanceRole` instance profile, so no static keys are written.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The `spinifex-ecs-node` AMI is imported (resolved here by the
|
||||
`tag:spinifex:managed-by=ecs` filter):
|
||||
- **Spinifex running**, with the AWS CLI configured for the `spinifex` profile (see [Installing Spinifex](/docs/install)) and OpenTofu (or Terraform) installed.
|
||||
- **The `spinifex-ecs-node` AMI imported** — resolved here by the `tag:spinifex:managed-by=ecs` filter:
|
||||
|
||||
```
|
||||
```bash
|
||||
aws ec2 describe-images \
|
||||
--filters 'Name=tag:spinifex:managed-by,Values=ecs' \
|
||||
--query 'Images[].[ImageId,Name]' --output text
|
||||
```
|
||||
|
||||
- A **LAN-reachable** gateway URL — the host's WAN/bridge IP, not `127.0.0.1`
|
||||
(a guest VM cannot reach the host loopback). For example
|
||||
`https://192.168.1.33:9999`.
|
||||
- **A LAN-reachable gateway URL** — the host's WAN/bridge IP, not `127.0.0.1` (a guest VM cannot reach the host loopback). For example `https://192.168.1.33:9999`.
|
||||
- **The gateway CA PEM** readable at `gateway_ca_cert_path` (default `/etc/spinifex/ca.pem`).
|
||||
|
||||
- The gateway CA PEM is readable at `gateway_ca_cert_path` (default
|
||||
`/etc/spinifex/ca.pem`).
|
||||
## Instructions
|
||||
|
||||
## Usage
|
||||
### 1. Fetch the workbook
|
||||
|
||||
```bash
|
||||
git clone --depth 1 --filter=blob:none --sparse https://github.com/mulgadc/spinifex.git spinifex-tf
|
||||
cd spinifex-tf
|
||||
git sparse-checkout set docs/terraform-workbooks
|
||||
cd docs/terraform-workbooks/ecs-quickstart
|
||||
```
|
||||
|
||||
### 2. Apply
|
||||
|
||||
```bash
|
||||
cd spinifex/docs/terraform-workbooks/ecs-quickstart
|
||||
export AWS_PROFILE=spinifex
|
||||
|
||||
tofu init
|
||||
tofu apply -var 'gateway_url=https://<host-lan-ip>:9999'
|
||||
```
|
||||
|
||||
`ecsInstanceRole` is account-global. If you have already used the console's
|
||||
provision-capacity action it exists already, so skip re-creating it:
|
||||
`ecsInstanceRole` is account-global. If you have already used the console's provision-capacity action it exists already, so skip re-creating it:
|
||||
|
||||
```bash
|
||||
tofu apply \
|
||||
@@ -50,7 +78,7 @@ tofu apply \
|
||||
-var 'create_instance_role=false'
|
||||
```
|
||||
|
||||
## Verify
|
||||
### 3. Verify
|
||||
|
||||
Container instances take ~30-60s to boot and register:
|
||||
|
||||
@@ -60,8 +88,7 @@ aws ecs describe-services --cluster ecs-quickstart --services ecs-quickstart-web
|
||||
--query 'services[0].[runningCount,desiredCount]'
|
||||
```
|
||||
|
||||
The ALB DNS name ends in `.elb.spinifex.local` and does not resolve from your
|
||||
host. Fetch its public IP and curl it:
|
||||
The ALB DNS name ends in `.elb.spinifex.local` and does not resolve from your host. Fetch its public IP and curl it:
|
||||
|
||||
```bash
|
||||
aws elbv2 describe-load-balancers --names ecs-quickstart-alb \
|
||||
@@ -70,7 +97,7 @@ aws elbv2 describe-load-balancers --names ecs-quickstart-alb \
|
||||
curl http://<alb_public_ip>
|
||||
```
|
||||
|
||||
## Variables
|
||||
### 4. Variables
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|---|---|---|
|
||||
@@ -84,12 +111,22 @@ curl http://<alb_public_ip>
|
||||
| `gateway_ca_cert_path` | `/etc/spinifex/ca.pem` | Host-readable gateway CA PEM. |
|
||||
| `create_instance_role` | `true` | Create `ecsInstanceRole`; set `false` if it already exists. |
|
||||
|
||||
## Teardown
|
||||
### 5. Teardown
|
||||
|
||||
```bash
|
||||
tofu destroy -var 'gateway_url=https://<host-lan-ip>:9999'
|
||||
```
|
||||
|
||||
`DeleteCluster` cascades through the service, its tasks, and the container
|
||||
instance registrations, so the destroy round-trips cleanly.
|
||||
```
|
||||
`DeleteCluster` cascades through the service, its tasks, and the container instance registrations, so the destroy round-trips cleanly.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Container instances never register.** The agent registers over the gateway, not a managed endpoint. Confirm `gateway_url` is the host's **LAN-reachable** IP (not `127.0.0.1`) and that `gateway_ca_cert_path` points at the real gateway CA. Because `cloud-init write_files` runs once per instance, a corrected user-data needs an instance **replacement** — `tofu apply -replace='aws_instance.node[0]'` — not an in-place modify.
|
||||
|
||||
**`apply` fails resolving the AMI.** The `spinifex-ecs-node` image is not imported, or its `spinifex:managed-by=ecs` tag is missing. Re-run the `describe-images` check in Prerequisites.
|
||||
|
||||
**`MissingParameter` on the instance.** The gateway's `RunInstances` requires a `KeyName`; the workbook generates a key pair for you, so this only appears if you have stripped that out.
|
||||
|
||||
**Service `runningCount` stays below `desiredCount`.** No instance has free capacity, or tasks cannot pull the image. Confirm at least one `ACTIVE` container instance and that the subnets have an Internet Gateway route.
|
||||
|
||||
**`create_instance_role` conflict.** If `ecsInstanceRole` already exists (from the console), pass `-var 'create_instance_role=false'` so Terraform does not try to recreate it.
|
||||
|
||||
Reference in New Issue
Block a user