CI/CD Practice 08
CodeDeploy: 배포 대상을 고르는 진짜 주체는 누구?
Application, Deployment Group, Service Role, EC2 tag가 모두 배포 설정처럼 보여서 어느 것이 논리 묶음이고 어느 것이 실제 대상 선택인지 헷갈린다.
근거 · CI/CD 교안 p116-p131
1장: Application은 단지 ‘이름표’일 뿐
솔라의 미간이 살짝 찌푸려졌다. AWS 콘솔 화면에 떠 있는 ‘애플리케이션 생성’이라는 제목을 가만히 들여다보고 있었다. 지금 따라 하는 실습 안내문은 분명 이렇게 말하고 있었다. user-AngularApp CodeDeploy Application을 만든다.
‘애플리케이션(Application)’이라니. 당연히 배포할 코드 묶음과 그 코드가 올라갈 서버까지를 포함하는 개념 아닐까? 솔라는 그렇게 생각했다. ‘user-AngularApp’이라는 애플리케이션을 배포하는 거라면, 당연히 어떤 서버 그룹에 배포할지 선택하는 과정이 있어야 했다. 하지만 솔라가 마주한 화면에는 그런 선택지가 보이지 않았다. 애플리케이션 이름, 그리고 컴퓨팅 플랫폼을 ‘EC2/온프레미스’로 고르는 것 외에는 설정할 수 있는 게 거의 없었다.
“언니, 잠깐만. 이거 좀 이상해.”
옆에서 자신의 코드를 들여다보던 루나가 고개를 돌렸다. 솔라는 자신의 노트북 화면을 루나 쪽으로 돌렸다.
“CodeDeploy에서 Application을 만들라고 해서 하는 중인데, 내가 생각한 거랑 달라. ‘user-AngularApp’을 배포할 서버들을 여기서 골라야 하는 거 아니야? 그런데 아무리 봐도 대상 서버를 지정하는 칸이 없어. 그냥 이름만 덩그러니 입력하는 게 끝이야. 이걸로 뭘 할 수 있다는 거지?”
솔라의 목소리에는 ‘분명 뭔가 빠뜨렸거나 내가 잘못 이해하고 있다’는 확신이 섞여 있었다. Application이라는 단어가 주는 무게감이 있는데, 실제 설정 화면은 너무나도 허전했다.
루나는 말없이 화면을 잠시 들여다보더니, 솔라를 보고 희미하게 웃었다. “솔라 네가 헷갈리는 게 당연해. ‘Application’이라는 단어 때문에 그렇지. 우리, 새 애플리케이션을 하나 더 만드는 척 시늉만 해볼까? 딱 두 가지만 입력하면 돼.”
루나는 솔라의 노트북에 있는 ‘애플리케이션 생성’ 버튼을 다시 한번 눌렀다. 방금 솔라가 봤던 바로 그 화면이 다시 나타났다.
애플리케이션 구성
- 애플리케이션 이름:
(필수) my-test-app - 컴퓨팅 플랫폼:
EC2/온프레미스
“자, 여기 봐. ‘애플리케이션 이름’ 필수가 있고, 그 아래에 ‘컴퓨팅 플랫폼’ 선택지가 있지. EC2 인스턴스에 배포할 거니까 아래 옵션을 고르는 건 맞아. 그런데 그 외에, 배포할 대상을 고를 만한 필드가 정말로 있니? 예를 들면 ‘인스턴스 태그’라든가, ‘서버 IP 주소’ 같은 걸 넣는 칸.”
솔라는 화면을 다시 꼼꼼히 훑어보았다. 없었다. 정말로 없었다. 인스턴스를 고르는 어떤 힌트나 필터, 하다못해 그런 설정을 하러 가는 링크조차 없었다.
”…없네. 정말 이름 말고는 아무것도 정하는 게 없네. 그럼 대체 왜 만드는 거야? 이건 그냥… 그냥 이름표잖아?”
솔라의 입에서 나온 ‘이름표’라는 단어에 루나가 고개를 끄덕였다.
“정확해. CodeDeploy의 Application은 그냥 이름표야. 우리 집에 있는 재활용 쓰레기통들을 생각해봐. ‘플라스틱’, ‘종이’, ‘캔’ 이렇게 이름표를 붙여놓지? 그 이름표는 그 통에 무엇을 담을지 알려줄 뿐, 어떤 브랜드의 페트병을, 어느 가게에서 산 신문지를 넣을지까지 결정하진 않잖아.”
“아…!”
“CodeDeploy Application도 똑같아. 앞으로 우리가 할 여러 배포 작업들을 논리적으로 구분하기 위한 가장 큰 단위의 이름표인 거야. ‘이건 user-AngularApp 배포와 관련된 모든 것들을 담는 상자’, ‘저건 나중에 만들 결제 시스템 배포를 담는 상자’ 하고 구분해주는 거지. 그 상자 자체가 내용물을 고르지는 않아.”
루나의 비유를 듣고 나니 눈앞의 화면이 다르게 보였다. 처음에는 ‘기능이 빠진 불완전한 설정창’으로 보였던 것이, 이제는 ‘원래부터 이름표를 붙이는 기능만 하는 곳’으로 명확하게 인식되었다. ‘Application을 만든다’는 지시문의 의미는 ‘배포할 서버 그룹을 선택한다’가 아니라, ‘앞으로 진행할 배포 작업을 담을, user-AngularApp이라는 이름의 상자를 하나 마련한다’는 뜻이었던 것이다.
“그럼 이 Application은 그냥 배포 프로젝트의 ‘제목’ 같은 거였구나. 난 여태껏 얘가 배포 대상을 선택하는 주체인 줄 알고 여기서 한참 헤맸네.”
솔라는 허탈하게 웃으며 ‘취소’ 버튼을 눌렀다. 더 이상 이 화면에서 고민할 필요가 없었다. 궁금증은 풀렸지만, 동시에 더 큰 질문이 머릿속을 채웠다.
“언니, 그럼 진짜 질문은 이제부터네. 이름표만 붙여서는 아무 일도 일어나지 않잖아. 실제로 저 ‘user-AngularApp’이라는 이름표가 붙은 상자 안에 어떤 EC2 인스턴스를 넣을지 결정하는 건, 대체 어디서, 누가 하는 거야?“
2장: 진정한 배포 대상 선정자: Deployment Group
솔라는 마침내 user-AngularApp이라는 이름표를 성공적으로 만들었다. 그리고 실습 안내문의 다음 단계로 넘어갔다. ‘배포 그룹 생성’. 솔라는 방금 만든 Application의 상세 페이지에서 ‘배포 그룹 생성’ 버튼을 클릭했다. 잠시 후, 화면이 바뀌었다.
솔라의 눈이 동그래졌다. 텅 비어 있던 애플리케이션 생성 화면과는 비교도 안 될 정도로 빽빽한 설정 항목들이 화면을 가득 채우고 있었다. 배포 그룹 이름, 서비스 역할(Service Role), 배포 유형, 환경 구성, 배포 설정… 스크롤을 내리자 더 많은 옵션이 나타났다. 이것은 이름표를 붙이는 수준이 아니었다. 이건… 조종실에 가까웠다.
“언니, 이거 봐. 완전 다른데?”
솔라는 흥분과 혼란이 뒤섞인 목소리로 말했다.
“Application 만들 때는 그냥 이름만 덜렁 쓰게 하더니, 여기는 무슨 설정이 이렇게 많아? ‘그룹’이라고 해서 이것도 그냥 비슷한 이름표 같은 건 줄 알았는데…”
솔라의 말처럼, ‘배포 그룹(Deployment Group)’이라는 이름은 또 다른 단순한 묶음처럼 들릴 수 있었다. ‘user-AngularApp’이라는 상자 안에 ‘개발 그룹’, ‘운영 그룹’ 같은 하위 폴더를 만드는 느낌. 솔라는 무심코 그렇게 짐작하고 화면을 훑어보고 있었다.
“그럴듯한 추측이야.”
루나가 솔라의 화면으로 시선을 옮겼다.
“만약 Deployment Group이 그냥 또 다른 이름표라면, 이 화면에도 이름 말고는 별다른 설정이 없어야겠지. 그런데 저기, ‘환경 구성’이라는 섹션을 좀 자세히 볼래?”
루나가 가리킨 곳에는 ‘Amazon EC2 인스턴스’, ‘Auto Scaling 그룹’ 같은 선택지가 있었다. 솔라는 실습 지시에 따라 ‘Amazon EC2 인스턴스’를 선택했다. 그러자 바로 아래에 새로운 입력 창이 나타났다.
| 키(Key) (선택 사항) | 값(Value) (선택 사항) |
|---|---|
Name | user-app-server |
“어…!”
솔라는 짧은 탄성을 뱉었다. 이것은 이전에 그토록 찾아 헤맸던 바로 그 기능이었다. 배포할 대상을 ‘선택’하는 필터.
“여기 있네. 서버를 고르는 부분이. 키-값으로 태그를 입력하게 되어 있어. 그럼… Name 태그가 user-app-server인 EC2 인스턴스를 찾아서 배포하겠다는 뜻이구나.”
“맞아. 이제 첫 번째 질문의 진짜 답을 찾았네. 배포 대상을 고르는 주체는 Application이 아니라, 바로 이 Deployment Group이었던 거야.”
루나의 말에 솔라는 화면을 다시 바라봤다. 이제야 모든 조각이 맞춰지는 기분이었다.
Application은 user-AngularApp이라는 배포 프로젝트 전체를 담는 가장 큰 상자. 그리고 그 상자 안의 Deployment Group은 ‘이름이 user-app-server인 EC2 인스턴스들만 골라서, 이런이런 방식으로 배포하라’는 구체적인 ‘규칙 묶음’이었던 것이다. 이름표가 아니라, 실제 배송 목록과 배송 방법을 적은 작업 지시서에 가까웠다.
“아하! 그러니까 Application은 ‘어떤 종류의 배포인지’를 나타내는 이름이고, Deployment Group은 ‘그래서 정확히 어느 서버에 배포할 건지’를 정하는 규칙이구나. 난 ‘그룹’이란 말 때문에 그냥 또 묶는 건 줄 알았지.”
솔라는 고개를 끄덕이며 스크롤을 아래로 내렸다. 이제 이 화면의 모든 설정 항목들이 새롭게 보였다. 배포 방식(한 번에 할지, 절반씩 할지), 실패 시 대처 방법 등, 모든 것이 ‘규칙’의 일부였다. 혼란스럽게 많아 보이기만 했던 옵션들이 이제는 ‘대상을 선정하고 배포하는 과정’을 제어하기 위한 당연한 도구들로 인식되었다.
한참 화면을 뜯어보던 솔라의 시선이 한 곳에 머물렀다. 태그를 입력하는 칸 바로 위에 있던 ‘서비스 역할(Service Role)’이라는 드롭다운 메뉴였다.
“언니, 궁금한 게 또 생겼어. 태그로 배포할 EC2 인스턴스를 고르는 건 이제 완벽히 이해했어. 그런데 여기 바로 위에 있는 ‘서비스 역할’은 뭐야? 이것도 배포 대상을 고르는 필터 같은 거야? 아니면 완전히 다른 역할을 하는 걸까? 이름만 봐선 권한이랑 관련된 것 같은데…“
3장: 태그와 서비스 역할로 최종 배포 대상 확정하기
솔라의 시선은 Deployment Group 설정 화면의 한 지점에 머물러 있었다. 방금 전까지만 해도 혼란스러웠던 ‘EC2 인스턴스 태그’ 섹션은 이제 명확한 ‘대상 필터’로 보였다. 하지만 그녀의 마우스 커서는 그 바로 위, ‘서비스 역할(Service Role)’이라는 드롭다운 메뉴를 망설이며 맴돌았다. 콘솔 화면은 이 두 설정을 마치 한 쌍인 것처럼 나란히 배치하고 있었다.
이 배치가 솔라에게는 하나의 모순처럼 느껴졌다. 태그는 ‘어느 서버에 배포할 것인가?’라는 질문에 대한 답이었다. 반면 ‘서비스 역할’이라는 이름은 ‘누가 배포할 권한을 가졌는가?’를 묻는 듯했다. 분명 다른 종류의 질문인데, 왜 Deployment Group은 이 둘을 분리할 수 없는 한 묶음으로 요구하는 걸까? 솔라는 이 두 조각이 어떻게 맞물려 하나의 완전한 규칙을 만드는지 알아내야 했다.
“언니, 이 두 개는 왜 꼭 같이 설정해야 해? 태그로 배포 대상을 고르는 건 이제 알겠어. 그런데 서비스 역할은 권한 문제잖아. 왜 대상을 고르는 규칙이랑 권한을 부여하는 규칙이 한 덩어리로 묶여 있는 거야?”
루나는 솔라의 질문에 대답하는 대신, 노트북 화면에서 잠시 눈을 떼고는 근처에 있던 메모지와 펜을 가져왔다. 그리고 간단한 그림 두 개를 그리기 시작했다.
“우리가 배달원이라고 상상해보자.”
루나는 메모지에 네모 상자 두 개를 그리고 각각 ‘빌딩 A’, ‘빌딩 B’라고 적었다. 그리고 빌딩 A 옆에는 (태그: user-app-server)라고 작게 덧붙였다.
“솔라 네가 방금 설정한 EC2 태그는, 이 배달원이 들고 있는 소포에 적힌 ‘주소’와 같아. 배달원은 ‘user-app-server’라는 주소가 적힌 빌딩 A로 정확하게 찾아가겠지. 빌딩 B는 쳐다볼 필요도 없어.”
“응, 거기까지는 알겠어. 태그는 필터니까.”
“좋아. 그럼 배달원이 빌딩 A 앞에 도착했어. 그런데 이 빌딩이 최첨단 보안 시설이라 아무나 들어갈 수 없는 곳이라면 어떨까? 배달원이 정확한 주소를 알고 찾아왔다는 사실만으로 정문을 통과하고, 각 층을 돌아다니며 물건을 배달할 수 있을까?”
루나의 비유를 듣는 순간, 솔라의 머릿속에 흩어져 있던 조각들이 맞춰지기 시작했다.
“아! 출입증이 필요하구나!”
“바로 그거야.”
루나가 펜으로 ‘서비스 역할’이라고 쓰고 그 주위에 동그라미를 그려 ‘출입증’이라고 표시했다.
“CodeDeploy라는 배달원이 EC2라는 빌딩에 접근해서 ‘어떤 태그가 붙어있는지 목록 좀 보겠습니다’, 그리고 ‘이 서버에 새로운 파일을 설치하겠습니다’ 같은 작업을 하려면 그에 맞는 권한이 필요해. 서비스 역할이 바로 그 권한을 담고 있는 출입증인 셈이지. 주소(태그)를 아무리 정확히 알아도, 출입증(서비스 역할)이 없으면 빌딩 안으로 한 발짝도 들어갈 수 없어.”
이제야 모든 것이 명확해졌다. EC2 태그와 서비스 역할은 각각 독립적인 설정이 아니었다. 둘은 배포 대상 확정이라는 하나의 목표를 위해 협력하는 한 팀이었다.
- EC2 태그: 수많은 EC2 인스턴스 중에서 ‘어디에’ 배포할 것인지 대상을 찾아내는 필터.
- 서비스 역할: 찾아낸 그 대상에 CodeDeploy가 접근하여 배포 작업을 수행할 수 있도록 허가하는 권한.
솔라는 다시 Deployment Group 생성 화면을 보았다. 이전에는 그저 나열된 옵션으로 보였던 ‘서비스 역할’과 ‘EC2 인스턴스 태그’가 이제는 하나의 유기적인 메커니즘으로 보였다. Deployment Group은 이 두 가지를 조합하여 ‘어떤 권한으로, 어떤 태그가 붙은 서버들에게 배포할 것인가’라는 완전한 하나의 명령을 만들어내고 있었던 것이다.
“그랬구나… 난 이 둘이 그냥 따로따로 작동하는 설정인 줄 알았어. Deployment Group이 태그로 대상을 고르고, 동시에 서비스 역할로 권한을 부여해서 배포를 실행하는 거였네. 하나의 규칙 묶음이라는 게 이런 뜻이었구나.”
솔라는 처음 실습을 시작할 때 보았던 안내문의 한 구절을 떠올렸다.
CodeDeploy Application과 Deployment Group을 만들고 EC2 태그로 배포 대상을 선택합니다.
처음 이 문장을 읽었을 때는 단순히 순서대로 해야 할 일들의 나열처럼 느껴졌다. 하지만 이제는 그 문장의 진짜 의미를 꿰뚫어 볼 수 있었다. 이 문장의 숨은 주어는 ‘Deployment Group’이었다. ‘Deployment Group이 EC2 태그를 사용하여 배포 대상을 선택한다’는 뜻이었던 것이다. 혼란을 주었던 모든 요소들—Application, Deployment Group, Service Role, EC2 태그—이 각자의 역할을 명확히 찾으며 제자리에 놓이는 순간이었다.
루나가 만족스러운 표정으로 솔라를 보며 마지막 질문을 던졌다.
“좋아. 그럼 이제 실전 문제야. 다음 달에 새로운 기능(v2)을 출시해야 하는데, 위험을 줄이기 위해 전체 서버가 아니라 새로 추가된 3대의 ‘카나리(canary) 서버’에만 먼저 배포해보고 싶어. 어떻게 해야 할까?”
솔라는 더 이상 망설이지 않았다. 마치 자신의 계획을 설명하듯 자신감 있게 말했다.
“간단해. 먼저 그 카나리 서버 3대에만 Group: Canary-v2 같은 특별한 태그를 붙여둘 거야. 그리고 새로운 Deployment Group을 만들어서, 환경 구성에서 EC2 태그 키는 Group, 값은 Canary-v2로 설정하면 돼. 물론, 기존에 쓰던 것과 같은 서비스 역할을 연결해서 CodeDeploy가 그 서버들에 접근할 권한을 주는 것도 잊으면 안 되지.”
솔라는 자신의 설계에 만족하며 미소 지었다. 더 이상 배포 대상을 고르는 진짜 주체가 누구인지 헷갈리지 않았다. 이름표 뒤에 숨어 있던 진짜 작업 지시서, Deployment Group의 작동 방식을 완벽하게 이해한 것이다. 솔라는 방금 자신이 구상한 대로 설정을 마치고 ‘배포 그룹 생성’ 버튼을 힘차게 클릭했다.