카카오페이증권이 생각하는 DevOps문화와 Platform Engineering의 방향성

카카오페이증권이 생각하는 DevOps문화와 Platform Engineering의 방향성

시작하며

안녕하세요. 카카오페이증권 DevOps 팀의 크리스입니다.

이번 글에서는 카카오페이증권 DevOps 팀에서 생각하고 있는 DevOps 문화와 플랫폼 엔지니어링에 대해서 말씀드리고자 합니다. 그리고 최근 AWS 2023 re:Invent 에서 카카오페이증권 CTO 블리츠가 발표한 일상과 투자를 연결하는 카카오페이증권의 클라우드 활용사례 의 내용 중 DevOps Platform과 그를 통한 Graviton 전환 내용에 대해 좀 더 자세하게 소개해 보도록 할게요.

카카오페이증권이 생각하는 DevOps 문화와 Platform Engineering 방향성

서비스의 규모가 확장되고, 안정적으로 서비스를 운영하기 위해서는 더 많은 도구와 환경들이 필요하게 됩니다. 그에 맞추어 많은 기업들이 각 환경에서 DevOps 문화를 잘 실현하기 위해 많은 노력들을 하게 되죠.

Giving developers operational responsibilities has greatly enhanced the quality of the services, both from a customer and a technology point of view. The traditional model is that you take your software to the wall that separates development and operations and throw it over and then forget about it. Not at Amazon. You build it, you run it. This brings developers into contact with the day-to-day operation of their software. It also brings them into day-to-day contact with the customer. This customer feedback loop is essential for improving the quality of the service.

  • Werner Vogels, Chief Technology Officer at Amazon

개발자에게 운영 책임을 주는 것은 고객과 기술 측면 모두 서비스 품질을 크게 향상시켰습니다. 전통적인 모델에서는 소프트웨어 개발과 운영을 분리했었습니다. 소프트웨어를 일단 개발하고 나서는 넘겨버리고, 운영은 잊어버리는 셈이었죠. 아마존은 그렇지 않습니다. 당신이 만들고, 운영합니다. 이것은 개발자들이 소프트웨어의 일상적인 운영에 접촉하게 합니다. 또한 고객과 일상적인 연락을 취할 수 있습니다. 이 고객 피드백 루프는 서비스 품질을 개선하는 데 필수적입니다.

  • Werner Vogels, Amazon CTO

2006년, Amazon의 CTO Werner Vogels 가 이야기했던 것처럼, DevOps 문화는 개발팀과 운영팀이 사일로로 묶여있던 기존의 조직 구조와는 다르게 직접 만들고 운영하며 개발담당자가 서비스 애플리케이션의 개발부터 운영, 고객 서비스 접점까지 소프트웨어 개발 수명 주기(Software Development Life Cycle, SDLC)에 걸친 대부분의 영역에서 오너쉽을 가져가게 됩니다.

Software Development Life Cycle, SDLC
Software Development Life Cycle, SDLC

DevOps AntiType

카카오페이증권에서는 Public Cloud 환경과 자체적으로 운영 중인 데이터센터, Container 와 Bare Metal 등 다양한 환경 속에서 다양한 도구와 툴들을 활용해 애플리케이션이 빌드, 배포, 운영되는데요. 이러한 환경 속에서 개발자가 전체 인프라, 네트워크 구조를 모두 파악하고, 그에 맞는 툴들을 구성하여 운영하는 것은 결코 쉬운 일이 아닙니다. 각 환경에 적합한 CI/CD 파이프라인, Kubernetes 클러스터 구성, 모니터링, 로깅 환경 구성 등 각 환경 구성하는 데에도 많은 리소스가 필요하고 해당 플랫폼들을 운영하는 데에도 상당히 많은 노력이 요구됩니다. 서비스 애플리케이션 별로 표준화되지 않은 채 파편화되어 있는 환경과 플랫폼들도 이슈 발생 시 트러블 슈팅에 어려움을 만들어낼 수 있습니다.

AntiType - 개발과 운영의 분리

DevOps Antipattern #1
DevOps Antipattern #1

