Deploying Infrastructure
Deploying infrastructure shares many patterns with deploying software - the same pipeline tools, similar rollback strategies, and comparable trigger mechanisms. But infrastructure adds unique concerns: state management, drift detection, and the fact that changes can destroy running resources. This page covers the full deployment lifecycle: how changes reach production, how projects are structured, and which platforms orchestrate the process.
Software vs. Infrastructure Deployment
Section titled “Software vs. Infrastructure Deployment”Understanding software deployment strategies provides the foundation for infrastructure deployment:
| Strategy | How it works | Best for |
|---|---|---|
| Push | A deployment tool runs whenever code changes - triggered by a pipeline stage, repo poll, or manual action | Most common; general-purpose |
| Pull | Infrastructure code defines the software to install (e.g., an RPM package in a server configuration) | Simple installations; limited for complex sequencing or rollback |
| GitOps | Software agents continuously pull declarative state from a Git repo and reconcile actual state against it | Kubernetes workloads; drift detection built in |
GitOps operates on four principles (per the CNCF):
- The desired state must be declarative
- The desired state must be versioned and immutable
- Agents must automatically pull state declarations
- Agents must continuously reconcile actual state against desired state
Unlike push/pull, GitOps doesn’t just deploy on new code - it redeploys whenever live state drifts from the source, automatically correcting manual changes or recovering from failures.
Infrastructure Deployment Strategies
Section titled “Infrastructure Deployment Strategies”Infrastructure deployment strategies focus on how infrastructure provisioning is orchestrated alongside software workload deployment:
Siloed Deployment
Section titled “Siloed Deployment”Infrastructure is provisioned separately from its workloads - often by a dedicated instance management team. This is the most common approach but frequently leads to lower effectiveness in delivery quality and flow.
Application Infrastructure Descriptors
Section titled “Application Infrastructure Descriptors”A descriptor file within the application deployment specifies the required infrastructure. When deployed, a service reads the descriptor and:
- Creates application-specific infrastructure (e.g., a dedicated database)
- Integrates the application with shared services (monitoring, container clusters)
Standardisation efforts like the Score specification are emerging to replace custom in-house descriptor formats.
Infrastructure from Code (IfC)
Section titled “Infrastructure from Code (IfC)”A leading-edge approach that embeds infrastructure definitions directly in application code. Resources may be provisioned at deploy time, first run, or the moment the code first uses them.
| Implementation | Example |
|---|---|
| Embedded low-level IaC | Application code calls IaaS platform APIs directly |
| Imported libraries | CDK constructs, Nitric SDK |
| Code annotations | Framework reads annotations and provisions matching resources |
Tools: Ampt, Darklang, Winglang, Nitric, AWS CDK (serverless developers writing infrastructure in the same language as application code).
Running Infrastructure Deployments
Section titled “Running Infrastructure Deployments”Deployment Execution Models
Section titled “Deployment Execution Models”| Model | Description | Trade-off |
|---|---|---|
| Local workstation | Run tools directly from a laptop with a local code copy | Useful for personal testing; causes overwrites and conflicts in teams |
| Central service | Pull code from a repository and apply from a shared server | Deployment history, governance enforcement, no “works on my machine” |
| Delivery pipeline | Deployment is a pipeline build stage; the service runs tools on an agent | Single team ownership; centralised visibility |
| Deployment service / TACOS | Separate the pipeline (code progression) from the deployment service | HCP Terraform, Pulumi Cloud, AWS Service Catalog, Spacelift, Atlantis |
| Infrastructure as Data | A controller continuously reconciles definitions with live infrastructure | Crossplane, AWS ACK, Config Connector; drift correction is automatic |
Infrastructure as Data
Section titled “Infrastructure as Data”Infrastructure as Data extends IaC by treating drift detection and resolution as a core, continuous feature rather than a one-time check.
How it works:
- A central service (typically a Kubernetes cluster) runs a control loop
- The loop continuously compares infrastructure definitions against actual resources
- Discrepancies are automatically corrected
Native tools:
| Tool | Cloud |
|---|---|
| ACK | AWS |
| Config Connector | GCP |
| Azure Service Operator | Azure |
| Crossplane | Multi-cloud |
Custom controllers can run standard Terraform/Pulumi from within Kubernetes: HCP Terraform Operator, Pulumi Kubernetes Operator, Tofu Controller.
Alternative: IaSQL - uses a PostgreSQL database instead of Kubernetes; infrastructure defined as SQL, synchronised with AWS.
Deployment Scripts
Section titled “Deployment Scripts”Deployments require orchestration beyond just running terraform apply - retrieving dependencies, assembling secrets, managing authentication, running post-deploy tests.
The spaghetti code trap: Custom wrapper scripts (Bash, Python, Make) tend to grow larger than the infrastructure code itself.
Best practices:
| Principle | What to do |
|---|---|
| Split the lifecycle | Separate scripts for building, testing, and deploying - never one monolith |
| Separate tasks | Keep integration points between tasks loosely coupled |
| Decouple deployment levels | Multi-stack orchestration scripts ≠ single-stack deployment scripts |
| Keep scripts generic | No hardcoded project configurations; reusable for any project using similar tools |
| Test your scripts | Validate with ShellCheck, Bats, or equivalent; apply single-responsibility principle |
Standardisation tools: Terragrunt, Atmos, InfraBlocks, Terraspace - purpose-built frameworks that replace ad hoc wrapper scripts.
GitOps for Infrastructure
Section titled “GitOps for Infrastructure”The GitOps Development Workflow
Section titled “The GitOps Development Workflow”GitOps mirrors standard software development:
- Developer checks out code, creates a branch, develops locally
- Opens a pull request - triggers CI tests and a speculative plan showing proposed infrastructure changes
- Reviewers evaluate the plan and code
- Once the PR is approved and merged to
main, the CD orchestrator automatically deploys
Continuous Reconciliation
Section titled “Continuous Reconciliation”Terraform can detect and fix drift, but only when manually triggered. True GitOps requires scheduled reconciliation - CD platforms run Terraform on a regular cadence, ensuring active infrastructure continuously matches the main branch, not just during PRs.
Project Structures
Section titled “Project Structures”The root module is the entry point for every deployment - the only place users inject variables and configure providers. How you structure root modules across environments determines how safely you can roll out changes.
Application as Root Module
Section titled “Application as Root Module”The application module is the root module. Environments are separated by variable files (staging.tfvars, production.tfvars).
my-app/├── main.tf├── variables.tf├── staging.tfvars└── production.tfvarsEnvironment as Root Module (Recommended)
Section titled “Environment as Root Module (Recommended)”Each environment gets its own folder and main.tf - a thin wrapper that calls a versioned application module.
environments/├── staging/│ └── main.tf # source = "registry.example.com/app" version = "1.2.0"├── production/│ └── main.tf # source = "registry.example.com/app" version = "1.1.4"└── modules/ └── app/ # The reusable application moduleKey advantages:
- Pin different module versions per environment - stage changes safely before production
- Parameters can be hardcoded directly in the module block (no complex
.tfvarsfiles) - Upgrading an environment requires a PR, creating an explicit audit trail
Repository organisation:
| Scenario | Recommendation |
|---|---|
| Single team manages all environments | One shared repository |
| Multiple teams own different environments | Separate repositories |
Terragrunt
Section titled “Terragrunt”Terragrunt takes the environment-as-root concept further - no literal Terraform root module is needed:
terraform { source = "tfr:///org/app/aws?version=1.2.0"}
inputs = { environment = "staging" instance_type = "t3.medium"}| Feature | Detail |
|---|---|
scaffold | Reads a registry module and auto-generates the boilerplate terragrunt.hcl with required inputs |
| Mirror commands | terragrunt plan, terragrunt apply - generates the root module behind the scenes |
run-all | Execute commands across all environment configurations simultaneously (terragrunt run-all plan) |
| Version pinning | No constraint ranges - exact versions only; manual updates create a clear audit trail |
Triggering Infrastructure Deployments
Section titled “Triggering Infrastructure Deployments”What Triggers a Deployment
Section titled “What Triggers a Deployment”| Driver | Example |
|---|---|
| Input material change | New code commit, updated dependency, changed configuration value |
| Rollback | Reverting to a previous known-good version |
| Drift correction | Live infrastructure no longer matches the defined code |
Best practice: bundle as many dependencies as possible with the versioned build rather than reassembling them at deploy time. Trigger deployments as soon as it is safe after any input changes.
Manual Triggers
Section titled “Manual Triggers”| Method | Use case |
|---|---|
| Pipeline / deployment service UI | Select specific build versions - useful for rollbacks and tester self-service |
| Developer portal | User-facing interface with authorisation and billing; deploys tagged builds (“latest dev”, “production”) |
| Ticketing system | Governance workflows - manages approvals, auditing, and compliance; integrates with pipelines |
| Source code branches | Promote by merging into an environment branch; deployment triggered by hook or poll |
Automatic Triggers
Section titled “Automatic Triggers”Pushing a commit kicks off the pipeline automatically. Builds progress through stages - deploy to test, run automated checks, deploy to integration - via automatic triggers at each stage boundary.
Active vs. Passive Triggers
Section titled “Active vs. Passive Triggers”| Type | Mechanism |
|---|---|
| Active | Pipeline/portal/ticket system makes an API call to the deployment service, passing build version and configuration |
| Passive | Service continuously monitors source repos, artifact packages, configuration registries, or dependent resources; deploys when a change is detected |
CD Platform Landscape
Section titled “CD Platform Landscape”Common Baseline Features
Section titled “Common Baseline Features”Every mature CD platform provides: GitOps-based workflows, role-based access control, OIDC support, secret management, and speculative plan generation.
Advanced Differentiators
Section titled “Advanced Differentiators”| Feature | Details |
|---|---|
| TACOS | Platforms bundling delivery + state management + private registries; transparent state backend with version history UI |
| Drift detection | Continuous reconciliation; alerts (Slack) vs. automatic correction |
| Multi-IaC support | Helm, Pulumi, Ansible alongside Terraform - avoid maintaining separate systems |
| Policy enforcement | Enforce rules at the deployment level; industry standardised on OPA / Rego (even HashiCorp added OPA support in 2023) |
| Cost estimation | Built-in (HCP Terraform) or via Infracost; limited to major clouds; estimates only |
The Terraform vs. OpenTofu Divide
Section titled “The Terraform vs. OpenTofu Divide”HashiCorp’s Business Source License forbids competitors from using newer Terraform versions. Commercial platforms have shifted to OpenTofu. Teams wanting the newest HashiCorp Terraform must use HCP Terraform or self-host.
Platform Comparison
Section titled “Platform Comparison”| Platform | Type | Strengths | Limitations |
|---|---|---|---|
| HCP Terraform | Managed TACOS | Deep CLI integration, built-in cost estimation | Terraform-only; per-resource hourly pricing can inflate costs |
| Env0 / Spacelift | Managed TACOS | OpenTofu sponsors; multi-framework (Terragrunt, Helm, Ansible, Pulumi) | - |
| Scalr | Managed TACOS | Pure Terraform/OpenTofu focus; CLI-driven workflows; easy HCP migration | No Helm/Kubernetes support |
| Digger / Terrateam | GitOps Plus | PR-comment-driven; tight GitHub integration | No state backend or registry out of the box |
| Harness / Octopus Deploy | Enterprise CD | Broad platform - physical hardware, containers, legacy systems | No built-in registries or state management |
| Atlantis / Terrakube | Self-hosted OSS | Free; legally allows newest HashiCorp Terraform | Administrative burden; must isolate securely |