Skip to content

인프라는 어떻게 관리했나요?

mintaek edited this page Dec 5, 2024 · 3 revisions

서비스 아키텍처

386078111-dc1e1a29-b9fa-47ad-8c58-df591ed922b7

인프라 설계

서버 인스턴스는 2개를 활용하였고, 목적에 따라 그 인스턴스의 성격을 분류하였습니다. 성격에 따라 서버를 분리함으로써 추후에 AutoScaling, LoadBalancer 등을 적용할 때 큰 리팩토링 없이 적용시킬 수 있도록 하였습니다.

서비스 인스턴스

외부 네트워크와 상호작용 해야 하는 성격의 서버들을 올리고 관리하였습니다. 배포를 담당해야 하는 젠킨스는 서버에 직접 설치하고 활용하였고, 웹 서버와 백엔드 서버의 경우는 도커를 활용하여 배포해주었습니다.

스토리지 인스턴스

데이터를 저장해야 하는 성격의 서버들을 올려주었습니다. 세션을 관리할 Redis , 서비스에서 활용할 Mysql , 쿼리 실행에 활용할 Mysql 3개의 서버를 올리고 관리하였습니다. Privite Subnet 에 위치시켜 외부 네트워크에서의 직접적인 접근을 제한하고, VPC 내부에서만 인터랙션을 허용 하였습니다.

구현 과정
배포환경 DB 세팅
nginx 설정 및 프론트 배포
백엔드 mySQL, redis 세팅

CICD 구축

젠킨스를 활용, 깃허브와 연동해서 CICD 를 구축해 주었습니다. 젠킨스가 많이 활용된다고 알고 있어 이번 기회에 경험해보고자 하는 이유가 컸습니다. 파이프 라인은 크게 3가지 경우로 나뉘어 동작합니다.

Main 브랜치에 대한 Push 이벤트

Main 브랜치를 기준으로 CD를 구축하였습니다. Main 브랜치에 대해 Push 이벤트가 발생하면 도커 컴포즈를 빌드하고 서버를 배포합니다.

Dev 브랜치에 대한 PR 이벤트

Dev 브랜치에 대한 PR 요청은 전부 CI 테스트 과정과 연동됩니다. 요청받은 브랜치의 모든 작업 내용을 Dev 브랜치로 머지합니다. 따라서 Dev 브랜치에 대해 PR 요청이 생성되면 타깃 브랜치와 Dev 브랜치를 머지하고, CI 테스트를 수행합니다. CI 테스트는 4가지를 수행하였습니다. 각 테스트는 도커환경에서 실행되며, 테스트 결과를 간단하게 코멘트로 남겨줍니다. 파이프라인 실행 과정은 과정은 CI Test 링크로 간단하게 확인할 수 있습니다.

  • FE - npm test , vite build
  • BE - npm test , npm buld
CI Test 코멘트 CI 파이프라인
image image

그 이외 브랜치에 대한 이벤트

이외의 브랜치에 대해서는 CI 테스트를 스킵하도록 하였고, PR 인 경우에는 간단한 코멘트를 남겨주었습니다. image

연동 과정
Jenkins 세팅
Jenkis 활용 CI 구축

배포 환경

배포 환경에서 비밀번호 등의 민감한 정보를 관리할 방법이 주요 고민거리였습니다. 기존 로컬환경에서는 .env 파일을 만들고, 그 안에 커넥션 관련 정보나 비밀번호 등의 민감한 정보를 저장하면 되었습니다. 그러나 Jenkins 를 활용해서 CD 를 수행해주고 있었고, 젠킨스는 Github Main 브랜치를 기준으로 Pull 한 뒤 배포를 진행하고 있습니다. .env 파일을 활용하고 싶으면 레포지토리에 .env 파일을 함께 업로드해서 젠킨스가 pull 받을 수 있도록 해야하는데, 모두가 접근할 수 있는 레포지토리에서 환경변수를 관리한다는 것은 말이 되지 않는 방법이었습니다.

따라서 젠킨스가 빌드를 수행하는 환경에서 환경변수를 어떻게 넣어줄 수 있을까를 고민하였습니다. 이런저런 방법을 찾아본 결과 Jenkins Credential 을 통해 비밀번호 등의 민감한 정보를 관리할 수 있다는 사실을 알 수 있었습니다. 환경변수 문제를 해결하기 위해 Jenkins Credential 기능을 활용하였고, 빌드 파이프라인 환경에서 환경변수를 주입해 받는 방법을 선택하였습니다. 결과적으로 환경변수는 다음과 같은 흐름으로 주입됩니다.

jenkins Credential -> Jenkins 배포 쉘 환경변수 -> 배포 도커 컴포즈 환경변수

//Jenkins file
// 빌드 과정에서 필요한 정보들을 가져와 환경변수로 주입해 사용합니다.

        stage('Build and Deploy') {
            steps {
                script {
                    withCredentials([
                    //환경변수로 주입
                        string(credentialsId: 'DB_PASSWORD', variable: 'DB_PASSWORD'),
                        string(credentialsId: 'QUERY_DB_PASSWORD', variable: 'QUERY_DB_PASSWORD'),
                        string(credentialsId: 'SESSION_SECRET', variable: 'SESSION_SECRET')
                    ]) {
                        // 기존 컨테이너 제거
                        sh 'docker-compose down'
                        
                        // Docker Compose 빌드
                        sh 'docker-compose build'

                        // Docker Compose 실행
                        sh 'docker-compose up -d'
                    }
                }
            }
        }

Jenkins에서 환경변수 관리 방법

테스트 환경

로컬에서 개발할 때, 백엔드와 프론트가 각각 기능테스트를 위해서 어떻게 환경을 구성할 지 고민하였습니다.

백엔드의 경우

기능 테스트를 위해 필요한 요소는 DB서버입니다. 테스트를 위해서 실제 배포환경의 DB를 활용하면 안되지만, 연결해서 기능을 시험해 볼 데이터베이스가 필요합니다. 따라서 서비스에 필요한 3개의 DB를 도커로 올리고, 테스트 DB 에 연결해 개발할 수 있도록 .env 파일과 도커 컴포즈를 관리하였습니다.

프론트의 경우

프론트의 경우도 api 를 연동해서 테스트할 필요가 있습니다. 그러나 백엔드와 마찬가지로 실제 배포환경의 백엔드 서버를 활용할 수는 없습니다. 프론트가 개발환경에서 API 테스트를 실제 배포환경과 최대한 비슷하게 연동해 볼 수 있도록, 배포환경과 유사한 백엔드 구성요소를 도커 컴포즈로 작성했습니다. 그 후 npm run start:container 명령어로 서버를 로컬에 띄울 수 있도록 하고, 개발환경에서 백엔드 로컬 서버와 인터랙션 할 수 있도록 했습니다.

로컬 백엔드 서버

image

Clone this wiki locally