Skip to main content
We’ve covered CRDs (CustomResourceDefinitions), Operators, Argo Workflows, and Crossplane — four Kubernetes-native automation primitives. Each can automate infrastructure and application tasks, but they follow different execution models and are optimized for different problem spaces. This guide provides a concise decision framework so platform teams can choose the right tool quickly and avoid over-engineering. The answer is often a combination of tools, not a single one. In this article you will:
  • Compare execution models and how they affect design.
  • Learn each tool’s sweet spots and common anti-patterns.
  • Apply a decision framework and platform patterns that combine tools effectively.
Example: Over-engineered operator vs simple composition An engineering team built a 2,000-line Go operator to provision dev environments: watch a DevEnvironment CR, create a namespace, apply RBAC, deploy monitoring, configure DNS, and handle errors. It worked, but it was heavy. A simpler Crossplane Composition plus a function (about 80 lines of YAML) would have satisfied the requirements: this was a run-to-completion provisioning task, not continuous reconciliation. The reconciliation loop in an operator was unnecessary.
Use these diagnostic questions to map problems to tools:
  • Is this a one-time task (run to completion) or continuous reconciliation?
  • Does it require complex, multi-step logic or DAG-style dependencies?
  • Am I provisioning cloud resources or managing runtime application state?
  • Who will maintain this automation and in which language?
Match answers to the execution model below.

Operators

  • Sweet spot: continuous reconciliation and operational lifecycle management of stateful applications (backups, scaling, upgrades, failover).
  • Use when you need continuous reconciliation: if resources drift or are deleted, the operator enforces desired state.
  • Use when operational runbooks and domain knowledge must be encoded (for example, safe zero-downtime PostgreSQL major upgrades).
  • Typical implementations: Go using Operator SDK and controller-runtime (also possible with Helm or Ansible-based operators via Operator SDK).
  • Anti-pattern: avoid writing an operator for run-to-completion multi-step jobs — the reconciliation loop adds unnecessary complexity.
Real-world examples: Postgres operators, Kafka, Redis, Prometheus operators, cert-manager.
Operators are best for long-lived, stateful responsibilities. If you only need to “create once and forget,” prefer a composition or workflow instead.

Argo Workflows

  • Sweet spot: complex, run-to-completion jobs with dependent steps and DAG-style orchestration.
  • Use when you need task orchestration: sequential or parallel steps, retries with backoff, artifact passing between steps, and conditional branching.
  • Workflows execute and exit — they do not perform long-lived reconciliation or drift correction.
  • Anti-pattern: do not use Argo Workflows to manage continuous runtime lifecycle of stateful services. For simple, single-container jobs, Kubernetes Job may suffice.
Typical use cases: data pipelines, ML training, ETL, nightly builds, integration test suites, environment provisioning scripts that run once.

Crossplane

  • Sweet spot: declarative cloud infrastructure exposed and managed as Kubernetes resources.
  • Use when provisioning cloud resources (databases, VPCs, storage, IAM). Crossplane exposes cloud APIs as CRDs and reconciles cloud resources continuously.
  • Use Crossplane to build self-service platform APIs (Compositions and XRDs) so developers can request cloud resources with Kubernetes-style kubectl apply.
  • Crossplane performs drift detection and self-healing for cloud resources.
  • Anti-pattern: avoid Crossplane for ephemeral compute jobs or complex multi-step workflows; use an orchestration engine (Argo Workflows). For runtime lifecycle of stateful apps, prefer operators.
Real-world examples: RDS provisioning, VPC and subnet management, S3 bucket lifecycle, IAM role automation.
Do not replace an operator’s runtime reconciliation responsibilities with Crossplane. Crossplane manages cloud resources; operators manage runtime application behavior and complex operational logic.

Quick Cheat-Sheet (execution model is the key)

  • Operators and Crossplane: run continuously, reconcile state, and correct drift.
  • Workflows (Argo Workflows): run to completion, execute a DAG of steps, then exit.
  • If you need drift correction or long-lived reconciliation → Operator or Crossplane.
  • If you need complex multi-step DAG logic → Workflow engine (Argo).
  • If you need managed stateful application lifecycle → Operator.
  • If you need declarative cloud resource provisioning → Crossplane.

Comparison Table


Decision Checklist (quick mapping)


Common Platform Patterns (combine tools)

  • Database-as-a-Service: Crossplane provisions RDS; a PostgreSQL operator manages backups, failover, and schema migrations.
  • ML platform: Crossplane provisions GPU nodes and object storage; Argo Workflows orchestrates training (data fetch → train → evaluate → upload).
  • Self-service infra: Git/GitOps triggers validation workflows; on success, Crossplane provisions requested infrastructure to an environment.
  • GitOps + infra: Argo CD deploys apps; Crossplane provisions cloud resources; both reconcile continuously.
Think in layers:
  • Infrastructure: Crossplane (declarative cloud resources)
  • Orchestration: Argo Workflows (complex run-to-completion pipelines)
  • Runtime management: Operators (stateful application lifecycle)
  • Deployment: Argo CD / Tekton (CI/CD and GitOps)

Key Takeaways

  • Use operators for stateful application management and continuous reconciliation.
  • Use workflows for complex multi-step, dependency-driven jobs that run to completion.
  • Use Crossplane for declarative cloud resource provisioning and drift correction.
  • Combine tools by layer: provision infra with Crossplane, orchestrate pipelines with Argo Workflows, manage runtime with operators, and deploy with GitOps/CI systems.
  • Avoid over-engineering: match the execution model (continuous vs run-to-completion) to the problem.
Further reading and references:

Watch Video