Mastering Cluster Observability with the kubernetes.core.k8s_info Module

The capacity to interact with a Kubernetes cluster is not limited to the deployment of manifests or the modification of state. A critical component of modern platform engineering is the ability to read cluster state, perform configuration audits, and feed real-time resource information into downstream automation tasks. Within the Ansible ecosystem, this capability is realized through the kubernetes.core.k8s_info module. Far from being a simple "get" command, this module serves as a sophisticated query engine that interfaces directly with the Kubernetes API to return structured data. This allows engineers to transition from "blind" automation—where changes are applied regardless of the current state—to "intelligent" automation, where playbooks respond dynamically to the actual condition of the cluster.

Technical Architecture and Functional Purpose

The kubernetes.core.k8s_info module is designed to query the Kubernetes API and return data in a structured format. This structured data is primarily returned as a list of objects within the resources field of the registered variable. Even when a query is specifically targeting a single resource by its name, the module consistently returns a list. This design choice ensures a predictable data structure for downstream processing, regardless of whether zero, one, or one hundred resources were matched by the query criteria.

By leveraging this module, administrators can transform Ansible from a configuration management tool into a powerful auditing and health-checking framework. The ability to filter, transform, and analyze this data using Jinja2 enables the creation of complex logic, such as identifying degraded deployments, auditing security contexts, or mapping external load balancer services across multiple namespaces.

Prerequisites and Environment Configuration

To successfully implement the kubernetes.core.k8s_info module, a specific set of software dependencies and configurations must be met. Failure to align these dependencies often leads to execution exceptions and module failure.

Required Software Stack

Component Requirement Installation/Command
Ansible Version 2.12+ Distributed via pip or system package managers
Collection kubernetes.core ansible-galaxy collection install kubernetes.core
Python Library kubernetes pip install kubernetes
Authentication Valid kubeconfig Standard ~/.kube/config or specified path

Technical Analysis of Dependencies

The requirement for Ansible 2.12+ is critical because earlier versions lack the full collection integration and updated API handling necessary for modern Kubernetes clusters. The kubernetes Python library acts as the underlying driver; without it, the kubernetes.core collection cannot communicate with the API server.

From a technical standpoint, the kubeconfig file is the administrative bridge. It provides the necessary certificates, tokens, and API endpoints required to authenticate the Ansible controller against the cluster. Without a valid configuration, the module cannot establish a secure handshake with the API, resulting in connection errors.

Detailed Module Parameter Analysis

The kubernetes.core.k8s_info module provides a comprehensive set of parameters to narrow the scope of API queries, reducing the amount of data transferred and increasing the precision of the results.

  • kind: This specifies the type of Kubernetes resource being queried. Examples include Deployment, Pod, Service, or Namespace. This is the primary filter that tells the API which endpoint to hit.
  • api_version: This defines the specific version of the API to use. Because Kubernetes APIs evolve (e.g., apps/v1, v1, networking.k8s.io/v1), specifying the version ensures compatibility and prevents "resource not found" errors during API version transitions.
  • name: This allows the user to target a specific resource by its unique name. When this parameter is used, the result is typically a list containing a single element.
  • namespace: This restricts the search to a specific logical partition of the cluster. If this is omitted, the module may perform a cluster-scoped query or an all-namespace query, depending on the resource kind.
  • label_selectors: This accepts a list of strings used to filter resources based on their labels. This is essential for grouping resources by environment (e.g., env=production) or application (e.g., app=web-api).
  • field_selectors: This allows for deeper filtering based on specific resource fields. The Kubernetes API specifically supports selectors for metadata.name, metadata.namespace, status.phase (specifically for pods), and spec.nodeName.

Implementation Patterns for Resource Querying

Direct Query by Name

The most straightforward use case is retrieving a specific resource to extract its metadata or status. This is often used to verify if a specific application is deployed and healthy.

