CI 는 코드를 작은 단위로 자주 커밋하고, 커밋마다 자동으로 빌드와 테스트를 돌려 문제를 빨리 찾는 방식입니다. 사람이 며칠에 한 번 몰아서 합치면 충돌과 버그가 쌓이지만, CI 는 합칠 때마다 바로 검증합니다.
핵심은 "자주, 자동으로, 빠르게" 세 가지입니다. 커밋 하나가 파이프라인을 한 번 돌리는 단위가 됩니다.
CD 는 CI 를 통과한 산출물을 실제 환경까지 내보내는 자동화입니다. 두 가지로 나뉩니다.
| 용어 | 의미 | 사람 개입 |
|---|---|---|
| Continuous Delivery | 배포 가능한 상태까지 자동 준비 | 실제 배포는 승인 후 수동 |
| Continuous Deployment | 검증 통과 시 운영까지 자동 반영 | 없음(전 과정 자동) |
두 용어 모두 약자는 CD 로 같아서 문맥으로 구분합니다. 이 레슨의 5번째 단계인 "배포"는 두 방식 모두에 공통으로 들어갑니다.
여섯 단계가 순서대로 이어집니다. 앞 단계가 실패하면 뒤 단계는 실행되지 않습니다.
체크아웃 --> 빌드 --> 테스트 --> 정적 검사 --> 패키징 --> 배포
(checkout) (build) (test) (static (package) (deploy)
analysis)| 단계 | 하는 일 | 실패하면 |
|---|---|---|
| 체크아웃 | 저장소 코드를 작업 공간에 가져옴 | 이후 단계 진행 불가 |
| 빌드 | 소스를 컴파일함(javac) |
문법 오류로 중단 |
| 테스트 | 자동 테스트를 실행함 | 로직 오류로 중단 |
| 정적 검사 | 경고·규칙 위반을 검사함 | 품질 기준 미달로 중단 |
| 패키징 | 실행 산출물을 만듦(jar) |
산출물 없음 |
| 배포 | 대상 서버·환경에 반영함 | 이전 버전 유지 |
이 레슨의 예제 스크립트는 이 여섯 단계를 그대로 셸 함수 하나로 구현합니다.
셸 명령은 끝나면 종료 코드(exit code)를 남깁니다. 0 은 성공, 0 이 아니면 실패입니다.
실무 파이프라인 스크립트는 흔히 set -e 를 써서 명령 하나가 실패하면 스크립트 전체가 즉시 멈추게 합니다. 이 레슨의 예제는 trap 과 조합하기 쉽도록 set -uo pipefail 만 켜고, 단계마다 종료 코드를 직접 검사해 실패 시 그 자리에서 멈추는 함수를 만듭니다.
두 방법 모두 목적은 같습니다. 실패를 뒤 단계까지 끌고 가지 않고 바로 알리는 것입니다.
실무 파이프라인은 단계마다 걸린 시간을 기록해 느려지는 지점을 찾습니다. 방법은 단계 시작 시각을 저장해 두고 끝났을 때 차이를 계산하는 것입니다.
start=$SECONDS
# ...단계 실행...
elapsed=$((SECONDS - start))이 레슨 예제도 같은 방식으로 elapsed 를 계산하지만 화면에는 출력하지 않고 timing.log 에만 남깁니다. 실제 걸리는 시간은 실행 환경마다 달라 화면 출력을 실행마다 똑같이 만들 수 없기 때문입니다.
GitHub Actions 없이도 같은 단계를 ci.sh 라는 셸 스크립트로 미리 돌려 볼 수 있습니다. 이 레슨의 예제 스크립트는 ci.sh 를 직접 생성하고 실행합니다.
ci.sh 는 run_step 이라는 함수 하나로 여섯 단계를 순서대로 부릅니다. 각 단계는 "이름"과 "실행할 명령"을 인자로 받습니다.
소스가 정상이면 여섯 단계가 모두 [OK] 를 남기고 파이프라인 성공 으로 끝납니다. 종료 코드는 0 입니다.
패키징 단계는 out/ 의 클래스 파일을 모아 deploy/app.jar 를 만듭니다. 배포 단계는 실제 서버 접속 없이 "복사한다고 가정"이라는 메시지만 남겨 로컬에서도 흐름을 볼 수 있게 합니다.
Calc.add 의 로직을 일부러 망가뜨리면 테스트 단계에서 실패합니다. 빌드는 통과하지만 테스트가 실패해 정적 검사·패키징·배포 는 실행되지 않습니다.
deploy/ 폴더를 실행 전에 비워 두면, 실패 후에도 폴더가 비어 있다는 사실로 "패키징까지 못 갔다"를 확인할 수 있습니다. 종료 코드는 1 입니다.
같은 소스를 같은 옵션으로 두 번 빌드하면 클래스 파일 내용은 항상 같아야 합니다. 이를 확인하려면 파일 내용의 체크섬(sha256sum)을 비교합니다.
jar 파일 자체는 내부에 항목 순서·메타데이터가 섞여 있어 해시가 흔들릴 수 있습니다. 그래서 이 레슨은 jar 안 클래스 파일 각각의 해시를 확인하는 방식을 씁니다.
세 도구는 개념(단계·잡(job)·러너(runner))은 비슷하지만 설정 위치와 운영 방식이 다릅니다.
| 항목 | GitHub Actions | Jenkins | GitLab CI |
|---|---|---|---|
| 설정 파일 | .github/workflows/*.yml |
Jenkinsfile 또는 UI | .gitlab-ci.yml |
| 실행 주체 | GitHub 제공 또는 self-hosted 러너 | 직접 설치한 서버 | GitLab 제공 또는 runner |
| 폐쇄망 적합성 | self-hosted 러너로 가능 | 사내 설치 전제라 적합 | self-hosted runner 로 가능 |
| 학습 난이도 | YAML 문법만 익히면 됨 | 플러그인·UI 개념 필요 | YAML 문법 비슷 |
| 대표 사용처 | GitHub 저장소 | 사내 전용 서버 | GitLab 저장소 |
폐쇄망 환경에서는 세 도구 모두 사내 서버에 러너를 직접 설치해야 합니다. 다음 레슨부터는 이 중 GitHub Actions 를 기준으로 워크플로 파일을 다룹니다.
커밋 --> [체크아웃 --> 빌드 --> 테스트 --> 정적 검사 --> 패키징 --> 배포]
이 구간 전체가 "파이프라인"
실패 시 어느 단계에서든 즉시 중단하고 이후 단계는 건너뜀