SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor

Cara abaikan unreachable host dalam Ansible

Ketahui cara menggunakan ignore_unreachable untuk mengurus hos yang gagal dihubungi. Elakkan ralat play dengan menggabungkan tetapan serial dan max_fail_percentage dengan tepat.

Hos yang tidak boleh dicapai bukanlah tugasan yang gagal

Untuk mengabaikan hos yang tidak boleh dicapai dalam Ansible, anda perlu menetapkan ignore_unreachable: true, dan suis tersebut akan berfungsi. Perkara yang penting ialah mengetahui bila untuk menggunakannya, kerana Ansible mengendalikan dua masalah berbeza dengan dua cara yang berbeza. Tugasan yang dijalankan pada hos dan mengembalikan ralat adalah satu kegagalan. Hos yang tidak dapat dihubungi langsung oleh Ansible adalah tidak boleh dicapai (unreachable). ignore_errors hanya meliputi kes pertama. ignore_unreachable hanya meliputi kes kedua.

Berikut adalah perbezaan dalam ringkasan play.

PLAY RECAP *********************************************************************
web1  : ok=7  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2  : ok=0  changed=0  unreachable=1  failed=0  skipped=0  rescued=0  ignored=0

Ansible telah bersambung ke web1 dan menjalankan tujuh tugasan. web2 menunjukkan unreachable=1 dan failed=0, yang bermaksud tiada apa-apa yang dijalankan pada hos tersebut. Ansible tidak pernah mendapat sambungan, jadi ia mengeluarkan hos tersebut daripada play dan meneruskan tugasan yang lain. Jika play tersebut bertujuan untuk memasang kemas kini keselamatan, salah satu pelayan anda tidak mempunyai kemas kini tersebut.

Punca hos tidak boleh dicapai

Tidak boleh dicapai bermaksud sambungan gagal sebelum sebarang modul sampai ke hos tersebut. Tiada output modul untuk dibaca, hanya ralat sambungan, dan ia muncul pada tugasan pertama yang menyentuh mesin tersebut.

fatal: [web2]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.20 port 22: Connection refused", "unreachable": true}

Medan msg membawa punca sebenar. Berikut adalah punca yang akan anda temui:

  • Connection refused: sambungan TCP ditolak, jadi tiada apa-apa yang mendengar pada port tersebut. sshd telah dihentikan, atau SSH telah dialihkan ke port lain manakala inventori anda masih menyatakan 22.
  • Connection timed out: tiada jawapan langsung. Firewall menggugurkan paket, atau pelayan dimatikan. Setiap percubaan memakan masa tamat sambungan penuh, iaitu 10 saat secara lalai.
  • Host key verification failed.: kunci dalam ~/.ssh/known_hosts tidak sepadan dengan kunci yang dibentangkan oleh pelayan. VPS yang dibina semula mengekalkan alamat IP tetapi mendapat kunci hos baharu, jadi ini dijangkakan selepas pemasangan semula dan merupakan perkara serius pada bila-bila masa lain.
  • Permission denied (publickey): SSH menjawab dan menolak kunci anda. Port adalah betul, jadi ini adalah masalah pengesahan, biasanya ansible_user yang salah atau kunci yang tidak dimuatkan.
  • Timeout (12s) waiting for privilege escalation prompt: sambungan berjaya tetapi become tidak. sudo sedang menunggu kata laluan yang tidak pernah sampai.

Penterjemah Python yang tiada adalah punca yang sering dijangkakan orang dalam senarai itu, namun ia tidak tergolong di situ. SSH bersambung, jadi hos boleh dicapai. Modul kemudiannya tidak mempunyai tempat untuk dijalankan:

fatal: [db1]: FAILED! => {"changed": false, "module_stdout": "/bin/sh: 1: /usr/bin/python3: not found\r\n", "msg": "The module failed to execute correctly, you probably need to set the interpreter", "rc": 127}

Baris itu menyatakan FAILED! dan rekap mengiranya di bawah failed, jadi ignore_unreachable tidak akan menyentuhnya. Tetapkan ansible_python_interpreter untuk hos tersebut, atau pasang python3 padanya.

Cara mengabaikan hos yang tidak boleh dicapai dalam play

Pada peringkat task, kata kunci ini diletakkan bersebelahan dengan modul:

- name: Read the package list, and do not stop if the host is down
  ansible.builtin.command: dpkg -l
  register: packages
  changed_when: false
  ignore_unreachable: true

