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 Articles
• Ansible vs Terraform in 2026 • Ansible CI/CD Pipeline Integration • Ansible for Docker Container Management • Ansible Check Mode and Diff Mode • Ansible OpenShift Automation Guide • Extend K8s API with Custom Resource Definitions • Fixing Kubernetes PersistentVolume Configuration ErrorCategory: installation