```yaml

playbook: query-by-name.yml

# Retrieves a specific Deployment by name and extracts key details

  • name: Query specific resource
    hosts: localhost
    connection: local
    gather_facts: false
    tasks:

    • name: Get the web-api deployment
      kubernetes.core.k8sinfo:
      kind: Deployment
      api
      version: apps/v1
      name: web-api
      namespace: production
      register: result

    • name: Show the full resource
      ansible.builtin.debug:
      var: result.resources[0]
      when: result.resources | length > 0

    • name: Handle missing resource
      ansible.builtin.debug:
      msg: "Resource not found"
      when: result.resources | length == 0
      ```

In this implementation, the register: result statement captures the API response. Because the resources field is always a list, the playbook uses result.resources[0] to access the actual object and a when clause to ensure the list is not empty before attempting to access the index.

Advanced Extraction of Resource State

Beyond simple retrieval, the module can be used to extract specific operational metrics, such as the number of ready replicas or the image version currently in use.

```yaml

playbook: get-resource-info.yml

# Retrieves details about a specific Deployment

  • name: Get Kubernetes resource information
    hosts: localhost
    connection: local
    gather_facts: false
    tasks:

    • name: Get deployment details
      kubernetes.core.k8sinfo:
      kind: Deployment
      name: web-api
      namespace: production
      register: deploy
      info

    • name: Display deployment status
      ansible.builtin.debug:
      msg:
      name: "{{ deployinfo.resources[0].metadata.name }}"
      replicas: "{{ deploy
      info.resources[0].spec.replicas }}"
      ready: "{{ deployinfo.resources[0].status.readyReplicas | default(0) }}"
      image: "{{ deploy
      info.resources[0].spec.template.spec.containers[0].image }}"
      created: "{{ deploy.resources[0].metadata.creationTimestamp }}"
      ```

This pattern demonstrates the impact of structured data. By drilling down into spec.template.spec.containers[0].image, an administrator can audit exactly which image version is running in production without manually inspecting the cluster via kubectl.

Data Processing with Jinja2 and Filters

The true power of k8s_info is unlocked when the returned data is processed via Jinja2 filters. This allows the playbook to perform complex calculations and filtering on the fly.

Extracting Names and Identifying Degraded States

When querying all resources in a namespace, the result is a large list. To make this useful, the map and selectattr filters are employed.

```yaml

playbook: process-results.yml

# Demonstrates advanced result processing with Jinja2

  • name: Process query results
    hosts: localhost
    connection: local
    gather_facts: false
    tasks:

    • name: Get all deployments in production
      kubernetes.core.k8sinfo:
      kind: Deployment
      namespace: production
      register: all
      deploys

    • name: Extract just the names
      ansible.builtin.setfact:
      deploy
      names: "{{ all_deploys.resources | map(attribute='metadata.name') | list }}"

    • name: Find deployments with fewer ready replicas than desired
      ansible.builtin.setfact:
      degraded
      deploys: "{{ alldeploys.resources | selectattr('status.readyReplicas', 'defined') | rejectattr('status.readyReplicas', 'equalto', none) | list | jsonquery('[?status.readyReplicas < spec.replicas]') }}"

    • name: Find deployments using a specific image registry
      ansible.builtin.setfact:
      internal
      deploys: "{{ all_deploys.resources | selectattr('spec.template.spec.containers', 'defined') | list }}"

    • name: Extract container images from all deployments
      ansible.builtin.setfact:
      all
      images: "{{ all_deploys.resources | map(attribute='spec.template.spec.containers') | flatten | map(attribute='image') | unique | sort | list }}"
      ```

Technical Breakdown of Data Transformation

  1. Mapping Attributes: The map(attribute='metadata.name') filter transforms a list of complex Kubernetes objects into a simple list of strings containing only the names.
  2. Degraded State Detection: The logic for degraded_deploys uses selectattr and rejectattr to ensure that status.readyReplicas exists and is not null, then applies a json_query to find instances where readyReplicas is less than the desired spec.replicas.
  3. Image Auditing: To find all unique images across a namespace, the playbook maps the container list, flattens the resulting nested list, extracts the image attribute, and then applies unique and sort.

