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 OpenShift Automation: Deploy, Manage, and Scale Kubernetes Workloads

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

Complete guide to automating Red Hat OpenShift with Ansible. Learn cluster provisioning, application deployment, route management, operators, CI/CD pipelines.

Red Hat OpenShift is an enterprise Kubernetes platform that adds developer workflows, built-in CI/CD, and operational tools on top of Kubernetes. Ansible provides powerful automation for OpenShift — from cluster provisioning to application deployment, route management, and day-2 operations. This guide covers production-ready patterns using the kubernetes.core and redhat.openshift collections.

Prerequisites

# Install required collections
ansible-galaxy collection install kubernetes.core
ansible-galaxy collection install redhat.openshift

# Install Python dependencies pip install kubernetes openshift PyYAML

# Verify OpenShift CLI oc version

Authentication Setup

# group_vars/all.yml
openshift_host: "https://api.ocp.example.com:6443"
openshift_api_key: "{{ vault_openshift_token }}"
openshift_validate_certs: true

# Or use kubeconfig openshift_kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}"

See also: Ansible on OpenShift 4.18 Automation Complete Guide

Project and Namespace Management

---
- name: Manage OpenShift projects
  hosts: localhost
  module_defaults:
    group/kubernetes.core.k8s:
      host: "{{ openshift_host }}"
      api_key: "{{ openshift_api_key }}"
      validate_certs: "{{ openshift_validate_certs }}"
  tasks:
    - name: Create project for application
      redhat.openshift.openshift_project:
        name: myapp-production
        display_name: "My Application - Production"
        description: "Production environment for MyApp"
        state: present

- name: Set resource quotas kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: ResourceQuota metadata: name: compute-quota namespace: myapp-production spec: hard: requests.cpu: "8" requests.memory: "16Gi" limits.cpu: "16" limits.memory: "32Gi" pods: "50"

- name: Set limit ranges kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: LimitRange metadata: name: default-limits namespace: myapp-production spec: limits: - type: Container default: cpu: "500m" memory: "512Mi" defaultRequest: cpu: "100m" memory: "128Mi"

- name: Configure network policy kubernetes.core.k8s: state: present definition: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-same-namespace namespace: myapp-production spec: podSelector: {} ingress: - from: - podSelector: {} policyTypes: - Ingress

Application Deployment

Deploy a Complete Application Stack

---
- name: Deploy application to OpenShift
  hosts: localhost
  vars:
    app_name: myapp
    app_namespace: myapp-production
    app_image: "registry.example.com/myapp:{{ app_version | default('latest') }}"
    app_replicas: 3
  module_defaults:
    group/kubernetes.core.k8s:
      host: "{{ openshift_host }}"
      api_key: "{{ openshift_api_key }}"
      validate_certs: "{{ openshift_validate_certs }}"
  tasks:
    - name: Create ConfigMap
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: ConfigMap
          metadata:
            name: "{{ app_name }}-config"
            namespace: "{{ app_namespace }}"
          data:
            APP_ENV: production
            LOG_LEVEL: warn
            DB_HOST: postgresql.{{ app_namespace }}.svc.cluster.local
            DB_PORT: "5432"

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

- name: Deploy application kubernetes.core.k8s: state: present definition: apiVersion: apps/v1 kind: Deployment metadata: name: "{{ app_name }}" namespace: "{{ app_namespace }}" labels: app: "{{ app_name }}" version: "{{ app_version | default('latest') }}" spec: replicas: "{{ app_replicas }}" selector: matchLabels: app: "{{ app_name }}" strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: "{{ app_name }}" spec: containers: - name: "{{ app_name }}" image: "{{ app_image }}" ports: - containerPort: 8080 name: http envFrom: - configMapRef: name: "{{ app_name }}-config" - secretRef: name: "{{ app_name }}-secrets" resources: requests: cpu: 200m memory: 256Mi limits: cpu: "1" memory: 1Gi readinessProbe: httpGet: path: /health/ready port: 8080 initialDelaySeconds: 10 periodSeconds: 5 livenessProbe: httpGet: path: /health/live port: 8080 initialDelaySeconds: 30 periodSeconds: 10 securityContext: runAsNonRoot: true allowPrivilegeEscalation: false capabilities: drop: - ALL

