kimyu0218
  • [etc] 쉘 스크립트 에러 핸들링하기
    2024년 01월 23일 05시 36분 26초에 업로드 된 글입니다.
    작성자: @kimyu0218
    서버 터뜨리는 경우의 수 다 해보기 😵‍💫
    (예비 서버 개발자지만 서버를 터뜨려요)

    지난 번에는 health check를 안 해줘서 서버를 터뜨렸는데, 이번에는 도커 컴포즈에 오타를 내서 서버를 터뜨렸다!

    하이픈인 줄 알았으나 언더바였다.

    이번 포스팅에서는 배포 스크립트에서 발생할 수 있는 에러를 선별하고, 에러가 발생하면 곧바로 종료하여 잘 돌아가는 서버에 영향을 미치지 않도록 만들어 줄 것이다.

    문제의 배포 스크립트

    echo "The $STOP_TARGET version is currently running on the server. Starting the $RUN_TARGET version."
    DOCKER_COMPOSE_FILE="compose.$RUN_TARGET-deploy.yml"
    sudo docker-compose -f "$DOCKER_COMPOSE_FILE" pull
    sudo docker-compose -f "$DOCKER_COMPOSE_FILE" up -d
    sleep 50

    이번에 서버가 터지게 된 원흉을 가져왔다. 도커 컴포즈 파일에 문법 오류가 발생하여 컨테이너들이 실행되지 않았는데 이에 대한 에러 핸들링이 없어 다음 작업들이 계속 진행된다. (뒤에 기존 버전의 어플리케이션을 종료하는 작업들이 있는데 여기서 안 멈추는 바람에 서버가 꺼졌다 ㅎㅎ)

    현재 스크립트를 기준으로 에러가 발생할 수 있는 부분을 추려봤다. (이외에도 에러 핸들링할 게 엄청 많지만, 자주 수정되는 부분에 대해서만 처리하기로 했다)

    • 도커 컴포즈 파일이 존재하지 않거나 도커 허브 권한 제한 등으로 이미지를 받아오지 못한 경우
    • 도커 컴포즈 파일의 문법 오류로 인해 컨테이너를 실행하지 못하는 경우
    • 엔진엑스 설정파일을 수정하고 리로드 하는 과정에서 업스트림을 찾지 못하는 경우

     

    에러가 발생하면 곧바로 종료하기

    에러 난 시점에 바로 종료하여 에러가 더 큰 에러로 번지는 것을 막아보자.

    set -e : exit immediately

    bash의 `set` 명령은 쉘 환경을 조작할 수 있다. `-e` 옵션을 사용하여 비정상적으로 종료되었을 때 즉시 종료할 수 있다. 해당 명령을 쉘 스크립트 상단에 적어 에러가 발생하면 곧바로 종료되도록 하자.

    #!/bin/bash
    
    set -e

     

    명시적으로 비정상 종료하기

    이제 `set -e`가 실행될 수 있도록 에러가 발생할 수 있는 부분에 명시적으로 종료하는 작업이 필요하다. 이때 `0`이 아닌 숫자로 종료해야 한다.

    sudo docker-compose -f "$DOCKER_COMPOSE_FILE" pull || exit 1
    sudo docker-compose -f "$DOCKER_COMPOSE_FILE" up -d ||  exit 1

    or 연산자로 왼쪽 명령에 실패했을 때 `exit 1`을 호출하여 비정상 종료를 수행할 수 있도록 한다. (엔진엑스 리로드에도 이와 같은 처리를 해줬다!)


    디버깅을 위한 로그를 남겨보자

    위의 코드로 에러가 더 큰 에러로 번지는 것을 막았다. 하지만 근본적인 문제가 남았다. 우리는 오류를 해결해야 한다ㅎ

    오류를 빠르게 바로 잡기 위해서는 어디에서 에러가 났는지, 어떤 에러가 났는지 확인할 수 있는 지표가 있어야 한다. 종료 전에 로그를 남겨보자.

    trap

    `trap`은 특정 이벤트나 신호에 대한 처리를 지정하는 데 사용되는 명령이다. 주로 오류 처리나 스크립트 종료 시 정리 작업을 수행하는 데 활용된다.

    trap [COMMAND] [SIGNALS|EVENTS]

    나는 trap으로 스크립트가 비정상적으로 종료되었을 때 로그를 출력할 것이다.

    trap 'echo "Error occured: $ERR_MSG. Exiting deploy script."; exit 1' ERR
    *ERR : 쉘 스크립트에서 명령이 실패했을 때 발생하는 이벤트


    이제 비정상 종료를 수행할 때 로그 메시지를 출력하도록 명령을 수정해보자. `ERR_MSG`라는 변수에 에러에 대한 정보를 전달해야 한다.

    sudo docker-compose -f "$DOCKER_COMPOSE_FILE" pull || { ERR_MSG='Failed to pull docker image'; exit 1; }
    sudo docker-compose -f "$DOCKER_COMPOSE_FILE" up -d || { ERR_MSG='Failed to start docker image'; exit 1; }

    중괄호로 명령들을 그룹화하여 한 줄에 `ERR_MSG`에 로그 메시지 값을 대입하고, 종료 이벤트를 발생시켰다.

    위의 두 가지 작업을 통해 하나의 에러가 다른 작업에 영향을 미치는 것을 방지하고, 신속하게 에러를 수정할 수 있게 되었다!

    🔗 배포 스크립트 전문 보러가기
    댓글