1. CI/CD Tools 종류
1-1. GitHub Actions
- 장점: GitHub과 완벽 통합, 간단한 설정 (.yml), Docker build/push 쉬움
- 단점: GitHub에 코드가 있어야 유리, 병렬 워크플로우는 요금제 제한
- 도커 친화도: ★★★★★
💡 추천 상황: GitHub에서 코드 관리 중이고 Docker 이미지 빌드/배포도 함께 하고 싶을 때
1-2. GitLab CI/CD
- 장점: GitLab과 완벽 통합, 강력한 권한 제어, 무료로도 강력한 기능 제공
- 단점: GitLab EE는 비쌈, 러닝커브 있음
- 도커 친화도: ★★★★★
💡 추천 상황: 자체 GitLab 운영 중인 기업, 보안/권한 제어가 중요한 환경
GitHub Actions와 GitLab CI/CD 차이 (실제 기업에서 GitLab을 많이 사용하는 이유)
GitHub Actions
운영 주체 : Microsoft
CI/CD 기능 : GitHub Actions 내장 (최근 빠르게 발전)
DevOps 통합성 : Actions + Copilot 등 최근 통합형 기능 강화
권한/권리 모델 : 권한 관리 단순 (협업에 최적)
사용자 인터페이스 : 직관적이고 깔끔
커뮤니티/생태계 : 오픈소스 커뮤니티 중심, 가장 활성화됨
GitLab CI/CD
운영 주체 : GitLab Inc.
CI/CD 기능 : GitLab CI/CD 내장 (초기부터 강력함)
DevOps 통합성 : 올인원 DevOps 플랫폼(코드→빌드→배포→모니터링)
권한/권리 모델 : 프로젝트·그룹 단위로 세밀한 권한 설정 가능
사용자 인터페이스 : 기능은 많지만 UI는 다소 복잡
커뮤니티/생태계 : 자체 호스팅에 강점(사내망 자체 서버에 GitLab 자체 설치 가능, 인터넷 없이 운영 가능)
- 그에 반해 GitHub는 ...
- Enterprise를 사용하면 자체 서버에 설치 가능(But 제약 많음)
- 인터넷 없이 Actions 사용 불가능
자체 호스팅이란? (Github 입장)
- GitHub.com 없이, 모든 GitHub 플랫폼 기능을 직접 사내에 설치
- 저장소
- PR 관리
- Actions 서버
- Runner Queue (자체 관리)
- 등등
- 인터넷 없이도 완전 독립 운영 가능
- 보통 보안상 사내망에서 GitHub을 완전히 자체 구축해야 할 때 사용
- GitHub Enterprise Server 라이선스가 필요
- 설치, 유지보수, 업그레이드도 전부 직접 해야 함
- 📌 즉: GitHub.com을 흉내 낸 자체 GitHub 클론을 회사 내부에서 운영하는 것 (Actions 서버도 직접 돌림, Runners도 내부적으로 관리)
요약
| 기준 | GitHub | GitLab |
| SaaS 중심 | ✅ | ✅ |
| 자체 서버 설치 | 제한적 | 🔥 강력 |
| CI/CD | GitHub Actions | 🔥 GitLab CI/CD 내장 |
| DevOps 통합성 | 낮음 | 🔥 전체 사이클 통합 |
| 보안/망분리 환경 | 제한적 | 🔥 최적 |
| 커스터마이징 | 제한적 | 가능 (오픈소스 기반) |
1-3. Jenkins
- 장점: 오래된 레거시 시스템에도 적합, 강력한 플러그인 생태계
- 단점: 관리가 힘듦 (서버 유지보수, 플러그인 충돌 등), 느릴 수 있음
- 도커 친화도: ★★★☆☆ (Docker로 돌릴 수는 있지만, 친화적이지는 않음)
- 도커 친화도가 낮은 이유
- 젠킨스는 서버에 설치해서 돌리는 설치형 프로그램이지만, 요즘은 모든걸 Docker로 띄우기 때문에 Jenkins도 Docker로 띄워서 사용함. ex) docker run -d -p 8080:8080 jenkins/jenkins:lts
- 하지만 jenkins 컨테이너에서 또 다른 Docker 명령어를 실행하려고 할 때(docker build -t my-app .) 컨테이너 안에서 Docker를 사용할 수 없기 때문에 문제가 발생함.
- 보통 DinD 또는 Docker socket 공유 방법을 사용해 해결
- DinD : Jenkins 컨테이너 안에 Docker도 설치해서, 그 안에서 Docker를 실행
- Docker socket 공유: Jenkins 컨테이너 실행할 때, 호스트 머신의 Docker 엔진을 공유
- 다른 툴은 보통 Docker환경에서 안전하게 Build/Deploy되도록 만들어짐
- 그게 반해 젠킨스는 Docker 자체도 설정 필요, 실행 권한도 설정 필요 등등 고려 사항 많음
- 도커 친화도가 낮은 이유
💡 추천 상황: 사내 CI/CD 시스템이 구축되어 있고 Jenkins 경험자가 많은 경우
1-4. Argo CD / Argo Workflows (쿠버네티스 중심 기업)
- 장점: GitOps 방식 CI/CD, 쿠버네티스 완벽 연동, MSA 배포에 유리
- 단점: 초심자에겐 러닝커브 있음
- 도커 친화도: ★★★★★ (K8s 기반이므로 Docker 전제)
💡 추천 상황: 클러스터 단위 GitOps CD 구축하고 싶을 때
1-5. 요즘 기업들이 많이 쓰는 Tool은?
| GitHub 기반 스타트업/중소기업 | GitHub Actions |
| 사내 GitLab 쓰는 대기업/기관 | GitLab CI/CD |
| Kubernetes-heavy 기업 | Argo CD / Tekton |
| 레거시 유지 중인 기업 | Jenkins |
| 빠른 빌드가 중요한 팀 | CircleCI |
2. Git commit 트리거 방식
2-1. GitHub Actions & GitLab CI/CD
GitHub Actions나 GitLab CI/CD는 그 자체가 클라우드 서비스 안에 포함된 CI/CD 시스템이기 때문에
- GitHub에 Push를 하면 GitHub Actions도 같은 GitHub 서버 안에서 실행됨
- GitHub 서버는 Push 이벤트를 실시간으로 감지해서 즉시 Actions workflow를 실행
이 때 Actions workflow(테스트, 빌드, 배포 등 CI/CD 스크립트)를 실행하며 내 서버에 접속 ←보안 문제 발생
2-1-1. 보안 문제 해결 방안
1. 역방향 터널링 (Reverse SSH Tunnel)
- 내 서버가 GitHub 서버에 먼저 연결을 맺고, 그 연결을 통해 GitHub Actions가 내 서버에 접속하는 방식
- 내 서버에서 **공용 중계 서버(또는 배포 게이트웨이)**로 ssh -R 터널을 연결
- GitHub Actions는 그 중계 서버를 통해 간접적으로 내 서버에 접근
- ex.
# GitHub Actions Script#- name: Deploy run: ssh -p 2222 user@relay-server.com "ssh localhost 'your deploy command'"- # 내 서버에서 미리 실행
- # ssh -R 2222:localhost:22 ubuntu@relay-server.com
- 장점 : 서버가 외부에 열려있지 않아도 배포 가능
- 단점 : 복잡하고 보안 설정 주의 필요 (키 인증, IP 제한 등)
2. GitHub Actions Runner를 내 서버에 설치
- GitHub Actions는 기본적으로 클라우드(**github-hosted runner)**에서 실행되지만,
- 내 서버에도 "self-hosted runner"를 설치할 수 있음 (GitHub 자체가 아닌, runner만 설치하면 됨)
- GitHub Push를 감지하는 흐름 (polling + long polling : 계속 대기 상태의 연결)
- 내 서버의 Runner가 GitHub 서버 API에 지속적으로 연결됨 (HTTPS 요청을 통해)
- GitHub 저장소에 Push 발생
- GitHub 서버가 “이 저장소에 등록된 Runner가 있나?” 확인
- Runner가 주기적으로 GitHub에 job pending 여부를 물어봄
- 새로운 작업이 생기면 GitHub이 Runner에 작업 정보를 응답
- Runner는 그걸 받아서 내 서버에서 직접 실행함
- Jenkins의 SCM Polling보다 훨씬 빠르고 효율적(거의 실시간 수준).
- GitHub Push를 감지하는 흐름 (polling + long polling : 계속 대기 상태의 연결)
⇒ Push 이벤트가 발생했을 때, GitHub은 내 서버에서 Actions를 실행
📌 즉, GitHub에서 내 서버로 SSH 접속하지 않고도 내 서버가 직접 Actions Script를 실행
설정 절차
- GitHub 저장소 → Settings → Actions → Runners → Add new self-hosted runner
- 안내에 따라 내 서버에 실행 파일 다운로드 & 등록
- actions-runner 프로세스가 내 서버에서 계속 대기
- Push 이벤트가 발생하면 GitHub이 내 서버에 명령을 내려줌 (방화벽 문제 없음)
장점 : 보안상 매우 유리 (외부에서 접속 불필요)
- GitHub 서버가 내 서버에 직접 접속하지 않음
- 내 서버는 인바운드 포트가 전혀 열릴 필요 없음
- Runner가 GitHub에 HTTPS로만 아웃바운드 연결을 유지하므로 방화벽 문제 없음
3. CI와 CD Tool 분리
- CI는 GitHub Actions를 사용하여 테스트를 진행
- CD는 ArgoCd등을 이용하여 배포를 진행
2-2. Jenkins
2-2-1. 폴링(Polling, 주기적 확인)방식
- Jenkins가 일정 시간 간격(ex. 5분, 10분)으로 Git 저장소 서버를 직접 확인해서 변경사항이 있으면 빌드를 시작하는 방법
- 설정 방식 : Jenkins Job 설정에서 "Poll SCM" 옵션을 켜고 주기(크론 형태) 지정
- 장점 : 간단히 설정 가능
- 단점 : 실시간성이 떨어지고 불필요한 요청이 많아질 수 있음
2-2-2. Webhook 방식 (Push 이벤트로 바로 호출)
- GitHub/GitLab 등에서 Webhook을 만들어 Github push가 일어나면 Webhook에 등록된 Jenkins 서버 URL로 POST 요청을 보내는 방식
- Jenkins에 플러그인 설치 후 Webhook 이벤트 수신 시 빌드가 트리거됨
- 대표 플러그인: GitHub Plugin, GitLab Plugin
- 장점 : 거의 실시간으로 빌드 시작 가능
- 단점 : Jenkins 서버가 외부에서 접속 가능해야 함 (방화벽, 보안, 복잡한 네트워크 문제)
2-2-3. Jenkins 요약
서버 방화벽·보안 이슈 때문에 외부에서 내부로 접근이 안 되는 경우
🚫 이런 상황에서는 Webhook 사용 X
- Webhook은 GitHub/GitLab이 Jenkins에게 "야, 푸시 들어왔어!" 하고 HTTP 요청을 보내는 구조
- 하지만 방화벽 때문에 Jenkins 서버가 외부에서 접근 불가능하면,
→ GitHub/GitLab이 요청을 보낼 수 없기 때문에
✅ 이럴 땐 Jenkins에서는 SCM Polling 방식 사용
SCM Polling이란?
- Jenkins가 일정 주기마다 Git 저장소 서버에 "새 커밋 생겼니?" 하고 확인하는 방식
예를 들어:
# cron
H/5 * * * *
→ 5분마다 SCM 저장소를 체크해서 변경 사항 있으면 빌드 트리거
📌 즉,
GitHub나 GitLab이 Jenkins를 "부르는" 방식이 아니라,
Jenkins가 GitHub에 "바뀐 거 있어?" 하고 직접 묻는 방식
2-3. 요약
항목 GitHub Actions / GitLab CI Jenkins
| 트리거 방식 | Git Push 이벤트가 기본 트리거 | Polling 또는 Webhook |
| 설정 복잡성 | 매우 간단 (repo 내 .yml 설정으로 자동 연결) | Polling은 간단, Webhook은 설정 필요 |
| 네트워크 요구사항 | 클라우드 서비스라 별도 서버 필요 없음 | Jenkins 서버가 외부 접근 가능해야 함 |
| 실시간성 | 기본 실시간 | Webhook 사용 시 빠름, Polling은 느림 |
2-4. GitHub Actions와 Jenkins의 Polling 방식 차이
항목 GitHub Actions Self-Hosted Runner Jenkins SCM Polling
| Polling 대상 | GitHub Actions API (GitHub 자체) | Git 서버 (예: GitHub, GitLab 등) |
| Polling 주체 | Runner 프로세스 | Jenkins 서버 (cron 주기 등) |
| 동작 방식 | GitHub API와 장기 연결 유지(long polling or event queue) | 주기적으로 Git 서버에 직접 HTTP 요청 |
| 리소스 소비 | 이벤트 수신 대기 상태 (Idle 대기, CPU 거의 안 씀) | 주기적 Git fetch → 디스크/CPU 많이 씀 |
| 실행 지연 | 거의 실시간 (수 초 이내) | 보통 수 분 단위 (예: 1분마다) |
| 네트워크 부하 | GitHub와만 통신 (자원 효율적) | 많은 Git 서버들이 자주 pull → 부하 큼 |
2-4-1. GitHub Actions Runner 방식 (더 빠름)
GitHub Actions의 Runner는 단순한 polling이 아니라 GitHub Actions 서버의 이벤트 큐를 장기 대기(long polling) 합니다.
- Runner가 GitHub Actions API에 연결
- 연결을 유지하면서 "새로운 작업이 있는지" 기다림 (idle wait, CPU 거의 안 씀)
- Push 이벤트 발생 시 GitHub 서버가 Runner에 즉시 작업을 전달
- Runner는 바로 Job을 실행
장점 :
- GitHub 서버에서 직접 이벤트 발생 시 알려주므로 지연이 거의 없음
- 실제로는 polling보다는 event-driven 구조에 가까움
- CPU, 네트워크 사용량이 훨씬 적음
2-4-2. Jenkins의 Poll SCM 방식
Jenkins에서 Poll SCM을 켜면 다음과 같이 작동합니다:
- Jenkins가 git fetch 요청을 주기적으로 보냅니다 (예: * * * * → 1분마다)
- 이전 커밋과 비교해서 새로운 커밋이 있으면 Job을 실행
- 이때 git fetch는 실제 리모트 Git 서버와 네트워크 통신 + 디스크 접근을 필요로 함
단점 :
- Git 서버에 지속적인 부담 (모든 Jenkins 인스턴스가 매분마다 접속)
- 실제 변경이 없어도 계속 요청함
- Job이 즉시 실행되지 않고, polling 주기에 따라 최대 수분 지연 가능
2-4-3. 요약
- GitHub Actions Runner = "이메일 알림이 오면 바로 알려주는 푸시 알림 시스템"
- Jenkins Poll SCM = "매 1분마다 이메일을 확인하러 서버에 가는 사람"
3. 사용 후보
현재 내 서버는 외부에서 접근이 불가능하기 때문에 사용할 수 있는 방법은 아래 두 가지이다.
두 방식 모두 내 서버에서 GitHub 서버로 요청을 보내고 있어, 현재 상황에서 사용할 수 있다.
GitHub Actions의 self-Hosted Runner 방식
내 서버의 Self-Hosted Runner가 GitHub API에 접근해 Pub-Sub방식으로 연결을 맺고 이벤트 발생 시 이벤트를 받아오는 방식
Jenkins의 polling 방식
Jenkins가 Github Server에 주기적으로 POST 요청을 보내 변경 사항을 감지하는 방식
선택 : GitHub Actions의 self-Hosted Runner 방식
이유 : Jenkins의 polling 방식에 비해 Docker 친화적이면서 부하가 적음. 또한 주기적으로 변경사항을 체크하는 Jenkins에 비해 실시간성이 보장됨
4. 사용 방법
4-1. GitHub Repository 설정에서 runner 생성 후, 본인의 Host에 등록
- runner 생성하면 아래 있는 명령어 따라 적으면 됨.
4-2. .github/workflows/deploy.yml파일을 만들어 CI/CD 스크립트 작성
- Docker 컨텍스트 내에서 (Dockerfile위치한 곳) docker build 완료
- docker compose로 서버 실행