Skip to content
isdnetworks
Go back

배포가 도는데 아무 일도 안 일어났다

브랜치 이름을 정리하면서 devdevelop 으로 바꿨다. 며칠 뒤 고친 게 안 올라간다는 말이 나왔는데 배포 이력은 전부 성공이었다.

Table of contents

Open Table of contents

증상 — 성공 이력과 안 바뀐 결과

배포 로그를 열었다.

Started by user ...
Fetching changes from the remote Git repository
Checking out Revision 3c81f0a (origin/dev)
...
Finished: SUCCESS

origin/dev 를 받고 있었다.

dev 는 이제 안 쓰는데 원격에 참조가 남아 있어서 받아지긴 했다. 받아지는데 옛 것이 받아지고 그 결과가 SUCCESS 로 남는다.

실패했으면 그 자리에서 알았을 것이다. 성공했기 때문에 며칠 동안 아무도 못 알아챘다.

원인 — 원격에 남은 옛 이름

이름을 바꿀 때 새 것을 만들고 옛 것을 안 지웠다.

$ git ls-remote --heads origin
3c81f0a  refs/heads/dev
8f2a1c3  refs/heads/develop

refs/heads/devrefs/heads/develop 이 둘 다 있으니 옛 것을 가리키는 설정이 계속 돈다.

$ git push origin --delete dev

--delete dev 로 지우고 나니 그 이름을 가리키는 것은 실패한다.

남겨 두는 것이 안전해 보였는데 실제로는 잘못된 상태를 조용히 유지하게 했다. 없어져야 드러나고 실패로 드러나는 편이 성공한 척 지나가는 것보다 낫다.

이름을 바꾸는 작업은 옛 이름을 지우는 것까지가 한 묶음이었다.

조치 — 가리키는 자리 전수 탐색

그 이름이 어디에 박혀 있는지 파일에서 찾았다.

$ grep -rn '\bdev\b' --include=*.xml --include=*.groovy /var/lib/jenkins/jobs/
/var/lib/jenkins/jobs/api-deploy/config.xml:  <name>*/dev</name>
/var/lib/jenkins/jobs/api-test/config.xml:    <name>*/dev</name>
/var/lib/jenkins/jobs/batch-deploy/config.xml:<name>*/dev</name>

config.xml 셋에 있었고 pull.sh 에도 있었다.

$ grep -rn 'dev' /srv/deploy/*.sh
/srv/deploy/pull.sh:12:  git pull origin dev

관리 화면만 봤으면 pull.sh 쪽을 놓쳤을 것이다.

화면으로 찾으면 화면에 나오는 것만 찾게 된다. 같은 값이 어디에 박혀 있는지는 파일에서 뒤져야 전부 나온다.

설정 — 이름을 한 자리에

각 설정에 문자열로 박혀 있으면 다음에 또 바꿀 때 또 흩어진다.

// Jenkinsfile
environment {
    DEPLOY_BRANCH = 'develop'
}
# /etc/deploy.env
DEPLOY_BRANCH=develop

스크립트는 DEPLOY_BRANCH 를 읽어 간다.

. /etc/deploy.env
git pull origin "$DEPLOY_BRANCH"

이제 이름이 바뀌면 deploy.env 한 곳만 고친다.

이번에도 config.xml 셋 중 하나만 고쳤으면 같은 증상이 다시 났을 것이다. 값을 한 자리로 모으는 것이 이 종류의 사고를 없애는 방법이었다.

검증 — 무엇을 배포했는지 남긴다

성공인데 안 바뀌는 상황을 다시 만나고 싶지 않았다.

REV=$(git rev-parse --short HEAD)
BR=$(git rev-parse --abbrev-ref HEAD)
echo "$BR@$REV  $(date -Is)  by ${BUILD_USER:-jenkins}" > /srv/app/REVISION
$ curl -s http://web01/health
{"rev":"develop@8f2a1c3","at":"2018-06-24T12:10:33+09:00"}

REVISIONhealth 응답으로 도는 것에서 본다.

기대한 것과 다르면 멈추게도 했다.

EXPECT=$(git rev-parse "origin/$DEPLOY_BRANCH")
ACTUAL=$(git rev-parse HEAD)
if [ "$EXPECT" != "$ACTUAL" ]; then
    echo "받은 것이 기대와 다릅니다: expect=$EXPECT actual=$ACTUAL"; exit 1
fi

일부러 다른 커밋으로 체크아웃해 놓고 expectactual 비교가 멈추는지 봤고 멈췄다.

교훈 — 종료 코드는 결과를 말하지 않는다

이 건에서 남은 것은 종료 코드의 뜻이었다.

받는 것에 성공했다   →  무엇을 받았는지는 안 말한다
스크립트가 끝났다    →  대상이 바뀌었는지는 안 말한다

성공은 명령이 끝났다는 뜻이지 의도한 상태가 됐다는 뜻이 아니다.

BEFORE=$(curl -s http://web01/health | ...)
# 배포
AFTER=$(curl -s http://web01/health | ...)
[ "$BEFORE" = "$AFTER" ] && { echo "배포됐는데 표시가 그대로입니다"; exit 1; }

배포 전후의 rev 를 비교하는 확인을 따로 붙였다.

바뀐 것을 보는 확인이 없으면 성공만 쌓인다. 이번에도 며칠치 성공 이력이 있었지만 그중 무엇도 실제로는 아무 일을 하지 않았다.

정리


Share this post on:

Previous Post
인과관계를 배제하는 세 단계
Next Post
전역 규칙이 하위에도 로드된다