GitHub Actions Reusable Workflows로 GitOps 패턴 구현하기
여러 마이크로서비스를 운영하다 보면 각 서비스마다 비슷한 배포 파이프라인을 중복으로 관리하게 됩니다. GitHub Actions의 Reusable Workflows를 활용해 중앙에서 배포 로직을 관리하고, 각 서비스에서는 간단한 설정만으로 배포를 트리거할 수 있는 GitOps 패턴을 구축했습니다.
들어가며
마이크로서비스 아키텍처를 운영하다 보면 각 서비스마다 비슷한 배포 파이프라인을 관리하게 됩니다. 처음에는 각 서비스 레포지토리에 개별적으로 workflow 파일을 만들어 관리했는데, 서비스가 늘어날수록 문제가 생기기 시작했습니다.
- 배포 로직을 수정하려면 모든 서비스 레포지토리를 수정해야 함
- 각 서비스마다 약간씩 다른 설정으로 인해 일관성 유지가 어려움
- 새로운 서비스 추가 시 기존 workflow를 복사-붙여넣기해야 함
이런 문제를 해결하기 위해 GitHub Actions의 Reusable Workflows 기능을 활용한 GitOps 패턴을 구축했습니다. 이번 글에서는 실제로 적용한 과정과 구체적인 구현 방법을 공유하려고 합니다.

현재 Dev 환경 배포 플로우
현재 각 서비스는 독립적인 GitHub 레포지토리로 관리되며, develop 또는 main 브랜치에 push하면 자동으로 GCP Cloud Run의 dev 환경에 배포됩니다.
sequenceDiagram
participant Dev as 개발자
participant GH as GitHub<br/>레포지토리
participant GA as GitHub Actions
participant Docker as Docker Build
participant AR as Artifact Registry
participant CR as Cloud Run
Dev->>GH: 코드 Push<br/>(main/develop)
GH->>GA: Workflow 트리거
GA->>GA: Checkout 코드
GA->>GA: GCP 인증<br/>(Service Account)
GA->>Docker: Docker 이미지 빌드<br/>(linux/amd64)
Docker-->>GA: 이미지 생성
GA->>AR: 이미지 푸시<br/>(sclass-repo)
GA->>CR: Cloud Run 배포<br/>(gcloud run deploy)
CR-->>GA: 배포 완료
GA-->>Dev: 배포 성공 알림
각 서비스의 배포 workflow는 다음과 같은 단계로 구성되어 있습니다:
- 코드 체크아웃: GitHub 레포지토리에서 소스 코드 가져오기
- GCP 인증: Service Account를 사용한 Google Cloud 인증 및 Docker 인증 설정
- Docker 이미지 빌드:
linux/amd64플랫폼용 이미지 빌드 (Cloud Run 호환) - 이미지 푸시: Artifact Registry의
sclass-repo에 이미지 업로드 - Cloud Run 배포: GCP Cloud Run에 서비스 배포 (dev 프로파일)
문제 상황: 중복된 배포 파이프라인
각 서비스마다 거의 동일한 배포 workflow가 중복되어 있었습니다.
graph LR
subgraph "account-service"
A1[Push to develop] --> A2[Build & Push Image]
A2 --> A3[Deploy to Cloud Run]
end
subgraph "lms-service"
L1[Push to develop] --> L2[Build & Push Image]
L2 --> L3[Deploy to Cloud Run]
end
subgraph "auth-service"
AU1[Push to develop] --> AU2[Build & Push Image]
AU2 --> AU3[Deploy to Cloud Run]
end
style A2 fill:#ffcccc
style L2 fill:#ffcccc
style AU2 fill:#ffcccc
style A3 fill:#ffcccc
style L3 fill:#ffcccc
style AU3 fill:#ffcccc
서비스가 5개, 10개로 늘어날수록 각 서비스마다 동일한 workflow를 유지보수하는 것이 점점 어려워졌습니다.
중복되는 부분:
- GCP 인증 및 Docker 설정
- Docker 이미지 빌드 및 푸시
- Cloud Run 배포 명령어
- 환경 변수 및 리소스 설정
변경이 필요한 부분:
- 서비스 이름
- 이미지 태그 (일부는
latest, 일부는github.sha) - 포트, 메모리, CPU 등 리소스 설정 (서비스별로 다를 수 있음)
해결 방안: Reusable Workflows
GitHub Actions의 Reusable Workflows 기능을 사용하면 중앙에서 배포 로직을 관리하고, 각 서비스에서는 간단한 설정만으로 배포를 트리거할 수 있습니다.

