Tools Used in DevOps · Spinnaker

Spinnaker

Spinnaker is a continuous-delivery platform built at Netflix to solve a problem most CI tools were never designed for: shipping the same release safely across dozens of AWS accounts, several cloud providers, and however many regions sit in between — from one pipeline definition, not one pipeline per target. Netflix open sourced it in November 2015 in partnership with Google, and it grew from there into the default answer for organizations whose deployment surface is genuinely large: not "one app, one cluster," but "one release, forty accounts, three clouds." Two features carry that pitch: a pipeline model built from composable stages instead of shell scripts, and Kayenta, Spinnaker's automated canary analysis engine, which replaces "it looked fine to me" with an actual statistical judgment on whether a canary is safe to promote.

☺ Explain it like I'm 10

Imagine you're not delivering one package to one house — you're delivering the same package to forty houses, in different cities, on different trucks, at the same time. Before any truck leaves the depot, a robot inspector sends out one trial truck first, compares it against a truck that changed nothing, and only waves the other thirty-nine through if the trial truck's numbers actually check out. That's Spinnaker: one shipping label, many destinations at once, and a robot inspector — Kayenta — who won't let the fleet leave on a hunch.

🐢Your host for this topic: Timmy the Turtle — the same guardrail behind deployment strategies, except here the verification isn't a metaphor. Kayenta runs real statistics before Timmy lets a release past even one of the accounts it's headed for, let alone all of them at once.

What Spinnaker is and the problem it solves

☺ Like you're 10: Most pipeline tools know how to build code. Spinnaker specializes in the part after that — pushing a finished build out to a lot of places at once, safely.

Spinnaker's origin explains its shape. It evolved out of Asgard, an internal Netflix tool for managing AWS Auto Scaling Groups, at a company that was already running production traffic across a large number of separate AWS accounts for isolation and blast-radius reasons. A tool that only knew how to deploy to "the account" was never going to work there, so Spinnaker was built from the start around an explicit account abstraction — a named set of cloud credentials plus a provider registration — and around pipelines that can target many accounts from a single stage. Netflix and Google jointly open sourced it in 2015; Microsoft, Pivotal, Target, and others joined as contributors soon after, and the project later became a founding member of the Continuous Delivery Foundation (CDF), a Linux Foundation initiative alongside Jenkins and Tekton.

Where a tool like Jenkins or GitHub Actions answers "how do I build and test this change," Spinnaker answers a narrower, later question: "how do I get an already-built artifact safely into every place it needs to run, with a real gate in front of each one." It doesn't compile code, and it isn't a general-purpose CI runner — it consumes an artifact (a container image, a machine image, a Kubernetes manifest) that your CI/CD pipeline already produced, and owns everything from "bake or find that artifact" through "deploy it, verify it, and either promote it everywhere else or roll it back." See deployment strategies for the general vocabulary this page assumes.

Architecture: the microservices behind one pipeline run

☺ Like you're 10: Spinnaker isn't one program — it's about ten small programs, each with one job, that hand a pipeline off to each other in sequence.

Spinnaker ships as roughly ten cooperating microservices rather than one binary, and knowing what each one does is most of what makes the system legible instead of mysterious. Deck is the browser UI. Gate is the API gateway everything else sits behind, and the layer that checks authorization via Fiat. Orca is the orchestration engine — it owns the pipeline's stage graph and actually executes it, stage by stage, tracking which ones are running, waiting, or blocked. Clouddriver is the cloud-provider abstraction layer: it holds every registered account's credentials, caches the live state of every cluster it can see, and is the only service that actually talks to AWS, GCP, Azure, or a Kubernetes API server. Front50 persists pipeline and application configuration, typically to S3, GCS, or Azure Blob Storage. Igor listens for build events from CI tools like Jenkins and translates them into pipeline triggers. Echo handles eventing more broadly — webhooks, cron triggers, pub/sub triggers, and outbound notifications to Slack or email. Rosco is the image bakery, driving Packer under the hood to produce machine images — the direct ancestor of what this course covers as immutable infrastructure & golden images. And Kayenta is the automated canary analysis engine, covered on its own below.

Deck browser UI Igor CI build triggers Gate API gateway · Fiat authz Echo webhooks · cron · notify Orca orchestration engine runs the stage graph Front50 pipeline & app config Kayenta automated canary analysis Clouddriver cloud provider abstraction AWS · prod-use1 account A, us-east-1 AWS · prod-euw1 account B, eu-west-1 GKE · prod-cluster a different cloud entirely score deploy stage One deploy stage, one Orca execution — three accounts and two cloud providers, all in parallel.