- name: Create Service kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: Service metadata: name: "{{ app_name }}" namespace: "{{ app_namespace }}" spec: selector: app: "{{ app_name }}" ports: - port: 8080 targetPort: http name: http

- name: Create Route (OpenShift-specific) redhat.openshift.openshift_route: name: "{{ app_name }}" namespace: "{{ app_namespace }}" service: "{{ app_name }}" tls: termination: edge insecure_policy: Redirect host: "{{ app_name }}.apps.ocp.example.com" state: present

- name: Wait for deployment rollout kubernetes.core.k8s_info: api_version: apps/v1 kind: Deployment name: "{{ app_name }}" namespace: "{{ app_namespace }}" register: deployment_status until: - deployment_status.resources[0].status.readyReplicas is defined - deployment_status.resources[0].status.readyReplicas == app_replicas retries: 30 delay: 10

- name: Display route URL ansible.builtin.debug: msg: "Application deployed at https://{{ app_name }}.apps.ocp.example.com"

See also: Install Minikube with Ansible Role on All Hosts

BuildConfig and ImageStream

---
- name: Configure OpenShift builds
  hosts: localhost
  module_defaults:
    group/kubernetes.core.k8s:
      host: "{{ openshift_host }}"
      api_key: "{{ openshift_api_key }}"
  tasks:
    - name: Create ImageStream
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: image.openshift.io/v1
          kind: ImageStream
          metadata:
            name: myapp
            namespace: myapp-production

- name: Create BuildConfig (Source-to-Image) kubernetes.core.k8s: state: present definition: apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: name: myapp-build namespace: myapp-production spec: source: type: Git git: uri: "https://github.com/myorg/myapp.git" ref: main strategy: type: Source sourceStrategy: from: kind: ImageStreamTag namespace: openshift name: "python:3.11-ubi9" output: to: kind: ImageStreamTag name: "myapp:latest" triggers: - type: ConfigChange - type: GitHub github: secret: "{{ vault_github_webhook_secret }}"

- name: Start a build redhat.openshift.openshift_build: name: myapp-build namespace: myapp-production build_type: Source wait: true wait_timeout: 600

Horizontal Pod Autoscaler

- name: Configure autoscaling
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: autoscaling/v2
      kind: HorizontalPodAutoscaler
      metadata:
        name: myapp-hpa
        namespace: myapp-production
      spec:
        scaleTargetRef:
          apiVersion: apps/v1
          kind: Deployment
          name: myapp
        minReplicas: 3
        maxReplicas: 20
        metrics:
          - type: Resource
            resource:
              name: cpu
              target:
                type: Utilization
                averageUtilization: 70
          - type: Resource
            resource:
              name: memory
              target:
                type: Utilization
                averageUtilization: 80

See also: Ansible vs Kubernetes: Key Differences & When to Use Each (2026 Guide)

Operator Management

---
- name: Install and manage operators
  hosts: localhost
  module_defaults:
    group/kubernetes.core.k8s:
      host: "{{ openshift_host }}"
      api_key: "{{ openshift_api_key }}"
  tasks:
    - name: Create operator subscription
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: operators.coreos.com/v1alpha1
          kind: Subscription
          metadata:
            name: elasticsearch-operator
            namespace: openshift-operators
          spec:
            channel: stable
            name: elasticsearch-operator
            source: redhat-operators
            sourceNamespace: openshift-marketplace
            installPlanApproval: Automatic

- name: Wait for operator to install kubernetes.core.k8s_info: api_version: operators.coreos.com/v1alpha1 kind: ClusterServiceVersion namespace: openshift-operators label_selectors: - "operators.coreos.com/elasticsearch-operator.openshift-operators" register: csv_status until: - csv_status.resources | length > 0 - csv_status.resources[0].status.phase == "Succeeded" retries: 30 delay: 10

Day-2 Operations

Certificate Rotation

---
- name: Rotate application certificates
  hosts: localhost
  tasks:
    - name: Update TLS secret with new certificate
      kubernetes.core.k8s:
        state: present
        force: true
        definition:
          apiVersion: v1
          kind: Secret
          metadata:
            name: myapp-tls
            namespace: myapp-production
          type: kubernetes.io/tls
          data:
            tls.crt: "{{ lookup('file', 'certs/new-cert.pem') | b64encode }}"
            tls.key: "{{ lookup('file', 'certs/new-key.pem') | b64encode }}"