Specialized Query Patterns

Identifying External Load Balancers

A common requirement in cloud environments is to identify all services exposed to the internet. This is achieved by filtering the spec.type attribute of the Service resource.

```yaml
- name: Find services of type LoadBalancer
kubernetes.core.k8sinfo:
kind: Service
register: all
services

  • name: List external services
    ansible.builtin.debug:
    msg: "External: {{ item.metadata.namespace }}/{{ item.metadata.name }} ({{ item.spec.type }})"
    loop: "{{ allservices.resources | selectattr('spec.type', 'equalto', 'LoadBalancer') | list }}"
    loop
    control:
    label: "{{ item.metadata.name }}"
    ```

In this case, the selectattr filter effectively acts as a server-side filter applied client-side, allowing the playbook to isolate only the LoadBalancer services and ignore ClusterIP or NodePort types.

Security Auditing for Pod Contexts

The module can also be used to find resources that are missing critical security configurations, such as a securityContext.

yaml - name: Check for missing security contexts ansible.builtin.debug: msg: "Security risk found" when: result.resources | selectattr('securityContext', 'undefined') | list | length > 0

This pattern allows an organization to implement "Policy as Code" by using Ansible to audit clusters and fail a pipeline if resources are deployed without the required security constraints.

Troubleshooting and Compatibility Issues

Integrating kubernetes.core.k8s_info into legacy environments can present significant challenges, particularly when using outdated versions of Ansible and Python.

Analysis of Failures in Ansible 2.9

Reports indicate that users attempting to use the kubernetes.core.k8s_info module in Ansible 2.9.9 or 2.9.27 often encounter "An exception occurred during task execution." This is typically caused by a combination of the following factors:

  1. Collection Path Mismanagement: Users attempting to manually install collections by untarring files into /home/sac/.ansible/collections/ansible_collections/ often face pathing issues where the Ansible manager cannot locate the module.
  2. Version Mismatch: Ansible 2.9 was released prior to the full maturity of the kubernetes.core collection. While some manual installations might work, the lack of native support for the collection architecture in 2.9 leads to instability.
  3. Python Versioning: Using Python 3.6 on CentOS 7.9 can lead to dependency conflicts with the kubernetes Python library, which may require newer Python versions for certain feature sets.
  4. Host Specification: In some failing cases, users explicitly define the host parameter as an HTTPS URL (e.g., https://api.abc.abc.com:6443) within the task. While the API server endpoint is necessary, the module typically relies on the kubeconfig file for this information rather than a direct parameter in the task.

Resolution Strategy for Legacy Systems

To resolve these issues, users must migrate to Ansible 2.12 or later. If migration is impossible, the focus should be on:
- Ensuring the kubernetes Python library is installed in the same Python environment used by Ansible.
- Verifying that the collection is installed via ansible-galaxy rather than manual folder creation.
- Using the standard kubeconfig authentication method instead of attempting to pass the API URL as a module parameter.

Conclusion: The Shift Toward State-Aware Automation

The kubernetes.core.k8s_info module is the fundamental building block for creating intelligent, state-aware automation. By moving away from declarative "push" models and incorporating "read-and-react" logic, engineers can build playbooks that are significantly more resilient.

The ability to query any resource type, combined with the power of Jinja2 for data transformation, allows Ansible to perform tasks that were previously reserved for custom Python scripts or complex Bash wrappers around kubectl. Whether it is auditing image registries for security compliance, identifying degraded deployments through readyReplicas analysis, or mapping external load balancers, this module provides a standardized, programmatic interface to the Kubernetes API. The transition from basic deployment to comprehensive cluster observability is achieved by mastering the query parameters, understanding the list-based nature of the resources return value, and applying rigorous filtering techniques.

Sources

  1. Ansible k8s_info: Get Kubernetes Resource Info
  2. Ansible k8s_info Module Query Guide
  3. GitHub Issue #635: Unable to use kubernetes.core.k8s_info module in ansible v2.9

Related Posts