OpenStack 모니터링 스크립트

RHOSP/OpenStack compute 노드, 컨테이너, 로그, 서비스, VM 배치 상태를 점검하는 모니터링 스크립트입니다. 스크립트의 SSH/임시파일 오류를 함께 다룹니다.

RHOSP/OpenStack 환경에서 compute 노드 상태, 컨테이너 상태, 주요 서비스 상태, VM 배치 상태를 한 번에 확인하기 위한 모니터링 스크립트를 절차입니다. 스크립트는 목적은 좋지만 root$host처럼 SSH 대상 표기가 잘못된 부분, 마지막에 존재하지 않는 mon.sh.temp를 처리하는 부분, controller 점검과 compute 점검이 섞여 있는 부분이 있어 운영 중 바로 쓰기에는 보완이 필요합니다. 아래는 같은 목적을 유지하면서 실행 전 변수, SSH 확인, 서비스 목록, 로그 검색을 분리한 버전입니다.

전제 조건

  • 스크립트는 stack 사용자 또는 OpenStack CLI 인증 파일을 source할 수 있는 사용자로 실행합니다.
  • ~/overcloudrc가 존재하고 openstack compute service list가 실행되어야 합니다.
  • compute 노드에는 heat-admin 계정으로 SSH 접근할 수 있어야 합니다.
  • RHOSP 버전에 따라 컨테이너 런타임은 podman 또는 docker일 수 있으므로 자동 감지합니다.
  • 스토리지 명령(iscsiadm, ScaleIO/PowerFlex drv_cfg)은 해당 구성에서만 의미가 있습니다.

실행 전 빠른 확인

su - stack
source ~/overcloudrc
openstack token issue
openstack compute service list

# compute 노드 SSH 확인
ssh heat-admin@compute-node "hostname; uptime"

개선한 모니터링 스크립트

환경에 맞게 COM_HOSTS, CON_HOSTS, COM_EXPECTED_CONTAINERS 값을 수정한 뒤 실행합니다. 컨테이너 개수는 배포 버전과 역할에 따라 달라지므로 절대값으로 장애를 단정하지 말고, 평상시 기준값과 비교하는 용도로 사용합니다.

#!/usr/bin/env bash
set -euo pipefail

RC_FILE="${RC_FILE:-$HOME/overcloudrc}"
SSH_USER="${SSH_USER:-heat-admin}"
CON_HOSTS="${CON_HOSTS:-}"
COM_HOSTS="${COM_HOSTS:-172.23.167.150}"
COM_EXPECTED_CONTAINERS="${COM_EXPECTED_CONTAINERS:-16}"
LOG_LINES="${LOG_LINES:-200}"

if [[ ! -f "$RC_FILE" ]]; then
 echo "ERROR: OpenStack RC file not found: $RC_FILE" >&2
 exit 1
fi

source "$RC_FILE"

run_ssh() {
 local host="$1"
 shift
 ssh -o BatchMode=yes -o ConnectTimeout=8 "${SSH_USER}@${host}" "$@"
}

remote_runtime() {
 local host="$1"
 run_ssh "$host" "command -v podman >/dev/null 2>&1 && echo podman || { command -v docker >/dev/null 2>&1 && echo docker; }"
}

section() {
 printf '\\n#============================================================\\n'
 printf '# %s\\n' "$*"
 printf '#============================================================\\n'
}