Pada peringkat play, ia menetapkan nilai lalai untuk setiap task dalam play tersebut, dan satu task individu boleh menetapkannya semula:

- name: Opportunistic fleet maintenance
  hosts: all
  ignore_unreachable: true
  tasks:
    - name: This runs, cannot connect, and the play carries on
      ansible.builtin.ping:

    - name: This one still ends the play for a host that is down
      ansible.builtin.ping:
      ignore_unreachable: false

Perkara yang berubah di sebalik tabir adalah penting untuk diketahui. Dengan ignore_unreachable ditetapkan, hos tidak lagi dibuang daripada play, jadi setiap task seterusnya akan cuba menyambung semula dan gagal dengan cara yang sama. Setiap percubaan tersebut akan menunggu sehingga tamat tempoh sambungan (connection timeout), iaitu 10 saat melainkan anda menukar timeout dalam ansible.cfg. Play yang mempunyai dua puluh task terhadap satu pelayan yang mati akan menambah kira-kira 200 saat pada masa pelaksanaan dan dua puluh baris merah dalam log.

Oleh itu, periksa sekali, kemudian hentikan hos tersebut dengan bersih:

- name: Opportunistic fleet maintenance
  hosts: all
  gather_facts: false
  tasks:
    - name: Check that the host answers before doing any work
      ansible.builtin.ping:
      register: reachable
      ignore_unreachable: true

    - name: End the play for this host if it never answered
      ansible.builtin.meta: end_host
      when: reachable.unreachable | default(false)

    - name: Gather facts now that the connection is known good
      ansible.builtin.setup:

    - name: Refresh the package index
      ansible.builtin.apt:
        update_cache: true
      become: true

Ini bermakna satu percubaan sambungan bagi setiap hos yang mati, bukannya satu bagi setiap task. end_host, yang ditambah dalam Ansible 2.8, menamatkan play untuk hos semasa tanpa menandakannya sebagai gagal. Kunci unreachable hanya wujud pada hasil yang didaftarkan (registered result) apabila sambungan gagal, jadi default(false) memastikan syarat tersebut kekal sah pada setiap hos yang menjawab. Pengumpulan fakta (fact gathering) dimatikan pada peringkat play kerana task Gathering Facts tersirat sebaliknya akan menjadi task yang bertemu dengan sambungan terputus, dan anda mahu itu menjadi ping anda sendiri.

ignore_unreachable ialah kata kunci play dan kata kunci task. Letakkannya dalam playbook supaya pembaca boleh melihatnya dan bukannya di dalam role, kerana ia menentukan hos yang mana dibenarkan untuk terlepas dalam sesuatu pelaksanaan. Perbezaan antara playbook dan role membincangkan lapisan mana yang sepatutnya mengurus tetapan seperti ini.

Mengapa ignore_errors bukan alat yang tepat di sini

Dokumentasi Ansible menyatakan had ini dengan jelas. ignore_errors "hanya berfungsi apabila tugasan boleh dijalankan dan mengembalikan nilai 'failed'. Ia tidak menyebabkan Ansible mengabaikan ralat pemboleh ubah yang tidak ditakrifkan, kegagalan sambungan, isu pelaksanaan (contohnya, pakej yang tiada), atau ralat sintaks."

Kegagalan sambungan tidak akan menjadi hasil tugasan dengan failed: true. Ia tiba sebagai flag berasingan, dan Ansible bertindak ke atas flag tersebut terlebih dahulu: hos akan dimasukkan ke dalam senarai unreachable dan dikeluarkan daripada play. Letakkan ignore_errors: true pada kesemua dua belas tugasan dalam satu play, dan hos dengan port SSH yang tertutup masih akan berhenti pada tugasan pertama. Ini adalah kekeliruan paling lazim dalam bidang ini, dan anda disyorkan untuk membuat carian grep pada playbook lama anda, terutamanya yang ditulis semasa belajar menulis playbook pertama untuk VPS.

Nyahpepijat sebelum anda menyekat

