26 Temmuz 2026 Pazar

Ansible değişkenlerini doğru yerde tutmak

Ansible Değişkenlerini Doğru Yerde Tutmak

Ansible · Değişkenler

Ansible değişkenlerini doğru yerde tutmak

Ansible'da 22 farklı değişken katmanı var. Asıl soru “hangisi kazanır?” değil — belgelerde yazıyor. Asıl soru şu: bu değişkeni nereye koymalıyım?

Ansible öğrenirken herkesin karşılaştığı bir an vardır: bir değişkeni değiştirirsiniz ama hiçbir şey olmaz. Başka bir yerde tanımlı aynı isimli değişken sizinkini eziyordur. Bu noktada çoğu kişi öncelik tablosunu ezberlemeye çalışır. Oysa tabloyu ezberlemek semptomu tedavi eder; hastalığı değil.

Hastalık şu: değişkeni ne olduğuna değil, o an aklınıza gelen yere koymak. Bu yazıda gerçek bir projeden — RHEL 9 ve RHEL 10 için osbuild-composer ile imaj üreten bir rolden — örneklerle, bir değişkenin yerini nasıl belirleyeceğinizi anlatacağım. Kendi yaptığım hatayı da göstereceğim.

Önce kısa hatırlatma: öncelik sırası

Ansible değişkenleri en düşükten en yükseğe doğru şu sırayla uygular. Sondakiler öncekileri ezer:

