AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible for Kubernetes: Deploy, Manage, and Automate K8s Clusters Complete Guide

By Luca Berton · Published 2024-01-01 · Category: installation

Complete guide to using Ansible with Kubernetes. Deploy pods, services, and deployments with the kubernetes.core collection.

Ansible automates Kubernetes the same way it automates everything else — with YAML playbooks, idempotent modules, and no agent on the cluster. The kubernetes.core collection gives you modules for deployments, services, Helm charts, RBAC, and custom resources. Here's how to use them.

Setup

Install the Collection

ansible-galaxy collection install kubernetes.core

Dependencies

# Python kubernetes client (required)
pip install kubernetes

# For Helm support
pip install kubernetes helm

# For dynamic inventory
pip install kubernetes

Authentication

The kubernetes.core modules use your kubeconfig by default:

# Uses ~/.kube/config automatically
- kubernetes.core.k8s:
    state: present
    definition: "{{ lookup('file', 'deployment.yml') }}"

Or specify explicitly:

# Explicit kubeconfig
- kubernetes.core.k8s:
    kubeconfig: /path/to/kubeconfig
    context: production-cluster
    state: present
    definition: "{{ deployment }}"

# Or use host/token
- kubernetes.core.k8s:
    host: https://k8s-api.example.com:6443
    api_key: "{{ k8s_token }}"
    validate_certs: true
    state: present
    definition: "{{ deployment }}"

See also: Ansible for Kubernetes: Automate K8s Cluster Management and Application Deployment

Deploying Resources

Create a Deployment

---
- name: Deploy application to Kubernetes
  hosts: localhost
  connection: local
  tasks:
    - name: Create namespace
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: Namespace
          metadata:
            name: production
            labels:
              environment: production

    - name: Deploy web application
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: web-app
            namespace: production
            labels:
              app: web
          spec:
            replicas: 3
            selector:
              matchLabels:
                app: web
            template:
              metadata:
                labels:
                  app: web
              spec:
                containers:
                  - name: web
                    image: "nginx:1.27"
                    ports:
                      - containerPort: 80
                    resources:
                      requests:
                        memory: "128Mi"
                        cpu: "100m"
                      limits:
                        memory: "256Mi"
                        cpu: "200m"
                    livenessProbe:
                      httpGet:
                        path: /healthz
                        port: 80
                      initialDelaySeconds: 10
                      periodSeconds: 30

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

Load Manifests from Files

- name: Apply manifest from file
  kubernetes.core.k8s:
    state: present
    src: manifests/deployment.yml

- name: Apply all manifests in directory
  kubernetes.core.k8s:
    state: present
    src: "{{ item }}"
  loop: "{{ lookup('fileglob', 'manifests/*.yml', wantlist=True) }}"

- name: Apply from template
  kubernetes.core.k8s:
    state: present
    definition: "{{ lookup('template', 'deployment.yml.j2') }}"

ConfigMaps and Secrets

- name: Create ConfigMap
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: app-config
        namespace: production
      data:
        DATABASE_HOST: "db.internal"
        LOG_LEVEL: "info"
        MAX_CONNECTIONS: "100"

- name: Create Secret
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: v1
      kind: Secret
      metadata:
        name: app-secrets
        namespace: production
      type: Opaque
      stringData:
        DATABASE_PASSWORD: "{{ vault_db_password }}"
        API_KEY: "{{ vault_api_key }}"

Helm Chart Management

Install a Helm Chart

- name: Add Helm repository
  kubernetes.core.helm_repository:
    name: ingress-nginx
    repo_url: https://kubernetes.github.io/ingress-nginx

- name: Install ingress-nginx
  kubernetes.core.helm:
    name: ingress-nginx
    chart_ref: ingress-nginx/ingress-nginx
    release_namespace: ingress-nginx
    create_namespace: true
    values:
      controller:
        replicaCount: 2
        service:
          type: LoadBalancer
        resources:
          requests:
            cpu: 100m
            memory: 128Mi

Upgrade and Rollback

