CodeDeploy의 현 위치
안녕하세요. StyleShare에서 커머스 개발을 맡고 있는 강성용입니다. 늘 모든 개발자들이 그러하듯, 어딘가에 올라가는 글은 원래는 거창한 주제여야 한다는 강박에 열심히 글을 쓰다(혹은 그런 생각을 하다가), 벌써 입사 이후 10개월이 지났습니다.
이런 식이라면 아무도 영원히 글을 쓰지 못할 것입니다. 그래서 아주 간단한 글로 시작해볼까 합니다.
많은 분들이 CodeDeploy라는 말을 들어본 적 있을 것입니다. 써보신 분들도 계실 것이고, 안 써보신 분도 계실 것입니다. 그리고 도입을 고려하는 분도 계실 것입니다. 이 글이 그러한 배포 도구를 선택할 때 도움이 되기를 바랍니다.
CodeDeploy는 2014년 경에 등장했습니다. 당시에도 이미 ECS는 있었습니다. 그러나 ECS는 특정한 기술(Docker)을 강요한다는 단점 아닌 단점이 있었습니다.
그렇기 때문에 CodeDeploy는 Docker를 적용할 수 없는 특정 환경에서 작업을 해야 하는, 안 그래도 이미 가상화 된 Cloud 플랫폼 위에서 더 이상의 Virtualization Overhead를 쌓기 싫은, 그리고 Task와 Task Definition, Service, Revision 등을 구분한답시고 만들어진 항공기 대시보드만큼이나 복잡한 대시보드를 보기 싫은, 또 그런 와중에 revision의 versioning 은 UUID지만 task definition 의 versioning 은 incremental 한 형태의 나이브한 postfix를 강제하는 안일함에 화가 난, 아무튼 각종 이유로 ECS가 마음에 들지 않는 엔지니어들에게는 하나의 대안이었습니다.
특히나 Deployment에 있어서 당시는 Environmental Deployment와 Source code Deployment가 혼재되어 이를 구분하려는 몸부림이 존재했습니다. CodeDeploy는 그러한 아이디어에 기반해, 순수한 AWS의 환경 위에서 Source code Deploy와 Environmental Deploy를 내부적으로 확실히 구분하면서도 심리스하게 동작시킬 수 있다는, 즉 ECS처럼 어플리케이션 배포와 소스코드 배포를 implicit하게 넘어가지 않고도 그만큼의 기능성을 확보할 수 있다는 확신을 가지고 시작한 프로젝트로 보입니다(물론 저는 AWS 개발자가 아니니 진실은 알 수 없습니다).
예전에 이와 90%이상 일치하는 컨셉의 Beanstalk 라는 제품이 존재하긴 했습니다만 사람들은 늘 같은 꿈을 꾸고 다음에는 더 잘 할 수 있으리라고 스스로 생각하곤 합니다. 저는 이러한 태도를 존경합니다. 인간이 복어를 먹게 된 이유도 결국 같은 이유일 테니 말입니다(먹으면 죽는 음식을 파는 건 다른 문제입니다만).
CodeDeploy의 이러한 시도는 일부 성공을 거두었습니다. 그러나 상기한 이유들로 인해 기존의 배포 도구 시장을 뒤엎지는 못했습니다. 만약 그랬다면 Kubernetes와 EKS의 출현은 조금 후가 되었을지도 모르겠습니다.
현대의 인프라스트럭쳐 시장에는 Kubernetes가 Gamechanger로써 등장했고 얼리어답터들은 기다렸다는 듯 EKS로 옮겨가는 추세입니다. 그만큼 사람들은 기존의 배포 도구에 만족하지 못하고 있다는 뜻이기도 합니다.
이 글은 2019년에 CodeDeploy를 적용하려는 회사들을 위해 남기는 메모입니다. 이를 공유함으로써 추후 다른 개발자들의 기술 선택에 도움이 되길 바랍니다.
CodePipeline과 사용시 주의할 점
CodePipeline 은 AWS의 각종 인프라스트럭쳐들을 Lambda로 체이닝하여 invoke함으로써 Continuous Deployement 라는 목적을 달성하기 위한 도구입니다. 보통 하나의 pipeline 은 AWS Codecommit/Github - Codebuild/Jenkins - Manual Approval - Codedeploy/EKS/ECS 등의 형태로 구성되곤 합니다.
이 도구가 하는 행위가 Continuous Integration 과 무슨 차이가 있는지는 어렴풋이 감이 오는 분도 계실 것이고 왜 있는지 모르겠다는 분도 계실 것입니다. 일단은 양쪽의 생각이 모두 맞습니다. 전자는 차치하고, 왜 있는지 모르겠다는 의견이 타당하냐면 CodePipeline의 완성도가 그리 높지 않기 때문입니다. 예를 들어 컨셉만 보자면 CodePipeline은 같은 리포지토리에 대해 Multi branch deployment 같은 걸 지원해야 할 것 같지만 안타깝게도 그런 기능을 지원하지는 않습니다. 만약 이를 달성하려면 Terraform 등을 병용하여 내부적으로 인프라를 별도로 관리해야 합니다.
아, 죄송합니다. 제가 방금 너무 있어 보이게 이야기했습니다. 정정하겠습니다. 일일히 브랜치마다 Pipeline을 손으로 만들어야 한다는 이야기입니다. 결국 특정 IaC solution 등을 통해서 사용하는 것이 아닌 이상 일반적으로 production과 staging용도로 사용하는 어플리케이션 두 개 정도 띄우는 게 일반적인 패턴이 됩니다.
단점을 먼저 열거했으나 CodePipeline가 가지는 장점은 상당히 큽니다. 아시다시피 Lambda의 컨셉은 매우 단순합니다. 일종의 function이죠. argument를 받아서 execute하고 필요할 경우 return을 하기도 합니다. 그리고 여기에 더해서, 하나의 pipeline은 동일한 scope안에서 순차적으로 이루어집니다. 일종의 sequential programmable flow-chart block이라고 보시면 됩니다.
이러한 컨셉을 AWS의 각종 서비스와 결부시키면 꽤 쓸 만한 서비스가 됩니다. 수백개의 서비스가 범람하는 마이크로-서비스-아키텍쳐 시대에 코드/빌드/배포를 일괄적으로 하나의 화면에서 관리할 수 있게 되는 것입니다. 심지어 이미 있는 것들을 활용할 수 있기 때문에 구성 비용이 크지도 않습니다.
물론 이것은 여러분이 AWS장애가 나면 자사의 서비스가 중단되는 시대에 태어났기 때문이기도 합니다. 마냥 기뻐할 일은 아닙니다.
CodePipeline과 함께 사용할 때, CodeDeploy가 전달받는 Build Artifacts의 확장자명은 .zip이 아닙니다
진짜 배포 파일의 Location
CodePipeline을 통해 invoke된 프로젝트가 Codebuild에서 넘겨주는 Build Artifacts는 Build step이 끝나고 S3에 업로드될 때 H4VB3Iu 같은 7글자의 Alphanumeric 한 이름을 갖습니다.
그리고 다음 step으로(CodeDeploy로) s3://bucket-name/application/H4VB3Iu.zip 이라는 이름을 넘겨주는 척 하지만 사실 그것은 Display name이 그럴 뿐이고 실제 Location은 s3://bucket-name/application/H4VB3Iu을 넘겨줍니다.
그래야 CodeDeploy 입장에서는 H4VB3Iu라는 파일이 zip으로 압축되어 있다는 사실을 알 수 있으면서도 실제 파일 이름은 H4VB3Iu일 수 있으니까요. 이는 CodePipeline으로 호출되는 CodeDeploy가 가진 암묵적인 약속으로 보입니다.
네, 동작이 조금 이상합니다.
물론 동작이 이상한 것과는 별개로 얼핏 보기에 사용하는 데에는 무리가 없어 보입니다. 어차피 머신이 flow를 컨트롤 하는 이상 이런 metadata는 인간에게 참고용일 뿐이니까요.
무슨 일이 일어나지만 않는다면 말입니다. 여기서 무슨 일이란 시간이 한참 지난 뒤의 롤백 등의 각종 이유를 든 CodePipeline을 통하지 않은, CodeDeploy 단일 실행을 통한 배포를 의미합니다. 그리고 그런 일은 자주 일어납니다.
재밌게도 CodeDeploy는 이 때 s3://bucket-name/application/H4VB3Iu라는 이름이 아닌s3://bucket-name/application/H4VB3Iu.zip라는 이름의 Build Artifact를 자동완성합니다(심지어, zip이라는 확장자를 제거하면 자동완성이 되지도 않습니다). 왜냐면 이전 배포 이력에 그렇게 남아있기 때문입니다.
그리고 이걸 믿고 배포했다간 어플리케이션이 뜨지 않고 배포가 실패하는 모습을 보실 수 있습니다. 심지어 이 경우 나는 에러는 File not found가 아닌 Access denied 에러이기 때문에 여러분은 절대 원인을 쉽게 발견할 수 없습니다. 아마 S3의 bucket의 policy부터 점검하기 시작하겠지요.
그리고 여러분은 진짜 원인을 찾느라 매우 추상화된 Sandbox 환경 여기저기를 한참을 들쑤신 뒤 원인을 발견하고는 허탈한 표정으로 커피를 들고 하늘만 하염없이 바라볼 것입니다.
하지만 괜찮습니다. 제가 여러분의 2시간을 구했습니다. 저에게 감사하셔도 좋아요.
Blue/Green 옵션 사용 시 주의할 점
Blue/Green이란 일부 인스턴스를 Warming up 시켜놓고 LB에 연결된 Blue 그룹과 Green 그룹을 Gracefully 서로 교체하는 옵션입니다. 이 동작이 실제로 Graceful한지는 둘째 치고서라도, 다들 ELB 혹은 ALB를 운용해 보았다면 이러한 식의 버전 배포가 익숙할 것입니다. 저도 이러한 작업을 Python script 로 만들어 배포 도구를 만든 적이 있습니다.
문제는 CodeDeploy의 책임과 역할이 이 Blue/Green Deployment에 있어서 과도하게 확장되었다는 사실에 있습니다. 왜냐면 필연적으로 Blue 그룹과 Green 그룹이 출현함에 따라 CodeDeploy가 그동안 전통적으로 수행했던 Source code deployment 뿐만이 아닌 Environmental deployment까지 그 책임이 미치기 시작했기 때문입니다.
본래의 CodeDeploy는 원래 특정한 인스턴스에 리비전만 다른 애플리케이션을 내부에 실행중인 agent가 서비스와 커뮤니케이션하며 버전을 교체하는 방식이었습니다(이를 in-place deployment라고 합니다). 그렇지만 Blue/Green 방식의 배포를 위해서는 어쩔 수 없이 Instance를 런칭하고, 제거하고 하는 등의 한 단계 위의 작업이 필요합니다. 그리고, CodeDeploy는 아마도 초기 설계 과정에서 앞으로 이러한 부분을 다룰 것이라 예상하지 못한 것으로 보입니다.
왜냐면 Blue/Green에는 이러한 가정을 바탕으로 한 것으로 보이는 수많은 문제들이 있기 때문입니다. 아래는 만약 여러분이 CodeDeploy를 Blue/Green Deploy로 사용한다면 필히 고려해야 할 점을 정리해봤습니다.
Blue/Green을 통해 런칭된 AutoScalingGroup에는 Target Group이 Implicit 하게 붙어 있습니다
여기엔 아마도 AWS의 private API 를 이용한 Trick 이 존재하는 것으로 보입니다. Blue/Green Deployment 를 통해 배포된 ASG의 Target Group은 빈칸이지만, 사실은 실제로 여기에 CodeDeploy에서 지정한 Target Group이 붙어 있습니다. 이유는 잘 모르겠습니다.
그러니까 단적으로 말하자면, "아, 없나보다. 다른 값을 내 마음대로 수정하고 저장해도 되겠지." 하고 저장하는 순간 Target Group이 분리되며 서비스는 장애를 일으키게 됩니다.
만약 CodeDeploy 배포로 만들어진 ASG를 손으로 수정해야 할 경우, 이 사실을 항상 염두에 두셔야 합니다. Target Group을 잊지 마십시오.
CodeDeploy ARN에 Blue/Green을 위한 별도 policy 를 적용해줘야 합니다
CodeDeploy의 기본 IAM 권한에는 Blue/Green 에 필요한 권한이 없습니다. 더욱 안타까운 점은 이에 대해 명시적으로 작성한 문서도 없다는 사실입니다. 다만 검색을 통해 누군가의 블로그 글을 찾을 수 있으며 이는 올해 2월에 밝혀진 버그입니다. 그리고 아직까지 수정되고 있지 않습니다.
어쩔 수 없습니다. 스스로 해결해야 합니다.
(참조 : https://h2ik.co/2019/02/28/aws-codedeploy-blue-green/)
"The IAM role does not give you permission to perform operations in the following AWS service: AmazonAutoScaling. Contact your AWS administrator if you need help. If you are an AWS administrator, you can grant permissions to your users or groups by creating IAM policies."
만약 여러분이 위와 같은 에러메시지를 보면 아래 Policy를 여러분이 사용하는 CodeDeploy Role에 별도로 추가해주시면 됩니다.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "iam:PassRole", "ec2:CreateTags", "ec2:RunInstances" ], "Resource": "*" } ] }
AutoScaling Group의 LifeCycle Hook이 중복되었는지 확인해야 합니다
이 버그는 Blue/Green 배포시 원래는 In-place로 배포했던 ASG를 복사하여 CodeDeploy를 통한 최초 시도 시에 발생합니다. Scheduled action이나 Cloudwatch alarm 등에 걸린 action에 의해 AutoScaling operation이 실행되면, 두 개의 LifeCycle Hook이(In-place 에서 쓰던 LifeCycle Hook과 Blue/Green 에서 새로 설정한 LifeCycle Hook) 서로 같은 인스턴스에 존재하게 되면서, 하나의 인스턴스에 두 가지 버전이 동시에 배포되는 비극이 일어납니다.
당연히 새 Instance에는 제대로 된 배포가 진행되지 않습니다. 그 인스턴스는 Create 된 직후 PendingWait 상태에서 Health check에 실패하여 Terminate 됩니다. 그러면 또 다시 ASG의 Desired capacity에 의해 다시 Instance가 런칭되고... 이런 상황이 무한하게 반복됩니다.
해결책은 간단합니다. Blue/Green 배포시 기존의 In-place에 있던 LifeCycle Hook을 삭제해줍시다.
Rollback을 하고 나면 AutoScaling Group의 LifeCycle Hook이 훼손됩니다
이 버그는 조금 치명적입니다. 여러분의 Deployment가 별 일 없이 끝났다면 이 문제를 밟지는 않겠지만, 아시다시피 현대의 웹 애플리케이션은 Buggy한 프로덕션을 롤백하는 일이 잦습니다. 이 버그는 만약 Blue/Green 배포가 끝난 버전에 대해 Rollback 할 경우 무조건 발생합니다.
상식적으로 Rollback이 실행 된 경우 LifeCycle Hook은 Blue version(롤백된 기존의 버전)에 다시 걸려 있어야 하고, Green version(새로 배포되었다 취소된 버전)에는 걸려있지 않아야 합니다. 그러나 롤백된 Blue Version 에는 응당 걸려있어야 할 LifeCycle Hook 이 없습니다.
이 LifeCycle Hook의 부재로, 현재 배포된 EC2 인스턴스를 제외한, 새로 런칭되는 인스턴스들에는 CodeDeploy의 automatic deployment 가 작동하지 않으며 애플리케이션의 아무 버전도 배포되지 않은 비어있는 인스턴스가 올라가게 됩니다. 그 결과 그런 깡통 인스턴스만 계속 떴다 죽었다를 반복하며 전반적인 장애내구성을 약화시키기 시작하고, 혹시라도 ASG의 Termination policy가 OldInstance 등으로 걸려있다면 여러분의 ASG는 순식간에 깡통 인스턴스로 가득찰 지도 모릅니다.
이 버그의 가장 큰 문제는, 이 상태를 문제가 생기기 전에 눈치채기가 쉽지 않다는 점입니다. 왜냐 하면, 이 문제는 평소에 잠재적으로만 존재하다가, Scheduled action 이나 Autoscaling Policy 등에 의해 Instance가 늘어났을 경우에만 가시화되기 때문입니다.
맺으며
이상으로 CodeDeploy를 production에 적용할 때 발생할 수 있는 주의점들에 대해 알아보았습니다. 생각보다 fragile한 프로덕트에 실망하신 분도 계실 것이고, 이 정도의 deployment system 을 만드는 데에 드는 비용에 비해서는 생각보다 낮은 trade-off 라고 생각하신 분도 계실 것입니다.
그러나 이래저래 따져도 가장 좋은 것은 위에서 언급한 주의사항들(이라고 쓰고 버그라고 읽는)을 더 이상 고려하지 않아도 되는 것입니다. 어쩌면 이 글을 통해 최근 EKS가 왜 주목받고 있는지를 실감하셨을 수도 있겠습니다.
다음에는 더 좋은 글로 찾아뵙겠습니다.








