[Jenkins] slave offline 상태 확인하는 Job 만들기

Illustration of cyberpunk style robot manager standing in front of several computers. Oil painting style.
“Illustration of cyberpunk style robot manager standing in front of several computers. Oil painting style.” created with DALL·E

우리 부서에서는 여러 용도로 젠킨스를 이용하고 있는데, jenkins slave agent가 여러 이유로 종종 offline이 되어서, 배치가 제대로 실행되지 않는 경우가 생겼다.

근본적인 해결책은 jenkins worker를 k8s pod로 동적 생성한다든가, k8s native cicd 툴을 쓴다든가, 아무튼 self healing이 되는 것으로 이전하는 것이다.

하지만 젠킨스의 수많은 plugin들과 groovy pipeline들을 타 플랫폼으로 옮기는 것은 많은 시간이 들 것이고, 그에 비해 offline 알림은 하루라도 빨리 만들어야 하기 때문에 jenkins 이전은 나중에 생각하고, 일단은 최소한의 땜질만 하는 것으로 결정했다.

slave agent 상태관리를 최소한의 공수로 어떻게 해결할까 고민하다 jenkins remote API를 호출해 slave agent 목록을 불러오는 쉘스크립트를 만들어 주기적으로 돌리기로 했다.

쉘스크립트는 zx를 이용해 작성했다.

Jenkins Remote API

Remote Access API
Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software
Jenkins Remote Access API

젠킨스는 여러 항목들에 대한 REST API를 제공한다. 주소 뒤에 "/api/"만 붙이면 된다. 예를 들어, 워커 노드 상태를 확인하는 주소가 ${젠킨스 주소}/computer/ 이므로 워커 노드 상태를 갖고오는 API는 ${젠킨스 주소}/computer/api/ 가 된다.

XML, JSON, Python 형식의 output을 제공하고, 맨 뒤에 xml, json, python을 붙이면 된다. ex) ${젠킨스 주소}/computer/api/json?pretty=true

API 사용 전 토큰을 만들어야 하며, 유저 페이지 - Configure - API Token 항목에서 생성할 수 있다.

curl -s -L --user USER:TOKEN ${JENKINS_URL}/computer/api/json

모든 노드 목록을 json 형식으로 가져오는 것은 위처럼 하면 된다

zx

더 나은 스크립팅, google zx
A tool for writing better scripts - zx GitHub - google/zx: A tool for writing better scriptsA tool for writing better scripts. Contribute to google/zx development by creating an account on GitHub.GitHubgoogle 개발, 운영시 스크립트를 많이 만들어 쓴다. 해 본 사람은 알겠지만 bash 스크립트 만들어 쓰는건 굉장히

이전에 zx에 대해 조사해보고 이번에 꼭 zx를 써보겠다고 생각했다. zx 덕분에 누구나 알기 쉬운 스크립트를 빠르게 작성할 수 있었다.

#!/usr/bin/env zx

// zx settings
$.verbose = false

// zx-bundled packages
const error = chalk.bold.red;
const success = chalk.green;

// constants
const SLACK_WEBHOOK = "..."

const JENKINS_ADMIN_TOKEN = "..."
const JENKINS_ADMIN_INFO = `admin:${JENKINS_ADMIN_TOKEN}`
const JENKINS_REMOTE_API_ENDPOINT = "http://localhost:80/computer/api/json"

try {
  const offline_agnets_str = await $`curl -s -L --user ${JENKINS_ADMIN_INFO} ${JENKINS_REMOTE_API_ENDPOINT} | jq '[ .computer[] | select( .offline ) | .displayName]'`
  const offline_agents = JSON.parse(offline_agnets_str)

  // send slack message
  if (offline_agents.length > 0) {
    const msg = `🔴 offline agents!!\n${offline_agnets_str}`
    
    // (slack 메시지 전송)
    
    echo(error(`Some agents are offline! please check.\n${offline_agnets_str}`))
    process.exit(0)
  }

  echo(success('No offline agents :)'))
  process.exit(0)
} catch (p) {
  echo(error(p))
  process.exit(1)
}
check_slave_connection.mjs

스크립트는 위처럼 작성했고, 내부에선 curl을 이용해 모든 노드 목록을 가져왔으며 jq를 이용해 "offline": true인 노드의 displayName만 뽑아냈다. (이정도는 스크립트가 아닌 커맨드를 이용하는게 나은 듯 하다)

그 다음, jenkins에서 Freestyle job을 만들어서 스케줄을 걸어놓았다.

스크립트는 master 서버에 넣어놓았고, 빌드시 이 스크립트를 실행하도록 했다.

zx 유의사항

#!/usr/bin/env -S zx --install

로컬에서 위처럼 shebang에 zx --install을 같이 넣었을 때 문제가 없었는데, 리눅스 머신에서 쓰니 오류가 발생했다.

/usr/bin/env: unrecognized option: S

zx 스크립트 실행시 위처럼 env에 -S 옵션을 넣을 수 없다고 나온다면, coreutils 버전이 낮은 것이다. env -S 옵션은 coreutils 8.30 버전부터 들어갔다.

(참고: coreutils/NEWS)

[deploy@my-centos ~]$ sudo yum list installed | grep -i coreutils
coreutils.x86_64                     8.22-21.el7                       @anaconda
policycoreutils.x86_64               2.5-22.el7                        @anaconda
coreutils 설치 확인 방법 (centos 7.5 기준)

coreutils 버전은 yum 등으로 확인 가능하다.

어쨌거나 env -S 옵션을 못쓰면, 최초 실행시에 zx --install 스크립트 를 수동으로 한번 해줘야 한다.

남은 과제

master -> slave node를 확인하는 것은 끝났지만.. master가 죽었을 때는 어떻게 확인을 해야 할까?

결국은 PagerDuty 같은 Incident management 플랫폼의 도움이 필요한데, 사내에선 여러모로 여의치 않아 😞 당분간은 최첨단 수동으로 처리하기로 했다.