Fiat (authorization), and the storage backends Front50 and Clouddriver's caches depend on, are left off the diagram for space, but the shape holds: a trigger comes in through Gate, Orca drives the stage graph and consults Kayenta when a stage calls for it, and Clouddriver is the only service that ever reaches out to a real cloud account. Everything upstream of Clouddriver is cloud-agnostic; everything the fan-out at the right represents is Clouddriver's actual job.

Applications, pipelines, and stages — the model you build against

☺ Like you're 10: Everything you own lives under an Application; every Application has Pipelines; every Pipeline is a chain of Stages, and a Stage is one real action — bake, deploy, wait for a human, check a canary.

Spinnaker organizes everything a team owns under an Application — a name, a set of permissions, and the pipelines and running infrastructure that belong to it. Within an application, resources follow a resource model borrowed from AWS's Auto Scaling vocabulary and reused across every provider: a Cluster (the logical, ongoing "checkout service in prod") contains one or more Server Groups (a specific deployed version — an ASG on AWS, a ReplicaSet-backed Deployment on the Kubernetes provider), which contain Instances. That's the terminology every screen in Deck and every deploy stage in a pipeline is built around, regardless of which cloud a given cluster actually runs on.

A Pipeline is a directed graph of Stages, each with a type, a set of parameters, and requisiteStageRefIds declaring which stages must finish first — stages without a dependency on each other run in parallel automatically. The common stage types are bake (Rosco builds a machine image via Packer), findImageFromTags (locate an already-built container or machine image by tag), deploy (stand up one or more clusters, across one or more accounts), manualJudgment (pause and wait for a human to click continue, with optional Slack/email notification), kayentaCanary (run automated canary analysis and gate on the score), webhook (call an arbitrary external HTTP endpoint and optionally wait on its result), and script or runJob (execute an arbitrary job, often a Kubernetes Job, for something Spinnaker has no native stage for). Triggers that start a pipeline include a Git push, a CI build finishing (via Igor), a new image landing in a registry, a cron schedule, a pub/sub message, or another pipeline completing.

{
  "name": "Deploy to prod",
  "application": "checkout",
  "stages": [
    {
      "refId": "1",
      "name": "Find image",
      "type": "findImageFromTags",
      "cloudProviderType": "kubernetes",
      "packageName": "checkout"
    },
    {
      "refId": "2",
      "name": "Canary analysis",
      "type": "kayentaCanary",
      "requisiteStageRefIds": ["1"],
      "canaryConfig": {
        "canaryConfigId": "checkout-latency-errors",
        "scoreThresholds": { "marginal": 75, "pass": 95 },
        "lifetimeDuration": "PT30M",
        "metricsAccountName": "prometheus-prod"
      }
    },
    {
      "refId": "3",
      "name": "Manual judgment",
      "type": "manualJudgment",
      "requisiteStageRefIds": ["2"],
      "notifications": [{ "type": "slack", "when": ["manualJudgment"] }]
    },
    {
      "refId": "4",
      "name": "Deploy — 3 accounts, parallel",
      "type": "deploy",
      "requisiteStageRefIds": ["3"],
      "clusters": [
        { "account": "prod-use1", "provider": "aws",        "strategy": "redblack" },
        { "account": "prod-euw1", "provider": "aws",        "strategy": "redblack" },
        { "account": "prod-gke",  "provider": "kubernetes", "strategy": "rollingredblack" }
      ]
    }
  ]
}

Read that stage graph left to right: find the artifact, score a canary against it, stop for a human to look at the score, then — only after both gates pass — deploy to three accounts across two cloud providers in one stage, in parallel. That last stage is the entire pitch of this page in eleven lines of JSON.

◆ Key idea

Almost everything about how a target is addressed reduces to the same four nouns: Application (who owns it), Cluster (the ongoing logical thing), Server Group (one deployed version of it), Instance (one running unit inside that version). Learn to read a deploy stage's clusters array as "one entry per account/region/provider I'm targeting, each producing its own server group," and pipeline JSON stops looking arbitrary.

Deployment strategies: Highlander, Red/Black, Rolling Red/Black, and native Canary

