인프라

Docker CI/CD 구성하여 자동배포중 발생한 오류 모음 (EC2, Github Action, NestJS, ECR)

김도리개발자 2023. 5. 1. 14:22

이후 docker-image.yaml 코드를 작성하면서 발생한 오류들을 차근차근 살펴보자.

바보같은 오류도 있었지만 하나하나 리뷰하려고 한다.

 

1. import worker-gridge code 과정에서 missing Dockerfile

  • 에러메시지 : ERROR: failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to read dockerfile: open /var/lib/docker/tmp/buildkit-mount2011953406/Dockerfile: no such file or directory
  • 문제 : Dockerfile을 로컬에서만 만들고 git에는 안올렸었다.
  • 솔루션 : Dockerfile을 git에 추가해주었다. (너무 부끄럽지만 첫 실패니까 올린다.)

 

2. git pull 착각

  • 에러메시지 : err: bash: line 1: cd: /var/www/html: No such file or directory
  • 문제 :
    • 테스트용으로 가져온 코드가 EC2 인스턴스에 Docker 없이 배포를 했었는데 그시절 기반으로 처음에 코드를 작성하다보니 EC2 인스턴스에 git pull을 해야하는 것으로 잠깐 착각했었다.
    • 우리는 git pull을 하는것이 아닌 ECR pull을 해서 github action에서 제작된 이미지만 가져올 것이다.
    • 심지어 내가 directory도 순서를 착각해서 터진 에러였다. (cd /var/html/www가 맞는 코드)
  • 솔루션 : cd: /var/www/html은 필요없는 코드이기 때문에 아예 지워줬다.

 

3. install Docker

  • 에러메시지 : err: bash: line 1: docker: command not found
  • 문제 : EC2 인스턴스에 Docker부터 깔아야 했다.
  • 솔루션 :
    • 스크립트에 Docker를 설치하고 실행하는 코드도 추가해주었다.
    • (하지만 잘못된 방법이었음을 다음 오류에서 알게된다.)

 

4. docker 설치 스크립트에서 누락된 내용 발생

  • 에러메시지 : 
    • err: Operation aborted.
      Process exited with status 1
      out: Is this ok [y/N]:
  • 문제 : Docker 설치 코드를 sudo yum install docker 이렇게 추가했었는데 스크립트가 돌아가면서 y를 눌러주지 못하는 상황이니 에러가 났다.
  • 솔루션 : sudo yum install docker -y 로 스크립트를 변경해주었다.

 

5. sudo의 늪

 

6. 이미 설치된 Docker

  • 에러메시지 : 
    • err: Redirecting to /bin/systemctl start docker.service
      err: Error response from daemon: Head "https://***.dkr.ecr.ap-northeast-2.amazonaws.com/v2/test-docker-nest/manifests/latest": no basic auth credentials
  • (잘못된) 문제 : 에러가 나지 않은 37번째 줄에 이미 docker를 설치했다는 것을 에러메시지로 잘못 인지했다.
  • (잘못된) 솔루션 : docker 설치 및 실행 코드를 지워주었다.

 

7. 로그인 필요

  • 에러메시지 :
    • err: Error response from daemon: Head "https://***.dkr.ecr.ap-northeast-2.amazonaws.com/v2/test-docker-nest/manifests/latest": no basic auth credentials
  • 문제 : 
    • docker pull 명령을 실행하면 HTTP 403 (Forbidden) 오류 또는 no basic auth credentials 오류 메시지가 표시되는 경우가 있다.
    • ECR내에 있는 private image이기 때문에 권한이 있는 유저의 로그인이 필요하다.
    • 위에서 ECR에 push할 때 로그인을 해두어서 괜찮을 줄 알았는데 ECR에서 pull 받을 때에는 EC2 인스턴스 내에서 하는 것이기 때문에 로그인을 다시 해주어야 한다.
    • https://docs.aws.amazon.com/ko_kr/AmazonECR/latest/userguide/common-errors-docker.html
  • 솔루션 :
    • aws cli 환경을 ec2 인스턴스에 직접 해주었다.
    • aws configure를 통해 유저의 정보들을 입력해주었다.
 