그렇기 때문에 많은 기업에서 개발팀과 운영팀을 분리해서 운영하기도 하죠. 이러한 경우 개발자는 운영에 대한 충분한 이해도가 없이 운영으로 코드를 전달하고, 운영팀에선 개발에 대한 이해 없이 운영되기 때문에 소프트웨어 운영성이 저하되고 빠른 피드백을 통한 개선도 힘들어질 수밖에 없습니다.

AntiType - 개발과 운영 사이의 DevOps 조직

DevOps Antipattern #2
DevOps Antipattern #2

DevOps가 필요하다고 생각되어 DevOps 조직을 구성하기도 하는데, 이런 경우 DevOps 조직은 개발팀과 운영팀 사이에 중간 역할을 하면서 개발팀과 운영팀의 갖가지 요구사항을 구성하며 처음에 빠르게 랜딩 하는 것처럼 보이지만, 서비스가 확장되고 규모가 커지면서 DevOps 조직에 부하는 점점 커지고 사일로가 확장될 수 있습니다.

Platform Engineering 목표

플랫폼 엔지니어링은 소프트웨어 엔지니어링 조직이 빠르게 소프트웨어를 개발 및 구성하고, 스스로 운영하며 개발자 경험과 생산성을 향상시키고 그로 인해 비즈니스 가치를 빠르게 상승시킬 수 있도록 합니다.

CNCF Platforms White Paper
CNCF Platforms White Paper

개발팀은 플랫폼 인터페이스를 통해 인프라를 비롯한 서비스 개발과 운영에 필요한 각종 환경을 스스로 구성하고, 테스트/운영할 수 있는 환경을 제공받음으로써 더욱 효율적이고 빠르게 소프트웨어를 설계, 개발, 운영해 나갈 수 있습니다.

플랫폼 엔지니어링팀은 서비스 개발 조직의 요청을 단순히 처리하는 개념을 넘어서서 플랫폼을 프로덕트로서(Platform as a Product) 개발하고 운영하여야 한다고 생각합니다. 서비스를 만들어 나가는 수많은 과정과 개발팀의 요구사항을 사용자 관점에서 폭넓게 이해할 수 있어야 하고, 개발팀에서 스스로 구성하는 과정이 힘들거나 병목이 걸리지 않도록 사용자 경험을 중심으로 플랫폼을 확장해 나가야 하죠.

카카오페이증권 DevOps 팀에서는 각종 도구들을 구성하고 추상화하여 DevOps 플랫폼을 제공함으로써 개발팀의 인지 부하를 줄이고, 보다 효율적인 DevOps “you build it, you run it” 를 할 수 있도록 방향성을 잡고 있습니다.

이번 글에서는 현재 DevOps 팀에서 개발하여 운영 중인 다양한 플랫폼 중 CI/CD 플랫폼에 대해 소개해드리고자 합니다.

CI/CD Platform - Wallga

DevOps Platform
DevOps Platform

카카오페이증권에서 컨테이너 환경에서 구성되고 있는 애플리케이션은 Wallga 플랫폼을 통해 빌드/배포되고 있습니다. Wallga 이름은 뉴욕 금융의 중심지인 Wall Street(월가)의 이름을 본떠서 만들었습니다. Wallga 는 애플리케이션 빌드/배포되는 과정과 운영에 필요한 여러 가지 도구들을 통합하고 자동화한 플랫폼입니다.

CI/CD를 자동화하기 위해서는 다양한 방법과 툴들이 있는데요. 카카오페이증권에서는 Jenkins와 ArgoCD 기반으로 구성하였습니다. Jenkins의 익숙함과 Groovy Pipeline의 자유로운 커스터마이징, Kubernetes 환경에서의 GitOps 기반의 선언적 상태 관리를 위해 위 툴들을 선택하게 되었습니다.