☺ Like you're 10: Four different answers to "how do I swap the old version for the new one," trading speed of rollback against how gently traffic gets moved.

A deploy stage's strategy field picks how a new server group replaces the old one within a cluster, and this is the concrete implementation of the general vocabulary in deployment strategies. Highlander is the bluntest: deploy the new server group, wait for it to become healthy, then immediately destroy every other server group in the cluster — "there can be only one." Red/Black (Spinnaker's name for blue/green) deploys the new server group alongside the old one, cuts traffic over, and disables — but doesn't destroy — the previous server group, so a rollback is "re-enable the old one and cut traffic back," not a redeploy. Rolling Red/Black shifts traffic between old and new in configurable percentage increments with a pause between each step, trading Red/Black's instant cutover for a gentler, slower one. And a native Canary strategy deploys a canary server group sized at a small fraction of the cluster's capacity, alongside a baseline — this is the strategy that pairs with the kayentaCanary stage below, and it's worth not confusing the deployment strategy (how traffic gets shifted) with the canary analysis stage (how the decision to promote gets made) — you can run a Red/Black deploy strategy and still gate its promotion on a separate kayentaCanary stage, which is exactly what the pipeline JSON above does.

Automated canary analysis with Kayenta

☺ Like you're 10: Kayenta doesn't ask a human "does this look okay" — it runs real statistics comparing the new version against an untouched twin, and only a passing score gets to move on.

A kayentaCanary stage deploys two server groups side by side: a baseline, running the current production build, and a canary, running the candidate, both sized and configured identically and receiving a comparable slice of real traffic. Over an analysis window — PT30M in the pipeline above, ISO-8601 duration syntax for thirty minutes — Kayenta pulls the same set of metrics from both, from whatever monitoring backend the platform has wired in: Prometheus, Datadog, Google Cloud Monitoring, SignalFx, and others are all supported query sources, and this is where monitoring & observability and Spinnaker actually meet. A canary config, referenced by canaryConfigId, names the specific metrics, their direction of badness, and how heavily each one counts:

{
  "name": "checkout-latency-errors",
  "configVersion": "1",
  "metrics": [
    {
      "name": "error-rate",
      "query": { "type": "prometheus", "metricName": "http_requests_total{status=~\"5..\"}" },
      "analysisConfigurations": { "canary": { "direction": "increase" } },
      "groups": ["critical"]
    },
    {
      "name": "p99-latency",
      "query": { "type": "prometheus", "metricName": "http_request_duration_seconds{quantile=\"0.99\"}" },
      "analysisConfigurations": { "canary": { "direction": "increase" } },
      "groups": ["critical"]
    }
  ],
  "judge": { "name": "NetflixACAJudge-v1.0" },
  "classifier": { "groupWeights": { "critical": 100 } }
}

Each metric's two time series — baseline and canary — go through a statistical judge (the default, NetflixACAJudge, uses a Mann-Whitney U test to compare the two distributions rather than a naive average) and come back with a per-metric score. Group scores roll up into an overall score against the scoreThresholds set on the stage — below marginal fails outright, at or above pass succeeds, and the band between is a judgment call the pipeline can route to a human via a following manualJudgment stage. Metrics marked "groups": ["critical"] can be configured so that a single failing critical metric fails the whole canary regardless of what the aggregate score says — the mechanism that stops one metric with a lot of noisy good days from washing out one metric that's genuinely on fire.

⚠ A canary is only as honest as its twin

Kayenta's statistics are only meaningful if baseline and canary are genuinely comparable: same instance type, same warm-up time, same rough traffic mix, running for the same window. Compare an under-warmed canary against a baseline that's been running for hours, or judge a fifteen-minute canary during a traffic lull, and the judge will still hand back a confident-looking score — it just won't mean what you think it means. Automated canary analysis removes the "did it look okay to me" guess; it does not remove the need to design the comparison correctly in the first place.

The real differentiator: multi-cloud, multi-account fan-out

☺ Like you're 10: Most deploy tools are built assuming there's one cloud account waiting on the other end. Spinnaker is built assuming there might be forty, and treats that as the normal case, not the exception.