Sekatan yang menjadi kekal adalah punca hanyutnya pengurusan pelayan, kerana hos yang tidak boleh dicapai juga merupakan hos yang tidak ditampal. Selesaikan masalah mengikut urutan ini dahulu. Setiap arahan di sini hanya membaca data.

  1. ansible web2 -i inventory.ini -m ansible.builtin.ping -o menjalankan satu modul terhadap satu hos dan mencetak satu baris output.
  2. Tambahkan -vvvv pada arahan yang sama. Ansible akan mencetak arahan ssh penuh yang dibinanya, termasuk pengguna sasaran, port, kunci peribadi dan pilihan yang dilaluinya.
  3. Jalankan arahan ssh tersebut sendiri dengan -v. Jika ssh biasa tidak dapat masuk, masalahnya terletak di bawah lapisan Ansible dan tiada kata kunci playbook yang dapat membaikinya.
  4. Baca rentetan msg dan padankan dengan senarai di atas. Connection refused dan Connection timed out merujuk kepada dua tempat yang berbeza, satu pada servis SSH dan satu lagi pada laluan rangkaian.
  5. Bagi Host key verification failed., lihat apa yang anda simpan dengan ssh-keygen -F web2.example.com. Jika pelayan dibina semula, buang entri lama dengan ssh-keygen -R web2.example.com dan terima kunci baharu selepas menyemaknya dengan konsol pembekal. Menetapkan host_key_checking = False dalam ansible.cfg akan menghilangkan ralat tersebut tetapi juga membuang semakan yang sepatutnya memberitahu anda bahawa mesin yang berbeza kini menjawab pada alamat tersebut.
  6. Bagi Permission denied (publickey), sahkan apa yang Ansible fikir ia patut gunakan. ansible-inventory -i inventory.ini --host web2 mencetak pemboleh ubah yang berkuat kuasa, termasuk ansible_user dan ansible_port.
  7. Jika SSH berfungsi tetapi modul tidak, semak penterjemah dengan ansible web2 -m ansible.builtin.raw -a 'command -v python3 || echo none'. Modul raw menjalankan arahan melalui shell dan tidak memerlukan python pada sasaran.

Hanya selepas langkah tersebut, mengabaikan hos menjadi satu keputusan dan bukannya satu tabiat.

Rekap mengira hos yang tidak boleh dicapai secara berasingan, dan CI biasanya terlepas perkara ini

ansible-playbook keluar dengan kod 0 jika berjaya, 2 apabila sekurang-kurangnya satu hos gagal, dan 4 apabila sekurang-kurangnya satu hos tidak boleh dicapai. Kedua-dua nilai tersebut merupakan bit flag dalam kod sumber, jadi pelaksanaan yang melibatkan hos gagal dan hos tidak boleh dicapai akan keluar dengan kod 6. Perintah ansible mengembalikan kod yang sama. Perkara ini telah disemak dengan kod sumber ansible-core pada Ogos 2026.

Sekarang, tetapkan ignore_unreachable: true dan jalankan playbook tujuh tugasan yang sama terhadap hos yang mati tersebut:

PLAY RECAP *********************************************************************
web1  : ok=7  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2  : ok=7  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=7

web2 melaporkan unreachable=0 dan tujuh tugasan ok, dan pelaksanaan keluar dengan kod 0. Apabila kata kunci ini ditetapkan, Ansible menambah pembilang ok dan ignored untuk hos tersebut dan bukannya pembilang yang dipanggil dark, iaitu pembilang yang mengisi lajur unreachable. Baris merah UNREACHABLE! masih dicetak, jadi log adalah jujur walaupun rekap dan kod keluar tidak menunjukkan keadaan sebenar.

Tugasan CI yang menjalankan playbook dan hanya menyemak $? akan menganggap pelaksanaan tersebut berjaya, dan tiada apa-apa dalam ringkasannya yang menyatakan bahawa sesebuah mesin tidak pernah dihubungi. Jadikan semakan kebolehcapaian sebagai langkah berasingan, sebelum playbook dijalankan:

ansible all -i inventory.ini -m ansible.builtin.ping -o

Langkah ini mencetak satu baris bagi setiap hos dan keluar dengan kod 4 jika mana-mana hos tidak boleh dicapai, yang memberikan pipeline sesuatu untuk digagalkan serta memberikan anda nama hos dalam log. ping memerlukan penterjemah Python yang berfungsi pada sasaran, jadi ia membuktikan lebih daripada sekadar sambungan, yang biasanya merupakan perkara yang anda perlukan. Kemudian, jalankan playbook dengan ignore_unreachable supaya hos yang aktif masih menerima perubahan tersebut.

any_errors_fatal dan max_fail_percentage merentas kelompok