그 과정에서도 다양한 고민들이 있었고, 아래와 같은 목표를 세우고 구현하였습니다.

  1. CI/CD의 분리: 코드는 지속적으로 테스트/빌드/통합되고, 릴리즈는 그와 완전히 분리되어 독립적으로 행해질 수 있어야 한다.
  2. 일원화된 툴과 사용 경험: CI/CD 를 통일된 사용자 경험(플랫폼)을 줄 수 있어야 한다.
  3. 다양한 코드 타입 지원: 자체 개발하지 않은 오픈소스(ex: Helm Chart)나 의존성 있는 서비스(ex: AWS Lambda)도 같은 Pipeline에서 통합할 수 있어야 한다.

Github으로 Push/Merge 된 코드는 Test, Build를 거쳐 Image Push까지의 CI 과정이 자동화되어 수행됩니다. 직접 개발한 Java/Kotlin뿐만 아니라 Elasticsearch/Hadoop/Flink 등과 같이 완성된 Helm Chart 기반 플랫폼들도 CI 과정을 동일하게 수행할 수 있습니다.

그리고 독립적으로 CD를 진행할 수 있도록 Jenkins에 CD JOB 생성까지 자동화하였고, CD JOB에서 배포에 필요한 다양한 파라미터를 입력/선택한 뒤 실행하면 Kubernetes 환경으로 애플리케이션이 배포됩니다.

애플리케이션이 Wallga 플랫폼을 통해 어떻게 배포되는지 좀 더 상세하게 살펴보겠습니다.

Requirements

Wallga 플랫폼을 사용하기 위해선 3가지 설정 파일이 준비돼야 합니다.

  1. 이미지 빌드를 위한 Dockerfile
  2. Jenkins Pipeline 트리거를 위한 Jenkinsfile
  3. Wallga 플랫폼 자동화를 위한 설정 파일

사용자는 원하는 형태 애플리케이션 코드와 일반적인 API, Consumer, Batch 애플리케이션, Helm chart, AWS Lambda 중 배포 타입에 맞는 설정 파일들을 Github repository root path에 함께 Push 합니다.

1. Project Structure

# Helm Chart 프로젝트 구조 예시
├── chart
│   ├── templates/  # Helm chart templates 디렉토리
│   ├── values/     # Cluster, Phase 별로 활용 가능한 values.yaml 디렉토리
│   ├── ...
│   └── Chart.yaml
├── Dockerfile
├── Jenkinsfile
├── README.md
...
└── wallga.yml
# AWS Lambda 프로젝트 구조 예시
├── src/
│   ├── api/
│   └── index.ts
├── Jenkinsfile
├── README.md
├── package-lock.json
├── package.json
├── tsconfig.json
...
└── wallga.yml
# Gradle 프로젝트 구조 예시
├── src/main
│   ├── java
│   └── resources
├── Dockerfile
├── Jenkinsfile
├── README.md
├── build.gradle
├── settings.gradle
...
└── wallga.yml

2. Dockerfile

FROM base/eclipse-temurin:17.0.3_7-jdk-focal
LABEL MAINTAINER="kris.brown"

ARG JAR_FILE
COPY --chown=deploy:deploy ${JAR_FILE} app.jar

EXPOSE 8080
ENTRYPOINT exec java $JAVA_OPTS -jar ./app.jar

3. Jenkinsfile

@Library('wallga') _

ci()

4. Wallga 설정 파일(yaml)

trigger_on: ### Wallga Pipeline 을 실행하게 하는 트리거 하는 설정
  push: ### Push 이벤트로 CI를 실행하게 하는 이벤트 조건
    branches:
      - develop
      - feature/.*|sandbox
      - master
  workflow_run: ### Wallga Pipeline workflow 트리거 하는 이벤트 설정
    workflows: deploy ### CI 동작 이후 다양한 workflow 자동화 동작하기 위한 옵션 (ex: deploy 는 CD 자동 수행 설정)
    phases:
      dev:
        branch: develop
      sandbox:
        branch: sandbox
        auto_cd: false ### 자동으로 CD를 실행하지 않는 옵션
      production:
        branch: master

general:
  project_name: sample-api ### 프로젝트명
  slack_channels: ### CI/CD 과정의 알림을 받을 슬랙 채널
    - A1234B5678