- name: Trigger rolling restart to pick up new certs kubernetes.core.k8s: state: present definition: apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: myapp-production spec: template: metadata: annotations: kubectl.kubernetes.io/restartedAt: "{{ ansible_date_time.iso8601 }}"

Backup and Restore

---
- name: Backup OpenShift resources
  hosts: localhost
  vars:
    backup_dir: "/backups/openshift/{{ ansible_date_time.date }}"
    namespaces:
      - myapp-production
      - myapp-staging
  tasks:
    - name: Create backup directory
      ansible.builtin.file:
        path: "{{ backup_dir }}"
        state: directory
        mode: "0750"

- name: Export namespace resources kubernetes.core.k8s_info: api_version: "{{ item.1 }}" kind: "{{ item.0 }}" namespace: "{{ ns }}" loop: "{{ ['Deployment', 'Service', 'ConfigMap', 'Secret', 'Route'] | product(['v1', 'apps/v1', 'route.openshift.io/v1']) | list }}" loop_control: label: "{{ item.0 }}" vars: ns: "{{ namespaces[0] }}" register: resources failed_when: false

- name: Save resources to files ansible.builtin.copy: content: "{{ item.resources | to_nice_yaml }}" dest: "{{ backup_dir }}/{{ item.item.0 | lower }}.yaml" loop: "{{ resources.results | selectattr('resources', 'defined') | list }}" loop_control: label: "{{ item.item.0 }}" when: item.resources | length > 0

Monitoring and Health Checks

---
- name: OpenShift cluster health check
  hosts: localhost
  tasks:
    - name: Check node status
      kubernetes.core.k8s_info:
        api_version: v1
        kind: Node
      register: nodes

- name: Report unhealthy nodes ansible.builtin.debug: msg: "WARNING: Node {{ item.metadata.name }} is NotReady" loop: "{{ nodes.resources }}" loop_control: label: "{{ item.metadata.name }}" when: >- item.status.conditions | selectattr('type', 'equalto', 'Ready') | map(attribute='status') | first != 'True'

- name: Check cluster operators kubernetes.core.k8s_info: api_version: config.openshift.io/v1 kind: ClusterOperator register: cluster_operators

- name: Report degraded operators ansible.builtin.debug: msg: "DEGRADED: {{ item.metadata.name }}" loop: "{{ cluster_operators.resources }}" loop_control: label: "{{ item.metadata.name }}" when: >- item.status.conditions | selectattr('type', 'equalto', 'Degraded') | map(attribute='status') | first == 'True'

Frequently Asked Questions

How do I authenticate Ansible with OpenShift?

Use an API token (oc whoami -t), a kubeconfig file, or a service account token. For automation, create a dedicated service account with appropriate RBAC roles and use its token.

What is the difference between kubernetes.core and redhat.openshift collections?

kubernetes.core provides modules for standard Kubernetes resources (deployments, services, configmaps). redhat.openshift adds OpenShift-specific modules for routes, builds, projects, and OpenShift-specific resources. Use both together.

Can I manage multiple OpenShift clusters from one Ansible playbook?

Yes. Use different connection parameters per task or leverage inventory groups with cluster-specific variables. The kubeconfig parameter or host/api_key can be set per-task.

How do I handle OpenShift upgrades with Ansible?

OpenShift cluster upgrades are managed through the Cluster Version Operator (CVO). Use Ansible to trigger upgrades via the kubernetes.core.k8s module to patch the ClusterVersion resource, then monitor the upgrade progress.

What RBAC permissions does Ansible need in OpenShift?

At minimum, create a service account with edit or admin role in target namespaces. For cluster-wide operations (nodes, operators, namespaces), use cluster-admin or custom ClusterRoles.

Related Articles

Ansible Kubernetes Automation Enterprise GuideAnsible Container Security AutomationAnsible CI CD Pipeline IntegrationAnsible Execution Environments

Conclusion

Ansible and OpenShift together create a powerful enterprise platform for cloud-native automation. From provisioning projects and deploying applications to managing operators and running day-2 operations, Ansible brings infrastructure-as-code consistency to your OpenShift environment. Use the patterns in this guide as building blocks for your own automation — start with deployment workflows, add health checks, then expand to operator management and cluster-wide automation.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home