Dua kata kunci play ini menentukan tindakan yang diambil selepas berlaku kegagalan pada sebahagian daripada armada, dan kedua-duanya melayan hos yang tidak boleh dicapai dengan cara yang berbeza.

any_errors_fatal: true bertindak balas terhadap hos yang tidak boleh dicapai. Ansible melengkapkan tugasan semasa pada baki hos dalam kelompok tersebut, kemudian menghentikan play untuk setiap hos di dalamnya. Gunakan tetapan ini apabila sesuatu pelaksanaan hanya bermakna jika ia berjaya sepenuhnya atau gagal terus, seperti perubahan skema yang diselaraskan.

max_fail_percentage: 30 tidak bertindak balas terhadap hos yang tidak boleh dicapai. Semakan ini membahagikan bilangan hos yang gagal dengan saiz kelompok, dan hos yang tidak boleh dicapai disimpan dalam senarai berasingan, jadi ia tidak pernah mengubah angka tersebut. Sepuluh hos dengan empat hos yang tidak boleh dicapai akan terus berjalan di bawah max_fail_percentage: 10, manakala dua hos yang gagal dalam sesuatu tugasan akan menghentikan play. Dokumentasi menambah satu lagi perangkap: "Peratusan yang ditetapkan mesti dilampaui, bukan sekadar sama." Dengan serial: 4, untuk berhenti selepas dua kegagalan daripada empat, anda perlu menulis 49, bukan 50.

Terdapat satu keadaan di mana hos yang tidak boleh dicapai menghentikan pelaksanaan dengan sendirinya. Jika setiap hos dalam kelompok tersebut gagal atau tidak boleh dicapai, Ansible tidak mempunyai baki hos untuk diproses dan menamatkan play dengan NO MORE HOSTS LEFT.

serial: melaksanakan perubahan secara berperingkat merentasi kumpulan pelayan

- name: Rolling nginx config update
  hosts: webservers
  serial: 2
  max_fail_percentage: 25
  tasks:
    - name: Deploy the site config
      ansible.builtin.template:
        src: site.conf.j2
        dest: /etc/nginx/conf.d/site.conf
        owner: root
        mode: "0644"
      become: true
      notify: Reload nginx
  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
      become: true

serial: 2 menjalankan keseluruhan play terhadap dua hos, menyelesaikannya, kemudian memulakan dua hos seterusnya. serial: "25%" berskala mengikut saiz kumpulan. Senarai, serial: [1, 5, 10], ialah bentuk canary: satu hos dahulu, kemudian lima, kemudian sepuluh, dengan mana-mana hos yang berbaki dijalankan dalam kelompok mengikut saiz terakhir. max_fail_percentage diukur bagi setiap kelompok, jadi kedua-duanya berfungsi bersama. Jika mesin pertama gagal, pelaksanaan akan berhenti sebelum ia menjejaskan empat puluh mesin yang lain. Inilah yang menjadikan pengurusan kumpulan pelayan Linux daripada satu mesin kawalan selamat untuk dilakukan melalui satu arahan tunggal.

Bilakah hos yang tidak boleh dicapai perlu diabaikan, dan bilakah tidak

Abaikan hos tersebut untuk tugasan yang bersifat oportunistik. Proses pengumpulan fakta atau pemeriksaan drift setiap jam tidak akan terjejas jika melangkau hos yang sedang mati, kerana pas seterusnya akan mengambilnya semula. Tahap play ignore_unreachable: true adalah jawapan yang tepat di sini, digandingkan dengan langkah ping supaya nama yang dilangkau direkodkan di tempat yang boleh dibaca oleh pengguna.

Jangan sekali-kali mengabaikan hos tersebut untuk proses tampalan keselamatan (security patch). Nilai proses tersebut adalah jaminan bahawa setiap hos mempunyai pembaikan, dan menyembunyikan status tidak boleh dicapai akan menukarkan keadaan "satu pelayan masih terdedah" kepada rumusan yang kelihatan sempurna. Hos yang tidak boleh dicapai selama dua minggu adalah hos yang paling berkemungkinan ketinggalan jauh. Biarkan proses tersebut keluar dengan kod 4 dan biarkan seseorang memeriksanya.