check_node() {
 local host="$1"
 section "NODE ${host}"

 echo "## Host basic"
 run_ssh "$host" "hostname; date; uptime"

 echo "## Container status"
 local runtime
 runtime="$(remote_runtime "$host")"
 if [[ -z "$runtime" ]]; then
 echo "WARN: no podman/docker runtime found"
 else
 local cnt
 cnt="$(run_ssh "$host" "sudo ${runtime} ps --format '{{.Names}}' | wc -l")"
 echo "runtime=${runtime} running_containers=${cnt} expected=${COM_EXPECTED_CONTAINERS}"
 if [[ "$cnt" -lt "$COM_EXPECTED_CONTAINERS" ]]; then
 run_ssh "$host" "sudo ${runtime} ps --format 'table {{.Names}}\\t{{.Status}}\\t{{.Image}}'"
 fi
 fi

 echo "## Disk"
 run_ssh "$host" "df -hT"

 echo "## Network"
 run_ssh "$host" "ip -br addr; ip route; ip neigh | egrep -i 'failed|incomplete' || true"

 echo "## Default gateway ping"
 run_ssh "$host" "gw=\\$(ip route | awk '/default/ {print \\$3; exit}'); [ -n \"\\$gw\" ] && ping -c 3 \"\\$gw\" || true"

 echo "## iSCSI session"
 run_ssh "$host" "sudo iscsiadm -m session -P 3 2>/dev/null | egrep 'Target:|Current Portal|State:' || true"

 echo "## ScaleIO/PowerFlex MDM"
 run_ssh "$host" "sudo /opt/emc/scaleio/sdc/bin/drv_cfg --query_mdms 2>/dev/null || true"

 echo "## Chrony"
 run_ssh "$host" "date; chronyc tracking 2>/dev/null || true; chronyc sources 2>/dev/null || true"

 echo "## Recent container errors"
 run_ssh "$host" "sudo find /var/log/containers -type f -name '*.log' -print0 2>/dev/null | xargs -0 sudo tail -n ${LOG_LINES} 2>/dev/null | egrep -i 'error|failed|traceback|critical' || true"
}

section "OpenStack service status"
openstack compute service list
openstack volume service list || true
openstack network agent list || true

section "Controller nodes"
if [[ -n "$CON_HOSTS" ]]; then
 for host in $CON_HOSTS; do
 check_node "$host"
 done
else
 echo "CON_HOSTS is empty. Skip controller SSH checks."
fi

section "Compute nodes"
for host in $COM_HOSTS; do
 check_node "$host"
done

section "VMs on target compute hosts"
tmp_hosts="$(mktemp)"
trap 'rm -f "$tmp_hosts"' EXIT

for chost_ip in $COM_HOSTS; do
 openstack hypervisor list --long | awk -v ip="$chost_ip" '$0 ~ ip {print $4}' >> "$tmp_hosts"
done

sort -u "$tmp_hosts" | while read -r hypervisor; do
 [[ -z "$hypervisor" ]] && continue
 echo "## hypervisor=${hypervisor}"
 openstack server list --all-projects --long --host "$hypervisor" \
 -c ID -c Name -c Status -c Networks -c Host
done

실행 방법

vi openstack-node-monitor.sh
chmod 750 openstack-node-monitor.sh

source ~/overcloudrc
COM_HOSTS="172.23.167.150 172.23.167.151" \
COM_EXPECTED_CONTAINERS=16 \./openstack-node-monitor.sh | tee "openstack-node-monitor-$(date +%Y%m%d-%H%M%S).log"

결과 해석 기준

점검 항목 정상 기준 이상 시 다음 확인
OpenStack service list compute, volume, network agent가 up/enabled 해당 서비스 컨테이너 로그와 systemd unit 상태
컨테이너 수 평상시 기준 개수와 일치 podman ps -a, restart loop, image pull 실패
디스크 루트, 로그, 컨테이너 볼륨 여유 공간 존재 /var/log, /var/lib/containers 사용량
네트워크 DOWN 인터페이스와 incomplete ARP 없음 bond, VLAN, OVS bridge, gateway ping
시간 동기화 chrony source가 정상이고 offset이 작음 NTP 서버, 방화벽, clock drift
로그 에러 최근 tail 범위에서 반복 ERROR 없음 request-id 기준으로 nova/neutron/cinder 로그 추적

스크립트에서 고친 부분

  • ssh root$host처럼 @가 빠진 형태를 사용하지 않도록 SSH 함수를 분리했습니다.
  • dockerpodman 중 존재하는 런타임을 자동 감지합니다.
  • 존재하지 않는 mon.sh.temp 파일을 마지막에 처리하던 부분을 제거했습니다.
  • 임시 파일은 mktemptrap으로 정리합니다.
  • 명령 실패가 전체 스크립트를 불필요하게 중단하지 않도록 선택 점검에는 || true를 사용했습니다.

운영 주의사항

이 스크립트는 조회용입니다. 장애 상황에서 바로 재시작이나 삭제를 수행하지 않습니다. 출력 로그를 남긴 뒤, 어떤 노드와 어떤 서비스에서 문제가 반복되는지 확인하고 조치해야 합니다. 특히 compute 노드 작업은 해당 노드 위의 VM, live migration 가능 여부, maintenance mode 여부를 확인한 뒤 진행해야 합니다.

BGM EVER