오늘 배운 것

어제의 작업을 통해서 배포 시간은 평균 20분에서 8분으로 약 10분 이상 단축되었다. 그러나 여전히 개발 서버가 develop 브랜치의 최신 내용을 반영하지 못하고 있었다. 이쯤 되면 혹시 develop 브랜치의 내용이 ECR에 안 반영되는 것이 아닌가 하는 의심도 들었는데, ECS 클러스터>서비스>태스크의 컨테이너 정보를 확인해보니 의문이 풀렸다. 

 

왜인지는 모르겠지만, 컨테이너는 ECR 레포지토리의 latest 태그가 붙은 이미지를 참조하고 있었다(참조한다는 표현이 맞는지 모르겠다).

 

그렇다면 다시 yaml 파일을 봐야 하겠다. 사실 지금은 yaml 파일을 이리저리 건드려보는 중이라서... 뭘 해도 어떤 근거로 무조건 develop 브랜치와 잘 연동될거다!는 확신은 없다. 그래도 바꿀 점이 또 있나 찾아본 결과, docker build 구문에서 기존에는 커맨드에 ECR 레포지토리의 값만 넣어주었는데, 막상 전체 주소는 이와 좀 다른 것 같았다. 그래서 이 값을 바꿔주었다. 

 

그리고 해당 아래의 값도 바꿔주었다. 

 

기존에 raw string으로 task definition을 입력해서 ecs-task-def.json 파일에 넣어주는데, 막상 해당 task-definition 필드를 보니 환경변수 값으로 되어있었다. 그보다는 방금 입력한 태스크 정의값이 들어있는 파일을 넣어 주는 것이 인식이 잘 될 것 같아서 값을 바꿔주었다. 


여전히 되지 않는다...(develop 브랜치와 개발 서버의 내용이 다르다) 다시 처음으로 돌아가서 GPT에게 질문을 해 보자. 

+ 검색하다가 yaml 파일의 설정이 어떻게 되어있는지를 알려주는 공식문서를 찾았다! 그동안 이게 뭔지 잘 모르면서 입력했던 설정값이 다 여기서 정의된 값들이었다. 

 

[공식문서]와 [파일]을 주고 GPT에게 문제를 내보았다

GPT는 크게 설정은 수정할 부분이 없으나, ECS 태스크 정의를 렌더링하는 과정에서 revision과 taskDefinitionArn 필드를 빼라고 알려주었다. 이유는 family 필드를 정의하면 이미 ECS에서 태스크 정의를 인식할 수 있고, revision 필드의 경우 수동으로 지정하기보다는 자동으로 (아마도 1씩 revision 값이 증가하도록) 지정하는 것이 원칙인 것 같았다. 

 

이렇게 또 yaml 파일을 변경하고 커밋을 올려보았는데, 아직도 개발 서버와 브랜치의 내용이 달랐다. 그리고 위에서와 같이 서비스가 어떤 태스크 정의를 사용하고 있는지도 보았는데, 또 이전 태스크 정의를 사용하고 있었다. 그래서 이번에는 강제로 서비스에서 사용하고 있는 태스크 정의를 바꿔주는 커맨드를 사용해 보았다. 

aws ecs update-service --cluster your-cluster-name --service your-service-name --task-definition your-task-definition-name

 

이 작업도 실패해서, 이번에는 ECS 클러스터>서비스에 들어가서 '서비스 업데이트'를 누르고 사용하는 태스크 정의를 최신 버전(현재는 27)으로 바꿔주었다. 

 

그런데 문득 이렇게 태스크 정의를 세세히 입력해 주었는데 '태스크 정의'에는 막상 등록한 json 파일 내용들이 잘 들어있고, 서비스에서 사용하는 태스크 정의는 정작 업데이트 되지 않았다는 점이 의아했다. 어쩌면 깃헙 워크플로우의 세부 단계에서 태스크 정의 렌더링(Render Task Definition)은 잘 되었는데 그 다음 작업(태스크 정의 등록 또는 ECS 서비스 배포)에서 무언가 오류가 나서 전체 작업이 롤백 되었을 가능성도 있겠다. 

 

실제로 ECS 클러스터>서비스의 '이벤트' 탭에서 찍힌 기록을 확인해보니 'roll back'이라는 문구가 보였다. ECS에서 새 태스크 정의를 통해 새 태스크를 만들고 이를 서비스와 연결하려다가 만약 실패하면 이 작업을 다시 롤백하는 것으로 보였다. 

 