build:
  language:
    name: jdk
    version: 17
  script: './gradlew build -p sample-api -x test'
  sonarqube: ### 정적 코드 분석 sonarqube 등록 정보
    project_key: 'sample-api_key' ### workflow_run에 선언된 branch merge scan 또는 PR comment로 수동 scan 가능
    language: 'kotlin'
    source_path: 'sample-api/src/main/'
    test_path: 'sample-api/src/test/'
deploy:
  type: online ### 배포 타입 정보, online|job|custom(==helm)|s3(==lambda) 등을 지원
  platform: neo-app ### 배포할 클러스터 정보
  namespace: sample-test ### 사용할 namespace 정보
  dns: sample-api.test.com ### 사용할 dns 정보
  health_check: ### K8S probe(readiness/liveness) 설정 정보
    type: http
    path: /actuator/health
  actuator: ### 메트릭 수집 정보
    enable: true
    path: /actuator/prometheus
    port: 8080

Jenkins Pipeline

1. CI

Jenkins Pipeline에서는 각 설정 파일들을 읽어서 각각의 스테이지를 수행합니다.

def call(){
  pipeline {
    ...
    stages {
      stage('PREPARE: INITIALIZE CONFIG') {
        steps {
          script {
            ### wallga.yml을 읽고 validation 및 초기 설정을 구성합니다.
          }
        }
        ...
      }
      stage('CI: TEST') {
        steps {
          script {
            ### 테스트를 진행합니다.
            ...
          }
        }
      }
      stage('CI: BUILD') {
        steps {
          script {
            ### build
            ...
          }
        }
      }
      stage('CI: PUBLISH') {
        steps {
          script {
            ### 이미지 publish
            ...
          }
        }
      }
      ...
    }
    ...
  }
}

2. CD

CI가 끝나면 Wallga 플랫폼에서 CD를 위해 Jenkins에 JOB을 생성합니다.

  ...
  stages {
    ...
    stage('CI: CREATE JENKINS CD JOB') {
      steps {
        script {
          ### Jenkins에 CD JOB 생성
          ...
        }
      }
    }
  }
  ...

Jenkins CD JOB
Jenkins CD JOB

개발자는 자동으로 생성된 Jenkins CD JOB에서 배포에 필요한 각 파라미터를 선택하고 실행합니다. 배포할 Image, Replicas, Spec, Deploy Strategy(rolling/canary/bluegreen), HPA 설정 등 배포, 운영 관련 다양한 옵션들을 선택하여 배포할 수 있습니다.

두 번의 업무 수행 (1번 Code push 과정 / 2번 CD JOB 실행) 과정만 진행하면 Kubernetes 환경으로 애플리케이션 배포할 수 있게 됩니다. 물론 아직 인프라의 모든 자원 영역을 통합하고 자동화하는 부분까지는 부족한 영역이 많고 지속적으로 개선 중입니다.

CI/CD
CI/CD

Wallga 플랫폼을 통한 Graviton Migration 과정 소개

2023년에는 비용과 성능 개선을 위해서 카카오페이증권에서 사용하고 있는 AWS 환경의 대부분의 워크로드를 3개월 안에 Graviton으로 전환하는 프로젝트를 진행했는데요. 추상화된 플랫폼 인터페이스인 Wallga 플랫폼이 있었기 때문에 Graviton Migration 과정도 어렵지 않았습니다.

Graviton Migration
Graviton Migration

1. ARM 기반의 node group 생성

module "eks" {
  # EKS Managed Node Group(s)
  eks_managed_node_group_defaults = local.node_group_defaults
  eks_managed_node_groups = local.node_groups
}

locals {
  node_group_defaults = {
    ...
  }
  node_groups = {
    ...
    app-node-arm = {
        ...
        instance_types          = ["m6g.8xlarge"]
        ami_type                = "AL2_ARM_64"
        ...
    }
  }
}

2. Multi Architecture Build 처리 및 Nodegroup 스케쥴링

