콘텐츠로 이동

GitLab Deploy Policy (운영 기준)

0. 전제

다음 환경 기준으로 작성:

  • 규모: 프로젝트 5~20개 / 서버 소수
  • 인력: 1~2명 (소수 정예)
  • 멀티 스택 환경: Node.js, Express, Next.js, Nuxt.js, PHP, Laravel, C++ 등
  • 운영 서버: Linux / Windows 혼합 가능
  • Docker 사용 범위: Runner 빌드 환경 및 Release Storage 서버의 AIStor 실행 용도
  • 배포 방식: 운영 서버가 Release Storage에서 빌드 결과물을 직접 가져가는 pull 배포

인프라 전제:

  • GitLab 서버, Runner 서버, Release Storage 서버, 운영 서버는 논리적, 물리적으로 분리 가능한 구성으로 보며, 분리 운영을 전제로 작성함.
  • GitLab 서버는 외부 비공개로 유지하며, 운영 서버는 GitLab 서버에 직접 접근하지 않음.
  • Release Storage 서버는 운영 서버가 접근 가능한 별도 서버로 구성함.

운영 원칙:

  • build -> publish -> operation server pull deploy 구조 유지
  • {YYYYMMDD-HHMMSS}-{declared_version}-{CI_COMMIT_SHORT_SHA} 기반 immutable package version 운영
  • 인증은 목적별 계정 및 Access Key로 분리
  • 빌드: Runner 서버
  • CI 내부 산출물 보관: GitLab Generic Package Registry
  • 운영 배포 기준 저장소: Release Storage (S3-compatible Object Storage)
  • 운영: download, verify, extract, activate, report 수행

금지 사항:

  • 운영 서버에 write 권한 Access Key 배치 금지
  • .env 및 서버 고유 설정 파일을 패키지에 포함 금지
  • 운영 서버에서 배포 파일을 수동 수정한 뒤 재사용 금지
  • Generic Package Registry에 업로드된 package version/file overwrite 금지
  • Release Storage 의 releases 경로 Release Object overwrite 금지
  • Release Storage 의 current/{RELEASE_ENV}.json 외 object overwrite 금지
  • 운영 서버가 GitLab 서버에 직접 접근하도록 구성 금지

1. 배포 방식 선택 배경

본 시스템은 운영 서버에 직접 명령을 전달하는 push 방식이 아니라,
운영 서버가 스스로 상태를 수렴하는 pull 기반 상태 수렴(State-based Reconciliation) 배포 구조를 사용함.

해당 구조는 다음 개념을 기반으로 설계됨:

  • GitOps pull 방식의 단순화 버전 (Netflix, Airbnb 등 대규모 서비스 구조)
  • Kubernetes 환경의 ArgoCD, FluxCD와 동일한 배포 모델
  • "중앙이 상태를 선언하면, 각 서버가 해당 상태로 수렴"하는 구조
  • 선언적 배포(Declarative Deployment) 및 상태 기반 배포(State-based Deployment)

2. 핵심 운영 개념

  • 선언적 배포

    • GitLab CI/CD 는 운영 서버에 직접 배포 명령을 전달하지 않음
    • GitLab CI/CD 는 Release Storage 에 desired release state 를 publish 하여 운영 서버가 수렴해야 할 상태를 선언함
  • 자율적 수렴

    • 운영 서버는 주기적으로 Release Storage 의 current/{RELEASE_ENV}.json 을 polling 함
    • 운영 서버는 현재 적용된 package_version 과 desired state 의 package_version 을 비교함
    • 값이 다르면 직접 download / verify / extract / activate 과정을 수행하여 상태를 일치시킴
  • GitLab CI/CD 역할 재정의

    • GitLab CI/CD 는 build, package, release state publish 까지만 수행함
    • GitLab CI/CD 는 운영 서버에 직접 접근하지 않음
    • GitLab CI/CD 는 운영 서버의 deploy executor 가 아님

운영 기준:

  • GitLab CI/CD 는 Release Storage 를 상태 선언 저장소로 사용함
  • 운영 서버는 Release Storage metadata 기준으로 상태 수렴(reconciliation)을 수행함
  • GitLab Runner 는 운영 서버 접근 권한을 가지지 않음
  • GitLab Runner 는 release package 와 release state publish 만 수행함

3. CI/CD 실행 정책

  • release target branch 는 GitLab CI rules 에 하드코딩하지 않음.
  • release 대상 여부는 Release Yaml 파일 존재 여부로 판단함.

경로:

.ops/ci/release-branch-versions/{CI_COMMIT_BRANCH}.yaml

운영 기준:

  • Release Yaml 파일 이 존재하는 branch 만 release target 으로 간주함
  • 해당 yaml 파일이 없으면 release package 와 release state publish 를 수행하지 않음
  • release target branch 를 추가하려면 동일한 이름의 yaml 파일을 추가함
  • Protected Variable 을 사용하는 경우 release target branch 도 Protected Branch 로 등록해야 함