아키텍처 설계
graph TB
subgraph "중앙 레포지토리"
RW[Reusable Workflow<br/>deploy-service.yml]
end
subgraph "각 서비스 레포지토리"
AS[account-service<br/>deploy.yml]
LS[lms-service<br/>deploy.yml]
Auth[auth-service<br/>deploy.yml]
end
subgraph "GCP"
AR[Artifact Registry]
CR[Cloud Run]
end
AS -->|workflow_call| RW
LS -->|workflow_call| RW
Auth -->|workflow_call| RW
RW --> AR
RW --> CR
style RW fill:#c8e6c9
style AS fill:#e3f2fd
style LS fill:#e3f2fd
style Auth fill:#e3f2fd
전체 구조는 다음과 같이 설계했습니다:
- 중앙 레포지토리 (또는
.github레포): Reusable Workflow 정의 - 각 서비스 레포지토리: 간단한 workflow로 중앙 workflow 호출
- 배포 설정: 각 서비스별로 필요한 설정만 파라미터로 전달
구현 단계
1단계: Reusable Workflow 생성
먼저 중앙 레포지토리(또는 .github 레포)에 Reusable Workflow를 생성합니다.
.github/workflows/deploy-service.yml:
name: Deploy Service
on:
workflow_call:
inputs:
service_name:
required: true
type: string
description: '서비스 이름 (예: lms-service, account-service)'
source_repo:
required: true
type: string
description: '소스 레포지토리 (예: s-class/lms-service)'
image_tag:
required: false
type: string
default: ${{ github.sha }}
description: 'Docker 이미지 태그 (기본값: commit SHA)'
region:
required: false
type: string
default: asia-northeast3
description: 'GCP 리전'
port:
required: false
type: string
default: '8080'
description: '서비스 포트'
memory:
required: false
type: string
default: '512Mi'
description: '메모리 할당량'
cpu:
required: false
type: string
default: '1'
description: 'CPU 할당량'
min_instances:
required: false
type: string
default: '1'
description: '최소 인스턴스 수'
max_instances:
required: false
type: string
default: '10'
description: '최대 인스턴스 수'
timeout:
required: false
type: string
default: '300'
description: '타임아웃 (초)'
secrets:
GCP_PROJECT_ID:
required: true
GCP_SA_KEY:
required: true
env:
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
GCP_REGION: ${{ inputs.region }}
SERVICE_NAME: ${{ inputs.service_name }}
IMAGE_NAME: asia-northeast3-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/sclass-repo/${{ inputs.service_name }}:${{ inputs.image_tag }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source repository
uses: actions/checkout@v4
with:
repository: ${{ inputs.source_repo }}
ref: ${{ github.sha }}
path: service-repo
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
with:
project_id: ${{ env.GCP_PROJECT_ID }}
- name: Authenticate to Google Cloud
run: |
echo '${{ secrets.GCP_SA_KEY }}' > $HOME/gcp-key.json
gcloud auth activate-service-account --key-file=$HOME/gcp-key.json
gcloud auth configure-docker asia-northeast3-docker.pkg.dev --quiet
- name: Build and push image (linux/amd64)
working-directory: service-repo
run: |
docker buildx create --name cloud-run-builder --use || docker buildx use cloud-run-builder
docker buildx build \
--platform=linux/amd64 \
-t $IMAGE_NAME \
--push \
.
- name: Deploy to Cloud Run
run: |
gcloud run deploy $SERVICE_NAME \
--image=$IMAGE_NAME \
--region=$GCP_REGION \
--platform=managed \
--allow-unauthenticated \
--port=${{ inputs.port }} \
--set-env-vars SPRING_PROFILES_ACTIVE=dev \
--min-instances=${{ inputs.min_instances }} \
--max-instances=${{ inputs.max_instances }} \
--memory=${{ inputs.memory }} \
--cpu=${{ inputs.cpu }} \
--timeout=${{ inputs.timeout }}
2단계: 각 서비스에서 Reusable Workflow 호출
이제 각 서비스 레포지토리에서는 간단한 workflow만 작성하면 됩니다.
lms-service/.github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [main, develop]
jobs:
deploy:
uses: s-class/.github/workflows/deploy-service.yml@main
with:
service_name: lms-service
source_repo: s-class/lms-service
image_tag: ${{ github.sha }}
region: asia-northeast3
port: '8080'
memory: '512Mi'
cpu: '1'
min_instances: '1'
max_instances: '10'
timeout: '300'
secrets:
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
account-service/.github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [develop]
jobs:
deploy:
uses: s-class/.github/workflows/deploy-service.yml@main
with:
service_name: account-service
source_repo: s-class/account-service
image_tag: latest # account-service는 latest 태그 사용
region: asia-northeast3
port: '8080'
memory: '512Mi'
cpu: '1'
min_instances: '1'
max_instances: '10'
timeout: '300'
secrets:
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
배포 프로세스 흐름

sequenceDiagram
participant Dev as 개발자
participant Repo as 서비스 레포지토리
participant RW as Reusable Workflow
participant AR as Artifact Registry
participant CR as Cloud Run
Dev->>Repo: 코드 Push (develop/main)
Repo->>RW: workflow_call 트리거
Note over RW: 서비스별 파라미터 전달<br/>(service_name, image_tag 등)
RW->>RW: 소스 코드 Checkout
RW->>RW: GCP 인증
RW->>RW: Docker 이미지 빌드
RW->>AR: 이미지 푸시
RW->>CR: Cloud Run 배포
CR-->>RW: 배포 완료
RW-->>Repo: 워크플로우 완료
Repo-->>Dev: 배포 성공 알림
주요 장점
1. 중앙 집중식 관리
graph LR
A[배포 로직 변경] --> B[Reusable Workflow 수정]
B --> C[모든 서비스에 자동 적용]
style B fill:#c8e6c9
배포 로직을 한 곳에서 관리할 수 있어 유지보수가 훨씬 쉬워졌습니다. 예를 들어, Docker 빌드 방식을 변경하거나 Cloud Run 배포 옵션을 수정할 때 중앙 workflow만 수정하면 모든 서비스에 자동으로 적용됩니다.
2. 일관성 보장
모든 서비스가 동일한 배포 프로세스를 따르게 되어, 배포 실패나 설정 오류를 줄일 수 있습니다.
3. 간단한 서비스 추가
새로운 서비스를 추가할 때는 간단한 workflow 파일만 작성하면 됩니다. 복잡한 배포 로직을 다시 작성할 필요가 없습니다.
4. 유연한 설정
각 서비스의 특성에 맞게 메모리, CPU, 인스턴스 수 등을 파라미터로 전달할 수 있어 유연하게 대응할 수 있습니다.
주의사항 및 팁
1. Secret 관리
각 서비스 레포지토리에서 GCP_PROJECT_ID와 GCP_SA_KEY secret을 설정해야 합니다. 조직 레벨에서 secret을 관리하면 더 효율적입니다.
2. Workflow 참조 경로
Reusable Workflow를 참조할 때는 다음 형식을 사용합니다:
uses: owner/repo/.github/workflows/workflow-file.yml@branch
3. 디버깅
Reusable Workflow에서 문제가 발생하면, 각 서비스의 workflow 실행 로그에서 상세한 정보를 확인할 수 있습니다. GitHub Actions UI에서 “Reusable workflow” 섹션을 확인하면 됩니다.
4. 버전 관리
Reusable Workflow를 수정할 때는 브랜치 전략을 명확히 해야 합니다. 프로덕션 서비스는 main 브랜치를 참조하고, 테스트는 develop 브랜치를 참조하는 방식을 권장합니다.
실제 적용 결과
이 패턴을 적용한 후 다음과 같은 개선 효과를 얻을 수 있었습니다:
- 배포 로직 수정 시간: 모든 서비스 수정 시 약 2시간 → 중앙 workflow 수정 시 약 10분
- 새 서비스 추가 시간: 약 30분 → 약 5분
- 배포 실패율: 약 5% → 약 1% (일관된 프로세스로 인해)
마무리
GitHub Actions의 Reusable Workflows를 활용하면 마이크로서비스 환경에서도 효율적으로 배포 파이프라인을 관리할 수 있습니다. 중앙에서 배포 로직을 관리하면서도 각 서비스의 특성에 맞게 유연하게 설정할 수 있어, 확장 가능한 CI/CD 인프라를 구축할 수 있습니다.
GitHub Actions의 Reusable Workflows는 간단하면서도 효과적인 GitOps 패턴을 구현할 수 있는 좋은 방법입니다. 더 복잡한 요구사항이 있다면 ArgoCD나 Flux 같은 전문 GitOps 도구를 고려해볼 수 있습니다.