안녕하세요, 백엔드 엔지니어 잭슨입니다.
오늘은 최근 맡게 된 검색 관련 프로젝트에 CI/CD 파이프라인을 구축하여 프로젝트 관리 및 배포를 개선한 경험을 공유하고자 합니다.
모바일 프로덕트의 홈 화면 개편 스프린트에서 홈 화면 중앙에 위치한 검색 기능의 중요도가 높아짐에 따라 검색 관련 요구사항 및 개선사항이 증가했습니다. 제가 검색 관련 태스크를 맡게 된 후 프로젝트를 파악해본 결과, 다음과 같은 문제점을 발견했습니다.
위의 문제점을 해결하기 위해 CI/CD 파이프라인을 도입하기로 결정했습니다. CI/CD 파이프라인은 다음과 같은 장점이 있습니다.
저희 프로젝트는 다음과 같은 4가지 환경으로 구성되어 있습니다.
효율적으로 CI/CD 프로세스를 관리하기 위해 여러가지 대안들을 고민해보았고 그 중 최종적으로 두가지의 대안이 떠올랐습니다.
기존에 CI/CD 프로세스와 가장 비슷하고 관리하기 쉬울 것 같단 판단에서 이 두가지 대안이 떠올랐으며 최종적으로 2번째 대안으로 선택하였습니다.
1번째 대안의 경우는 Apache Spark의 인덱싱 작업이 조금 무거워 Karpenter Auto Scaling으로 인해 K8S Node가 배치주기마다 새로 뜰 수 있고 그로 인한 비용문제로 인해 채택되지 못했습니다.
다음은 CI/CD 구축 과정입니다.
def MERGE_RESULT=true //Variable For Merge Fail Check
def NOTIFICATION_GROUPS="@backend" //Slack Notification Group
def buildspec() { // 지정된 브랜치만 빌드 되도록
def deploy_enables = ["develop", "rc", "staging", "production"]
if (deploy_enables.contains(env.BRANCH_NAME))
"ci/${env.BRANCH_NAME}/buildspec.yml"
else
""
}
def channel() { // 프로덕션의 경우 다른 채널에 알림이 오도록
if (env.BRANCH_NAME.contains("production"))
"#product_deployment"
else
"#product_development"
}
def cron_expression(){ // Production의 경우 배치의 간격을 5분으로 조정
if (env.BRANCH_NAME.contains("production"))
"H/5 * * * *"
else
"H/10 * * * *"
}
pipeline {
agent none
triggers { cron(cron_expression()) }
stages {
stage('Build') {
agent {
label 'node-linux'
}
steps {
awsCodeBuild(
// 생략
)
}
}
stage('Git backward Merge And Push'){ // auto back merge
agent {
label 'node-linux'
}
steps{
sshagent(credentials: ['ssh_key']) {
script{
// 생략
}
}
}
}
}
post { // slack 알림
success {
// 생략
}
failure {
// 생략
}
}
}
env:
parameter-store: // parameter store에서 보안관련 키를 받아옵니다.
EKS_CLUSTER_BLUEGREEN: "/develop/..."
AWS_ACCESS_KEY_ID: "/develop/..."
AWS_SECRET_ACCESS_KEY: "/develop/..."
variables:
BUILD_CI_ENV: develop
ECR_ARN: "비밀.dkr.ecr.ap-northeast-2.amazonaws.com/search"
AWS_ACCOUNT_ID: "비밀"
AWS_DEFAULT_REGION: "ap-northeast-2"
APP_FOLDER: src
phases:
install:
commands:
- nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 &
- timeout 15 sh -c "until docker info; do echo .; sleep 1; done"
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
build:
commands:
- cp ./cd/Dockerfile $APP_FOLDER/Dockerfile
- cd $APP_FOLDER
- docker build -t spark . --build-arg AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID
- docker run spark
정상적으로 동작하는 것을 확인한 후 다음날 확인한 결과 간헐적으로 빌드가 실패한 것을 확인할 수 있었습니다. 로그를 확인해보니 아래와 같은 로그를 확인할 수 있었습니다.
ERROR: toomanyrequests: Too Many Requests.
관련 링크 : https://subicura.com/k8s/2021/01/02/docker-hub-pull-limit/
도커 허브에서 익명의 무료사용자에게는 요청량을 제한한 것이었습니다. 이를 해결하기 위해 자체적으로 Docker Image를 만들어 AWS ECR(Elastic Container Registry)를 통해 미리 생성된 Private 이미지를 통해 빌드 되도록 수정하였습니다.
CI/CD 파이프라인 도입을 통해 검색 관련 프로젝트의 개발 및 배포 효율성을 크게 향상시키고 신뢰성을 높일 수 있었습니다. 특히, 이후에 있었던 스프린트에서 개발요구사항을 빠르게 배포하고 테스트해볼 수 있어 개발 생산성에 큰 도움이 되었습니다.
오늘은 방치된 Spark 프로젝트에 CI/CD 파이프라인을 구축하여 개발 및 배포 효율성을 향상시킨 경험을 공유해보았습니다. 이 글이 CI/CD 파이프라인 도입을 고려하고 있는 분들에게 도움이 되기를 바랍니다.
GraphQL 기반 애플리케이션 MSA 여정기 pt.2 (0) | 2024.02.18 |
---|---|
GraphQL 기반 애플리케이션 MSA 여정기 pt.1 (0) | 2024.01.28 |