🔍 [네트워크 자동화 Ep.3] 일일점검 자동화 — 14대 상태를 한 번에, 그리고 숨은 장애 발견
명령 묶음의 함정, 기종별 명령 차이, 그리고 자동화가 찾아낸 진짜 네트워크 문제
📋 이 글의 흐름
- 1. 무엇을 점검할 것인가 — 일일점검 항목 정의
- 2. 첫 플레이북과 첫 전멸 — 명령 묶음의 함정
- 3. ignore_errors — 하나가 전체를 죽이지 않게
- 4. 기종별 명령 차이 — 자동화가 드러낸 이질성
- 5. 자동화가 찾아낸 진짜 장애 — MAC Flapping
- 6. ansible 단발 명령 vs ansible-playbook
Ep.2에서 데이터 수집 원리를 이해했다. 이제 실무의 핵심 — 일일점검을 통째로 자동화한다. 사람이 매일 14대 × 여러 항목을 수동 확인하던 것을 명령 한 줄로 바꾸는 작업이다. 그리고 이 과정에서 나는 실제 네트워크 문제 하나를 발견하게 된다.
1. 무엇을 점검할 것인가
| 점검 항목 | IOS 명령어 | 판정 포인트 |
|---|---|---|
| CPU | show processes cpu | include CPU | 5분 평균 70%↑ 주의 |
| 메모리 | show memory statistics | 지속 우상향 시 릭 의심 |
| 온도/팬/전원 | show environment all | “OK” 아닌 항목 경고 |
| 인벤토리 | show inventory | 전원·모듈 정상 여부 |
| 인터페이스 | show interfaces status | connected 포트 수 |
| 이상 로그 | show logging | include % | 심각도별 로그 카운트 |
2. 첫 플레이북과 첫 전멸
처음엔 위 명령들을 한 번에 묶어 던졌다. 결과는 14대 전멸이었다.
[ERROR]: show memory statistics
^
% Invalid input detected at '^' marker.
fatal: [sw_10_20_0_2]: FAILED! ...
fatal: [sw_10_20_0_3]: FAILED! ... (14대 줄줄이)① 명령어 불일치: show memory statistics가 이 장비들에선 안 먹힌다. % Invalid input은 “이 명령 모르겠다”는 IOS의 표준 거부다.
② 치명적 동작: ios_command는 묶인 명령 중 하나만 실패해도 그 장비 전체 task를 중단한다. 그래서 멀쩡한 다른 명령 결과까지 전부 날아갔다.
3. ignore_errors — 하나가 전체를 죽이지 않게
해결의 핵심은 두 가지. 명령 실패를 허용하고, 호환되는 명령으로 교체하는 것이다.
- name: 14대 일일점검 데이터 수집
hosts: switches
gather_facts: no
tasks:
- name: 점검 명령 일괄 실행 (실패 허용)
cisco.ios.ios_command:
commands:
- show clock
- show processes cpu | include CPU
- show environment all
- show inventory
- show interfaces status
- show logging | include %
register: result
ignore_errors: yes # ★ 하나 실패해도 멈추지 않음
- name: 장비별 결과를 파일로 저장
delegate_to: localhost # 파일 저장은 내 PC에서 수행
copy:
content: |
===== {{ inventory_hostname }} ({{ ansible_host }}) =====
{% if result.stdout is defined %}
{% for cmd_out in result.stdout %}
----- 명령 {{ loop.index }} -----
{{ cmd_out }}
{% endfor %}
{% else %}
[수집 실패: {{ result.msg | default('알수없음') }}]
{% endif %}
dest: "./check_{{ inventory_hostname }}.txt"
점검 명령은 스위치에서 실행하지만, 결과를 파일로 저장하는 작업은 내 PC(localhost)에서 한다는 뜻. 스위치엔 파일을 쓸 수 없으니 당연한 처리다.
ansible-playbook -i inventory.yml daily_check.yml \
-e 'sw_user=admin sw_pass=P@ssw0rd!2030 sw_enable=En@bleKey'
4. 기종별 명령 차이 — 자동화가 드러낸 이질성
개선판을 돌리자 이번엔 14대 전부 failed=0으로 완주했다. 그런데 결과(PLAY RECAP)를 읽으니 흥미로운 사실이 드러났다.
sw_10_20_0_2 : ok=2 changed=1 failed=0 ignored=1 # L3, 일부명령 실패
sw_10_20_0_3 : ok=2 changed=1 failed=0 ignored=1 # L3, 일부명령 실패
sw_10_20_0_31 : ok=2 changed=1 failed=0 ignored=0 # L2, 전부 성공
...
sw_10_20_0_58 : ok=2 changed=1 failed=0 ignored=0
L3 스위치 2대(4500 계열)만 ignored=1 — show environment all이 이 2대에서만 거부됐다. 나머지 12대(3650 계열)는 정상. 즉 같은 “Cisco 스위치”라도 기종에 따라 명령 형식이 다르다는 게 데이터로 확정됐다.
14대를 손으로 점검했다면 “L3 2대는 environment 명령이 다르네”를 언제 발견했을지 모른다. 자동화는 이질성(기종 차이)을 즉시 가시화한다. 장비가 100대라면 이 가치는 폭발적으로 커진다 — 어떤 장비가 표준에서 벗어났는지 명령 한 줄로 드러난다.
이 문제의 근본 해법은 인벤토리를 기종별 그룹으로 나누는 것이다. l3_core(4500), l2_access(3650)로 그룹을 나누고, 그룹별로 다른 명령셋을 주면 명령 불일치가 구조적으로 사라진다. (다음 편에서 활용)
5. 자동화가 찾아낸 진짜 장애 — MAC Flapping
저장된 점검 파일을 열어보다, 로그 항목에서 심상치 않은 패턴을 발견했다. 한 L2 스위치의 로그에 같은 메시지가 수백 건 쏟아지고 있었다.
%SW_MATM-4-MACFLAP_NOTIF: Host xxxx.xxxx.xxxx in vlan 20 is
flapping between port Gi1/0/13 and port Gi1/1/3
%SW_MATM-4-MACFLAP_NOTIF: Host yyyy.yyyy.yyyy in vlan 20 is
flapping between port Gi1/0/14 and port Gi1/1/3
... (5일간 수백 건 지속)
같은 단말(MAC 주소)이 여러 포트 사이를 계속 오간다고 스위치가 보고하는 경고다. 전부 VLAN 20, 전부 AP 연결 포트(Gi1/0/13~15)와 L3 업링크(Gi1/1/3) 사이에서 발생.
무선 AP 환경에서 단말 로밍 시 일부 발생은 정상이지만, 이 정도 빈도(분당 여러 건, 5일 내내)는 무선 로밍 설계 문제이거나 L2 루프 가능성을 의심해야 한다.
심하면 스위치 CPU가 MAC 테이블을 계속 재작성하느라 부하가 오르고, 무선 사용자 체감 품질이 저하된다. 흔히 놓치는 숨은 범인이다.
손으로 14대를 점검했다면 이 로그를 끝까지 안 읽고 넘겼을 가능성이 높다. 자동 수집이 “평소 안 보던 것”을 눈앞에 끌어다 놨다. 점검 자동화의 목적은 “수집”이 아니라 “이상을 빨리 발견”이다. 사람은 로그 200줄을 안 읽지만, 플레이북은 다 긁어오고, 다음 단계에선 그중 위험한 것만 자동으로 골라줄 수 있다.
6. ansible vs ansible-playbook
| 명령 | 용도 |
|---|---|
| ansible | 단발성 명령 한 개 실행 (예: 접속 테스트, facts 조회) |
| ansible-playbook | 여러 task를 정리한 .yml 파일(플레이북) 실행 |
여기까지의 “원시 수집”은 SecureCRT 세션 로깅으로도 가능하다. 하지만 방금 본 MAC Flapping을 “매일 자동으로 골라내 경고”하는 것, 기종 차이를 자동 분류하는 것 — 이건 텍스트 로그로는 안 된다. 다음 편에서 이 수집 결과를 판정된 엑셀 점검표로 바꾼다. 거기서부터 SecureCRT가 따라올 수 없는 영역이 시작된다.