Satu peraturan terpakai dalam kedua-dua kes: sekat pemberhentian, jangan sekali-kali sekat rekod. Jika sesuatu hos dilangkau, sesuatu perkara perlu menyatakannya, sama ada dalam rumusan, log CI, atau makluman pemantauan. Ansible hanya mengetahui kewujudan hos semasa saat play dijalankan terhadapnya, jadi ia bukan tempat yang sesuai untuk mengetahui bahawa pelayan telah mati sejak hari Selasa. Tugas itu adalah tanggungjawab pemantauan, dan playbook Ansible yang memasang Zabbix memberikan pandangan menyeluruh ke atas seluruh armada yang boleh disiapkan dalam satu petang.

FAQ

Apakah perbezaan antara ignore_errors dan ignore_unreachable dalam Ansible?

ignore_errors: true digunakan untuk tugasan yang telah dijalankan pada hos dan mengembalikan kegagalan, contohnya arahan yang keluar dengan status bukan sifar. ignore_unreachable: true digunakan untuk hos yang tidak dapat dihubungi oleh Ansible, di mana tiada modul yang sempat dijalankan. Kedua-duanya membaca medan yang berbeza pada hasil tugasan, dan tiada satu pun yang meliputi kes yang lain. Dokumentasi Ansible menyatakan bahawa ignore_errors "tidak menyebabkan Ansible mengabaikan ralat pemboleh ubah yang tidak ditakrifkan, kegagalan sambungan, isu pelaksanaan (contohnya, pakej yang tiada), atau ralat sintaks", dan port SSH yang tertutup merupakan satu kegagalan sambungan.

Adakah ignore_unreachable menyembunyikan hos daripada ringkasan play?

Secara praktikalnya, ya. Dengan kata kunci ini ditetapkan, Ansible berhenti mengira hos tersebut di bawah unreachable dan mengiranya sebagai ok dan ignored sekali bagi setiap tugasan, dan pelaksanaan kemudian keluar dengan kod 0. Baris fatal: [host]: UNREACHABLE! masih dicetak, jadi log adalah tepat walaupun ringkasan dan kod keluar tidak menunjukkan kegagalan. Pantau lajur ignored, atau jalankan ansible all -m ansible.builtin.ping -o sebagai langkah berasingan supaya hos yang tidak dapat dihubungi masih menghasilkan kod keluar bukan sifar di suatu tempat.

Apakah kod keluar yang dikembalikan oleh ansible-playbook apabila hos tidak dapat dihubungi?

Ia mengembalikan 4. Pelaksanaan dengan sekurang-kurangnya satu hos yang gagal mengembalikan 2, dan kedua-dua nilai ini adalah bit flag, jadi pelaksanaan dengan kegagalan dan hos yang tidak dapat dihubungi mengembalikan 6. Pelaksanaan yang berjaya mengembalikan 0. Kod-kod ini telah disemak terhadap sumber ansible-core pada Ogos 2026. Menetapkan ignore_unreachable: true akan membuang nilai 4 tersebut, itulah sebabnya pipeline yang hanya menguji kod keluar tidak dapat mengesan mesin yang dilangkau.

Bagaimanakah cara untuk melangkau baki tugasan dalam satu play bagi hos yang tidak memberi respons?

Jadikan tugasan pertama ansible.builtin.ping dengan ignore_unreachable: true dan register: reachable, kemudian ikuti dengan ansible.builtin.meta: end_host di bawah syarat when: reachable.unreachable | default(false). end_host menamatkan play bagi hos tersebut tanpa menandakannya sebagai gagal. Tetapkan gather_facts: false pada play supaya ping anda menjadi tugasan yang mengesan sambungan terputus. Tanpa corak ini, hos yang mati akan kekal dalam play, dan setiap tugasan seterusnya akan menunggu tamat tempoh sambungan (timeout) sekali lagi.

Patutkah saya mengabaikan hos yang tidak dapat dihubungi semasa menjalankan patch keselamatan?

Tidak. Pelaksanaan patch perlu dilakukan kerana ia memberi jaminan bahawa setiap hos telah menerima kemas kini, dan mengabaikan hos yang tidak dapat dihubungi akan menggantikan jaminan tersebut dengan ringkasan berwarna hijau yang mengelirukan. Biarkan pelaksanaan keluar dengan kod 4, baca nama hos yang tidak memberi respons, dan baiki hos tersebut. Penindasan ralat hanya sesuai untuk pelaksanaan oportunistik berulang di mana pas seterusnya akan menangkap apa sahaja yang terlepas.

#ansible#playbooks#error-handling#inventory#automation