[ 발자국 ]Docker와 Github Action을 사용한 CI/CD 환경 개선하기

무심코·2023년 2월 15일
3
post-thumbnail

1년 넘게 유지해온 '발자국' 서비스의 AWS 프리티어 계정 사용기간이 만료되었다. 그에 따라 신규 계정을 생성하고 해당 계정으로 EC2와 RDS, S3를 이전하기로 결정하였다. 이때 그저 계정 및 데이터 이전만 진행하는 것이 아닌 기존 사용해온 CI/CD 환경을 개선하고자 하였고, 이 과정에서 Docker와 Github Action, 추가로 Git Submodule를 사용한 CI/CD 환경을 구축하였다.


기존 CI/CD 환경

기존 CI/CD 환경은 다음과 같았다.

Github Action에서 CI를 진행하고 Github Action에서 소스 코드를 AWS S3로 압축하여 저장 후 AWS CodeDeploy를 사용하여 AWS EC2에 배포하는 환경이었다.
해당 환경에는 몇가지 문제점(불편한점)이 존재했다.

민감한 파일 관리

먼저 민감한 정보(aws 계정 정보등)를 가진 application.yml, aws.yml 파일의 경우 .gitignore에 등록하여 Github상 공개되지 않도록 하였다. 이 때문에 Github Action에서 해당 YAML 파일들이 없는 상태로 빌드하여 CI를 진행 할 수 밖에 없었고, CodeDeploy를 통해 배포 서버 환경으로 전달된 이후 해당 서버에 존재하는 YAML 파일을 포함한 상태로 다시 빌드된 후에야 빌드된 jar 파일을 정상적으로 돌릴 수 있었다.

이 경우 매 배포마다 두번씩 빌드된다는 비효율과 특정 yml 파일이 변경되는 경우 배포 서버로 직접 접근하여 해당 파일을 최신화 해줘야하는 불편함이 있었다.

AWS CodeDeploy의 디버깅 어려움

AWS CodeDeploy의 경우 디버깅이 어렵다는 단점이 있었다. 기존 CodeDeploy의 appspec.yml을 튜닝할 때 Event LifeCycle 안에서 어느 부분에서 오류가 발생했는지 파악하기 어려웠고 실제로 처음 CodeDeploy로 CD 환경을 구축할때 디버깅의 어려움으로 오랜시간 어려움을 겪은 경험이 있다.

배포때마다 진행해야하는 환경설정

AWS EC2 서버를 옮기는 현 상황, 서버를 옮기는데 필요한 리스트들을 정리하면서 보니 생각보다 많은 부분의 서버 환경설정을 다시 설정해줘야 했다. 같은 서버 안에서도 배포, 개발 jar 파일 별 환경 설정이 다른 부분도 존재하여 이러한 환경을 개별적으로 설정해줘야했다.
또한 만약 서비스가 이후 서버를 늘리거나 다시 이전해야하는 경우 과거의 환경설정을 매번 맞춰줘야한다는 비효율이 존재할 것이라 판단하였다.

이와 같은 이유들로 인해 새로운 CI/CD 환경을 구축하기로 결정하였다.


신규 CI/CD 환경

GitHub SubModule을 사용한 YAML 파일 관리

우선 첫번째 문제였던 민감한 파일들을 관리 방법을 개선하기 위해 GitHub SubModule을 사용하였다.
초기 GitHub Secret을 사용하여 사용하는 정보들을 저장해볼까 했지만, Secret화 해야하는 정보가 너무 많고 이후 변경사항이 생기면 수정하기 쉽지 않은 환경이 된다 생각하여 노선을 변경하였다.
또한 Jasypt으로 암호화하는 방법도 생각했지만 프로덕션 코드에 암호화를 위한 코드를 추가해야 한다는 부담이 있어 최종적으로 subModule을 선택하게 되었다.


다음과 같이 subModule로 사용할 Private Repository를 하나 생성하여 해당 저장소 안에 공개하면 안되는 민감한 파일들을 추가한다.