- name: Upgrade application chart
  kubernetes.core.helm:
    name: my-app
    chart_ref: ./charts/my-app
    release_namespace: production
    values:
      image:
        tag: "{{ app_version }}"
      replicas: "{{ replica_count | default(3) }}"
    wait: true
    timeout: 10m0s

- name: Rollback on failure
  kubernetes.core.helm:
    name: my-app
    release_namespace: production
    state: absent
  when: deploy_failed | default(false)

Full Helm Workflow

---
- name: Deploy application stack with Helm
  hosts: localhost
  connection: local
  vars:
    app_version: "2.1.0"
    environment: production
  tasks:
    - name: Add required repositories
      kubernetes.core.helm_repository:
        name: "{{ item.name }}"
        repo_url: "{{ item.url }}"
      loop:
        - { name: bitnami, url: "https://charts.bitnami.com/bitnami" }
        - { name: prometheus, url: "https://prometheus-community.github.io/helm-charts" }

    - name: Deploy PostgreSQL
      kubernetes.core.helm:
        name: postgresql
        chart_ref: bitnami/postgresql
        release_namespace: "{{ environment }}"
        create_namespace: true
        values:
          auth:
            postgresPassword: "{{ vault_pg_password }}"
            database: myapp
          primary:
            persistence:
              size: 20Gi

    - name: Deploy application
      kubernetes.core.helm:
        name: my-app
        chart_ref: ./charts/my-app
        release_namespace: "{{ environment }}"
        values:
          image:
            tag: "{{ app_version }}"
          database:
            host: postgresql.{{ environment }}.svc.cluster.local
        wait: true

    - name: Deploy monitoring
      kubernetes.core.helm:
        name: prometheus
        chart_ref: prometheus/kube-prometheus-stack
        release_namespace: monitoring
        create_namespace: true
        values:
          grafana:
            adminPassword: "{{ vault_grafana_password }}"

See also: Ansible Kubernetes (k8s) Module: Manage K8s Resources (Guide)

RBAC Management

---
- name: Configure RBAC
  hosts: localhost
  connection: local
  tasks:
    - name: Create service account
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: ServiceAccount
          metadata:
            name: deploy-bot
            namespace: production

    - name: Create role
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: rbac.authorization.k8s.io/v1
          kind: Role
          metadata:
            name: deployer
            namespace: production
          rules:
            - apiGroups: ["apps"]
              resources: ["deployments", "replicasets"]
              verbs: ["get", "list", "watch", "create", "update", "patch"]
            - apiGroups: [""]
              resources: ["pods", "services", "configmaps"]
              verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

    - name: Bind role to service account
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: rbac.authorization.k8s.io/v1
          kind: RoleBinding
          metadata:
            name: deploy-bot-deployer
            namespace: production
          subjects:
            - kind: ServiceAccount
              name: deploy-bot
              namespace: production
          roleRef:
            kind: Role
            name: deployer
            apiGroup: rbac.authorization.k8s.io

Querying Cluster State

Get Resource Info

- name: Get all pods in namespace
  kubernetes.core.k8s_info:
    kind: Pod
    namespace: production
  register: pod_list

- name: Show running pods
  ansible.builtin.debug:
    msg: "{{ item.metadata.name }} - {{ item.status.phase }}"
  loop: "{{ pod_list.resources }}"
  when: item.status.phase == "Running"

- name: Get specific deployment
  kubernetes.core.k8s_info:
    api_version: apps/v1
    kind: Deployment
    name: web-app
    namespace: production
  register: deployment_info

- name: Check replica count
  ansible.builtin.debug:
    msg: "Ready: {{ deployment_info.resources[0].status.readyReplicas | default(0) }}/{{ deployment_info.resources[0].spec.replicas }}"

Wait for Resources

- name: Wait for deployment to be ready
  kubernetes.core.k8s_info:
    api_version: apps/v1
    kind: Deployment
    name: web-app
    namespace: production
    wait: true
    wait_condition:
      type: Available
      status: "True"
    wait_timeout: 300

- name: Wait for pod to be running
  kubernetes.core.k8s_info:
    kind: Pod
    namespace: production
    label_selectors:
      - app=web
    wait: true
    wait_condition:
      type: Ready
      status: "True"
    wait_timeout: 120

