Ansible Kubernetes Automation

Kubernetes runs containers across a cluster of machines. Teams describe the wanted state in YAML files, and Kubernetes works to match it. Ansible adds value on top of that model. A playbook can create the cluster, deploy applications, tune settings, and connect Kubernetes steps with work outside the cluster, such as DNS records and database setup. Picture an orchestra: Kubernetes is the conductor who keeps musicians in time, and Ansible is the event manager who books the hall, sends invitations, and prints the programs.

Diagram: Ansible and the Cluster

  ┌─────────────┐   kubeconfig    ┌───────────────────────────┐
  │   Ansible   │───────────────▶│ Kubernetes API Server     │
  │ (kubernetes │                 └───────────┬───────────────┘
  │  .core)     │                             │
  └─────────────┘                ┌────────────┼────────────┐
                                 ▼            ▼            ▼
                           ┌─────────┐  ┌─────────┐  ┌─────────┐
                           │ Node 1  │  │ Node 2  │  │ Node 3  │
                           │ Pod Pod │  │ Pod Pod │  │ Pod     │
                           └─────────┘  └─────────┘  └─────────┘

Ansible talks to the API server from the control node. Managed nodes and SSH play no part in these tasks, so the play targets localhost.

Prepare the Control Node

ansible-galaxy collection install kubernetes.core
python3 -m pip install kubernetes pyyaml
kubectl get nodes

A working kubectl connection confirms the kubeconfig file is valid. The modules read the same file, found at ~/.kube/config by default.

Key Modules

ModuleJob
kubernetes.core.k8sCreate, change, or delete any Kubernetes object
kubernetes.core.k8s_infoRead object details
kubernetes.core.k8s_scaleChange replica counts
kubernetes.core.helmInstall and upgrade Helm charts
kubernetes.core.k8s_execRun a command inside a pod
kubernetes.core.k8s_logRead pod logs

Create a Namespace and a Deployment

- name: Deploy the shop application
  hosts: localhost
  connection: local
  gather_facts: false
  tasks:
    - name: Create the namespace
      kubernetes.core.k8s:
        name: shop
        api_version: v1
        kind: Namespace
        state: present

    - name: Create the deployment
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: shop-web
            namespace: shop
          spec:
            replicas: 3
            selector:
              matchLabels:
                app: shop-web
            template:
              metadata:
                labels:
                  app: shop-web
              spec:
                containers:
                  - name: web
                    image: nginx:1.25
                    ports:
                      - containerPort: 80

Expose the Application

    - name: Create a service
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: Service
          metadata:
            name: shop-web
            namespace: shop
          spec:
            type: ClusterIP
            selector:
              app: shop-web
            ports:
              - port: 80
                targetPort: 80

Apply Templates

Keep object definitions in Jinja2 templates and feed them variables per environment.

    - name: Apply deployment from a template
      kubernetes.core.k8s:
        state: present
        template: templates/deployment.yml.j2

Scale and Wait

    - name: Scale to five replicas
      kubernetes.core.k8s_scale:
        api_version: apps/v1
        kind: Deployment
        name: shop-web
        namespace: shop
        replicas: 5
        wait: true
        wait_timeout: 120

Check Status

    - name: Read pod details
      kubernetes.core.k8s_info:
        kind: Pod
        namespace: shop
        label_selectors:
          - app=shop-web
      register: pods

    - name: Print pod names
      ansible.builtin.debug:
        msg: "{{ pods.resources | map(attribute='metadata.name') | list }}"

Install a Helm Chart

    - name: Add a chart repository
      kubernetes.core.helm_repository:
        name: bitnami
        repo_url: https://charts.bitnami.com/bitnami

    - name: Install Redis
      kubernetes.core.helm:
        name: cache
        chart_ref: bitnami/redis
        release_namespace: shop
        create_namespace: true
        values:
          architecture: standalone

Good Habits

  • Use separate namespaces per application or environment
  • Store sensitive values in Kubernetes Secrets created from vault variables
  • Pin image tags and chart versions
  • Use --check to preview changes
  • Let Kubernetes control pod placement, and let Ansible control the desired objects

Try This

Start a local cluster with minikube or kind. Run the playbook above and confirm three pods with kubectl get pods -n shop. Change replicas to two and rerun the playbook. Watch Kubernetes remove one pod.

Summary

The kubernetes.core collection lets playbooks manage clusters through the API. The k8s module creates any object from YAML definitions or templates, k8s_scale adjusts replicas, k8s_info reads state, and the Helm modules install charts. Ansible ties cluster work to the wider infrastructure, and Kubernetes keeps the wanted state alive.