Ansible and Pulumi: Two Automation Philosophies Coexisting

Engranajes metálicos entrelazados representando automatización cooperativa

Ansible and Pulumi are often compared but solve different problems. Ansible is configuration management: what’s installed on a server, config files, users, services. Pulumi is Infrastructure as Code: what cloud resources exist (VPC, instances, load balancers, buckets). Using them together is a common productive pattern — this article covers how to combine without duplicating effort.

The Natural Division

Pulumi — Infrastructure

  • Create VPCs, subnets, security groups.
  • Provision instances, databases, buckets.
  • Configure DNS, certificates.
  • Managed services (RDS, Redshift, K8s clusters).

Ansible — Configuration

  • Install packages on servers.
  • Deploy applications.
  • Manage users and SSH keys.
  • Config files (nginx.conf, postgresql.conf).
  • Orchestrate operations (rolling restarts, patches).

Both address automation but at different levels.

Concrete Example

Pulumi creates infrastructure:

import * as aws from "@pulumi/aws";

const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16" });
const subnet = new aws.ec2.Subnet("private", {
  vpcId: vpc.id,
  cidrBlock: "10.0.1.0/24",
});
const instance = new aws.ec2.Instance("web", {
  ami: "ami-xxx",
  instanceType: "t3.medium",
  subnetId: subnet.id,
});

export const instanceIp = instance.publicIp;

Ansible configures what runs on it:

- hosts: web
  tasks:
    - apt:
        name: [nginx, postgresql-client]
        state: present
    - template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: restart nginx
  handlers:
    - name: restart nginx
      systemd:
        name: nginx
        state: restarted

Both together cover the complete stack.

Pulumi vs Terraform

Pulumi is Terraform alternative with real code (TypeScript, Python, Go, .NET) instead of HCL:

Advantages:

  • Native loops, conditionals.
  • Abstractions: classes, reusable functions.
  • Test with standard unit testing.
  • Full IDE autocomplete.

Disadvantages:

  • More cognitive load (program vs declare).
  • Smaller community than Terraform.
  • Terraform-similar but different state management.
  • Some newer features arrive at Terraform first.

Pulumi vs Terraform decision is preference — both do cloud-agnostic IaC.

Ansible vs Chef/Puppet/SaltStack

Ansible won the config-management war:

  • Agentless (simple SSH).
  • YAML: readable declarative.
  • Low curve vs Puppet DSL.
  • Massive modules: >5000 built-in.

Chef/Puppet continue in traditional enterprises but new projects lean Ansible.

Combining: Typical Stack

Productive flow:

  1. Pulumi creates infra: VPCs, servers, databases, K8s cluster.
  2. Pulumi exports outputs: IPs, credentials, endpoints.
  3. Ansible receives outputs: dynamic inventory with Pulumi stack outputs.
  4. Ansible configures: apps, users, services.
  5. Both in CI/CD: Pulumi preview → apply → Ansible playbook.

Dynamic Inventory from Pulumi

# pulumi_inventory.py
import pulumi
stack = pulumi.automation.select_stack(...)
outputs = stack.outputs()

print({
    "web": {
        "hosts": [o["ip"] for o in outputs["instances"]]
    }
})

Ansible consumes this inventory dynamically.

Cases Where Ansible Alone Suffices

  • Legacy on-premise: no cloud infra to provision.
  • Static VMs: infra doesn’t change, only configuration.
  • Network devices: Ansible has excellent modules (Cisco, Juniper).

Cases Where Pulumi Alone Suffices

  • Serverless / containerized: everything runs on managed services.
  • Kubernetes-native: K8s manifests generated by Pulumi cover app config.
  • VM-less cloud-only: nothing Ansible would do.

Antipatterns

Things not to mix:

  • Pulumi configuring things inside VM: complicated user-data scripts. Ansible better.
  • Ansible creating AWS resources: there are amazon.aws.* modules but for >10 resources, Pulumi is better.
  • Terraform + Ansible + Pulumi: pick one IaC (Terraform or Pulumi), not both.

Testing

Ansible:

  • Molecule: test playbooks with Docker/Vagrant.
  • ansible-lint: linting.

Pulumi:

  • Unit tests with Pulumi mocks.
  • Integration tests creating ephemeral stacks.
  • Policy-as-code with CrossGuard.

Both have similar testing maturity.

Secrets

Ansible Vault: integrated, encrypts YAML files.

Pulumi:

  • Config.setSecret(): encrypted in state.
  • Integration with AWS SSM, Azure Key Vault, HashiCorp Vault.

For production-grade secrets, integration with external secret manager is the path.

Modern Alternatives

  • Terragrunt: Terraform wrapper with DRY patterns.
  • CDKTF: Terraform with TypeScript/Python (like Pulumi).
  • Crossplane: K8s-native IaC.
  • OpenTofu: Terraform fork post-license change.
  • Kapitan: GitOps config management.
  • ArgoCD: K8s-specific GitOps.

Rich panorama. Choice depends on stack and philosophy.

When to Learn One

  • Junior DevOps starting: basic Terraform + basic Ansible covers 80% of jobs.
  • Cloud-native: Pulumi + K8s-native tools.
  • Legacy / enterprise: Ansible + Chef/Puppet still relevant.
  • Full-stack engineer: probably only Pulumi or Terraform enough if Ansible unnecessary.

Typical ROI

Team adopting proper IaC + Config Management:

  • First month: negative (setup time).
  • Three months: break-even.
  • One year: 40-60% time saved in repetitive operations.
  • Years 2+: disaster recovery in minutes/hours vs days.

Value accumulates. Not starting is growing invisible cost.

Conclusion

Ansible and Pulumi are complementary, not competitors. Pulumi (or Terraform/OpenTofu) for infrastructure provisioning. Ansible for configuration management. Combining is productive stack for organisations with mix of cloud and servers. For complete cloud-native greenfield, Pulumi alone sometimes suffices. For legacy hybrid, Ansible remains fundamental piece. Decision isn’t “pick one” but “orchestrate both effectively”. Teams understanding this division have cleaner, more maintainable automation.

Follow us on jacar.es for more on IaC, automation, and DevOps.

Entradas relacionadas