GitHub Actions에서 쉘 스크립트 활용
GitHub Actions는 GitHub 저장소에 내장된 CI/CD 플랫폼입니다. 코드를 푸시하거나 PR을 생성하는 이벤트에 반응해 자동으로 작업을 실행합니다. 그리고 그 작업의 대부분은 쉘 스크립트로 작성됩니다.
기본 구조
워크플로우 파일은 .github/workflows/ 디렉토리에 YAML 형식으로 작성합니다.
프로젝트/
├── .github/
│ └── workflows/
│ ├── ci.yml ← CI 파이프라인
│ └── deploy.yml ← 배포 파이프라인
├── scripts/
│ ├── ci_lint.sh
│ └── ci_test.sh
└── src/
워크플로우의 핵심 구조입니다.
# 새 파일: .github/workflows/ci.ymlname: CI Pipeline# 언제 실행할지on: push: branches: [ main, develop ] pull_request: branches: [ main ]# 실행할 작업들jobs: build: runs-on: ubuntu-24.04 steps: - name: 저장소 체크아웃 uses: actions/checkout@v4 - name: 쉘 스크립트 실행 run: | echo "Hello from GitHub Actions" bash --version
run 키에서 쉘 스크립트 실행
run 키에 직접 쉘 명령을 작성합니다. 여러 줄은 |(파이프 블록)로 씁니다.
# 인라인 스크립트steps: - name: 환경 정보 출력 run: | echo "운영체제: $(uname -s)" echo "아키텍처: $(uname -m)" echo "Bash 버전: $BASH_VERSION" echo "현재 디렉토리: $(pwd)"
외부 .sh 파일을 호출할 수도 있습니다. 복잡한 로직은 별도 파일로 관리하는 것이 더 좋습니다.
# 외부 스크립트 호출steps: - name: 저장소 체크아웃 uses: actions/checkout@v4 - name: 스크립트 실행 권한 부여 run: chmod +x scripts/ci_lint.sh scripts/ci_test.sh - name: 린트 검사 run: bash scripts/ci_lint.sh - name: 테스트 실행 run: bash scripts/ci_test.sh
환경 변수와 시크릿
GitHub Actions에는 두 종류의 변수가 있습니다. 환경 변수는 워크플로우 파일에서 직접 설정하고, 시크릿은 GitHub 저장소 설정에서 암호화된 형태로 관리합니다.
# 환경 변수와 시크릿 활용jobs: deploy: runs-on: ubuntu-24.04 # 워크플로우 레벨 환경 변수 env: APP_NAME: myapp DEPLOY_DIR: /var/www/myapp steps: - uses: actions/checkout@v4 - name: 배포 환경 확인 run: | echo "브랜치: ${{ github.ref_name }}" echo "커밋: ${{ github.sha }}" echo "앱 이름: $APP_NAME" - name: SSH 키 설정 run: | mkdir -p ~/.ssh echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts - name: 서버에 배포 run: | ssh "${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" \ "cd $DEPLOY_DIR && git pull origin main && ./scripts/restart.sh"
${{ secrets.KEY }} 형식으로 시크릿을 참조합니다. 시크릿 값은 로그에 출력되지 않도록 GitHub Actions가 자동으로 가립니다.
조건부 실행
if 조건으로 특정 상황에서만 스텝을 실행합니다.
steps: - name: main 브랜치에서만 배포 if: github.ref == 'refs/heads/main' run: echo "프로덕션 배포 실행" - name: PR에서만 실행 if: github.event_name == 'pull_request' run: echo "PR 검사 실행" - name: 이전 스텝 실패 시 알림 if: failure() run: echo "파이프라인 실패 알림 전송"
실습: CI 워크플로우 전체 코드
린트, 테스트, 빌드를 순서대로 실행하는 CI 파이프라인을 작성합니다.
# 새 파일: .github/workflows/ci.ymlname: CI Pipelineon: push: branches: [ main, develop ] pull_request: branches: [ main ]jobs: # ─── 린트 검사 ──────────────────────────────────────────────────────────── lint: name: 린트 검사 runs-on: ubuntu-24.04 steps: - name: 저장소 체크아웃 uses: actions/checkout@v4 - name: ShellCheck 설치 run: sudo apt-get install -y shellcheck - name: 스크립트 실행 권한 run: chmod +x scripts/ci_lint.sh - name: 린트 실행 run: bash scripts/ci_lint.sh # ─── 테스트 ─────────────────────────────────────────────────────────────── test: name: 테스트 runs-on: ubuntu-24.04 needs: lint # lint 완료 후 실행 steps: - name: 저장소 체크아웃 uses: actions/checkout@v4 - name: 스크립트 실행 권한 run: chmod +x scripts/ci_test.sh - name: 테스트 실행 run: bash scripts/ci_test.sh - name: 테스트 결과 업로드 if: always() uses: actions/upload-artifact@v4 with: name: test-results path: test-results/ # ─── 매트릭스 빌드 ──────────────────────────────────────────────────────── # 매트릭스는 여러 환경 조합을 자동으로 테스트하는 기능입니다. # 여기서는 OS 조합으로 호환성을 검증합니다. # (각 OS에 사전 설치된 Bash 버전이 사용됩니다) matrix-test: name: 호환성 테스트 (${{ matrix.os }}) runs-on: ${{ matrix.os }} needs: lint strategy: matrix: os: [ ubuntu-22.04, ubuntu-24.04 ] fail-fast: false # 하나 실패해도 나머지 계속 실행 steps: - uses: actions/checkout@v4 - name: Bash 버전 확인 run: bash --version - name: 스크립트 테스트 run: bash scripts/ci_test.sh
#!/bin/bash# 새 파일: scripts/ci_lint.sh# CI 린트 검사 스크립트set -euo pipefailGREEN='\033[0;32m'RED='\033[0;31m'NC='\033[0m'echo "ShellCheck 린트 검사를 시작합니다..."echo ""ERRORS=0# 모든 쉘 스크립트 검사while IFS= read -r -d '' script; do echo -n "검사 중: $script ... " if output=$(shellcheck "$script" 2>&1); then echo -e "${GREEN}통과${NC}" else echo -e "${RED}실패${NC}" echo "$output" ERRORS=$((ERRORS + 1)) fidone < <(find scripts/ -name "*.sh" -print0 2>/dev/null)echo ""if [ $ERRORS -gt 0 ]; then echo -e "${RED}린트 실패: ${ERRORS}개 파일에서 오류 발견${NC}" exit 1fiecho -e "${GREEN}모든 린트 검사 통과${NC}"exit 0
#!/bin/bash# 새 파일: scripts/ci_test.sh# CI 테스트 스크립트set -euo pipefailGREEN='\033[0;32m'RED='\033[0;31m'NC='\033[0m'RESULTS_DIR="test-results"mkdir -p "$RESULTS_DIR"PASSED=0FAILED=0# 간단한 테스트 함수assert_equal() { local description=$1 local expected=$2 local actual=$3 if [ "$expected" = "$actual" ]; then echo -e "${GREEN} PASS${NC}: $description" PASSED=$((PASSED + 1)) else echo -e "${RED} FAIL${NC}: $description" echo " 기대값: $expected" echo " 실제값: $actual" FAILED=$((FAILED + 1)) fi}echo "테스트를 시작합니다..."echo ""# 테스트 실행 (실제 프로젝트에 맞게 수정)source scripts/lib.sh 2>/dev/null || trueassert_equal "Bash 버전 5 이상" "5" "${BASH_VERSINFO[0]}"assert_equal "운영체제 확인" "Linux" "$(uname -s)"# 테스트 결과 저장cat > "$RESULTS_DIR/summary.txt" << EOF테스트 결과: $(date)통과: $PASSED실패: $FAILEDEOFecho ""echo "결과: 통과 $PASSED, 실패 $FAILED"if [ $FAILED -gt 0 ]; then exit 1fiecho -e "${GREEN}모든 테스트 통과${NC}"exit 0
실행 결과 확인
워크플로우 파일을 저장소에 푸시하면 GitHub 저장소의 Actions 탭에서 실행 상태를 확인할 수 있습니다.
CI Pipeline — 실행 중
├── lint ✓ 통과 (12초)
├── test ✓ 통과 (8초)
└── matrix-test
├── ubuntu-22.04 ✓ 통과
└── ubuntu-24.04 ✓ 통과
매트릭스 빌드는 여러 환경에서 동시에 테스트를 실행해 호환성을 보장합니다. 각 OS 조합이 별도의 가상 머신에서 병렬로 실행됩니다.