Amazon ECR 사용 시 Docker 명령을 실행하면 발생하는 오류 문제 해결 - Amazon ECR

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 

7.5. 보너스 에러 당첨

  • 에러메시지 :
    • Unable to locate credentials. You can configure credentials by running "aws configure".
      Error: Cannot perform an interactive login from a non TTY device
  • 문제 : EC2 인스턴스 내의 터미널에서 직접 aws cli 환경을 구성하고 로그인을 시키는데 aws configure를 통해 올바른 계정 정보를 입력했음에도 불구하고 로그인에서 자꾸 credential 에러가 남
  • 솔루션 : | 로 2개의 스크립트를 이어 붙였는데 앞에는 sudo를 붙여주었지만 뒤의 login 스크립트에는 sudo를 붙여주지 않아 생기는 문제였다. (그래서 내가 sudo su 하는게 좋다고 했던것이었다,,,,,, 여기서 많이 힘들었다.)

 

8. 이미지 태그 :latest

  • 에러메시지 : 
    • err: WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
      err: Configure a credential helper to remove this warning. See
      err: https://docs.docker.com/engine/reference/commandline/login/#credentials-store
      err: Error response from daemon: manifest for ***.dkr.ecr.ap-northeast-2.amazonaws.com/test-docker-nest:latest not found: manifest unknown: Requested image not found
  • 문제 : 이미지를 pull 받을 때 latest 태그를 붙여주었는데 docker hub에서는 latest 태그를 붙이면 자동으로 가장 최신의 이미지가 불러와지지만 ECR에서는 latest 태그로 자동으로 불러와지지 않고, 직접 붙인 태그로만 불러와진다.
  • 솔루션 :
    • image를 ECR에 push할 때 latest 태그를 붙였다.
    • 추가 걱정은 이미 latest 태그의 이미지가 ECR에 있을텐데 중복으로 latest 태그를 지정하면 어떻게 되지? 였다.
      • 아래의 이미지를 보면 가장 최근에 올린 이미지의 태그는 남아있고,
        기존 이미지중 중복되는 태그들을 가지고 있던 이미지들은 untagged 된다.

 

9. docker stop의 늪

  • 에러메시지 : err: Error response from daemon: No such container: test-docker-nest
  • 문제 : 
    • 여기서 진짜 힘들었다. docker container를 띄우기 전에 기존 container는 내려주어야 하니까 sudo docker stop test-docker-nest 코드를 추가했었는데
      띄워져 있는 container가 아직 없을 때에는 알아서 분기처리 되어서 무시하고 다음 스크립트로 넘어갈 줄 알았더니
      아직 실행중인 container 없으니 실행 불가 하면서 에러가 뜸
  • 솔루션 : 
    • 일단 생각해보니 stop이 아닌 container 지우기까지 해줘야 할 것 같아 sudo docker rm -f test-docker-nest로 바꿔주었다.
      • 원래는 stop 하고 rm 하는게 정석인데 한방에 강제 종료 및 삭제 해버릴 수 있는 스크립트를 썼다. (정석은 아니라고 알고 있음)
    • 그 이후는 막막했다. docker 내부적으로 실행중이면 지우고 아니면 무시하고 하는 옵션 자체도 없고,
      그럼 shell script를 짜서 if/else 처리를 해줘야하나? 생각이 들어 실행중인 container 검사하고 그 개수로 비교하고 하는 등의 삽질들을 했었다. 이 과정에서 스크립트 언어도 살짝 공부하게 되어 오히려 좋긴 한데,,, 이 당시에는 너무 많은 시간을 이 오류 해결에 쏟았다. 
    • 뭐때문인진 모르겠지만 배열의 개수가 돌아가고 있는 container가 없음에도 불구하고 1개를 차지하고 있고, 그 1개의 길이도 1 초과일때만 rm 하는 식으로 했는데 비교 연산자체도 안 통했다. 스크립트 언어에 대한 이해가 낮은 상태에서 진행하려니까 포기 선언 GG 때리고 싶었다.
    • 그러다 비슷한 오류를 겪은 블로그중에 스크립트 뒤에 2>&/dev/null 를 붙여줌으로써 에러나는 스크립트는 휴지통으로 버리는 옵션을 찾게 된다.
      (하지만 이것도 통하지 않았지만 일단 시도해보았다.)

 

