들어가며
현 회사 데이터 개발팀에서는 리팩토링, 로직 개선, 디버깅 등 다양한 이유로 데이터 파이프라인 스크립트를 수정하면 해당 스크립트 파일을 스케줄에 반영하기 위해 S3에 업로드를 하는 구조로 운영하고있다.
이 과정에서 10번 중 2번 꼴로 인적 오류(Human Error)가 발생하여 ETL 작업 에러가 발생하곤 했다. 이런 사소한 부분을 자동화해둔다면 보다 중요한 업무에 더 집중할 수 있는 환경을 만들 수 있음을 기대하고 데이터 파이프라인 CI/CD 도입을 위한 리서치를 시작했다.
CI/CD 란?
Continuous Integration(지속적 통합) 과 Continuous Deployment(지속적 배포)는 소프트웨어 개발 프로세스를 자동화하고 효율적으로 만드는 데 중심적인 역할을 한다.
- 지속적 통합 (CI)
지속적 통합이란 개발자들이 코드 변경 사항을 자주, 그리고 정기적으로 GitHub과 같은 공유 레포지토리에 병합하는 것을 의미한다. 코드 변경이 발생할 때마다 자동으로 빌드와 테스트를 실행하여 문제를 조기에 발견하고 해결하는 것이 주된 목적이다. 이를 통해 통합 과정에서 발생할 수 있는 충돌을 최소화하고 코드의 일관성을 유지할 수 있다.
- 지속적 배포 (CD)
지속적 배포란 지속적 통합의 다음 단계로, 코드 변경 사항이 자동으로 프로덕션 환경에 배포되는 것을 의미한다. 코드가 항상 배포 가능한 상태를 유지하는 것이 주된 목적이며 이를 통해 새로운 기능이나 버그 수정을 빠르고 안정적으로 사용자에게 제공할 수 있다.
높은 코드 품질 유지, 빠른 시간 내 버그를 발견하고 대응, 자동화된 빌드,테스트,배포 과정을 통해 개발에 집중할 수 있는 환경 조성 등의 이유로 CI/CD는 필요하다.
CI/CD Tool 비교 분석
사용 가능한 CI/CD 툴은 너무나 많았기에 관련 기술들을 하나씩 비교 분석하여 현재 우리팀에게 가장 적합해보이는 GitHub Actions를 도입하기로 결정했다. 아래와 같은 사고 과정으로 선택했다.
GitHub Actions 🥇
- 장점
통합성
: GitHub 리포지토리와 높은 통합성 제공사용 용이성
: YAML 파일로 Config 설정
- 단점인 듯 단점 아닌 장점 같은 단점
비용 및 제한된 리소스
: 무료 플랜은 월 2,000분까지 무료. 그 이상은 추가 비용 지불 필요
- 총평
- 코드 변경 시 자동으로 워크플로우 트리거가 가능한 점이 가장 메리트. 또한 YAML 파일로 설정을 관리 할 수 있어 직관적이고 간단한 운영 가능. 무료 플랜에서는 리소스 제한이 존재하지만 월 2,000분까지 사용할 정도의 작업량이 아니라고 판단하여 문제 없을 것으로 확인
AWS CodeBuild, CodeDeploy, CodePipeline 🥈
- 장점
통합성
: AWS 서비스와 높은 통합성, 다양한 AWS 리소스와 쉽게 연동 가능확장성
: AWS 의 다른 서비스와 연동하여 확장성 뛰어남관리형 서비스
: 인프라 관리 필요 없음. AWS에서 자동으로 스케일링 관리
- 단점
비용
: 사용량에 따른 비용 발생러닝 커브
: AWS 서비스들 간의 연동 및 설정이 처음에 다소 복잡
- 총평
- GitHub Actions를 사용하기 위해 회사 계정 secret key를 GitHub에 저장해두는 것이 너무나 무서워서 찾아본 AWS 코드 삼형제. 보안적인 측면에서는 1등이었으나 자동화하고자 하는 작업(수정한 코드를 GitHub에 반영하는 시점에 맞추어 S3에 해당 파일을 업로드하는 명령어 실행)에 비해 무거운 점+ 굳이 비용 지불이라는 점이 아쉬워 탈락
AWS Lambda
- 장점
서버리스
: 서버 관리 필요 없으며 이벤트 기반 동작비용 효율성
: 사용한 만큼만 지불확장성
: AWS Lambda는 자동 스케일링
- 단점
제한된 실행 시간
: 최대 15분의 실행 시간 제한 존재상태 관리 어려움
: 상태를 유지하는 작업에 부적합
- 총평
- 위와 동일한 이유로 탈락
Jenkins
- 장점
유연성
: 다양한 플러그인을 통해 높은 유연성과 확장성 제공커뮤니티
: 오픈 소스 프로젝트로서 큰 커뮤니티와 많은 리소스 제공자체 호스팅
: 자체 호스팅이 가능하여 모든 설정과 데이터를 직접 관리 가능
- 단점
복잡성
: 설치 및 유지 관리 복잡인프라 관리
: 자체 호스팅이므로 인프라 직접 관리
- 총평
- 위와 동일한 이유로 탈락
Cron job + Custom Script 🥉
- 장점
단순성
: 간단한 작업 스케줄링과 실행에 적합비용
: 비용들지 않으며 기본적인 시스템 자원 활용
- 단점
유연성 부족
: 복잡한 파이프라인 구현하기에 제한적관리
: 에러 처리 및 로깅, 모니터링 어려움확장성
: 대규모 프로젝트에 적합하지 않음
- 총평
- 단순성과 비용이 들지 않는 부분에서 높은 점수를 부여하였지만 수정한 파일을 GitHub에 업로드한 시점에 맞추어 S3파일 업로드 명령어를 실행시켜야 하는 타이밍을 구현하고 운영하는 리소스 보다 GitHub Actions를 도입하는 것이 더 효율적이라 판단. 즉, 관리의 어려움으로 탈락
GitHub Actions 적용기
아래와 같은
as-is
, to-be
를 설정하고 PoC 과정을 거쳐 실 데이터파이프라인에 적용했다. as-is
1. 로컬 환경에서 ETL 스크립트를 작성/변경하고 GitHub에 반영
2. S3에 해당 소스코드 파일 수동 업로드 to-be
1. 로컬 환경에서 ETL 스크립트를 작성/변경하고 GitHub에 반영
2. GitHub Actions를 통해 변경된 소스코드 파일을 S3에 자동 업로드1️⃣ S3 접근 가능한 AWS IAM 생성
GitHub Actions를 사용할 Repository가 준비되었다면 GitHub Actions가 AWS에 접근할 수 있도록 AWS Access Key와 Secret Key를 생성해 GitHub Secrets에 저장해야 한다.
AmazonS3FullAccess
,AWSCodeDeployFullAccess
,deny-delete-s3-bucket
나는 S3에 접근 가능, S3 버킷 삭제 불가, CodeDeploy 작업 가능한 위 3개의 권한 정책을 설정하여 IAM 자격 증명을 만들었다. (작업을 끝내고 보니 AWSCodeDeployFullAccess는 필요 없었다)
2️⃣ GitHub Secrets에 Secret Key를 환경변수로 저장
GitHub Actions를 사용할 Repository에 Access Key와 Secret Key를 환경 변수로 저장해야 한다.
settings - secrets and variables - actions - repository secretes
경로로 이동하여 아래와 같이 키를 등록해주면 된다. 추가로 접근할 S3 Bucket명도 환경변수로 저장하여 사용했다.