This is the specific reason organizations reach for Spinnaker over a single-cloud-native alternative, and it's worth being precise about the mechanism rather than the marketing. An account in Spinnaker is a named registration inside Clouddriver: a set of credentials (an IAM role to assume, a service account key, a kubeconfig context) plus which provider it belongs to. Registering an account is a one-time, per-target operation — after that, any pipeline in any application on that Spinnaker instance can address it by name in a deploy stage's clusters array, exactly as the pipeline JSON above targets prod-use1, prod-euw1, and prod-gke in one stage. Because those cluster entries execute in parallel within Orca's single stage execution, one pipeline run genuinely deploys to three accounts across two cloud providers concurrently — not three separate pipeline runs a human or a script has to trigger and track separately.

Contrast that with a single-cloud-native tool. AWS CodePipeline and CodeDeploy are excellent inside one AWS account, or a small number reached via CodePipeline's cross-account actions — see AWS Developer Tools — but fanning the same release out to twenty AWS accounts means either duplicating pipeline definitions per account or building your own StackSets-style orchestration on top; the platform has no first-class concept of "the same deploy, many accounts." A GitOps reconciler like Argo CD is genuinely multi-cluster, but its multiplicity is Kubernetes clusters specifically — it has no native concept of an AWS Auto Scaling Group, a Cloud Foundry org, or Netflix's own Titus container runtime, all of which Spinnaker treats as equally first-class providers alongside Kubernetes. Spinnaker's account abstraction is the thing that makes "one release, many non-uniform targets" a native pipeline concept instead of a scripting problem layered on top of a single-target tool.

⚠ The hard part is the trust relationship, not the pipeline JSON

Registering an account is one hal or config-file entry, but making it actually work means Clouddriver has a real, working IAM trust relationship into that account — an assume-role policy on the target side that names Spinnaker's own execution role, correctly scoped. Get that trust policy wrong and the failure is quiet: the account simply doesn't show up as deployable, or a deploy to it silently no-ops, rather than throwing an error a pipeline author would notice. Budget real time for account onboarding, and verify a new account with a harmless dry-run deploy before anyone routes production traffic through it.

Day-to-day: installing, configuring, and triggering pipelines

☺ Like you're 10: One tool configures Spinnaker itself, a second tool talks to a running Spinnaker to manage pipelines, and a plain HTTP call can kick one off from anywhere.

Halyard (the hal CLI) was the original tool for configuring and deploying Spinnaker's own microservices — registering cloud accounts, choosing a persistence backend, and rendering the whole stack. It still shows up in a lot of existing documentation and installs:

# Halyard — configures Spinnaker itself, not your applications
$ hal config provider aws account add prod-use1 --account-id 111111111111 --assume-role role/spinnakerManaged
$ hal config provider aws account add prod-euw1 --account-id 222222222222 --assume-role role/spinnakerManaged
$ hal config provider kubernetes account add prod-gke --context gke_acme_prod-gke_us-central1_prod
$ hal config storage s3 edit --bucket spinnaker-config-acme --region us-east-1
$ hal deploy apply                                   # renders and applies Spinnaker's own microservices

Halyard's own maintenance has slowed considerably, and most current guidance points teams toward the Spinnaker Operator — a Kubernetes operator that manages a SpinnakerService custom resource instead — for installing and upgrading Spinnaker itself; check spinnaker.io's current installation guide before committing to either path, since this has shifted more than once. Whichever installer stands the platform up, day-to-day interaction with a running Spinnaker goes through the official spin CLI or the Gate API directly:

# spin — the CLI for managing applications and pipelines on a running Spinnaker
$ spin application list
$ spin application get checkout
$ spin pipeline save -f checkout-deploy.json          # create or update a pipeline from JSON
$ spin pipeline execute -a checkout -n "Deploy to prod" --parameter imageTag=1.4.4
$ spin pipeline get -a checkout -n "Deploy to prod" | jq '.stages[].type'

# Gate's REST API — the same thing, called directly, e.g. from another CI system
$ curl -X POST https://spinnaker.acme.internal/gate/pipelines/v2/checkout/Deploy%20to%20prod \
    -H "Content-Type: application/json" \
    -d '{"parameters": {"imageTag": "1.4.4"}}'

Most real setups wire a CI pipeline — Jenkins, GitHub Actions, GitLab CI/CD — to call that Gate endpoint as its final step, handing off from "build and test" to "deploy and verify" at exactly the boundary this page opened with. A newer, more declarative option called Managed Delivery lets a team commit a delivery-config.yml describing environments and promotion constraints directly to the application's Git repo instead of authoring pipeline JSON by hand; it's a meaningfully different, GitOps-flavored model, and — being newer — it's less universally battle-tested than the classic stage-graph pipeline, so read the current docs closely before betting a first production rollout on it.