10. 이하동문

  • 에러메시지 : err: bash: line 5: /dev/null: ambiguous redirect
  • 문제 : sudo docker rm -f test-docker-nest 2>&/dev/null 코드에서 2>&/dev/null 이 뒤의 내용으로 인한 문제 발생
  • 솔루션 : 2>&/dev/null 를 2>/dev/null로 바꿔줌 (이것도 통하지 않았다.)

 

11. 이하동문

  • 에러메시지 : err: Unable to find image 'test-docker-nest:latest' locally
  • 문제 : sudo docker rm -f test-docker-nest 2>/dev/null 스크립트가 원하는 방식대로 작동하지 않는다.
  • 솔루션 :
    • 다른 분기처리 스크립트 조합으로 작성을 해보았다. (9에서 시도하다 포기한 shell 스크립트 작성)
    • 실행중인 컨테이너 중 "test-docker-nest"를 검색하여 그 개수를 변수에 저장시켜두었다가 해당 변수와 1을 비교하여 
      true면 docker container 강제종료 및 삭제하고, false면 echo "false" 하는 코드를 추가했다.
    • counter=docker container ls | grep -c "test-docker-nest"; if [ $counter -eq 1 ]; then docker container rm -f "test-docker-nest"; else echo "false" ;fi
      • 이 스크립트에 잘못된 점이 있습니다. 먼저 찾는 사람 천재 & 마스터

 

