summary
ECS 도커 오케스트레이션 환경에서 Git submoudule을 사용한다.
Pain point
ECS를 활용한 도커 오케스트레이션 환경에서 다른 서비스 환경과 공유하는 UI 컴포넌트를 사용할 일이 생겼다.
npm private package를 사용하여 공통 패키지 컴포넌트를 사용할까 하다가 배포와 관리의 불편함 떄문에 git submodule을 사용하기로 결정했다.
로컬 환경에서 서브모듈을 사용하여 개발을 하고, 클라우드 환경에 배포해보니 서브모듈 코드가 제대로 불러와 지지 않아 오류가 생겼다.
구성 환경
필자가 구성한 오케스트레이션 환경은 Code Pipeline을 통해 배포되는데, 파이프라인의 첫 번째 스테이지는 Github Webhook을 통해 소스코드를 가져온다.
Github webhook을 통해 가지고 온 소스코드는 submodule의 전체 소스코드를 가지고 있지 않고 submodule의 커밋정보만을 가지고 있다.
따라서 실제 구동시킬 소스코드파일이 존재하지 않아 클라우드 환경에서 오류가 발생했던 것이다.
해결
Pipeline에서 소스코드를 기반으로 Docker image를 빌드할 때 submodule의 실제소스 코드를 받아와야한다.
이를 위해 Docker의 Multi stage build 기능을 사용한다.
Multi stage build?
Multistage builds are useful to anyone who has struggled to optimize Dockerfiles while keeping them easy to read and maintain.
멀티스테이지 빌드를 사용하면, 아래와 같은 이점이 있다.
- 이미지 사이즈를 줄일 수 있다.
- 다른 베이스에서 이미지를 만들고, artifact를 다른 스테이지에서 사용할 수 있다.
자세한 내용은 공식문서를 참고하자.
Multi stage build 적용
before
먼저 적용 전 front 컨테이너의 docker file이다.
FROM node:12
WORKDIR /app
COPY package.json /app/package.json
RUN npm install
CMD ["npm", "start"]
dockerfiled에서는 아래 순서로 작업을 진행한다.
- 베이스 이미지를 pull
- app 디렉토리를 생성하고 이동
- package.json 파일을 work dir 로 복사
- npm install 을 통해 dependecies 설치
- npm start 스크립트를 통해 어플리케이션 실행
하지만 여기서 가지고 있는 소스코드 파일의 submodule 부분은 커밋의 정보만 가지고 있을 뿐, 실제 소스코드를 포함하고 있지 않다.
after
FROM node:13.12.0-alpine3.11 as build
RUN apk add --no-cache git
ARG GIT_TOKEN
RUN git clone https://${GIT_TOKEN}@github.com/{YOUR_REPOSITOY}
WORKDIR /{YOUR_REPOSITOY}
RUN git checkout -t origin/master
RUN git config --file=.gitmodules submodule.{YOUR_SUBMODULE_NAME}.url https://${GIT_TOKEN}@github.com/{YOUR_SUBMODULE_REPOSITOY}
RUN git submodule update --init --recursive
FROM node:12
WORKDIR /app
COPY package.json /app/package.json
RUN npm install
COPY --from=build /{YOUR_REPOSITOY}/application/frontend/ /app/
CMD ["npm", "start"]
멀티 스테이지 빌드는 첫 번째 FROM 부터 두 번째 FROM 이전까지이며, as 를 통해서 builder의 이름을 지정해 줄 수 있다.
여기서는 build라는 이름으로 빌더를 지정했다.
빌더에서 수행하는 작업은 아래와 같다.
- 노드 알파인 이미지를 pull (일반 노드 이미지 보다 가볍고 빨라서 빌더에 적합하다고 판단)
- apk응 이용해 git을 설치 (알파인 이미지에는 git이 기본으로 설치되어 있지 않음)
- build-arg를 통해 GIT_TOKEN을 전달받음 (파이프라인에서 빌드명령 실행 시 전달해 준다) (프라이빗 레포가 아니면 해당 과정 생략 가능)
- GIT_TOKEN을 통해 레포지토리를 클론받음 (프라이빗 레포가 아니면 http로 클론)
- 클론 받은 레포지토리로 이동
- origin/master로 checkout
- 서브모듈의 url을 변경 (프라이빗 레포가 아니면 해당 과정 생략 가능)
- git submodule update –init –recursive 명령어로 소스 코드를 가져온다.
빌더가 작업을 수행 한 뒤, 빌터에서 소스코드를 가져올 때는 –from을 이용한다.
COPY --from=build /{YOUR_REPOSITOY}/application/frontend/ /app/
명령어를 통해 빌더에서 전체 소스코드를 workdir 로 옯겨온 뒤 실핼스크립트를 실행한다.
end
도커의 멀티스테이지 빌드를 통해 서브모듈의 소스코드 전체를 불러오고, 사용하는 방법에 대해 알아보았다.
프라이빗 레포에 적용하기 위해 Gitbhub Webhook에 사용한 GIT_TOKEN를 사용하였는데, 퍼블릭 레포라면 해당 과정을 건너뛰어도 좋다.
운영환경이라면 GIT_TOKEN도 AWS Secrets Manager 등을 사용해 관리하면 더 안전한 서비스가 될 것이다.