Gotchas and failure modes

☺ Like you're 10: The tool that deploys everything else is, itself, about ten separate programs someone has to keep running — and a couple of its behaviors surprise people the first time.

The most consistently underestimated cost of Spinnaker is Spinnaker itself: roughly ten microservices, each with its own scaling characteristics, its own persistence dependency, and its own upgrade cadence, is a genuine distributed system to operate — the tool responsible for safe deploys needs safe deploys of its own. Teams below a certain scale often find the operational overhead outweighs the benefit until the multi-account or multi-cloud need is real, not hypothetical; see the comparison table below for when that threshold is actually crossed.

Two Spinnaker-specific behaviors bite in production regularly. First, Red/Black "disables" rather than deletes — that's the whole point, since it's what makes rollback instant — but disabled server groups still consume capacity and cost until something cleans them up; most platforms configure Spinnaker's server-group TTL or a separate cleanup job rather than relying on someone remembering to prune manually. Second, the Kubernetes v2 provider applies manifests directly rather than routing everything through the AWS-flavored server-group abstraction — which means a deploy (Manifest) stage's failure modes look more like a raw Kubernetes rollout problem (a stuck ReplicaSet, a failed readiness probe) than a classic ASG one, and debugging it means reading Kubernetes events, not Clouddriver's AWS caching layer.

Finally, a fair question before adopting Spinnaker for new infrastructure in 2026: project governance and commit velocity have visibly cooled since Netflix scaled back its own day-to-day involvement, and more than one commercial vendor built around Spinnaker has since redirected part of its own roadmap elsewhere. That doesn't make Spinnaker a wrong choice — the multi-account, multi-cloud pipeline model described on this page has no exact substitute — but it's worth checking the Continuous Delivery Foundation's current Spinnaker project page and recent release history yourself rather than assuming the project's 2019 momentum still applies unchanged.

✎ Try it

You don't need a running Spinnaker to practice the part that actually matters for understanding it. Take the pipeline JSON above and rewrite its clusters array for a scenario of your own — five AWS accounts across two regions, plus one GKE cluster — and decide, for each target, whether it should share the same kayentaCanary gate or get its own. Then sketch a canary config with three metrics instead of two, pick which ones you'd mark "groups": ["critical"], and justify why. Getting that design right on paper is most of the actual skill; the JSON syntax is the easy part.

Spinnaker vs. the alternatives

☺ Like you're 10: Other tools also move a release from build to production — they just draw the line between "simple" and "handles forty accounts at once" in different places.

OptionModelBest whenCosts you
SpinnakerSelf-hosted multi-cloud CD platform: stage-graph pipelines, an explicit account abstraction, native automated canary analysisThe same release genuinely has to reach many AWS accounts, or more than one cloud provider, from one pipeline, with a statistically scored canary gate built inOperating ~10 microservices yourself; real setup cost per cloud account (IAM trust); project momentum has cooled since Netflix's peak involvement
Argo CD + Argo RolloutsGitOps reconciler plus a progressive-delivery CRD, both Kubernetes-nativeEverything you deploy already lives on Kubernetes, across one or many clusters, and Git is the source of truthNo first-class EC2/ASG, Cloud Foundry, or Titus provider — "multi-cloud" here means "multiple Kubernetes clusters," not multiple non-Kubernetes platforms
AWS CodePipeline / CodeDeployManaged, AWS-native CD, single-account by defaultYou're deploying inside one AWS account, or a small number reachable through cross-account actions, and want zero CD infrastructure to run yourselfFanning out to many accounts means duplicated pipelines or hand-built StackSets-style orchestration — there's no built-in "one deploy, many accounts" concept; nothing outside AWS
HarnessCommercial SaaS CD platform with its own verification/canary engineYou want Spinnaker's ambitions — multi-cloud pipelines, automated deployment verification — without operating the microservices yourselfVendor lock-in and recurring licensing instead of a self-hosted open-source stack
GitLab CI/CD environmentsDeploy jobs, environments, and manual approval gates bolted onto the same CI pipelineCI already lives in GitLab and the deploy surface is simple enough not to need a dedicated CD platformNo purpose-built statistical canary judge, and no cross-provider account model — multi-target fan-out has to be scripted by hand