See also: Kubernetes Core 6.4.0: Helm v4 Support & k8s_drain Improvements

Dynamic Inventory

Use the Kubernetes inventory plugin to target pods or nodes:

# k8s_inventory.yml
plugin: kubernetes.core.k8s
connections:
  - kubeconfig: ~/.kube/config
    namespaces:
      - production
      - staging

# Then use in playbook
# ansible-playbook -i k8s_inventory.yml playbook.yml

Scaling and Rolling Updates

- name: Scale deployment
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: web-app
        namespace: production
      spec:
        replicas: "{{ desired_replicas }}"

- name: Rolling update (change image)
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: web-app
        namespace: production
      spec:
        template:
          spec:
            containers:
              - name: web
                image: "myapp:{{ new_version }}"
    wait: true
    wait_timeout: 600

Execute Commands in Pods

- name: Run database migration
  kubernetes.core.k8s_exec:
    namespace: production
    pod: "{{ migration_pod }}"
    command: python manage.py migrate
  register: migration_result

- name: Show migration output
  ansible.builtin.debug:
    msg: "{{ migration_result.stdout }}"

Common Patterns

Blue-Green Deployment

---
- name: Blue-green deployment
  hosts: localhost
  connection: local
  vars:
    new_color: "{{ 'green' if current_color == 'blue' else 'blue' }}"
  tasks:
    - name: Deploy new version ({{ new_color }})
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: "web-{{ new_color }}"
            namespace: production
          spec:
            replicas: 3
            selector:
              matchLabels:
                app: web
                color: "{{ new_color }}"
            template:
              metadata:
                labels:
                  app: web
                  color: "{{ new_color }}"
              spec:
                containers:
                  - name: web
                    image: "myapp:{{ new_version }}"

    - name: Wait for new deployment
      kubernetes.core.k8s_info:
        api_version: apps/v1
        kind: Deployment
        name: "web-{{ new_color }}"
        namespace: production
        wait: true
        wait_condition:
          type: Available
          status: "True"
        wait_timeout: 300

    - name: Switch service to new color
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: Service
          metadata:
            name: web
            namespace: production
          spec:
            selector:
              app: web
              color: "{{ new_color }}"
            ports:
              - port: 80

    - name: Scale down old deployment
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: "web-{{ current_color }}"
            namespace: production
          spec:
            replicas: 0

FAQ

Should I use Ansible or kubectl for Kubernetes?

Use Ansible when you need reproducible, version-controlled deployments that integrate with your existing automation. Use kubectl for quick debugging and ad-hoc commands. For CI/CD, Ansible playbooks are more maintainable than shell scripts full of kubectl commands.

How does Ansible compare to ArgoCD or Flux for GitOps?

ArgoCD/Flux continuously sync cluster state with a Git repo (pull-based GitOps). Ansible runs on-demand (push-based). For continuous reconciliation, use ArgoCD/Flux. For orchestrated deployments that need to coordinate with non-Kubernetes systems, Ansible is more flexible.

Can Ansible manage multiple Kubernetes clusters?

Yes. Use different kubeconfig files or contexts per task. You can deploy the same application across dev, staging, and production clusters in a single playbook by parameterizing the context.

Do I need Ansible if I already use Helm?

Ansible adds orchestration around Helm — install charts in order, wait for dependencies, configure secrets from Vault, and coordinate with non-Kubernetes systems. If your entire stack is Helm charts with no external dependencies, you might not need Ansible.

What about Ansible on Kubernetes (AWX/AAP)?

AWX (open-source) and Ansible Automation Platform (enterprise) run on Kubernetes themselves. This gives you Ansible-managed Kubernetes managing the Ansible that manages other things — it's automation all the way down.

Conclusion

The kubernetes.core collection gives Ansible full control over Kubernetes — deployments, Helm charts, RBAC, scaling, and cluster queries. Use it when you need orchestrated, reproducible K8s operations that integrate with your broader infrastructure automation. For pure GitOps, consider ArgoCD alongside Ansible for the best of both worlds.

Related reading: Ansible-driven Kubernetes operations covers this in real-world detail.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home