Введение
Ansible – это мощный инструмент автоматизации инфраструктуры, упрощающий управление сложными ИТ-средами. Однако пользователи часто сталкиваются с ошибкой 'UNREACHABLE!', которая может нарушить процессы автоматизации. Эта ошибка обычно возникает, когда Ansible не может установить соединение с целевыми хостами. В этой лабораторной работе вы узнаете, как идентифицировать, устранять неполадки и предотвращать ошибку 'UNREACHABLE!' в ваших развертываниях Ansible.
К концу этой лабораторной работы вы поймете распространенные причины проблем с подключением в Ansible и сможете реализовать эффективные решения для обеспечения бесперебойной работы вашей автоматизации.
Настройка среды Ansible
На этом шаге мы настроим базовую среду Ansible для работы. Мы установим Ansible, настроим необходимые файлы и убедимся, что все готово для наших экспериментов.
Установка Ansible
Сначала установим Ansible на виртуальную машину LabEx, используя следующие команды:
sudo apt update
sudo apt install -y ansible
Это установит последнюю версию Ansible, доступную в репозиториях Ubuntu. После завершения установки проверьте установку, проверив версию Ansible:
ansible --version
Вы должны увидеть вывод, аналогичный следующему, показывающий версию Ansible и сведения о конфигурации:
ansible [core 2.12.x]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.x (default, Apr 8 2022, 09:04:19) [GCC 11.2.0]
jinja version = 3.0.3
libyaml = True
Создание рабочего каталога
Давайте создадим выделенный каталог для нашей работы с Ansible:
mkdir -p ~/project/ansible-lab
cd ~/project/ansible-lab
Создание файла конфигурации Ansible
Теперь давайте создадим базовый файл конфигурации Ansible в нашем каталоге проекта:
cat > ansible.cfg << 'EOF'
[defaults]
inventory = ./inventory
host_key_checking = False
remote_user = labex
EOF
Этот файл конфигурации:
- Указывает местоположение нашего файла инвентаризации
- Отключает проверку ключей хоста SSH (полезно для лабораторных сред)
- Устанавливает пользователя по умолчанию для удаленного доступа (remote user) как 'labex'
Создание файла инвентаризации
Файл инвентаризации определяет хосты, которыми будет управлять Ansible. Давайте создадим простой файл инвентаризации:
cat > inventory << 'EOF'
[local]
localhost ansible_connection=local
[virtual]
virtual-host ansible_host=10.10.10.10
EOF
Эта инвентаризация содержит две группы:
local: Содержит только localhost, который использует локальное подключениеvirtual: Содержит виртуальный хост, который мы будем использовать для демонстрации ошибки 'UNREACHABLE!'
virtual-host настроен с IP-адресом (10.10.10.10), который не существует в нашей среде, что поможет нам сгенерировать ошибку 'UNREACHABLE!'.
Тестирование Ansible
Давайте протестируем нашу настройку Ansible, запустив простую команду ping против локального хоста:
ansible local -m ping
Вы должны увидеть успешный ответ, например:
localhost | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
Это подтверждает, что Ansible работает правильно для локального подключения. Теперь давайте попробуем пропинговать виртуальный хост, который должен завершиться неудачей:
ansible virtual -m ping
Это приведет к ошибке 'UNREACHABLE!', потому что хост не существует:
virtual-host | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 10.10.10.10 port 22: Connection timed out",
"unreachable": true
}
Теперь вы успешно настроили Ansible и создали сценарий, в котором возникает ошибка 'UNREACHABLE!', которую мы рассмотрим на следующем шаге.
Понимание ошибки 'UNREACHABLE!'
На предыдущем шаге мы столкнулись с ошибкой 'UNREACHABLE!' при попытке подключиться к несуществующему хосту. Теперь давайте подробнее разберем эту ошибку и рассмотрим распространенные причины.
Анализ сообщения об ошибке
Давайте посмотрим на полученное сообщение об ошибке:
virtual-host | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 10.10.10.10 port 22: Connection timed out",
"unreachable": true
}
Сообщение об ошибке предоставляет ценную информацию:
UNREACHABLE!указывает на то, что Ansible не смог установить соединение с хостом- Поле
msgсообщает нам почему: "Failed to connect to the host via ssh" (Не удалось подключиться к хосту через ssh) - Конкретная ошибка - "Connection timed out" (Превышено время ожидания соединения), что означает, что Ansible пытался подключиться, но не получил ответа
Распространенные причины ошибок 'UNREACHABLE!'
Ошибка 'UNREACHABLE!' может возникнуть по нескольким причинам:
- Проблемы с сетью: Хост может находиться за брандмауэром, или могут быть проблемы с сетевым подключением.
- Неверная информация о хосте: Имя хоста или IP-адрес в инвентаризации могут быть неверными.
- Настройка SSH: SSH может быть настроен неправильно на целевом хосте.
- Проблемы аутентификации: SSH-ключ или пароль могут быть неверными.
- Недоступность хоста: Хост может быть выключен или недоступен.
Создание тестового плейбука
Давайте создадим простой плейбук, чтобы дополнительно продемонстрировать ошибку:
cat > test_playbook.yml << 'EOF'
---
- name: Test Connectivity
hosts: all
gather_facts: no
tasks:
- name: Ping the hosts
ping:
EOF
Этот плейбук пытается пропинговать все хосты, определенные в нашей инвентаризации. Давайте запустим его:
ansible-playbook test_playbook.yml
Вы должны увидеть вывод, аналогичный следующему:
PLAY [Test Connectivity] ************************************************
TASK [Ping the hosts] ***************************************************
ok: [localhost]
fatal: [virtual-host]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 10.10.10.10 port 22: Connection timed out", "unreachable": true}
PLAY RECAP *************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
virtual-host : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
Плейбук успешно выполнился для localhost, но завершился неудачей для virtual-host с ошибкой 'UNREACHABLE!'.
Проверка уровней детализации Ansible
Ansible предоставляет различные уровни детализации (verbosity) для помощи в диагностике проблем. Давайте попробуем запустить плейбук с повышенной детализацией:
ansible-playbook test_playbook.yml -v
Для еще более подробного вывода используйте -vv или -vvv:
ansible-playbook test_playbook.yml -vvv
Опция -vvv предоставляет наиболее подробный вывод, показывая точные команды SSH, которые пытается использовать Ansible:
<virtual-host> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o User=labex -o ConnectTimeout=10 -o ControlPath=/home/labex/.ansible/cp/ansible-ssh-%h-%p-%r 10.10.10.10 '/bin/sh -c '"'"'echo ~labex && sleep 0'"'"''
Этот уровень детализации может быть бесценным для устранения неполадок с подключением SSH.
Использование опции --limit
При работе с большой инвентаризацией вы можете ограничить Ansible для запуска команд против определенных хостов или групп, используя опцию --limit:
ansible-playbook test_playbook.yml --limit localhost
Эта команда запустит плейбук только против localhost, избегая ошибки 'UNREACHABLE!' от virtual-host.
Теперь, когда мы лучше понимаем ошибку 'UNREACHABLE!', давайте перейдем к устранению неполадок и исправлению этих проблем на следующем шаге.
Устранение неполадок и исправление ошибок 'UNREACHABLE!'
Теперь, когда мы понимаем, что вызывает ошибки 'UNREACHABLE!', давайте узнаем, как устранять неполадки и исправлять их. Мы будем использовать различные подходы для диагностики и решения проблем с подключением.
Исправление проблем с инвентаризацией
Одной из наиболее распространенных причин ошибок 'UNREACHABLE!' является неверная информация об инвентаризации. Давайте исправим наш файл инвентаризации:
cd ~/project/ansible-lab
Сначала обновим наш файл инвентаризации, чтобы включить действительный хост. В этой лабораторной среде мы сосредоточимся на использовании localhost с различными методами подключения, чтобы продемонстрировать методы устранения неполадок:
cat > inventory << 'EOF'
[local]
localhost ansible_connection=local
[ssh_local]
local-ssh ansible_host=127.0.0.1 ansible_connection=ssh
[virtual]
virtual-host ansible_host=10.10.10.10
EOF
Мы добавили новую группу ssh_local с хостом, который попытается подключиться к localhost через SSH вместо метода локального подключения.
Прямое тестирование подключения SSH
Прежде чем использовать Ansible, всегда рекомендуется напрямую протестировать подключение SSH:
ssh 127.0.0.1
Вам может быть предложено ввести пароль или вы увидите сообщение о ключе хоста. Это хороший знак, так как это означает, что подключение SSH работает, но вам может потребоваться правильно настроить SSH для Ansible.
Нажмите Ctrl+C, чтобы выйти, если вы застряли в запросе пароля.
Настройка SSH-ключей для аутентификации без пароля
Ansible обычно использует SSH-ключи для аутентификации. Давайте настроим доступ к localhost без пароля:
## Generate an SSH key if you don't have one
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
## Add the key to authorized_keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
## Set proper permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Теперь попробуйте подключиться к localhost через SSH:
ssh 127.0.0.1
Вы должны иметь возможность подключиться без запроса пароля. Введите exit, чтобы вернуться в исходную сессию.
Тестирование Ansible с подключением SSH
Теперь давайте протестируем Ansible с подключением SSH к localhost:
ansible ssh_local -m ping
Если настройка SSH правильная, вы должны увидеть успешный ответ:
local-ssh | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
Если вы все еще видите ошибку 'UNREACHABLE!', давайте добавим больше параметров подключения в наш файл инвентаризации:
cat > inventory << 'EOF'
[local]
localhost ansible_connection=local
[ssh_local]
local-ssh ansible_host=127.0.0.1 ansible_connection=ssh ansible_user=labex ansible_ssh_private_key_file=~/.ssh/id_rsa
[virtual]
virtual-host ansible_host=10.10.10.10
EOF
Попробуйте команду ping еще раз:
ansible ssh_local -m ping
Использование Ansible с пользовательской конфигурацией SSH
Иногда вам нужны более сложные конфигурации SSH. Давайте создадим пользовательский файл конфигурации SSH:
mkdir -p ~/.ssh
cat > ~/.ssh/config << 'EOF'
Host local-ssh
HostName 127.0.0.1
User labex
IdentityFile ~/.ssh/id_rsa
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
## Set proper permissions
chmod 600 ~/.ssh/config
Обновите инвентаризацию, чтобы использовать запись конфигурации SSH:
cat > inventory << 'EOF'
[local]
localhost ansible_connection=local
[ssh_local]
local-ssh
[virtual]
virtual-host ansible_host=10.10.10.10
EOF
Снова протестируйте подключение:
ansible ssh_local -m ping
Создание плейбука для тестирования всех подключений
Давайте создадим всеобъемлющий плейбук для тестирования всех наших подключений:
cat > connection_test.yml << 'EOF'
---
- name: Test Local Connection
hosts: local
gather_facts: no
tasks:
- name: Ping local
ping:
register: local_ping
- name: Display local ping result
debug:
var: local_ping
- name: Test SSH Connection
hosts: ssh_local
gather_facts: no
tasks:
- name: Ping via SSH
ping:
register: ssh_ping
- name: Display SSH ping result
debug:
var: ssh_ping
EOF
Запустите плейбук:
ansible-playbook connection_test.yml
Вы должны увидеть успешные подключения как к локальному, так и к SSH-хостам:
PLAY [Test Local Connection] ********************************************
TASK [Ping local] ******************************************************
ok: [localhost]
TASK [Display local ping result] ****************************************
ok: [localhost] => {
"local_ping": {
"changed": false,
"ping": "pong"
}
}
PLAY [Test SSH Connection] **********************************************
TASK [Ping via SSH] ****************************************************
ok: [local-ssh]
TASK [Display SSH ping result] *****************************************
ok: [local-ssh] => {
"ssh_ping": {
"changed": false,
"ping": "pong"
}
}
PLAY RECAP *************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
local-ssh : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Успешный вывод подтверждает, что мы исправили ошибки 'UNREACHABLE!' для наших действительных хостов. Единственный хост, который остается недоступным, - это virtual-host, что сделано намеренно, поскольку он не существует.
Теперь вы успешно диагностировали и исправили ошибки 'UNREACHABLE!' путем:
- Тестирования прямого подключения SSH
- Настройки SSH-ключей для аутентификации без пароля
- Настройки инвентаризации Ansible с правильными параметрами подключения
- Использования пользовательской конфигурации SSH
- Проверки подключения с помощью всеобъемлющего плейбука
Внедрение лучших практик для предотвращения ошибок 'UNREACHABLE!'
Теперь, когда мы исправили непосредственные ошибки 'UNREACHABLE!', давайте сосредоточимся на лучших практиках, чтобы предотвратить их в будущем. Это включает в себя надлежащее управление инвентаризацией, конфигурации подключений и методы обработки ошибок.
Создание надежной структуры инвентаризации
Хорошо организованная инвентаризация упрощает устранение неполадок. Давайте создадим более структурированную директорию инвентаризации:
cd ~/project/ansible-lab
mkdir -p inventory/{group_vars,host_vars}
Теперь давайте создадим основной файл инвентаризации:
cat > inventory/hosts << 'EOF'
## Production Servers
[production]
## prod-server ansible_host=prod.example.com
## Development Servers
[development]
## dev-server ansible_host=dev.example.com
## Local Connections
[local]
localhost ansible_connection=local
## SSH Connections
[ssh_local]
local-ssh ansible_host=127.0.0.1
EOF
Далее давайте создадим переменные группы для группы подключений SSH:
cat > inventory/group_vars/ssh_local.yml << 'EOF'
---
ansible_connection: ssh
ansible_user: labex
ansible_ssh_private_key_file: ~/.ssh/id_rsa
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
EOF
Обновите конфигурацию Ansible, чтобы использовать новую директорию инвентаризации:
cat > ansible.cfg << 'EOF'
[defaults]
inventory = ./inventory/hosts
host_key_checking = False
retry_files_enabled = True
retry_files_save_path = ~/.ansible/retry-files
timeout = 30
connect_timeout = 30
command_timeout = 30
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
control_path_dir = ~/.ansible/cp
EOF
Создание плейбука для тестирования подключений с логикой повторных попыток
Ansible позволяет повторно выполнять неудачные задачи. Давайте создадим плейбук с логикой повторных попыток:
cat > connection_test_with_retry.yml << 'EOF'
---
- name: Test All Connections
hosts: all
gather_facts: no
tasks:
- name: Ping hosts
ping:
register: ping_result
retries: 3
delay: 5
until: ping_result is not failed
ignore_unreachable: yes
- name: Display ping status
debug:
msg: "Connection to {{ inventory_hostname }} was successful"
when: ping_result is success
- name: Report unreachable hosts
debug:
msg: "Host {{ inventory_hostname }} is unreachable"
when: ping_result is unreachable
EOF
Запустите плейбук с нашей новой структурой инвентаризации:
ansible-playbook connection_test_with_retry.yml
Вы должны увидеть вывод, показывающий успешные подключения к localhost и local-ssh.
Аккуратная обработка ошибок 'UNREACHABLE!'
Давайте создадим более продвинутый плейбук, который аккуратно обрабатывает ошибки 'UNREACHABLE!' и генерирует отчет:
cat > connection_report.yml << 'EOF'
---
- name: Test Connections and Generate Report
hosts: all
gather_facts: no
tasks:
- name: Try to connect to hosts
ping:
register: ping_result
ignore_unreachable: yes
- name: Create reachable hosts list
set_fact:
reachable_hosts: "{{ (reachable_hosts | default([])) + [inventory_hostname] }}"
when: ping_result is success
delegate_to: localhost
delegate_facts: true
- name: Create unreachable hosts list
set_fact:
unreachable_hosts: "{{ (unreachable_hosts | default([])) + [inventory_hostname] }}"
when: ping_result is unreachable
delegate_to: localhost
delegate_facts: true
- name: Generate Connection Report
hosts: localhost
gather_facts: no
tasks:
- name: Display reachable hosts
debug:
msg: "Reachable hosts: {{ reachable_hosts | default([]) | join(', ') }}"
- name: Display unreachable hosts
debug:
msg: "Unreachable hosts: {{ unreachable_hosts | default([]) | join(', ') }}"
- name: Write report to file
copy:
content: |
Connection Report
-----------------
Reachable hosts: {{ reachable_hosts | default([]) | join(', ') }}
Unreachable hosts: {{ unreachable_hosts | default([]) | join(', ') }}
Generated on: {{ ansible_date_time.iso8601 }}
dest: ~/project/ansible-lab/connection_report.txt
register: report
- name: Show report location
debug:
msg: "Report saved to {{ report.dest }}"
EOF
Запустите плейбук отчета:
ansible-playbook connection_report.yml
Давайте проверим отчет:
cat ~/project/ansible-lab/connection_report.txt
Вы должны увидеть отчет со списком доступных и недоступных хостов.
Использование плагинов инвентаризации Ansible
Ansible предоставляет плагины инвентаризации для динамического управления хостами. Давайте создадим простой скрипт, чтобы продемонстрировать это:
cat > inventory_script.py << 'EOF'
#!/usr/bin/env python3
import json
import socket
def is_host_reachable(host, port=22, timeout=1):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex((host, port))
sock.close()
return result == 0
except:
return False
## Define our hosts
hosts = {
'localhost': '127.0.0.1',
'local-ssh': '127.0.0.1',
'virtual-host': '10.10.10.10'
}
## Check reachability and build inventory
inventory = {
'all': {
'hosts': list(hosts.keys())
},
'reachable': {
'hosts': []
},
'unreachable': {
'hosts': []
},
'_meta': {
'hostvars': {}
}
}
for hostname, ip in hosts.items():
reachable = is_host_reachable(ip)
group = 'reachable' if reachable else 'unreachable'
inventory[group]['hosts'].append(hostname)
inventory['_meta']['hostvars'][hostname] = {
'ansible_host': ip,
'reachability_checked': True,
'is_reachable': reachable
}
print(json.dumps(inventory, indent=2))
EOF
chmod +x inventory_script.py
Протестируйте скрипт динамической инвентаризации:
./inventory_script.py
Вы должны увидеть вывод JSON, показывающий хосты, классифицированные как доступные или недоступные.
Давайте запустим плейбук, используя эту динамическую инвентаризацию:
ansible-playbook -i ./inventory_script.py connection_test.yml --limit reachable
Это приведет к попытке подключения только к хостам, которые скрипт определил как доступные, что поможет вам полностью избежать ошибок 'UNREACHABLE!'.
Эти лучшие практики обеспечивают надежную основу для управления подключением Ansible и предотвращения ошибок 'UNREACHABLE!' в производственных средах.
Резюме
В этой лабораторной работе вы узнали, как идентифицировать, устранять неполадки и предотвращать ошибки 'UNREACHABLE!' в Ansible. Вы:
Настроили базовую среду Ansible и столкнулись с ошибкой 'UNREACHABLE!' на практике.
Проанализировали сообщение об ошибке и поняли распространенные причины проблем с подключением.
Использовали различные методы устранения неполадок для диагностики проблем с подключением.
Реализовали решения для исправления ошибок, включая:
- Настройку SSH-ключей для аутентификации без пароля
- Настройку правильных файлов инвентаризации
- Использование параметров конфигурации SSH
Применили лучшие практики для предотвращения будущих ошибок 'UNREACHABLE!', такие как:
- Создание структурированной организации инвентаризации
- Реализация логики повторных попыток
- Разработка стратегий обработки ошибок
- Использование скриптов динамической инвентаризации для проверки доступности хостов
Эти навыки помогут вам поддерживать надежные развертывания Ansible и быстро решать любые возникающие проблемы с подключением. Понимая основные причины ошибок 'UNREACHABLE!' и применяя надлежащие профилактические меры, вы можете обеспечить бесперебойную и эффективную работу автоматизации вашей инфраструктуры.