The practical rule: reach for Spinnaker when the deploy target is genuinely plural and heterogeneous — several AWS accounts, more than one cloud, or both — and the operational cost of running it is smaller than the cost of hand-rolling that fan-out somewhere else. Reach for a lighter, platform-native tool when the target is one cloud, or one Kubernetes footprint, because that's exactly the case those tools were built for and Spinnaker's extra machinery buys nothing. Spinnaker itself isn't a named domain on the AWS DevOps Engineer – Professional (DOP-C02) exam covered on this course's certifications page, but the deployment-strategy and canary-analysis concepts it implements are — verify the current exam guide's exact wording before assuming any one tool name will appear. See feature flags & progressive delivery for how canary analysis fits alongside flag-based rollouts, and release trains & change management for how a multi-account promotion pipeline like the one on this page fits into a broader release process.

🎬 At the Ship-It Guild
🦊

Foxy: We just picked up a fourth AWS account for the EU launch. Do we write a fourth deploy pipeline now?

🐢

Timmy the Turtle: One pipeline, one deploy stage, four cluster entries — Clouddriver fans it out to all four accounts in parallel. I still don't let anything past the canary gate first, no matter how many accounts are waiting on it.

🦫

Benny the Beaver: CI's already wired through Igor. New image tag lands, Orca picks the pipeline up on its own — nobody has to remember to click deploy.

🦥

Sol the Sloth: ...and I want that canary score computed off thirty real minutes of traffic, not five. A confident number from a five-minute window is still just a guess, wearing more decimal places.

👺

Gizmo: Or skip the analysis stage and manual-judge it yourself in ten seconds. Nobody will know. 🤑

🐢

Timmy the Turtle: That's exactly how a bad build reaches four accounts at once instead of one. The canary stage stays, Gizmo.

🐦

Pip the Hummingbird: And if something does slip through anyway, I'm already three channels ahead of you paging whichever account it landed in.

✓ Checkpoint

1. Where did Spinnaker originate, and which company open sourced it with Netflix in 2015? 2. Name at least four of Spinnaker's core microservices and what each one does. 3. Distinguish Red/Black, Rolling Red/Black, and Highlander as deployment strategies. 4. What does Kayenta's judge actually compare, and what's the danger of a badly matched baseline/canary pair? 5. What Spinnaker concept lets one pipeline stage deploy to many AWS accounts or multiple cloud providers at once, and how does that differ from a single-account-native tool like plain AWS CodeDeploy? 6. Why is Spinnaker's own operational footprint worth weighing before adopting it?

Check your answers
  1. It evolved from Asgard, an internal Netflix tool for managing AWS Auto Scaling Groups. Netflix open sourced it in November 2015 in partnership with Google.
  2. Any four of: Deck (UI), Gate (API gateway/authz boundary), Orca (orchestration engine — runs the pipeline's stage graph), Clouddriver (cloud provider abstraction and the only service that talks to real accounts), Front50 (persists pipeline/app config), Igor (turns CI build events into triggers), Echo (webhooks, cron triggers, notifications), Rosco (bakes machine images via Packer), Kayenta (automated canary analysis), Fiat (authorization).
  3. Highlander deploys the new server group and immediately destroys every other one in the cluster. Red/Black deploys new alongside old, cuts traffic over, and disables (not deletes) the old one for instant rollback. Rolling Red/Black shifts traffic between old and new in percentage increments with pauses, instead of an instant cutover.
  4. It compares metrics pulled from a baseline server group (unchanged) against a canary server group (the candidate), over the same analysis window, using a statistical judge (the default uses a Mann-Whitney U test) rather than a simple average. A badly matched pair — mismatched warm-up time, traffic mix, or window length — still produces a confident-looking score that doesn't mean what it appears to mean.
  5. The account abstraction in Clouddriver: a named registration of credentials plus provider, addressable by name in a deploy stage's clusters array, with multiple entries executing in parallel within one stage. Single-account-native tools like plain AWS CodeDeploy/CodePipeline have no built-in concept of this — fanning out to many accounts means duplicating pipelines or building custom orchestration on top.
  6. Because Spinnaker itself is roughly ten cooperating microservices with their own scaling, persistence, and upgrade needs — a real distributed system to run, not a single binary — and that operational cost only pays for itself once the multi-account or multi-cloud need is real rather than hypothetical.