이후 해당 subModule을 사용하고자 하는 프로젝트 git에 git submodule add {submodule_repository_url} 를 사용하여 메인 레포지토리에 submodule을 추가하고 상태를 확인하면, 새로 커밋해야 할 파일이 나타난다. 이 파일을 add하고 commit해야 비로소 메인 레포지토리에 submodule이 반영된다.

submodule이 반영되었다면 submodule 저장소 안에 있는 민감한 파일들을 CI/CD 과정에서 원래 위치(src/main/resources)로 옮겨줘야 한다. 이때 Github Action에서 해당 파일들을 복사하여 옮겨준다. 해당 과정을 이후 더 자세하게 설명하겠다.

주의할 점

이때 연결된 submodule은 submodule화된 시점의 Repository와 연결된 것을 주의해야한다.

다음과 같이 submodule을 진행한 특정 커밋에서의 저장소가 연결되므로, 만약 submodule 저장소에서 파일을 변경 후 커밋할 경우 해당 변경사항에 대해서 submodule 저장소를 연결하고 있는 저장소는 알지 못한다.

추가적인 고려사항

발자국 서비스는 배포 환경과 개발환경을 분리하기 위해 prod와 dev 서버를 각각 사용하고 있다. 이때 prod 서버와 dev 서버에서 사용하는 aws 자원이 다른데, 이를 application.yml에서 profile 환경을 분리하여 prod 서버와 dev 서버에 각각 할당해준다. prod의 경우 master 브랜치에 push 될 경우 배포되고, dev의 경우 dev 브랜치에 push 될 경우 배포된다.

문제는 profile 환경 분리를 application.yml 하나의 파일로 하고 있어 master와 dev 브랜치가 push할 경우 하나의 profile 밖에 사용할 수 없었다. 이를 해결하기 위해 submodule 저장소에 prod와 dev profile을 각각 설정한 applicationMaster.ymlapplicationDev.yml을 만들고, 이를 이후 CI/CD 과정에서 master 브랜치에서는 applicationMaster.yml을 dev 브랜치에서는 applicationDev.ymlapplication.yml로 복사하여 사용하도록 설정하였다.

Docker를 사용한 배포 프로그램 Image화

Github에 올라간 소스코드 그 자체를 서버에 배포하는 방식과 다르게 Docker를 사용하여 CI를 거친 소스코드를 소스코드 구동에 필요로 하는 환경설정들과 함께 Image화 시키고 해당 Image를 서버에서 실행하는 방식으로 배포 환경을 구성하였다.

CI/CD 실행 구조

CI/CD 실행 구조는 다음과 같다.

[ CI ]
Github에 코드가 push되면 Github Action을 통해 branch에 해당하는 CI 진행
1. submodule의 저장된 민감한 파일(YAML..)을 소스코드가 필요로 하는 디렉토리로 복사
2. Gradle build 후 Unit Test 진행
[ CD ]
CI 완료 후 branch에 해당하는 CD 진행
1. submodule의 저장된 민감한 파일(YAML..)을 소스코드가 필요로 하는 디렉토리로 복사
2. Gradle build
3. Docker Image build
4. Docker Hub로 build한 Image publish
5. EC2 서버에 접근
6. 서버 안에서 docker Image pull
7. docker run으로 실행

개선점

  1. Docker Image를 사용함으로 기존 배포 버전마다 서버에서 직접 관리해줘야했던 환경설정 부분을 배포 전 개발자의 소스코드 부분에서 관리할 수 있고 이를 통해 서버 환경과의 싱크를 맞추는(환경설정 버전이나 사용하는 환경들을 맞추는) 부담을 줄일 수 있어 좀더 가볍게 서버 배포를 진행할 수 있게 되었다.
  2. 또한 GitHub Action과 Docker hub를 사용하여 기존 AWS CodeDeploy보다 명확하게 CD 과정에서 발생하는 에러를 디버깅할 수 있게 되었다.
  3. 마지막으로 Submodule을 사용하여 민감한 파일을 효과적으로 관리할 수 있게 되었고 해당 파일들을 배포할 때 개발자의 개입이 필요없게 개선되었다.
profile
지나치지 않기 위하여

0개의 댓글