
최근 DevOps 환경 구축 프로젝트를 진행하면서, 일반적인 서버 배포 작업과 다르게 애플리케이션 배포 외에도 별도의 Extension Import 단계가 추가되어야 했다.
이 과정에서 여러 검토를 거쳐 Git Tools 사용을 제안했는데 감사하게도 고객사 쪽에서 프로젝트 구성에 대한 개선 제안을 긍정적으로 검토해주셨다. 그 결과과 Submodule 기능을 도입해서 빌드 자동화 까지 적용하게 되었다.
Submodule 사용을 제안하기까지의 배경이된 요구사항에 대한 이야기와 의사 결정 과정, 설득까지의 이야기를 풀어보고자 한다.
DevOps 환경에서 배포 자동화를 고려한 Extension 프로젝트들 구성 시에 고려해야할 점들이 있었는데, 먼저 두가지 관점에서 요구사항을 분석해보겠다.
DevOps 환경 구축은 협업 효율 향상 및 배포 자동화에 최우선으로 목적을 두고 있다.
기존 환경에서는 Extension 개발 시에 개발한 사람이 너무 여럿이고 프로젝트들이 압축파일 단위로 돌아다녀서 형상관리도 부족했는데 이번 기회에 흩어져 있는 프로젝트들을 형상관리가 가능하면서도 배포 자동화가 가능하도록, 형상관리 서버(GitHub)에 프로젝트들을 구성해서 협업 효율을 높이기로 했다.
이 프로젝트 환경에서는 Extension 프로젝트들을 빌드한 후 결과물을 서버에 Import하는 과정이 필요했는데, 수동으로 배포하던 환경에서는 일일히 필요한 프로젝트들만 IDE에 로드해서 ANT 빌드하고 결과물만 웹상에서 UI를 이용하여 수동 Import 하는 방식으로 작업했었던 일이다.
배포를 완전 자동화 하려면 흩어져 있는 Extension 프로젝트들을 배포툴에서 가져올 수 있는 방법과 기존의 웹 UI를 통한 Import 방식 외에 배포툴에서 Import할 수 있는 방법을 찾아야 했는데, Extension 프로젝트들을 형상관리서버에 관리하게되면 배포툴에서 간단히 가져올 수 있기 때문에 이 문제는 해결되었고 다행히 애플리케이션에서 웹 UI를 통한 방식 이외에도 Importer 모듈에서 API를 제공해 스크립트 상에서 cURL을 통해 업로드 하는 것으로 배포툴에서 Import할 수 있었다.
Extension 프로젝트들을 형상관리서버에서 관리하게 되면 기본적인 프로젝트 목표를 달성할 수 있으나 고객사에서 추가로 Import할 Extension 프로젝트들의 목록을 동적으로 관리하고자 했다.
추후 새로운 Extension을 추가하게 될 수도 있는데 이 경우에는 자동 배포 대상으로 추가할 수 있어야 하고, 시스템을 운영하면서 필요없어진 Extension은 배포에서 제외하고 싶은데 그렇다고 형상관리 시스템에서 프로젝트를 삭제하고 싶진 않은 것이다.
그리고 옵션으로 되어있는 커밋 버전 지정에 대한 것은 물론 그런일은 없어야 하지만, 최종 커밋 버전이 사용에 문제 있는 경우 이전에 정상적으로 사용했던 커밋 버전의 프로젝트를 배포 대상으로 지정할 수 있는 선택지가 있으면 좋겠다는 혹시모를 불상사를 위한 요청이다. 일단 옵션이기 때문에 필요성을 인지만 해둔다.
요구사항들을 모아보면 다음과 같다.
1) Extension 프로젝트들이 형상관리가 되어야 함
2) 모든 Extension 프로젝트들은 GitHub에 Repository로 관리할 것
3) GitHub에 구성된 Extension 프로젝트들의 빌드를 자동화 할 것
4) 기존에 UI로 수동 Import 하던 빌드 결과물의 배포를 자동화 할 것
5) 배포할 Extension 목록이 동적으로 관리 가능할 것
6) (옵션) 배포할 Extension 프로젝트의 커밋 버전지정이 가능하면 좋음
요구사항들에 대해 살펴보자.
일단, 형상관리를 위한 GitHub 구성에 대한 점은 확정적으로 이야기 된 상황이라 1, 2번 요구사항은 해결된다.
배포 자동화에 대한 것은 배포툴을 검토하면서 GitHub에서 체크아웃 받아서 ANT로 빌드가 가능한 것을 확인했다. 3번 요구사항도 해결된다.
UI를 통한 Import하는 방법 외에도 시스템에서 Importer 모듈 API를 제공한 덕분에 배포툴의 스크립트 상에서 cURL을 통해 API로 업로드가 가능한 것 까지 확인을 완료했기 때문에 4번 요구사항 또한 해결된다.
따라서 남은 요구사항인 5번, 6번에 대한 내용을 중점으로 해결 방법을 찾기 시작했다.
GitHub에 프로젝트들을 어떻게 구성할지, 목록을 어떻게 동적으로 관리할지를 위주로 필요하면 커밋 버전지정에 대한 옵션을 고려하며 검토한다.
검토했던 선택지들은 아래와 같다.
빌드 스크립트에 프로젝트 목록을 하드코딩하는 방식은 비효율적이고, 유지보수에 어려움이 있을 수 있다.
내가 프로젝트를 완료하고 철수하면 사실상 담당자가 시스템을 관리하면서 사용해야하는데 관리자가 빌드 스크립트에 이해도가 있다고 할 지라도 구성이 완료된 배포 환경의 스크립트를 수정한다는 것 자체가 굉장히 리스크로 다가온다.
그리고 이 방식은 5번 요구사항인 "배포할 Extension 목록이 동적으로 관리 가능할 것"을 충족시키지 못한다.
이 선택지는 패스 하기로 했다.
언듯 생각했을 때 빌드 스크립트 수정 자체가 리스크가 있는 거면, 파라미터로 프로젝트 Repo명들을 문자열로 넘기거나 또는 저장소를 리스트로 추가하여 필요한 것만 선택해서 배포되도록 할 수 있다면 스크립트 수정 없이 요구사항도 달성하지 않을까 해서 고려했다.
하지만 프로젝트 Repo명들을 문자열로 넣는 것 조차 휴먼에러를 피할 수 없다고 생각이 되었고,
저장소를 리스트에서 선택해서 배포하게 만들 수도 있었지만 일단 프로젝트 목표가 배포 전체 자동화였기 때문에 수동으로 리스트를 선택한다는 방법은 고려 대상이 아니었다.
빌드 시작 조차 담당자가 빌드 버튼을 누르는게 아니라 Git Hook을 통해서 자동으로 triggering되도록 세팅을 원했기 때문에 젠킨스 자체를 접속할 필요가 없게 되는것이 고객의 목표였다.
이 선택지도 패스 했다.
사실 Submodule 기능을 고려하기 전 까지는 가장 유력한 선택지였다.
루트가 되는 Extensions Repository를 생성하고 모든 프로젝트들을 폴더 단위로 다 때려 넣는 것이다.
이 방식은 GitHub Repository 단위 전체 Extension 프로젝트 묶음이라 커진다는 단점은 있지만 가장 직관적인 방법이었다. 다만, 프로젝트 추가에서는 문제가 없는데 프로젝트를 배포에서 제외하고 싶은 경우에는 곤란함이 있었다. Repository에서 프로젝트를 제거해 버리면 배포 대상에서 제거할 수는 있지만 관리되고 있던 형상관리 히스토리는 전부 날아가버릴 것이 아닌가. 그렇다고 배포용 프로젝트 모음 Repo와 별도 프로젝트 형상관리용 Repo를 이중으로 관리하는 것은 동기화가 힘들 수 있고 비효율 적이다.
그리고 6번 요구사항인 "배포할 Extension 프로젝트의 커밋 버전지정이 가능하면 좋음"에 대한 것은 옵션이긴 해도 전혀 해당 사항이 없다.
이 선택지에 여러 아쉬움이 있어서 기술검토를 하다가 Submodule 기능의 존재를 알게 되었다.
Submodule 기능은 Git에서 Tool로 제공하는 기능으로 하나의 Git 프로젝트 내에서 다른 Git 저장소를 독립적으로 포함시켜, 각 프로젝트를 별도로 관리하고 버전 제어할 수 있게 하는 기능이다.
Submodule은 Repository간의 링크를 연결하기 위해 부모 Repo에 .gitmodules 파일을 생성하고 부모 Repo와 자식 Repo간의 연결 정보를 기록한다. 여기서 자식 Repo를 연결하기 위해 사용하는 정보는 부모 Repo에서 어느 경로에 Submodule을 연결할지를 정하는 path 정보와 자식 Repo의 url이다.
이렇게 연결된 자식 Repo는 부모 Repo에서 형상관리를 참조해 볼 수는 있지만 기본적으로 자식 Repo의 형상관리는 독립적으로 이루어진다. 이말인 즉슨, Submodule을 부모 Repo인 배포용 루트 Repo에 연결함으로써 배포 대상 프로젝트 목록을 동적관리 하면서도 연결을 끊더라도 형상관리 히스토리를 날리지 않을 수 있다는 것이다. 이 점 만으로도 Submodule 사용이 유용하다고 생각했다.
Submodule로 연결하면 기본적으로 자식 Repo의 최신 커밋을 참조한다.
커밋을 참조한다는 의미를 다시 생각해보면, 커밋 해쉬를 참조한다는 뜻이다. 이 의미는, 배포할 Extension 프로젝트의 커밋 버전지정이 가능하다는 뜻이다.
커밋 해쉬에 대한 정보는 부모 Repo의 .git에 저장된다고 한다. 부모 Repo상에서 자식 Repo를 원하는 커밋 버전으로 체크아웃 한 후 부모 Repo를 커밋하면, 자식 Repo의 커밋 버전이 반영된다. 6번 옵션 요구사항인 "배포할 Extension 프로젝트의 커밋 버전지정이 가능하면 좋음"에 대한 것 또한 해결할 수 있는 방법이라고 생각해 Submodule 기능 도입을 제안하기로 결정했다.
고객사에 Submodule 기능 도입에 대한 운을 띄웠을 때 반응이 별로 안좋았다.
해당 사이트에서는 GitHub를 적극적으로 사용하고는 있지만 Submodule 기능을 사용하지는 않았던 것이다. 새로 도입하는 기능의 기술 부채를 걱정하는 것은 당연하다.
기능에 대한 간략한 설명을 부탁하셔서 Submodule의 간단한 설명과, Submodule을 사용하지 않는 방식 중 그나마 최선의 방식이었던 "모든 Extension 프로젝트들을 Extensions Repo 하위에 포함시켜 배포 대상 Repository를 단일화" 하는 방법과의 장단점 비교를 제시했다.
단순히 위에서 서술한 Submodule 도입 시 해결할 수 있는 요구사항들 말고도 프로젝트 목표와 지향점을 생각해보면 추가적으로 제시할 수 있는 장점들이 있었다.
이런점들을 더 어필하려고 노력했다. 도표로 표현하면 다음과 같다.
| 항목 | Extension 프로젝트들 Repo 단일화시 | Submodule 방식 적용시 |
|---|---|---|
| 작업 단위 | 단일 Extension 프로젝트 개발 또는 수정 시 모든 Extension 프로젝트를 한 번에 체크아웃 받아서 작업해야 함. | 단일 Extension 프로젝트 개발 시 단일 프로젝트만 체크아웃하여 개발 및 수정할 수 있음. 작업 완료 시에 Submodule 연결만 완료하면 배포 대상으로 추가 가능 |
| 버전 관리 | 모든 Extension 프로젝트의 버전 관리가 하나의 Repo에서 이루어지기 때문에 모든 변경사항을 한 번에 관리해야 함. | 각 서브모듈은 독립적인 버전 관리가 가능. 필요한 버전만 명확하게 체크아웃하여 관리할 수 있음. |
| 배포 대상 관리 | 새로운 Extension 프로젝트를 추가하거나 제거할 때 단일 Repo에서 모든 변경을 해야 함. | 서브모듈을 추가하거나 제거할 때 각 프로젝트를 독립적으로 관리할 수 있어 배포 대상 목록을 쉽게 동적으로 관리할 수 있음. |
| 형상관리 히스토리 | 프로젝트를 삭제하거나 제외할 때, 형상 관리 히스토리가 날아갈 수 있음. 관리가 어려워질 수 있음. | 서브모듈을 제거해도 형상 관리 히스토리는 보존됨. 필요한 커밋 해시를 지정하여 과거 버전도 쉽게 유지 가능. |
| 배포할 Extension 프로젝트의 버전 지정 | 프로젝트 버전이 관리되는 곳이 하나라, 버전 지정이 불명확할 수 있음. | 각 서브모듈의 커밋 해시를 통해 정확한 버전을 지정할 수 있음. 원하는 버전으로 배포 가능. |
| 확장성 | 프로젝트가 추가되어 커질수록 관리가 어려워지고, 확장성이 제한됨. | 서브모듈을 추가하는 방식으로 프로젝트가 커져도 확장성이 용이하고, 각 서브모듈이 독립적으로 관리됨. |
| 자동화 및 협업 효율 | 모든 Extension 프로젝트를 관리하려면, 수동 관리가 필요하고 자동화가 어려워짐. | 자동화된 빌드 및 배포가 가능하며, 각 서브모듈이 독립적으로 관리되어 협업 효율성이 높아짐. |
| 권한 관리 | 개별 Extension 프로젝트별로 권한을 달리하여 관리할 수 없음. Extension 작업자는 모든 프로젝트에 권한이 주어져야 작업이 가능함. | 프로젝트별로 작업자의 권한 관리가 가능함. 배포 시 사용 계정에서는 모든 프로젝트에 대한 권한이 있기 때문에 개별 프로젝트 권한 설정에는 영향이 없음. |
| 사용 난이도 | 수정할 내용이 없다면 프로젝트 사용시에는 문제 없음. 다만, 프로젝트 삭제와 버전 관리, 프로젝트별 권한 관리가 불가능 함. | Submodule 사용에 익숙하지 않으면 개념이 어렵게 느껴질 수 있어 최초 Submodule 추가가 다소 복잡하게 보일 수 있음. |
결과적으로, 고객사에서도 달성할 수 있는 이점들과 Submodule의 부담을 저울질 한 결과 Submodule을 도입하게 되었다.
매우 진귀한 경험이었다고 생각한다.
이 글 또한 구구절절 말이 길었지만 사실 모든것을 다 적어내지는 못했다.
실제 프로젝트에서는 Submodule 도입에 대한것이 메인 안건이 아니었어서 고려 되어야 했던 사항들과 저울질 할 안건들은 더 많았다.
물론 회사의 자유로운 분위기 덕분에 좋은 아이디어가 있으면 기술 검토해서 근거를 가지고 방향성을 제안하고는 했지만 그건 개발팀 내부적으로 이미 충분한 배경에 대한 공유가 이루어진 사람들 끼리의 설득이고, 고객 대상으로 격식을 갖추면서 자료를 준비해서 설득할 기회는 흔치 않다고 생각한다.
내 길다면 길고 짧다면 짧은 애매한 프로젝트 경험에 빗대어봐도 이렇게 많은 방면으로 고려하고, 검토해서 설득의 기회가 주어지고 본격적으로 자료를 준비해서 설득해본 기회는 쉽게 주어지지 않는 것임을 알고있다. 작은 안건이라도 그 설득의 결과가 성공으로 마무리 된 것 또한 운이 좋았다고 생각한다.
프로젝트 중에는 이 안건 말고도 워낙 고려할 것들이 많아서 솔직히 부담스럽기는 했지만 지나고 보니 다시 없을 발전과 경험의 기회였던 것 같다.