Intro
안녕하세요. 하루에 수십 번 크고 작은 배포들이 이뤄지고 있는 베이글코드의 서버 디플로이 시스템을 소개해보려고 합니다.
Background
베이글코드의 Club Vegas, Jackpotjoy Slots, Star Spins Slots 서버들은 MSA(Microservice Architecture) 로 설계되었으며, Docker 로 containerized 되어 있습니다. 그리고 많은 Service & Container 들을 AWS 위 Kubernetes 클러스터에서 운영하고 있습니다.
Overview

Jenkins
권한을 부여받은 개발자라면 Jenkins 를 통해 누구나 쉽게 서버를 deploy, restart, rollback 을 할 수 있습니다. 아래 그림과 같이 parameter 로 commit hash 나 context 만 넣고 job 을 build 하면 됩니다.

생성된 job 은 Build Executor (EC2) 의 workspace 에서 진행됩니다.
Pipeline script 들이 과거에는 Jenkins 에 존재해서 히스토리 추적이 어려웠고 중복이 많았습니다. 지금은 Groovy 파일로 작성해서 Shared Library repo 에서 관리하고 있습니다.
Details
Club Vegas 서버 디플로이는 크게 다음과 같이 이루어져 있습니다.

Checkout
GitLab 에서 필요한 repository 들을 checkout 한 뒤, job 에 revision/target badge (
manager.addShortText
) 를 달아줍니다.
Release
release 스크립트를 실행해서 Docker 이미지를 만들고 Docker Hub 에 push 합니다.
Upload artifacts
다른 팀과 협업하는 데 필요한 특정 파일들을 AWS S3 에 upload 합니다.
Apply config
Kubernetes 를 처음 적용하던 시절에는 환경 (QA, ST, PROD …) 별로 ConfigMap, Service 파일 등이 따로 존재했습니다. 작년에 Helm 을 도입하면서 하나의 template 에 여러 values 를 쓸 수 있도록 관리하고 있습니다.
helm template
로 얻은 manifest (ConfigMap) 를
kubectl apply
합니다.
helm template ${releaseName} ${chart} --show-only ${template} --values ${value} --set-string image.tag=${tag} | kubectl apply --context=${context} --kubeconfig=${kubeconfig} -f -
Deploy services
대부분은 점검 없이 Rolling Update 를 통해 서비스 품질에 영향을 주지 않고 빨리 pod 를 교체해서 새로운 서버를 배포할 수 있습니다.
kind: Deployment
...
spec:
progressDeadlineSeconds: 300
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 25%
type: RollingUpdate
...

이전 stage 와 같은 방법으로 얻은 manifest (Deployment) 를
kubectl apply
한 뒤,
kubectl rollout
를 진행합니다.
kubectl rollout status deployment ${deploymentName} --context=${context} --kubeconfig=${kubeconfig}
Rebalance
rolling update 이후 nodes 에 고르게 분산되지 않은 pods 를 rebalance 를 해줍니다.
따로 custom 스케줄러를 쓰고 있지는 않고,
podsPerNode
를 직접 계산해서 pod 를 새로 띄우고 있습니다.
kubectl get pods -o custom-columns=node:{.spec.nodeName},name:{.metadata.name} --no-headers=true -l app=${app} --context=${context} --kubeconfig=${kubeconfig}`
...
kubectl delete pods ${podToKill} --context=${context} --kubeconfig=${kubeconfig}
Tagging
환경별로 어떤 commit 까지 배포되었는지 쉽게 알 수 있도록,
env.JOB_NAME
과
env.BUILD_NUMBER
를 이용해서 tag 를 만들고 git origin 에 push 합니다.

Further Consideration
- Jenkins (master) 와 Agent (node) 에 강한 dependency 가 있기 때문에 Jenkins 장애 발생 시 배포를 할 수 없는 상황이 있었습니다.
- MySQL Schema 변경이 필요할 때도 Zero Downtime 이 가능하도록 연구하고 있습니다.