Ansible'da Python Interpreter Not Found Hatası

Selamlar arkadaşlar, bu yazımda Ansible kullananların eninde sonunda karşısına çıkan o klasik hatayı, yani 'python interpreter not found' veya 'ansible-core requires a minimum of Python version 3.8' uyarısını biraz didikleyeceğiz. Konu sıkıcı gibi durabilir ama açıkçası bu hatanın bir kere doğru çözüldüğünü gördüğünüzde, fresh bir VM ya da minimal container karşınıza çıktığında elin ayağın titremiyor. Hadi başlayalım.

Hata neden çıkıyor?

Ansible'ın çoğu modülü aslında hedef makineye SSH ile push edilen ufak Python script'leri. Yani kontrol makinenizde Ansible olsa bile, asıl iş hedef sunucudaki Python yorumlayıcıyla yapılıyor. Hedefte Python yoksa veya Ansible onu beklenen yerde bulamıyorsa şuna benzer bir mesaj alıyorsunuz:

[WARNING]: No python interpreters found for host server1
fatal: [server1]: FAILED! => {
    "msg": "ansible-core requires a minimum of Python version 3.8. Current version: None"
}

Bence en sık tetikleyen üç senaryo şunlar: minimal kurulu cloud image'ları (özellikle Ubuntu minimal, Debian slim), Alpine tabanlı container'lar ve eski RHEL/CentOS sistemleri. RHEL 8 mesela /usr/libexec/platform-python diye bir şey kullanıyor ve auto-discovery bazen bunu seçince paket modülleri huysuzlanıyor.

ansible_python_interpreter ile yolu sabitlemek

En hızlı çözüm interpreter yolunu inventory'de açıkça yazmak. Bunu host bazında veya grup bazında verebilirsiniz:

[all:vars]
ansible_python_interpreter=/usr/bin/python3

[webservers]
server1 ansible_host=10.0.1.10 ansible_python_interpreter=/usr/bin/python3.11

[alpine_hosts]
alpine1 ansible_python_interpreter=/usr/bin/python3

Tabii her host'a tek tek yol yazmak istemiyorsanız ansible.cfg üzerinden auto-discovery'yi de açabilirsiniz:

[defaults]
interpreter_python = auto_silent

auto_silent yerine auto da seçebilirsiniz, fark sadece uyarı satırının basılıp basılmaması. Modern Ansible sürümlerinde INTERPRETER_PYTHON_DISTRO_MAP denen bir iç tablo var; Ansible hedefin distro ve sürümüne bakıp 'bu sistemde Python muhtemelen şuradadır' diyor. Çoğu zaman doğru tahmin ediyor ama RHEL 8 platform-python meselesinde benim tercihim auto'ya güvenmek yerine yolu sabitlemek olur.

raw modülü ile bootstrap

Peki ya hedef makinede gerçekten Python yoksa? İşte bu noktada raw modülü hayat kurtarıyor. Çünkü raw Python beklemez, doğrudan SSH üzerinden komut çalıştırır:

- hosts: new_servers
  gather_facts: false
  become: true
  tasks:
    - name: Hedefte Python kuralim
      raw: |
        if command -v apt-get >/dev/null; then
          apt-get update && apt-get install -y python3 python3-apt
        elif command -v dnf >/dev/null; then
          dnf install -y python3
        elif command -v apk >/dev/null; then
          apk add --no-cache python3
        fi

    - name: Artik fact toplayabiliriz
      setup:

Buradaki kritik nokta gather_facts: false. Eğer bunu kapatmazsanız Ansible playbook'un en başında fact toplamak için Python aramaya kalkar ve daha ilk task çalışmadan patlarsınız. Önce raw ile Python'u kuruyoruz, sonra setup modülünü manuel çağırıp fact'leri topluyoruz. Bana sorarsanız bu sıralamayı her bootstrap rolünde standart hale getirmek lazım.

Container'lar için de hikaye benzer:

- hosts: containers
  gather_facts: false
  vars:
    ansible_python_interpreter: /usr/bin/python3
  pre_tasks:
    - name: Container'a Python kur
      raw: apt-get update && apt-get install -y python3

Fact caching ile aynı acıyı tekrar tekrar çekmemek

Bootstrap aşamasını geçtikten sonra her playbook çalıştırışınızda fact toplamak hem yavaş hem de gereksiz. ansible.cfg üzerinden fact caching'i açın:

[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400

smart modu, fact'i daha önce toplanmış host'lar için tekrar toplamıyor. Production'da Redis backend'ini de tercih edebilirsiniz ama jsonfile küçük envanterler için fazlasıyla yeterli.

Sık karşılaşılan tuzaklar

  • gather_facts: false unutmak: Bootstrap playbook'unda bunu kapatmazsanız, Python yoksa setup modülü hata verir, raw task'ınıza hiç sıra gelmez.
  • python3-apt'ı atlamak: Debian/Ubuntu'da apt modülü python3-apt paketine bağımlı. Sadece python3 kurarsanız sonraki paket task'ları 'Could not import python modules: apt, apt_pkg' diye çığlık atar.
  • platform-python'a güvenmek: RHEL 8'de auto-discovery bazen /usr/libexec/platform-python seçer ve dnf modülü dışındaki paket işlerinde tuhaflıklar olur. Açık /usr/bin/python3 sabitlemesi daha öngörülebilir.
  • Alpine'da python3 yerine python aramak: Alpine'da binary doğrudan python3. python symlink'i yok, ansible_python_interpreter=/usr/bin/python yazarsanız bulamaz.

Kapanış

Özetle, bu hatanın iki kalıcı çözümü var: ya interpreter yolunu inventory'de sabitleyin, ya da Python'u raw modülü ile kurup sonra normal akışa devam edin. Şahsi kanaatim, fresh sunucularda bootstrap rolünü her zaman ayrı tutmak ve fact caching'i baştan açmak uzun vadede en az dert çıkaran yol. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.