최근 사내 웹 프론트엔드에서 앱과 웹에서 사용할 수 있는 모듈을 사용하기 위해
Submodule을 사용하고 있는데, 배포 과정에서 문제가 생겼었습니다.
그래서 이 글은 약간의 Submodule에 대한 제 생각과, 당시 자동화과정에서 생긴 문제를 해결한 과정을 작성한 글입니다.
해당 모듈은 현재 사내 웹가 앱에 전반적으로 사용되는 비즈니스로직이 포함돼있으며, 각 서비스에서 Submodule형태로 App과 Web에 전반적으로 사용중에 있습니다.
이를 Submodule형태로 레포지토리를 분리한 이유는 다음과 같습니다.
간단하게 Submodule과, Subtree를 비교해보겠습니다.
Submodule과 유사한 방법으로 Subtree가 있습니다. Subtree의 특징은 다음과 같습니다.
Submodule과는 다르게 Subtree를 사용하게되면 참조한 외부 레포지토리의 코드를 그대로 가져옵니다. 그래서 해당 소스코드를 clone하게되면 소스코드가 같이 clone하게 됩니다. Submodule과는 달리 소스코드를 직접 사용하기 떄문에 해당 코드에 대한 변경사항에 대한 내용을 직접적으로 git으로 추적이 가능합니다.
아래의 명령어를 사용하여 submodule을 업데이트 하고 소스코드를 작업 로컬환경으로 가져옵니다. 이러면 내가 가져온 submodule의 최신 Head값으로 참조가 바뀌게 되고 이 변경 이력을 깃 형상관리에 추가해줍니다. → 이를 해주지 않으면 해당 소스코드를 받은 사람들은 참조가 바뀐지 알 수 없게 됩니다.
즉 Submodule의 레포지토리를 작업하는 개발자가 소스코드를 추가적으로 배포하면 해당 코드를 사용하는 레포지토리에서는 마지막 커밋을 바라보게 됩니다.
// subModule에 있는 코드까지 clone 받는 방법
git clone --recurse-submodules <repository_URL>
// 지속적으로 Submodule의 변경점을 update하는 방법
git submodule update --init --recursive
저는 웹을 개발했고, 이 과정에서 자동화부분을 데브옵스 개발자님과 같이 신경썼습니다. 이미 CI/CD가 적용돼있어서 깃허브에서 코드 푸시이벤트를 구독하여 Jenkins에서 배포하고 있었습니다. 프로세스는 다음과 같습니다.
이 과정에서 아무런 문제가 없었으면 제가 이 글을 쓰지 않았을겁니다. 이 부분에 대해서 자동화에 대한 자세한 과정은 이번 글에서 다루지 않기에 넘어가겠습니다.
웹 배포를 Jenkins 환경에서 배포할때 DokcerFile의 명령어에 따라 다음과 같은 프로세스로 진행합니다.
문제는 4번에서 생겼습니다. Submodule로 받아온 파일의 경로를 읽을 수 없다는것이었습니다.
이를 해결하기 위해 2가지 실험을 했습니다.
2가지 경우에서 모두 소스코드가 존재하지 않았고 로컬환경에서 추가적으로 위 사용법의 코드를 입력했을때 소스코드를 받아 올 수 있었습니다.
하나의 추가적으로 의문이었던점은 로컬에선 DockerBuild가 가능했다는것인데, 이 소스코드를 불러오는 과정을 CI과정에서 추가해주면 해결될거라는 확신을 얻었습니다.
그래서 이 문제를 해결하기 위해 Docker환경에서 직접 Submodule을 받아올 수 있도록 했지만 이는 잘 되지 않았습니다. Docker환경에서는 .git 파일이 없기 때문입니다. 그리고 원래 Docker환경에 git을 올리는 행위가 보안적으로 좋은 방법은 아니였습니다.
그래서 다른 방법을 모색하여 Jenkins에서 코드를 Clone할때 git submodule update --init --recursive 명령어를 한번 더 실행하여 문제를 해결했습니다.
Jenkins + Docker환경에서 CI/CD를 진행중이며 이 과정에서 Submodule과 호환이 원활하지 않아 Jenkins 설정에 직접 Submodule을 받아오는 코드를 추가하여 해결.
서브모듈을 사용하면서 얻은 장점은 명확합니다. 우선 앱과 웹에 필요한 소스코드를 동시에 작성하지 않아도 하나의 레포지토리에서 개발해도 되기에 이를 사용하는 곳에선 해당 참조를 최신화해주기만 하면 됩니다.
그리고 Subtree와는 다르게 소스코드를 직접 수정하여 배포하는게 불가능한데 만약 공통으로 사용하는 모듈을 각 서비스에서 로직이 수정돼야하고 각각의 버젼으로 디벨롭돼야한다면 Submodule보다는 Subtree를 추천드립니다.