12. 스크립트의 늪 + sudo의 늪

  • 에러메시지 : err: bash: line 5: [: -eq: unary operator expected
  • 문제 :
    • counter=docker container ls | grep -c "test-docker-nest"; if [ $counter -eq 1 ]; then docker container rm -f "test-docker-nest"; else echo "false" ;fi
    • -eq는 숫자끼리 비교하는 연산이라고 하는데 앞에 counter가 문자열 취급이 됐던건가? 하면서 로컬에서도 이것저것 해봄
      • (스포) ==도 써보고 =도 써보고 counter에 "" 큰따옴표도 붙이고 했지만 똑같았다. (아래 나옴)
      • 진짜 문제는 따로 있었는데,,, 바로바로,,,,,,
    • counter라는 변수에 들어가는 스크립트에 sudo가 안붙어 0이나 1의 값이 할당되지 못한 것 (하지만 이 오류 뿐만이 아니었다. 여기서 찾는 사람 진짜 천재)
  • 솔루션 : 
    • sudo가 빠진 부분들에 쏙쏙 넣어주었다! (그래 sudo su 쓰자고,,,)
    • 이번엔 두 번의 똑같은 실수는 없다! 하면서 뒤쪽의 then 이후 스크립트에서 sudo 잘 넣어줌
    • counter=sudo docker container ls | sudo grep -c "test-docker-nest"; if [ $counter -eq 1 ]; then sudo docker container rm -f "test-docker-nest"; else echo "false" ;fi

 

13. 이하동문 

  • 에러메시지 : err: bash: line 5: [: -eq: unary operator expected
  • 문제 : counter가 변수 취급을 못받아서 [ -eq 1] 이렇게만 돌아가고 있나? 했다.
    (하지만 똑같았다.)
  • 솔루션 :
    • 비교하는 스크립트 중 $counter에 ""큰따옴표를 붙여 존재감을 알려주기로 해보았다.
    • if [ "$counter" -eq 1 ];

 

14. 이하동문

  • 에러메시지 : err: bash: line 5: [: : integer expression expected
  • 문제 : 에러메시지만 보면 counter 변수가 integer가 아니어서 생긴 문제였다. 
  • 솔루션 : -eq를 ==로 바꿔주었다. (매우 잘못된 접근)

 

15. 이미지를 찾으러 왔단다.

  • 에러메시지 : err: Unable to find image 'test-docker-nest:latest' locally
  • 문제 :
    • 잘못된 접근으로 에러 해결을 해서 생긴 오류라서 근본적인 원인을 찾기 시작했다. 
    • 위의 에러 메시지는 test-docker-nest:latest 이미지를 못찾겠다는 말이다.
    • 스크립트는 잘못 짜여지긴 했지만 false로 돌아가서 rm이 실행되지 않았고,
      이제 container를 run 하는 코드가 돌아가다가 직면한 문제다.
    • ECR에서 pull받은 이미지의 이름이 ECR 주소부터 통으로 설정되기 때문에 그에 맞춰서 써줘야하는데
      이미지 이름으로 레포지토리 이름과 태그값만 띡 써줘서 생긴 문제였다.
  • 솔루션 :
    • container 실행시에 이미지 이름을 잘 확인하여 ECR로부터 가져와지는 이미지 이름으로 설정해주었다.

 

16. 뜻밖의 안 반가운 손님 (`ㄴㅇㄱ`)

sudo aws ecr get-login*** ap-northeast-2 | sudo docker login --username AWS --password-stdin ***.dkr.ecr.ap-northeast-2.amazonaws.com
sudo docker pull ***.dkr.ecr.ap-northeast-2.amazonaws.com/test-docker-nest:latest
counter=sudo docker container ls | sudo grep -c "test-docker-nest"; if [ "$counter" == 1 ]; then sudo docker container rm -f "test-docker-nest"; else echo "false" ;fi
sudo docker container run -p 3232:3232 -d --name test-docker-nest ***.dkr.ecr.ap-northeast-2.amazonaws.com/test-docker-nest:latest
  • 문제 :
    • 그렇게 작성된 스크립트 코드이고 잘 돌아가서 빌드까지 성공했으나 여기서도 어이없는 오류가 있다. 
    • 스크립트를 친구와 같이 각자 짜봤었는데 그 스크립트를 디스코드 메시지로 주고 받았었다. 이번에 돌린 코드도 친구가 짜준 코드였고 그대로 돌렸었는데 친구가 로컬에서 실행할 땐 잘만 되던 코드가 내가 할때에는 안되길래 뭐지? 하고 코드를 유심히 봤다.
    • 친구의 화면을 보면서 내게 디코 메시지로 보내준 코드를 비교해보니 뭔가 틀린 그림이 있었다.
      • 찾았다 요놈!
    • 디스코드에서 백틱(backtick)을 치면 자동으로 코드로 변환해주어 메시지 내에서 백틱 자체는 사라지던 것이었다.
  • 솔루션 : 
    • 코드에 백틱이 필요한 부분에 추가해주었다.

디스코드 메시지로 보내진 메시지 (백틱이 사라져있다.)

 

17. 빌드는 됐으나,, 약해,,,

  • 문제 :
    • CI/CD는 잘 돌아갔으나 문제가 또 발생했으니,,,,
    • 바로 EC2 인스턴스가 배포를 마쳤으나 실제 배포 테스트를 해보니 서버에 접근이 안되는 문제
      • 물론 여기서 port 열고 하는것 까지 다 미리 해줬었다.
    • EC2 인스턴스 내에서 로그를 보려 하니 서버가 죽어버렸다.
    • t2.micro로는 docker를 돌리기에 너무 버거웠다.
  • 솔루션 : 
    • 큰맘 먹고 t3.medium으로 인스턴스를 새로 생성하여 빌드했다.
    • 위에서 났던 에러들 중 docker install, docker start, aws configure, ecr login 등등 하나하나 차근차근 다 했다.

 

18. 마참네

성공한 배포와 api 통신

 

 

Docker CI/CD 구성하여 자동배포중 발생한 오류 해결기를 마친다.