3️⃣ 워크플로 디렉토리 생성 및 YAML 파일 작성
Repository에 워크플로를 설정할 준비를 하기 위해
.github/workflow/
를 생성하고 S3에 파일을 업로드하는 작업을 설정한다. - .github/workflow/deploy.yml
# 워크플로 이름 지정
name: Deploy to AWS S3
on: # 워크 플로 트리거 이벤트 지정
push:
branches:
- master # master 브랜치에 push될 때 트리거되도록 설정
# 하나 이상의 작업 정의
jobs:
deploy:
runs-on: ubuntu-latest # 작업이 실행될 환경
# 작업 내에서 실행될 단계 지정
steps:
- name: Checkout source code
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Get list of changed files
id: changes
run: |
git diff --name-only HEAD~1 HEAD > changed_files.txt
cat changed_files.txt
- name: Upload to S3
run: |
while IFS= read -r file; do
if [ -f "$file" ] && [[ "$file" != .github/* ]] && [[ "$file" != config/* ]]; then
aws s3 cp "$file" "${{ secrets.S3_BUCKET }}/$file"
fi
done < changed_files.txt
- Checkout source code
- 빌드, 테스트, 배포 등 작업을 수행하기 위해 GitHub 리포지토리에 있는 소스 코드를 워크플로가 실행되는 가상 머신이나 컨테이너 환경으로 가져와 사용할 수 있도록 준비
- 소스코드를 체크아웃 할 때 커밋 내역을 최소 2개 이상 가져오기
- 이후 단계에서 이전 커밋과 현재 커밋을 비교할 때 필요한 커밋 개수가 최소 2개이기 때문에
- Configure AWS credentials
- AWS 사용자 인증 단계
- Get list of changed files
- 이전 커밋과 현재 커밋을 비교하여 변경된 스크립트 파일만 S3에 업로드 해야하기 때문에 변경된 파일 목록은
changed_files.txt
에 담기 - 위의 1. Checkout source code 단계에서
fetch-depth
를 지정해주지 않으면 에러 발생 - Upload to S3
changed_files
에서 빈칸을 기준으로(IFS=) 한 줄씩 읽어와 file 변수에 저장read
: 입력을 받아 변수에 저장-r
옵션 : 백슬래시를 escape 문자로 처리하지 않기 위함- 아래 3가지 조건을 모두 만족하는 경우에만 S3 버킷에 복사
- 변경된 파일이 존재할 때
- 해당 파일이
.github/*
경로에 위치하지 않을 때 - 해당 파일이
config/*
경로에 위치하지 않을 때 - 대괄호 안에 조건문 명시시 꼭 앞 뒤로 한 칸씩 띄워주기 ⭐
aws sync
를 사용할 경우 변경되지 않은 모든 파일들까지 일괄적으로 매번 재업로드하기 때문에aws cp
선택
4️⃣ Push 후 Actions 성공 여부 확인
위와 같이 워크플로 파일까지 잘 작성해준다면 Master에 변경된 소스코드를 Push할 때마다 GitHub Actions가 잘 실행되는지 확인하면 된다.

추가로 롤백 작업시에도 S3에도 변경된 내역이 잘 반영된다.
마치며
GitHub Actions를 도입하여 데이터 파이프라인 소스 코드 배포 작업 자동화를 통해 ETL 에러발생률을 20% 감소시켰다. 하지만 여전히 100% 자동화가 된 것은 아니기에 여전히 보완할 점은 존재한다.
- 중요 보안 정보를 갖고 있는 config.ini를 포함 여러 파일을 압축한 config.zip은 여전히 수동 업로드 필요
- 삭제한 소스코드 파일을 GitHub에 반영해도 S3에서는 수동 삭제 필요
처음에는 간단하고 사소한 작업이라고 생각하여 ‘굳이 리소스를 들여 자동화 할 필요성이 있을까?’라는 의문을 가졌지만 GitHub Actions가 적용된 환경에서 더 중요한 업무에 집중할 수 있는 상승된 업무환경을 경험할 수 있었다. 또 문제를 해결하면서 특정 기술이 무조건 좋은 것이 아니라 현재 우리 팀의 상황에 맞는 것이 최고의 기술이 될 수 있음을 깨달았다.
written by salmonavocado🥑
Share article