Pipeline source 별 동작:

Pipeline source 동작
merge_request_event branch 승격 경로 검증만 수행함
push release target branch 이면 package/release state publish 를 수행함
web New Pipeline 수동 실행이며, release target branch 이면 강제 package/release state publish 를 수행함

New Pipeline 운영 기준:

  • GitLab UI 에서 New Pipeline 실행 시 별도 variable 입력은 필요하지 않음
  • production, jp-dev-testRelease Yaml 파일 이 있는 branch 를 선택하면 수동 release 실행 요청으로 처리함
  • New Pipeline 실행 결과는 새 package_version 생성과 Release Storage current metadata 갱신으로 이어짐
  • 동일 commit / 동일 declared version 이라도 New Pipeline 실행 시 새 datetime 기반 package version 이 생성될 수 있음

4. 구조적 장점

  • 확장성

    • 서버 수 증가 시 CI/CD 작업량 증가 없음 (O(1))
  • 관리 효율

    • CI에서 운영 서버 목록(IP 등)을 관리할 필요 없음
  • 장애 격리

    • 특정 서버 장애가 전체 배포 흐름을 차단하지 않음
  • 역할 단순화

    • GitLab Runner 는 배포 실행자가 아니라 release package 와 release state 를 publish 하는 역할로 단순화됨

5. 운영 고려사항 및 대응

  • 배포 즉시성

    • Polling 주기 기반 지연 발생
    • 현재 구조에서는 systemd timer 주기 기준으로 수렴함
    • 필요 시 향후 signal / webhook / queue 기반 보조 구조를 추가할 수 있음
  • 배포 완료 가시성

    • 운영 서버의 poll-release.log, systemd journal, PM2 상태를 기준으로 확인함
    • 필요 시 향후 Slack, API report, central status store 로 확장할 수 있음
  • 스크립트 관리

    • release 판단과 publish 는 GitLab CI/CD script 기준으로 관리함
    • 실제 운영 서버 deploy 절차는 poll-release.sh 기준으로 관리함
    • 서비스별 검증/후처리는 01-after-prepare-release.sh hook 으로 분리함
  • 실패 감지

    • GitLab CI/CD 실패는 pipeline log 기준으로 확인함
    • 운영 서버 deploy 실패는 poll-release.log, systemd journal, PM2 상태 기준으로 확인함
    • 현재 구조에서는 운영 서버별 deploy 결과를 중앙에서 강제 수집하지 않음
  • 멱등성 보장

    • 같은 desired state 를 반복 polling 하더라도 이미 적용된 package_version 이면 skip 함
    • New Pipeline 수동 실행은 새 package version publish 를 통해 의도적 재패치를 수행함

6. 보안 관점 핵심 특징 (Zero-Inbound)

본 구조는 배포를 위해 운영 서버에 대한 외부 접근을 허용하지 않음.

운영 기준:

  • 운영 서버는 inbound 접근 없이 outbound 통신만 수행함
  • GitLab CI/CD 및 Runner 가 운영 서버에 직접 접근하지 않음
  • SSH 포트 및 SSH Key 기반 배포 권한 관리가 필요 없음
  • 운영 서버는 Release Storage 에 대해 read-only 권한만 사용함
  • 운영 서버는 GitLab 서버에 직접 접근하지 않음

효과:

  • 운영 서버 공격 표면 최소화
  • SSH Key 유출에 따른 전체 서버 침해 리스크 제거
  • CI/CD 침해 시 운영 서버로의 횡적 이동(Lateral Movement) 차단
  • 배포 권한과 운영 서버 접근 권한 분리
  • 네트워크 정책 단순화

본 구조는 운영 서버에 대한 inbound 접근을 제거하여 배포 관련 주요 보안 리스크를 근본적으로 차단함.


7. 결론

본 Pull 기반 배포 구조는 다음을 동시에 확보하기 위한 운영 전략임.

  • 확장성

    • 서버 수 증가 시 GitLab CI/CD 작업량이 서버 수에 비례하여 증가하지 않음
  • 운영 단순성

    • GitLab CI/CD 는 build, package, release state publish 까지만 담당함
    • 운영 서버는 Release Storage current metadata 기준으로 스스로 상태를 수렴함
  • 보안성

    • 운영 서버는 GitLab 및 Runner 로부터 inbound 접근을 받지 않음
    • 운영 서버는 Release Storage read-only 권한만 사용함
  • 유연성

    • release target branch 는 Release Yaml 파일 (.ops/ci/release-branch-versions/{CI_COMMIT_BRANCH}.yaml) 로 확장 가능함
    • New Pipeline 을 통해 별도 variable 없이 수동 패치를 실행할 수 있음

특히 소수 인력 환경에서 다수의 서비스와 여러 runtime stack 을 안정적으로 운영하기 위한 배포 모델로 사용함.