#KatmanNe zaman kullanılır
2Rol defaults/Rolün makul varsayılanı
3Envanter dosyasındaki grup değişkenleriNadiren; dağınık olur
4Envanter group_vars/allTüm makinelere ortak makine bilgisi
5Playbook group_vars/allPlaybook'a özgü, tüm gruplara
6Envanter group_vars/*Ortama/gruba özgü makine bilgisi
7Playbook group_vars/*Playbook'un gruba özgü zorlaması
9Envanter host_vars/*Tek makineye özgü
11Facts ve set_factÇalışma anında keşfedilen
12Play vars:Playbook'un kendi bağlamı
15Rol vars/Rolün ezilmemesi gereken sabitleri
18include_varsKoşullu yükleme (ör. sürüme göre)
22-e extra varsTek çalıştırmaya özgü; her şeyi ezer

Dikkat edilecek iki nokta var. Birincisi: group_vars/ ve host_vars/ iki ayrı yerde bulunabilir — envanterin yanında ve playbook'un yanında. İkincisi: playbook'un yanındaki, envanterinkini ezer.

Bunu kanıtlayalım

İddiaya güvenmeyin, ölçün. Üç katmanda aynı değişkeni tanımlayıp tek tek kaldıralım:

$ tree
├── inventory/
│   ├── hosts.yml
│   └── group_vars/all.yml        → nereden: "2-INVENTORY group_vars/all"
├── group_vars/all.yml            → nereden: "3-PLAYBOOK group_vars/all"
├── roles/demo/defaults/main.yml  → nereden: "1-ROLE defaults"
└── pb.yml
$ ansible-playbook -i inventory/hosts.yml pb.yml
kazanan -> 3-PLAYBOOK group_vars/all

$ rm group_vars/all.yml && ansible-playbook ...
kazanan -> 2-INVENTORY group_vars/all

$ rm inventory/group_vars/all.yml && ansible-playbook ...
kazanan -> 1-ROLE defaults
Playbook group_vars > envanter group_vars > rol defaults. Beklendiği gibi.

Pratik ipucu. Bir değerin nereden geldiğini merak ettiğinizde tahmin etmeyin: ansible-inventory --graph --vars ve ansible-inventory --host <makine> size envanterden gelenlerin tamamını gösterir. Rol katmanları için de ansible-playbook --list-tasks ve bir debug görevi en hızlı yoldur.

Asıl soru: bu değişken neyi tarif ediyor?

Karar kuralı bu kadar basit. Değişkenin adına değil, anlamına bakın:

Değişken neyi tarif ediyor?YeriNeden
Makineyi / ortamı
“RHEL 9 sunucusu şudur”
Envanter group_vars/ Envanterle birlikte seyahat eder. Aynı envanteri kullanan her playbook aynı bilgiyi alır.
Rolün makul varsayılanını
“aksi söylenmedikçe böyle davran”
Rol defaults/ En düşük öncelik = her katmandan ezilebilir. Rol kendi kendine yeter hale gelir.
Playbook'un kendi bağlamını
“çıktıları buraya yaz”
Play vars: Hedef makineyle ilgisi yoktur; envantere konursa yanlış yere yayılır.
Bu çalıştırmaya özgü seçimi
“şimdi RHEL 10 üret”
-e Her şeyi ezer, kalıcı değildir. Tam da geçici seçim için.
Ezilmemesi gerekeni
iç sabitler, eşleme tabloları
Rol vars/ Yüksek önceliklidir; kullanıcının kazara ezmesini istemediğiniz şeyler.

Gerçek bir örnek: osbuild imaj üretim rolü

Bu rol, parametre alarak RHEL 9 veya RHEL 10 için ISO / qcow2 / vmdk imajları üretiyor:

ansible-playbook build-image.yml \
  -e rhel_version=10 -e image_template=devel \
  -e '{"image_types":["qcow2","vmdk"]}'

rhel_version doğrudan hedef grubu seçiyor: RHEL 9 imajı RHEL 9 sunucusunda üretilmeli, çünkü osbuild-composer kendi host sürümünü varsayılan distro olarak alır.

Envanterde ne var

# inventory/group_vars/osbuild_rhel10.yml
ansible_user: remzi
ansible_become: true
osbuild_expected_major: "10"
osbuild_extra_sources:
  - id: crb
    url: https://cdn.redhat.com/.../codeready-builder/os
    required_for_templates: ["devel"]

Bunların hepsi makineyi tarif ediyor. “RHEL 10 sunucusunda CRB deposu gerekir” bilgisi, hangi playbook'u çalıştırdığınızdan bağımsızdır. Yarın bir cleanup.yml yazarsanız o da aynı envanteri kullanıp aynı bilgiyi alır.

Rol varsayılanlarında ne var

# roles/osbuild_image/defaults/main.yml
run_boot_test: true
enable_kdump: true
kdump_crashkernel: "2G-64G:256M,64G-:512M"
min_free_gib: {minimal: 12, devel: 30}

lvm_volumes:
  - {name: rootlv,     mount: /,          size_gib: 30, label: root}
  - {name: varcrashlv, mount: /var/crash, size_gib: 2,  label: var_crash}
  # ... 11 mantıksal birim

Disk şeması burada olmalı, çünkü rolün ne ürettiğini tarif ediyor. Üstelik tek kaynak olması sayesinde hem customizations.disk (qcow2/vmdk) hem de kickstart logvol satırları (ISO) aynı listeden üretiliyor — ikisinin birbirinden ayrışması yapısal olarak imkânsız hale geliyor.

Playbook'ta ne var

# build-image.yml
  vars:
    image_fetch_dir: "{{ playbook_dir }}/imajlar"
    artifact_dir: "{{ playbook_dir }}/artifacts"

Bunlar kontrol makinesinin yolları. Hedef sunucuyla hiçbir ilgileri yok. Ayrıca playbook_dir ancak playbook bağlamında anlamlıdır — envantere koyarsanız, aynı envanter başka bir dizinden kullanıldığında yanlış çözülür.

Benim yaptığım hata

İlk versiyonda politika değişkenlerinin hepsini envanterin group_vars/all.yml dosyasına koymuştum:

# inventory/group_vars/all.yml   ← YANLIŞ
run_boot_test: true
enable_kdump: true
min_free_gib: {minimal: 12, devel: 30}
compose_timeout_min: 90
image_fetch_dir: "{{ playbook_dir }}/imajlar"

Çalışıyordu. Ama iki gerçek sakıncası vardı:

  1. Ezme zinciri yanlış yerden başlıyordu. enable_kdump rolün varsayılanı olmalıydı. Envantere konunca rol defaults'ı sessizce eziliyor ve rol tek başına anlamsız hale geliyor — birisi rolü başka bir projede kullanmak istese, hangi değişkenleri tanımlaması gerektiğini bilemez.
  2. İkinci bir ortam eklendiğinde kopyalama zorunluluğu. inventory/prod/ ve inventory/test/ açtığınızda, ortamla hiç ilgisi olmayan politika değişkenlerini de iki kez yazmanız gerekir. Kopya olan yerde er geç ikisi birbirinden ayrışır.

Düzeltilmiş hali:

DeğişkenÖnceSonra
ansible_user, osbuild_extra_sourcesenvanter group_varsaynı — doğruydu
enable_kdump, run_boot_test, min_free_gibenvanter group_vars/allrol defaults
image_fetch_dir, artifact_direnvanter group_vars/allplay vars:
rhel_version, image_types-eaynı — doğruydu

Envanterin group_vars/all.yml dosyası artık boş — ama silmedim. İleride gerçekten tüm makinelere ortak bir makine ayarı gerektiğinde (proxy, zaman sunucusu, ortak depo) yeri orasıdır. Dosyanın içine bunu bir yorum olarak yazdım; boş bir dosyadan çok, niyeti belgelenmiş bir dosya bırakmak daha iyidir.

Sürüme göre değişenler: include_vars

Bu projede öğrendiğim en değerli şeylerden biri, sürüm farklarını veri olarak tutmaktı. RHEL 10'da kdump, kexec-tools paketinden ayrılıp kdump-utils'e taşınmış. Bunu göreve gömmek yerine:

- name: "Sürüme özel değişkenleri yükle"
  ansible.builtin.include_vars:
    file: "rhel{{ rhel_version }}.yml"

Böylece vars/rhel9.yml ve vars/rhel10.yml sürüm farklarını taşır, görevler sürümden bağımsız kalır. include_vars'ın önceliği yüksektir (18. sıra) — bu tam olarak istediğimiz şey: sürüme özgü veri, genel varsayılanı ezmeli.

Daha da iyisi: bu projede kdump paketini sabit yazmak yerine çalışma anında sorduk — dnf repoquery --file /usr/lib/systemd/system/kdump.service. Sonuç: RHEL 9'da kexec-tools, RHEL 10'da kdump-utils bulundu, hiçbir yere sabit yazılmadan. Değişkene hiç gerek kalmadı. En iyi değişken, yazmak zorunda kalmadığınız değişkendir.

Kaçınılması gereken üç tuzak

1. set_fact tipi sessizce değiştirir

Bir JSON dosyasını okuyup metin araması yapmak istedim:

- set_fact:
    manifest_text: "{{ manifest_raw.content | b64decode }}"

- assert:
    that: "'org.osbuild.lvm2.create' in manifest_text"   # her zaman False!

İçerik JSON'a benzediği için Ansible onu otomatik olarak dict'e çevirdi. Dolayısıyla in operatörü metin değil anahtar araması yaptı. Aradığım şey dosyada vardı ama testi hiç geçmiyordu. Çözüm: metin araması yerine from_json ile ayrıştırıp yapısal denetim yapmak.

2. delegate_to bağlantı değişkenlerini değiştirir

- command: "{{ 'cp ...' if ansible_connection == 'local' else 'scp ...' }}"
  delegate_to: localhost      # ← ansible_connection artık 'local'!

Delegasyon yapılan görevde ansible_connection, delegasyon hedefinin bağlantı türüdür. Asıl hedefin bilgisini kullanacaksanız, onu delegasyondan önce bir set_fact ile saklayın. Bu hatayı fark etmem, aynı kodun bir sunucuda çalışıp diğerinde patlamasını görmemi gerektirdi.

3. -e geri alınamaz

Extra vars her şeyi ezer ve playbook içinden değiştirilemez. Bu yüzden -e'yi yalnızca o çalıştırmaya özgü seçimler için kullanın (rhel_version, image_types). Kalıcı politikayı -e ile taşımaya başlarsanız, her çalıştırmada uzun bir komut satırı ezberlemek zorunda kalırsınız — ve bir gün birini yazmayı unutursunuz.

Özet: karar ağacı

SoruCevap
Makineyi/ortamı mı tarif ediyor?Envanter group_vars/ · host_vars/
Rolün makul varsayılanı mı?Rol defaults/
Sürüme/platforma göre mi değişiyor?Rol vars/ + include_vars
Playbook'un kendi bağlamı mı?Play vars:
Bu çalıştırmaya mı özgü?-e
Kullanıcı ezerse bozulur mu?Rol vars/ (defaults değil)

Bu kuralı uyguladığınızda öncelik tablosunu ezberlemenize gerek kalmaz — çünkü çakışma çıkmaz. Tablo, ancak aynı değişkeni birden fazla katmanda tanımladığınızda gerekir; ve bunu yapıyorsanız muhtemelen değişkeni yanlış yere koymuşsunuzdur.

Bu yazıdaki örnekler, RHEL 9 ve RHEL 10 için osbuild-composer ile ISO / qcow2 / vmdk imajları üreten gerçek bir Ansible rolünden alınmıştır. Öncelik sırasının tamamı için: Ansible — Using Variables.

16 Haziran 2026 Salı

Podman'da "unresolvable CDI devices nvidia.com/gpu=all" Hatası ve Çözümü

Podman'da "unresolvable CDI devices nvidia.com/gpu=all" Hatası ve Çözümü

Podman ile GPU gerektiren bir container (örneğin RHEL CLA, ollama, vllm gibi) çalıştırmaya çalışırken şu hatayı alabilirsiniz:

Error: setting up CDI devices: unresolvable CDI devices nvidia.com/gpu=all


















Bu hata, NVIDIA sürücünüz düzgün çalışıyor olsa bile (nvidia-smi çıktısı normal görünse bile) ortaya çıkabilir. Sorunun kaynağı, Podman'ın GPU'ya erişmek için kullandığı CDI (Container Device Interface) spec dosyasının sisteminizde bulunmamasıdır.

CDI Nedir?

CDI, container runtime'larının (Podman, Docker vb.) GPU gibi özel donanımlara erişimini standartlaştıran bir arayüzdür. Podman, --device nvidia.com/gpu=all gibi bir parametre aldığında, /etc/cdi/nvidia.yaml dosyasına bakarak GPU'nun container'a nasıl sunulacağını öğrenir. Bu dosya yoksa veya güncel değilse, yukarıdaki hatayı alırsınız.

Çözüm Adımları

1. NVIDIA Container Toolkit Kurulumu

Öncelikle nvidia-container-toolkit paketinin kurulu olup olmadığını kontrol edin:

rpm -q nvidia-container-toolkit

Kurulu değilse, NVIDIA'nın resmi repo'sunu ekleyip kurun:

curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | \
  sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo

sudo dnf install -y nvidia-container-toolkit

2. CDI Spec Dosyasını Oluşturun

Bu adım sorunun asıl çözümüdür. Aşağıdaki komut, sisteminizde bulunan NVIDIA GPU'ları tarayarak CDI spec dosyasını oluşturur:

sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

3. Doğrulama

Spec'in başarıyla oluşturulduğunu doğrulayın:

nvidia-ctk cdi list

Çıktıda şuna benzer satırlar görmeniz gerekir:

INFO[0000] Found 2 CDI devices
nvidia.com/gpu=0
nvidia.com/gpu=all

4. Container'ı Tekrar Çalıştırın

Artık Podman GPU'yu CDI üzerinden çözebilir durumda. Uygulamanızı tekrar başlatın:

rhel-cla start

Alternatif: Spesifik GPU Belirtme

Eğer gpu=all hâlâ çözülemiyorsa, uygulamanızın yapılandırma dosyasında cihazı spesifik olarak belirtmeyi deneyin:

# nvidia.com/gpu=all yerine:
nvidia.com/gpu=0

Örneğin RHEL CLA için bu ayar ~/.config/rhel-cla/.env dosyasındadır.

Önemli Not

Kernel veya NVIDIA sürücü güncellemesi sonrasında CDI spec dosyası geçersiz hale gelebilir. Sürücü güncellemesi yaptıktan sonra sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml komutunu tekrar çalıştırmayı unutmayın.

Ortam Bilgisi

Bu yazıdaki çözüm aşağıdaki ortamda test edilmiştir:

  • Fedora / RHEL tabanlı dağıtımlar
  • NVIDIA GeForce RTX 4060 Laptop GPU
  • NVIDIA Driver 595.80, CUDA 13.2
  • Podman (rootless ve rootful)



















Umarım işinize yarar. Sorularınız varsa yorumlarda belirtebilirsiniz.

27 Şubat 2026 Cuma

Ne işe yarar; sar -n DEV

sar -n DEV|awk 'BEGIN{mak=0} !/txpck|x86|CPU|^[ \t]*$/{if (mak<$5) {mak=$5;li=$0}} END{print mak,li;}'

Ansible değişkenlerini doğru yerde tutmak

Ansible Değişkenlerini Doğru Yerde Tutmak Ansible · Değişkenler Ansible değişkenlerini doğru yerde tutmak Ansible'd...