한 번에 ARM 기반으로 빌드하여 대상 노드로 기동 되게 할 순 있지만, 생각지 못한 이슈들이 발생할 수도 있습니다. 그러한 경우 기존에 정상적으로 기동 중이던 AMD 기반 노드에서 정상적으로 운영될 수 있도록 ARM/AMD Multi Architecture로 이미지를 build 하도록 하였습니다. 가장 많이 사용되는 jdk 베이스 이미지는 DevOps 팀에서 Multi Architecture로 미리 올려두었고, CI Build 과정에서도 Multi Architecture 빌드를 추가하였습니다.

 ...
 stage('CI: BUILD') {
    steps {
      script {
        ### Multi Architecture Build
        docker buildx create --name multi-arch-builder --driver docker-container --use --platform linux/arm64,linux/amd64;
      }
    }
  }
  ...
  stage('CD: CONFIG MANIFESTS') {
    steps {
      script {
        ### ARM 기반의 node group 스케쥴링
        ...
        helm template . -f values.yaml \
        --namespace ${namespace} \
        --set kubernetes.io/arch=${config.build.nodeArch}
        ...
      }
    }
  }

3. 설정 파일 변경 및 push

Wallga 플랫폼 자동화를 위한 설정 파일

---
deploy:
  node_selector:
    kubernetes.io/arch: arm64

4. 점진적 적용

처음엔 Wallga 설정 파일에 옵션을 받아 준비된 서비스들부터 개발 환경에서 시작하여 차례차례 Graviton 노드로 이사를 가게 되었습니다. 개발 환경에서 일정 기간 모니터링 후 이슈가 없는 경우 운영환경에 적용되었죠. JVM 기반 애플리케이션뿐 아니라, Golang, Python 등 개발팀과 지속적으로 커뮤니케이션하며 차근차근 이사를 하게 되었고, 3개월 만에 서비스 애플리케이션 전체 전환을 완료했습니다.

글 서두에서 설명한 플랫폼 엔지니어링의 목적대로 Wallga 플랫폼이 구성되어 있었기 때문에 Kubernetes 클러스터 운영 담당팀이 개입할 필요가 없었고, 서비스 개발팀에선 주체적으로 가이드에 맞게 Pipeline 설정 파일 변경(wallga.yml) 하나만으로 쉽고 안정적으로 전환할 수 있었습니다.

플랫폼 엔지니어링팀과 서비스 개발팀의 리소스 병목 문제를 전혀 느낄 수 없을 정도로 전환 과정이 수월했고 만족도가 굉장히 높은 프로젝트였습니다.

마치며

카카오페이증권에서는 플랫폼 엔지니어링을 통해 자체적으로 적절한 플랫폼들을 구성하고 확장해 나가면서 속도, 커뮤니케이션, 비용 등 많은 문제들을 해결해 나가고 있습니다.

플랫폼 엔지니어링의 방향성에 맞는 플랫폼들을 만들어 나가려면 무엇보다 플랫폼을 직접적으로 사용하게 될 사용자(개발팀)와의 활발한 커뮤니케이션이 중요합니다. 그 과정에서 개발자에게 최대한 자유도를 주면서 표준화되고 안정적인 아키텍처를 유지해나가야만 하죠. 카카오페이증권의 DevOps 팀에서는 Cloud/On-Premise, Kubernetes 등 환경에서 사용자 친화적인 DevOps 플랫폼들이 유기적으로 잘 동작할 수 있도록 계속해서 개선해 나갈 예정입니다.

이번에 카카오페이증권의 CI/CD 플랫폼 Wallga 에 대해 소개해 드렸는데요. 앞으로 다양한 플랫폼들을 주제로 찾아뵐 카카오페이증권 DevOps 팀에 많은 관심 부탁드립니다!

감사합니다.

참고 자료

kris.brown
kris.brown

카카오페이증권에서 DevOps팀을 리드하고 있는 크리스입니다. 개발자가 스스로 빠르고 안정적으로 개발, 운영을 할 수 있도록 하는 단단한 플랫폼을 만들고 싶습니다.(절대 내가 귀찮아서가 아님.)