Introduction
2026's AI infrastructure challenge isn't just buying GPUs — it's balancing model choice, inference cost, deployment architecture, and token economics. Deloitte calls this an "AI infrastructure reckoning." Ansible automates GPU cluster lifecycle, model serving deployment, multi-model routing, cost optimization, and capacity planning.
GPU Cluster Provisioning
---
- name: Provision GPU cluster
hosts: gpu_nodes
become: true
tasks:
- name: Install NVIDIA driver
ansible.builtin.package:
name: "nvidia-driver-{{ nvidia_driver_version | default('560') }}"
state: present
notify: Reboot for driver
- name: Install CUDA toolkit
ansible.builtin.package:
name: "cuda-toolkit-{{ cuda_version | default('12-6') }}"
state: present
- name: Install cuDNN
ansible.builtin.package:
name: libcudnn9-cuda-12
state: present
- name: Install NCCL (multi-GPU communication)
ansible.builtin.package:
name: libnccl2
state: present
- name: Verify GPU inventory
ansible.builtin.command: >
nvidia-smi --query-gpu=index,name,memory.total,driver_version
--format=csv,noheader
register: gpu_inventory
changed_when: false
- name: Report GPU fleet status
ansible.builtin.debug:
msg: |
Host: {{ inventory_hostname }}
GPUs:
{{ gpu_inventory.stdout }}
- name: Set GPU persistence mode
ansible.builtin.command: nvidia-smi -pm 1
changed_when: false
- name: Configure GPU clock speeds for inference
ansible.builtin.command: >
nvidia-smi -lgc {{ gpu_min_clock }},{{ gpu_max_clock }}
when: gpu_clock_lock | default(false)
changed_when: false
handlers:
- name: Reboot for driver
ansible.builtin.reboot:
reboot_timeout: 600
NVIDIA Triton Inference Server
- name: Deploy Triton Inference Server
hosts: inference_servers
become: true
vars:
triton_version: "24.09"
model_repo: /opt/triton/models
tasks:
- name: Create model repository
ansible.builtin.file:
path: "{{ model_repo }}/{{ item }}/1"
state: directory
loop: "{{ triton_models }}"
- name: Deploy model configurations
ansible.builtin.template:
src: "triton/{{ item }}/config.pbtxt.j2"
dest: "{{ model_repo }}/{{ item }}/config.pbtxt"
loop: "{{ triton_models }}"
- name: Deploy Triton container
community.docker.docker_container:
name: triton
image: "nvcr.io/nvidia/tritonserver:{{ triton_version }}-py3"
state: started
restart_policy: unless-stopped
ports:
- "8000:8000" # HTTP
- "8001:8001" # gRPC
- "8002:8002" # Metrics
volumes:
- "{{ model_repo }}:/models"
command: "tritonserver --model-repository=/models --log-verbose=0"
device_requests:
- driver: nvidia
count: -1
capabilities: [[gpu]]
- name: Wait for Triton ready
ansible.builtin.uri:
url: http://localhost:8000/v2/health/ready
register: triton_health
until: triton_health.status == 200
retries: 30
delay: 5
- name: Verify loaded models
ansible.builtin.uri:
url: http://localhost:8000/v2/models
register: loaded_models
- name: Display model status
ansible.builtin.debug:
msg: "Loaded: {{ loaded_models.json.models | map(attribute='name') | list }}"
Multi-Model Routing (Cost Optimization)
- name: Deploy model router for cost optimization
hosts: api_gateway
become: true
tasks:
- name: Deploy model router configuration
ansible.builtin.template:
src: model-router.yml.j2
dest: /opt/model-router/config.yml
notify: Restart model router
- name: Deploy model router service
community.docker.docker_container:
name: model-router
image: "{{ model_router_image }}"
state: started
ports: ["8080:8080"]
volumes:
- /opt/model-router/config.yml:/app/config.yml
{# templates/model-router.yml.j2 #}
# Route requests to cheapest adequate model
models:
- name: gpt-4o
endpoint: https://api.openai.com/v1
cost_per_1k_tokens: 0.005
quality_tier: premium
max_tokens: 128000
- name: llama-3.1-70b
endpoint: http://{{ hostvars[groups['inference_servers'][0]]['ansible_host'] }}:8000/v1
cost_per_1k_tokens: 0.0002
quality_tier: standard
max_tokens: 8192
- name: llama-3.1-8b
endpoint: http://{{ hostvars[groups['inference_servers'][1]]['ansible_host'] }}:8000/v1
cost_per_1k_tokens: 0.00005
quality_tier: economy
max_tokens: 8192
routing_rules:
- match: { complexity: high, quality: premium }
model: gpt-4o
- match: { complexity: medium }
model: llama-3.1-70b
- match: { complexity: low }
model: llama-3.1-8b
- default: llama-3.1-70b
budget:
daily_limit_usd: {{ ai_daily_budget | default(100) }}
alert_threshold: 0.8
GPU Monitoring and Autoscaling
- name: Deploy GPU monitoring
hosts: gpu_nodes
become: true
tasks:
- name: Deploy DCGM exporter
community.docker.docker_container:
name: dcgm-exporter
image: nvcr.io/nvidia/k8s/dcgm-exporter:latest
state: started
ports: ["9400:9400"]
device_requests:
- driver: nvidia
count: -1
capabilities: [[gpu]]
- name: Deploy GPU utilization alerting
ansible.builtin.template:
src: gpu-alerts.yml.j2
dest: /etc/prometheus/rules/gpu-alerts.yml
notify: Reload Prometheus
delegate_to: "{{ monitoring_host }}"
{# templates/gpu-alerts.yml.j2 #}
groups:
- name: gpu_alerts
rules:
- alert: GPUHighUtilization
expr: DCGM_FI_DEV_GPU_UTIL > 95
for: 10m
labels: { severity: warning }
annotations:
summary: "GPU {{ $labels.gpu }} on {{ $labels.instance }} above 95%"
- alert: GPUMemoryExhausted
expr: DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_FREE > 0.95
for: 5m
labels: { severity: critical }
- alert: GPUTemperature
expr: DCGM_FI_DEV_GPU_TEMP > 85
for: 5m
labels: { severity: critical }
- alert: InferenceLatencyHigh
expr: histogram_quantile(0.99, rate(inference_duration_seconds_bucket[5m])) > 2
for: 5m
labels: { severity: warning }
Capacity Planning
- name: GPU capacity audit
hosts: gpu_nodes
become: true
tasks:
- name: Collect GPU metrics
ansible.builtin.command: >
nvidia-smi --query-gpu=name,memory.total,memory.used,utilization.gpu,temperature.gpu,power.draw
--format=csv,noheader,nounits
register: gpu_metrics
changed_when: false
- name: Calculate fleet capacity
ansible.builtin.set_fact:
gpu_data: >-
{{ gpu_data | default([]) + [{
'host': inventory_hostname,
'gpu': item.split(',')[0] | trim,
'mem_total_mb': item.split(',')[1] | trim | int,
'mem_used_mb': item.split(',')[2] | trim | int,
'util_pct': item.split(',')[3] | trim | int,
'temp_c': item.split(',')[4] | trim | int,
'power_w': item.split(',')[5] | trim | float
}] }}
loop: "{{ gpu_metrics.stdout_lines }}"
- name: Generate capacity report
ansible.builtin.template:
src: gpu-capacity.j2
dest: /tmp/gpu-capacity-report.json
delegate_to: localhost
run_once: true
Related Articles
Conclusion
AI infrastructure in 2026 is about optimization, not just procurement. Ansible automates the full stack: GPU provisioning with driver pinning and clock management, Triton/vLLM model serving, multi-model routing for cost optimization, DCGM monitoring with utilization alerts, and fleet capacity planning. The key insight: treat inference infrastructure like any other fleet — provision it declaratively, monitor it continuously, and optimize costs by routing to the cheapest adequate model. Ansible makes the "AI infrastructure reckoning" manageable at scale.