그래서 롤백하기 전 시도했던 이벤트를 CloudWatch의 로그 그룹에서 찾아서, 구체적인 로그를 찾아보았다. 그랬더니 문제는 예상 외로 다른 곳에서 발생하고 있었다. 

 

 

이 부분은 aws.py라는 직접 만든 파이썬 파일에서 AWS Secrets Manager를 통해 환경변수들을 불러오는 부분이었다. 여기서 에러가 나고 있어서 이후에 ECS 클러스터에서 태스크가 정상적으로 실행되지 않았고, 그래서 다시 서비스가 기존 태스크를 사용하도록 롤백했을 가능성이 있다. 

 

문제를 찾아보기 위해서 AWS Secrets Manager와 develop 브랜치의 aws.py 파일을 확인해 보았다. 추측되는 원인 중 하나는, prod 값에 따라서 해당 파일에서 "AWS_SECRET_NAME_PROD" 라는 변수를 조회하게 될 수 있는데 이 값이 로컬 환경변수에는 있고 태스크를 정의하면서 선언해준 환경변수에는 없다는 것이었다. 

로컬의 .env 파일
태스크 정의 파일에서 주입한 환경변수들

그래서 태스크 정의 파일에다 하나의 환경변수를 더 넣어 주었다. 그리고 다시 로그를 봐야겠다. 


연결 성공했다! 즉 원인은 환경변수가 주입되지 않아서 runserver 명령어 실행 시 에러가 났고, 그것 때문에 다시 새 태스크 정의로 만든 태스크가 롤백이 되었던 것이다. 

위의 투두를 추천해주는 API가 계속 반영이 안 되어서 애를 먹었는데, 이제는 API 목록에 잘 뜬다. 

 

다만 한 가지 걱정되는 점은, 원래는 /swagger URL로 접속하면 django swagger 라이브러리에 의해 모든 API들을 편하게 볼 수 있는 페이지가 나오는데, 이게 더 이상 나오지 않는다는 것이다. (/swagger URL로 접속하면 오류는 안 나지만 빈 페이지가 나온다) 짚이는 원인으로는 settings에 설정한 DEBUG=False 값이 걸리는데, 원래 DEBUG 모드가 아니면 해당 창이 안 나오는 게 정상적인 것인지, 아니면 어떻게 잘 커스텀해서 DEBUG 모드가 아니어도 API를 모아보는 페이지를 보이게 할 수는 없는지도 알아봐야겠다. 

 

이제 이걸 참고해서 main 브랜치의 setting도 위와 같이 바꿔주면 되겠다. 


main 브랜치의 workflow 파일을 바꾸려다 깨달은 점인데, develop 브랜치에서 프로덕션 서버 세팅을 사용하고 있었다... 왜인지 찾아보니 이전에 Dockerfile에서 프로덕션 환경을 주입하는 명령어를 써 놓고는 까먹은 것이었다. 

 

그래서 이 환경을 분리하는 작업도 해 줘야 하겠다. 

 

기타 정보들

1. 관련 문서를 보니 yml 파일에서 github.sha 값을 사용하길래, 이게 커밋을 고유한 값으로 나타내는 것이라고만 알고 있었다. 그런데 SHA는 해싱 알고리즘이었다. 해싱과 암호화의 차이가 뭔가 싶어서 문서를 찾아보니, 해싱은 단방향이고 암호화는 양방향이라고 한다. 즉 커밋 해시값은 커밋의 내용(정확히 어떤 내용인지는 모르겠다. git diff 명령어에서 나오는 커밋에서 변경된 부분을 입력하는 것일 수도 있다고 추측해본다)을 SHA 해싱 알고리즘을 통해 해시 값으로 바꿔서 커밋을 고유하게 나타내기 위해서 사용한다고 이해했다. 

 

2. 참고할 수 있는 좋은 문서를 찾았다! 다음에 또 유사한 문제가 생길 경우 얘를 참고해야겠다. 

 

 궁금한 점

1. github settings에서 secrets와 env의 차이가 궁금하다. 

2. ECS에서 태스크가 실패했을 경우 롤백을 하는 방법이나 그 원리가 궁금하다. 

3. yaml 파일에서 커맨드로 브랜치에 따라 각기 다른 변수값을 주입하지 않고, 설정에서 GUI로 미리 브랜치별 환경변수를 설정하고 싶다. 

 

 

+ Recent posts