이식 가능한 YAML로 CI/CD 벤더 종속(Vendor Lock-In) 방지하기: 유연한 파이프라인 구축을 통해 얻은 교훈
요약
CI/CD 플랫폼의 YAML 설정이 특정 벤더에 종속되는 문제를 방지하기 위한 전략을 다룹니다. 파이프라인을 단순한 오케스트레이터로 활용하고 핵심 로직을 이식 가능한 스크립트로 분리하는 방법을 제안합니다.
핵심 포인트
- YAML 구문은 유사해도 플랫폼 특화 기능은 이식성을 저해함
- 비즈니스 로직을 YAML 내부가 아닌 외부 스크립트로 모듈화할 것
- 파이프라인은 스크립트 실행 시점을 결정하는 오케스트레이터 역할에 집중
- 벤더 전용 기능은 전체 프로세스가 아닌 가장자리(Edge)에만 제한적으로 사용
지난 몇 년 동안 저는 GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Azure DevOps, 그리고 최신 AI 네이티브 배포 플랫폼을 사용하는 팀들과 함께 일해 왔습니다. 그 과정에서 반복적으로 나타나는 교훈이 하나 있습니다.
파이프라인 YAML이 특정 벤더(vendor)에 특화될수록, 나중에 마이그레이션하기가 더 어려워집니다.
파이프라인 정의를 모듈화하고, 비즈니스 로직을 플랫폼 특화 설정(platform-specific configuration)과 분리하며, 가능한 경우 이식 가능한 스크립트(portable scripts)에 의존함으로써, 팀은 유연성을 유지하면서도 마이그레이션 노력을 크게 줄일 수 있습니다.
문제점
대부분의 CI/CD 플랫폼은 YAML을 사용합니다.
언뜻 보기에는 매우 유사해 보입니다.
steps:
- checkout
- install
- test
- build
- deploy
하지만 그 익숙한 구문 아래에는 플랫폼 특화 기능들이 숨어 있습니다:
커스텀 액션 (Custom actions)
독자적인 표현식 (Proprietary expressions)
벤더 전용 러너 (Vendor-specific runners)
비밀 관리 API (Secret management APIs)
환경 변수 (Environment variables)
배포 전략 (Deployment strategies)
시간이 흐를수록 이러한 의존성들은 풀어내기 어려워집니다.
저는 팀들이 다른 플랫폼으로 마이그레이션하고 싶어 하거나, 단순히 다른 옵션을 검토하려고 할 때에야 비로소 이 사실을 깨닫는 것을 보았습니다.
YAML은 기본적으로 이식 가능하지 않습니다
많은 개발자가 YAML이 곧 이식성(portability)을 의미한다고 가정합니다.
그렇지 않습니다.
다음 GitHub Actions 예시는:
name: CI
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
...
GitHub Actions 내부에서는 완벽하게 작동합니다...
하지만 이를 GitLab CI나 다른 플랫폼으로 옮기는 것은 대개 작업(jobs), 트리거(triggers), 환경 변수(environment variables), 인증(authentication), 그리고 배포 단계(deployment steps)를 다시 작성해야 함을 의미합니다.
YAML 파일은 살아남지만,
워크플로(workflow)는 살아남지 못합니다.
실제로 잘 이동하는 것은 무엇인가?
저는 파이프라인을 모든 로직이 거주하는 장소가 아니라, 오케스트레이터(orchestrator)로 취급했을 때 훨씬 더 좋은 결과를 얻었습니다.
모든 것을 YAML 내부에 임베딩(embedding)하는 대신, 재사용 가능한 로직을 스크립트로 옮기십시오.
예를 들어:
steps:
- run: ./scripts/install.sh
- run: ./scripts/test.sh
- run: ./scripts/build.sh
- run: ./scripts/deploy.sh
이제 이 스크립트들은 거의 어디에서나 재사용될 수 있습니다:
GitHub Actions
GitLab CI/CD
Jenkins
CircleCI
Azure DevOps
Self-hosted runners
파이프라인은 단순히 이 스크립트들을 언제 실행할지만 결정합니다.
벤더 전용 기능은 가장자리(Edge)에 유지하기
일부 플랫폼 전용 기능들은 사용할 가치가 있습니다.
예시는 다음과 같습니다:
GitHub Actions Marketplace
GitLab Review Apps
Azure DevOps Environments
CircleCI Orbs
실수는 전체 전달 프로세스(delivery process)를 이러한 기능들을 중심으로 구축하는 것입니다.
대신, 저는 벤더 전용 기능을 파이프라인의 작은 섹션으로 격리하려고 노력합니다.
그렇게 하면 향후 마이그레이션(migration)이 훨씬 덜 고통스러워집니다.
워크플로(Workflow) 표준화하기
프로젝트 전반에 걸쳐, 저는 플랫폼에 관계없이 동일한 전달 단계(delivery stages)를 유지하는 것을 선호합니다:
Checkout (체크아웃)
↓
Dependencies (의존성)
↓
Lint (린트)
↓
Tests (테스트)
↓
Build (빌드)
↓
Security Scan (보안 스캔)
↓
Package (패키징)
↓
Deploy (배포)
오케스트레이션(orchestration) 도구는 바뀔 수 있습니다.
하지만 워크플로는 익숙하게 유지됩니다.
인프라 또한 이식 가능해야 합니다
동일한 철학이 CI/CD 외부에도 적용됩니다.
하나의 플랫폼에 종속된 배포 기능에 의존하는 대신, 실용적인 경우 이식 가능한 인프라 도구(infrastructure tooling)를 사용하세요.
예시는 다음과 같습니다:
Docker
Kubernetes
Terraform
OpenTofu
OpenTelemetry
이러한 표준들은 주변 생태계가 일관되게 유지되기 때문에, CI/CD 플랫폼을 변경할 때 발생하는 혼란을 훨씬 줄여줍니다.
AI가 도움을 줄 수 있는 부분
AI가 소프트웨어 전달(software delivery)에 더욱 통합됨에 따라, 이식성(portability)은 더욱 중요해질 것이라고 생각합니다.
여러분의 전달 워크플로를 이해하는 AI 시스템이 특정 CI/CD 벤더에 완전히 의존해서는 안 됩니다.
대신, AI는 다음과 같은 개념들에 대해 추론할 수 있어야 합니다:
Build failures (빌드 실패)
Test results (테스트 결과)
Security findings (보안 취약점 발견)
Infrastructure changes (인프라 변경)
Deployment health (배포 상태)
이러한 개념들은 파이프라인이 GitHub Actions, GitLab CI/CD, Jenkins 또는 다른 플랫폼에서 실행되는지 여부와 관계없이 존재합니다.
그것이 제가 Revolte와 같은 AI-native delivery platform (AI 네이티브 전달 플랫폼)에 관심을 갖는 이유 중 하나입니다. 기존의 CI/CD 도구를 대체하는 것이 아니라, 팀이 자신의 환경에 적합한 도구를 계속 사용할 수 있도록 허용하면서—파이프라인, 배포, 인프라 및 런타임 동작을 분석함으로써—전달 워크플로우 (delivery workflow) 주변에 지능을 추가하는 것이 핵심 아이디어입니다.
오늘날 제가 한다면
만약 제가 처음부터 CI/CD platform (CI/CD 플랫폼)을 설계한다면, 몇 가지 간단한 규칙을 따를 것입니다:
- YAML을 가능한 한 가볍게 유지할 것.
- 비즈니스 로직을 재사용 가능한 스크립트로 옮길 것.
- 독점적인 통합 (proprietary integrations)보다 개방형 표준 (open standards)을 선호할 것.
- 리포지토리 전반에 걸쳐 파이프라인 단계 (pipeline stages)를 표준화할 것.
- 벤더 전용 기능 (vendor-specific functionality)을 격리할 것.
- CI/CD를 영구적인 의존성 (dependency)이 아닌, 교체 가능한 인프라 (interchangeable infrastructure)로 취급할 것.
이러한 결정들이 마이그레이션 (migration) 작업을 완전히 없애주지는 않지만, 향후 변경 사항을 극적으로 더 쉽게 만들어 줍니다.
마치며
벤더 종속 (Vendor lock-in)은 좀처럼 하룻밤 사이에 일어나지 않습니다.
한 번에 하나씩, 편리한 기능을 도입할 때마다 발생합니다.
그러한 기능들 대부분은 유용하며, 상당수는 채택할 가치가 있습니다. 핵심은 편리함이 끝나고 장기적인 유연성이 시작되는 지점을 아는 것입니다.
저에게 있어, 이식 가능한 파이프라인 (portable pipelines)은 내일 당장 CI/CD 벤더를 바꾸기 위해 준비하는 것이 아닙니다. 팀의 요구 사항이 변화함에 따라 엔지니어링 스택 (engineering stack)을 진화시킬 수 있는 자유를 보존하는 것에 관한 것입니다.
오늘 YAML을 구조화하는 방식에 약간의 규율을 갖추는 것만으로도, 나중에 수 주, 혹은 수개월의 마이그레이션 노력을 아낄 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기