Github Actions Workflows
워크플로우(workflow)
워크플로우(workflow)는 CI/CD 파이프라인에서 작업을 실행하는 자동화된 프로세스로, 파이프라인의 실행 계획을 의미한다.
워크플로우는 .github/workflows
디렉터리에 YAML 파일로 정의된다.
워크플로우 파일은 프로젝트 폴더 아래 .github/workflows
디렉터리를 만든 후 안에 저장해야 한다.
⊙ ⊙ ⊙
워크플로우(workflow) 구문
워크플로우 구문에 이해를 돕기 위해 구성 요소에 대한 설명 시 자유롭게 작성 가능한 요소와 참조 값을 사용해야야 되는 요소로 구분했다.
<custom>
은 자유롭게 작성할 수 있는 요소를 의미한다.
<ref>
는 정해져 있는 참조 값만 사용해야 되는 요소를 의미한다.
아무 표시도 없는 요소는 하위 요소를 포함하는 상위 요소의 역할을 나타낸다.
name: backend workflows # 워크플로우의 이름
# 워크플로우가 실행되는 조건
on:
push:
branches: # main 브랜치에 push될 때
- main
# 실행할 작업들을 정의
jobs:
job: # 작업 이름
runs-on: ubuntu-latest # 실행될 환경
# 작업의 단계들
steps:
- name: Checkout repository # 단계 이름
uses: actions/checkout@v2 # 사용할 액션
주요 구성 요소
name <custom>
워크플로우의 이름을 정의한다. 자유롭게 작성하면 된다.
⊙ ⊙ ⊙
on
워크플로우가 실행될 트리거를 정의한다.
push, pull_request, schedule 등 다양한 이벤트를 지정할 수 있다.
branches <ref>
지정된 브랜치에 push 된 경우 트리거로 작동한다.
⊙ ⊙ ⊙
jobs
실행 할 작업들을 정의하는 최상위 요소이다. 하위 요소로 job을 정의할 수 있다.
job <custom>
각 job은 독립된 환경에서 실행된다. job
부분을 실행될 작업을 의미하는 이름으로 자유롭게 지정하면 된다.
runs-on
에 지정된 환경의 가상머신 또는 컨테이너에서 실행된다.
runs-on <ref>
job이 실행되는 환경을 지정한다.
실행 환경은 github의 러너(runner)에서 실행되며, Github 러너(runner)는 크게 Github 호스팅 러너(Github-hosted runner)
와 셀프 호스팅 러너(self-hosted runner)
로 구분된다.
사용하는 러너에 맞게 정의해야 한다.
(Github 공식 문서 - 실행 환경 )
- Ubuntu: ubuntu-latest, ubuntu-22.04, ubuntu-20.04
- Windows: windows-latest, windows-2022, windows-2019
- macOS: macos-latest, macos-12, macos-11
⊙ ⊙ ⊙
steps
작업의 실행 단계를 정의하는 요소이다.
하위 uses
를 단위로 실행될 작업을 정의할 수 있다.
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 소스 체크아웃
- id: checkout
name: Checkout Repository
uses: actions/checkout@v3
repository: my-repo
ref: main
# Node.js 설정
- id: setup-node
name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
id <custom>
step을 식별하기 위한 고유 식별자를 지정한다.
step은 -
하이픈을 기준으로 구분된다.
name <custom>
실행 할 단계의 작업 이름을 지정한다.
uses <ref>
실행 할 작업의 Actions을 정의한다.
Actions란 워크플로우에서 실행하는 작업 단위
로 특정 작업을 자동화하기 위해 설계된 코드 패키지
라 보면 된다.
예를 들어 github에서 코드를 체크아웃 하기
, Docker 이미지 빌드하기
, 애플리케이션 빌드하기
, 테스트 스크립트 실행하기
등을 할 수 있다.
Actions는 공식 Actions을 사용할 수도 있고, 다른 사람이 만들어 놓은 Actions를 사용할 수도 있고, 직접 Actions를 만들어서 사용할 수도 있다. 일반적으로는 Github에서 제공하는 액션을 사용한다. (Github Marketplace) 하지만 CI/CD 과정에서 별도의 테스트 작업이나 특별한 작업을 수행하고자 할 경우 Actions를 직접 만들어 활용할 수 있다.
Actions을 활용하면 반복적인 작업을 자동화하여 쉽고 효율적으로 처리할 수 있다.
with
action에 전달할 입력 매개변수를 설정한다.
Actions의 입력값(input)을 설정하는 데 사용되기 때문에 uses에 정의된 actions에 따라 사용되는 옵션 값이 달라진다.
그래서 action 별로 사용되는 주요 변수를 익혀두는 것이 좋다. 여기서는 별도의 변수 설명은 하지 않는다.
(Github Marketplace)에 접속해서 actions별 정의된 변수를 확인할 수 있다.
⊙ ⊙ ⊙
env <custom>
env는 워크플로우 내에서 사용할 환경 변수를 설정한다.
env
의 설정 위치에 따라 적용되는 범위가 다르다.
기본 YAML 문법은 키-값
을 정의할 때 콜론을 사용한다.
워크플로우에서 사용
1. env
가 step 레벨에서 정의된 경우:
steps:
- name: HI
env:
VAR_NAME: "value"
run: echo $VAR_NAME
- name: Hello
run: echo $VAR_NAME
- 해당 step에만 적용된다.
- step 내에서 실행되는 모든 명령어(
run
) 또는 액션(uses
)에서 환경 변수를 사용할 수 있다. - 첫 번째 step에서는
VAR_NAME
을 사용할 수 있지만, 두 번째 step에서는 사용할 수 없다.
2. env
가 job 레벨에서 정의된 경우:
jobs:
example-job:
runs-on: ubuntu-latest
env:
VAR_NAME: "value"
steps:
- name: First step
run: echo $VAR_NAME
- name: Second step
uses: actions/checkout@v3
run: echo $VAR_NAME
- 해당 job의 모든 step에 적용된다.
VAR_NAME
은 모든 step에서 접근 가능하다.run
명령어와uses
로 호출된 액션 모두에서 사용할 수 있다.
3. env
와 uses
의 관계:
steps:
- name: Use an action with env variable
env:
VAR_NAME: "value"
uses: username/repo-name@v1
uses
로 호출된 액션 내부에서도 환경 변수를 사용할 수 있다.- 액션이 환경 변수를 참조하도록 설계된 경우 해당 환경 변수가 적용된다.
username/repo-name
액션에서VAR_NAME
이 필요하다면 전달된다.
도커파일(Dockerfile)에 전달
워크플로우에서는 build-args와 env로 환경 변수를 설정할 수 있다.
build-args
: 빌드 시점에 사용할 환경 변수를 설정할 수 있다.env
: 런타임에 전달할 환경 변수를 설정할 수 있다.
Dockerfile에는 ARG
와 ENV
라는 환경 변수 지시어가 존재한다.
ARG
: 빌드 과정에서만 사용되는 환경 변수를 지정할 때 사용된다.ENV
: 컨테이너 런타임에서 어플리케이션 내부에서 사용될 환경 변수를 지정할 때 사용된다.
워크플로우에서 Dockerfile로 환경 변수를 전달할 수 있다.
build-args
로 설정된 환경 변수 값을 도커 파일로 전달할 수 있다. 이때 Dockerfile에는 반드시ARG
지시어로 환경 변수를 선언해야 값을 받을 수 있다.- 어플리케이션에서 사용 할(런타임 시 사용 할) 환경 변수가 필요한 경우,
build-args
를 사용해 ARG로 값을 받고 이를 ENV로 전달해야 된다. - 참고로
env
에 설정된 값은 도커 파일로 전달되지 않는다.
워크플로우에서 컨테이너 실행 명령까지 진행하는 경우가 아니고, 이미지만 빌드 후 컨테이너 실행은 따로 진행하는 경우에는 이미지 안에 환경 변수를 포함시키거나, 컨테이너 실행 시점에 직접 환경 변수를 넘겨줘야 한다.
이미지에 환경 변수를 포함시키려면 위에서 말한 바와 같이 build-args
를 사용하면 된다.
name: Docker Build
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
# Docker 빌드 및 푸시
- name: Build and push
uses: docker/build-push-action@v5
with:
# 환경변수 전달 방법 1: build-args로 전달
build-args: |
API_URL=$
DB_HOST=$
NODE_ENV=production
# 환경변수 전달 방법 2: 런타임 환경변수로 전달
env: |
RUNTIME_VAR1=$
RUNTIME_VAR2=$
# build-args로 전달된 값을 런타임시 사용하려면 아래와 같이 ENV로 전달해줘야 한다.
ARG DB_HOST
ENV DB_HOST=${DB_HOST}
# env로 전달된 값은 이렇게 변수만 선언해도 값이 전달된다.
ENV RUNTIME_VAR1
ENV RUNTIME_VAR2
⊙ ⊙ ⊙
steps:
- id: build
name: Build application
uses: actions/setup-node@v2
with:
node-version: '16'
working-directory: ./frontend
env:
NODE_ENV: production
continue-on-error: false
timeout-minutes: 10
run: |
npm install
npm run build
continue-on-error <ref>
continue-on-error는 step의 작업을 실행하는 중 오류가 발생했을 때 워크플로우를 계속 실행할지 여부를 설정할 수 있다.
기본값이 false 이기 때문에 별도의 설정이 없으면 오류가 발생하면 워크플로우는 중단된다.
true
로 설정하면 이 step이 실패해도 다음 step이 실행된다.
timeout-minutes <custom>
step의 최대 실행 시간을 설정할 수 있다. 분 단위로 설정되고, 기본 값은 360분이다. 지정된 시간을 초과하면 step이 자동으로 중단된다.
run <custom>
shell에서 실행될 명령어를 지정할 수 있다.
|
파이프를 사용하면 여러 줄의 명령어로 실행할 수 있다.
⊙ ⊙ ⊙
보안 설정
워크플로우가 실행되면 GitHub 리소스에 접근하여 필요한 자원을 사용한다. 이는 워크플로우를 통해 원하는 작업을 손쉽게 할 수 있는 큰 장점이다. 하지만 반대로 말하면 워크플로우가 보안 리스크의 시발점이 될 수 있음을 시사한다.
워크플로우는 아래와 같은 작업들이 가능하다.
- repository의 모든 secrets에 접근 가능
- 다른 브랜치 생성/삭제 가능
- issues 생성/수정/삭제 가능
- PR 생성/수정/닫기 가능
- GitHub Packages에 패키지 업로드/삭제 가능
즉 워크플로우 통해 내가 아닌 누군가도 위와 같은 것들을 할 수 있다는 말이 된다. 보안 위험 사례로는 워크플로우에서 사용되는 actions나 패키지(npm, pip 등 의존성 패키지) 등의 악의적인 코드가 심어져 있는 경우나 PR시 악의적인 코드를 push한 경우 등이 있을 수 있다.
따라서 워크플로우 보안을 위한 기본적인 설정들은 반드시 필요하다.
permissions
permissions
는 워크플로우가 GitHub 리소스에 접근할 수 있는 권한 범위를 정의하는 설정이다.
permissions는 크게 워크플로우 레벨과 job 레벨로 정의할 수 있다.
워크플로우 레벨
워크플로우 레빌로 설정할 수 있는 스코프는 write-all
와 read-all
이다.
- write-all: 읽고, 수정하고, 삭제하는 등의 모든 권한을 가짐.
- read-all: 리소스를 읽을 수만 있음.
- permissions를 명시하지 않으면 기본값은
write-all
이다.
# 워크플로우 전체에 대한 기본 권한 설정
name: CI Pipeline
permissions: read-all # 또는 write-all
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Job 레벨 설정 Job 기준으로 권한을 설정할 수 있다.
name: CI Pipeline
permissions: read-all # 기본적으로 모든 권한 읽기로 제한
jobs:
test:
runs-on: ubuntu-latest
# job별로 필요한 권한만 추가
permissions:
contents: read
pull-requests: write
- Job 스코프
# Job 스코프
permissions:
actions: read|write|none # GitHub Actions 관련
checks: read|write|none # 체크 실행 결과
contents: read|write|none # 리포지토리 컨텐츠
deployments: read|write|none # 배포 관련
issues: read|write|none # 이슈 관련
packages: read|write|none # 패키지 관련
pull-requests: read|write|none # PR 관련
repository-projects: read|write|none # 프로젝트 관련
security-events: read|write|none # 보안 이벤트
statuses: read|write|none # 커밋 상태
기본적인 전략은 워크플로우의 전체 권한은 읽기 전용으로 설정하고, 각 Job별로 필요한 권한만 추가하면 된다.
name: CI/CD Pipeline
# 기본적으로 모든 권한을 읽기로 제한
permissions: read-all
jobs:
test:
runs-on: ubuntu-latest
# 테스트 job은 코드를 읽고, 결과를 PR에 코멘트만 하면 됨
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v3
- run: npm test
security-scan:
runs-on: ubuntu-latest
# 보안 검사 job은 코드를 읽고, 보안 결과를 등록
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v3
deploy:
runs-on: ubuntu-latest
# 배포 job은 패키지 배포와, 배포 상태 업데이트 필요
permissions:
contents: read
packages: write
deployments: write
steps:
- uses: actions/checkout@v3
pull_request
GitHub Actions의 pull_request 이벤트는 Pull Request(PR)와 관련된 다양한 활동이 발생했을 때 워크플로우를 실행하도록 트리거하는 이벤트이다.
누군가 악의적인 PR을 올렸을 때 위험을 줄이기 위해서는 push 이벤트만 사용하는 방법은 자제하고 pull_request를 거치도록 전략을 짜는 것이 좋다. 이는 단순히 보안을 위해서 뿐만 아니라 개발자들의 실수를 줄이기 위한 방법으로도 충분히 활용할 수 있다.
기본 정의
on:
pull_request: # PR 관련 모든 이벤트에 반응
branches: # 특정 브랜치로의 PR만 감지
- main
- dev
types: # 특정 PR 액션만 감지
- opened # PR이 생성될 때
- synchronize # PR이 업데이트될 때
- reopened # PR이 다시 열릴 때
주요 types: 타입 설정으로 다양한 PR 이벤트에 맞는 설정을 할 수 있다.
- opened: PR이 처음 생성될 때
- synchronize: PR에 새로운 커밋이 추가될 때
- reopened: 닫혔던 PR이 다시 열릴 때
- closed: PR이 닫히거나 머지될 때
- ready_for_review: 드래프트 PR이 리뷰 준비 상태가 될 때
types를 지정하지 않으면 opened, synchronize, reopened가 기본값으로 설정된다.
주의사항: fork된 레포지토리에서의 PR은 보안상 추가 검증이 필요할 수 있다. 민감한 secrets는 PR 환경에서 노출되지 않도록 주의해야 한다.
기본 전략
GitHub Actions은 PR이 요청된 브랜치의 코드와 대상 브랜치(예: main)를 자동으로 병합한 상태에서 워크플로우를 실행한다. 작동 방식은 아래와 같다:
- PR이 생성되면 GitHub은 가상의 병합 커밋(merge commit)을 생성한다.
actions/checkout@v4
액션은 이 가상 병합 상태의 코드를 체크아웃 한다.- 따라서 빌드나 테스트는 “PR이 실제로 병합되었을 때의 상태”를 미리 검증할 수 있다.
기본 전략은 다음과 같다.
- 별도의 dev 브랜치를 생성하고, main 브랜치로 직접적인 push는 막는다.
- main 브랜치로는 PR을 통해서만 push 할 수 있다.
- dev 브랜치에서 main 브랜치로 PR이 생성하면 기본적인 검증을 진행한다. 이 시점에 PR 워크플로우 job이 실행된다.
- PR 워크플로우 검증이 성공하면 병합 후 main 브랜치로 push가 되면서 실제 job을 실행한다.
PR(Pull Request) 워크플로우 파일을 추가로 만든다. 이렇게 하면 유지보수에 유리하다.
적용할 서비스: Gradle 기반 API Server
- main 브랜칠
name: PR Pipeline
on:
pull_request:
branches:
- main
jobs:
pull_request_build_test:
runs-on: ubuntu-latest
steps:
-
name: Checkout Repository
uses: actions/checkout@v4
# 현재 리포지토리를 체크아웃합니다.
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Docker Buildx를 설정합니다.
-
name: Build and Push
uses: docker/build-push-action@v2
with:
# 빌드 컨텍스트 : Dockerfile이 있는 위치
context: .
# Dockerfile의 경로
file: Dockerfile
build-args: |
GOOGLE_CLIENT_ID=$
# 이미지 푸시 여부
push: false
-
name: Notify Failure
if: failure()
run: echo "Docker build failed."
브랜치 룰셋 설정
PR(Pull-Request) 생성 시 PR 워크플로우를 실행하기 위해 룰셋을 생성해야 한다.
1. 레포지토리 > Settgins > Branches > “Add branch ruleset” 클릭
2. “Ruleset Name” 이름 작성한다.
3. Target branches > Add target을 설정한다.
- Target은 룰셋을 적용할 브랜치를 선택하는 과정이다.
- Add target에 적용할 브랜치는 “Include by pattern”에 직접 브랜치명을 적어줘야 한다.
4. “Require a pull request before merging” 체크. 추가 항목은 일단 패스
- 룰셋이 적용된 브랜치는 병합 전 pull request를 필수로 해야 한다는 의미이다. 직접 push가 불가능하게 만들어 준다.
5. “Require status checks to pass” 체크.
- 하위 항목 “Require branches to be up to date before merging” 체크
- “Add checks”는 실행할 워크플로우 job을 등록하는 항목이다.
- 실행할 워크플로우 job 이름을 입력하면 자동 검색된다. 검색된 job을 선택해준다.
⊙ ⊙ ⊙
Actions 시크릿(Secrets)과 변수(Variables)
GitHub Actions에서 Secrets와 Variables는 워크플로우의 효율성과 보안을 높이기 위해 사용되는 두 가지 주요 개념이다. 이러한 기능을 활용하면 워크플로우의 보안과 유연성을 높일 수 있다.
Secrets (비밀)
Secrets는 API 키, 비밀번호 등과 같은 민감한 정보를 안전하게 저장하고 워크플로우에서 사용할 수 있도록 도와준다.
설정 수준:
- 리포지토리 수준: 특정 리포지토리 내에서만 사용 가능.
- 환경(Environment) 수준: 배포 환경별로 설정하여 세분화된 관리 가능.
- 조직(Organization) 수준: 조직 내 여러 리포지토리에서 공유 가능.
사용 방법:
- 리포지토리의 Settings > Secrets and variables > Actions로 이동한다.
- Secrets 탭에서 New repository secret을 클릭한다.
- 이름과 값을 입력하고 Add secret을 클릭하여 저장한다.
워크플로우에서 참조:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Use secret
run: echo "Secret is $"
env: |
- 위 예시에서
$
를 통해 저장된 시크릿을 참조할 수 있다. - 시크릿 값은 GitHub 인터페이스에서 조회할 수 없으며, 한 번 설정하면 수정 또는 삭제만 가능하다.
- 워크플로우 로그에 시크릿이 노출되지 않도록 주의해야 하며, GitHub는 로그에서 시크릿 값을 자동으로 마스킹 처리한다.
Variables (변수)
Variables는 민감하지 않은 구성 값이나 설정 정보를 저장하는 데 사용된다.
설정 위치:
- 리포지토리 수준: 해당 리포지토리 내에서 사용 가능.
-
환경(Environment) 수준: 특정 환경에 맞는 변수 설정 가능.
- 사용 방법:
- 리포지토리의 Settings > Secrets and variables > Actions로 이동한다.
- Variables 탭에서 New repository variable을 클릭한다.
- 이름과 값을 입력하고 Add variable을 클릭하여 저장한다.
워크플로우에서 참조:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Use variable
run: echo "Variable is $"
- 위 예시에서
$
를 통해 저장된 변수를 참조할 수 있습니다. - 변수 값은 GitHub 인터페이스에서 조회 및 수정이 가능합니다.
- 민감한 정보는 변수 대신 시크릿에 저장해야 합니다.
⊙ ⊙ ⊙
환경 변수 키-값 콜론(:
)과 등호(=
)의 사용 규칙
기본 규칙
내부 처리용 YAML 구문 (콜론 :
사용)
- 워크플로우 내부에서만 사용되거나 actions으로 전달되는 환경 변수는 YAML의 기본 문법을 따라 콜론 (
:
)을 사용한다.
jobs:
job:
env:
MODE_ENV: "dev"
steps:
# 1. Shell 명령어에서 사용
- name: Use in shell
run: echo "Current mode is $"
# 2. 조건문에서 사용
- name: Conditional step
if: env.MODE_ENV == 'dev'
run: echo "Development mode specific tasks"
# 3. Composite Action에 전달
- name: Use in composite action
uses: ./my-composite-action
with:
environment: $
# 시크릿 값 actions으로 전달
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: $
password: $
외부 전달용 할당 구문 (등호 =
사용)
- Docker나 shell과 같은 외부 시스템으로 전달하는 목적으로 환경 변수를 설정하는 경우가 있다.
- 이때는 YAML 문법이 아닌 shell 명령어 형식을 따라 등호(
=
)를 사용해서 환경 변수를 매핑해야 한다. build-args
,run
는 CLI의 Shell 명령어 스타일로 처리되므로, 등호(=
)를 사용해야 한다.
name: Build and Push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
build-args: |
DB_PASSWORD=$
다중 문자열 (등호 =
사용)
다중 문자열을 처리하기 위해 파이프(|)
를 사용한다.
파이프(|)
를 사용하면 Shell 명령어로 처리되기 때문에 등호(=)
를 써야 한다.
# env 기본 문법 콜론(:) 사용
env:
VAR_NAME_1: "value"
VAR_NAME_2: "value"
VAR_NAME_3: "value"
# 다중 문자열 입력을 위해 파이프(|)를 사용하는 경우 등호(=) 사용
env: |
VAR_NAME_1="value"
VAR_NAME_2="value"
VAR_NAME_3="value"
환경변수 전달 시나리오
시나리오 1: 워크플로우 → Compose → Docker
컨테이너 실행 시점에 환경변수 주입 (Dockerfile에 ENV 불필요
)
1. GitHub Actions Workflow
name: Deploy with Compose
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
env:
DB_PASSWORD=$
run: docker-compose up -d
2. docker-compose.yml
services:
app:
image: myapp
environment:
- DB_PASSWORD=${DB_PASSWORD}
3. Dockerfile
FROM node:16
# ENV 설정 불필요 (Compose가 실행 시 주입)
시나리오 2: 워크플로우 → Dockerfile → 이미지
도커 파일에 환경 변수를 전달하기 위해서는 build-args
를 사용해야 한다.
env
에 설정한 환경 변수 값은 도커 파일로 전달되지 않는다.
1. GitHub Actions Workflow
name: Build and Push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
build-args: |
DB_PASSWORD=$
2. Dockerfile
FROM node:16
ENV DB_PASSWORD="" # 필수! (이미지에 포함)
정리
- GitHub Actions 내부 설정 → 콜론(
:
) 사용with
섹션의 모든 설정- 워크플로우 자체 환경변수
- 외부 시스템 전달 → 등호(
=
) 사용- Docker 빌드 인자
- 컨테이너 환경변수
- Shell 스크립트 변수
⊙ ⊙ ⊙
멀티 환경(Multi Environments)
environment <ref>
GitHub Actions에서 Environments는 배포 대상(예: 프로덕션, 스테이징, 개발 등)을 정의하고 관리하는 기능이다. 이를 통해 실제 서비스를 운영할 때 각 환경에 맞게 배포 프로세스를 제어하고, 환경 별로 다른 시크릿(Secrets)과 변수(Variables)를 설정하며, 승인 절차나 보호 규칙을 적용할 수 있다.
Docker Compose에서 Override를 활용해 환경별 파일을 관리하던 부분을 대체할 수 있다.
예를 들어 개발 환경과 운영 환경이 있다고 가정해보자. 두 환경이 갖는 내부 설정 값은 다르게 적용되어야 다른 환경을 구성할 수 있다. environment를 사용하면 이런 환경 구성을 하나의 워크플로우 파일 안에서 설정할 수 있다.
우선 environment를 사용하려면 github 레포지토리에 등록을 해야한다.
- 리포지토리의 [Settings] 탭에서 [Environments]를 선택한다.
- [New environment]를 클릭하여 새로운 환경을 생성하고, 이름을 지정한다.
사전에 등록된 environment name
을 워크플로우의 job 단위로 지정할 수 있다.
name: Deploy Workflow
on:
push:
branches:
- main
jobs:
deploy-development:
runs-on: ubuntu-latest
# 개발 환경 정의
environment: development
steps:
- name: Deploy to Development
with:
build-args: |
API_URL=$
DB_HOST=$
NODE_ENV=development
env: |
RUNTIME_VAR1=$
RUNTIME_VAR2=$
deploy-production:
runs-on: ubuntu-latest
# 운영 환경 정의
environment:
name: production
steps:
- name: Deploy to Production
with:
build-args: |
API_URL=$
DB_HOST=$
NODE_ENV=production
env: |
RUNTIME_VAR1=$
RUNTIME_VAR2=$
Environments의 시크릿(Secrets)과 변수(Variables)
환경 별 시크릿과 변수를 등록할 수 있다.
이렇게 environment로 지정된 job들은 각각의 environment에 등록된 시크릿(secrets)과 변수(variables)를 사용할 수 있다.
name <ref>
environment에 값을 직접 지정할 수도 있고, name을 사용하여 지정할 수도 있다.
Environments의 시크릿과 변수 사용
등록된 environment를 지정한 job에 environment에 등록된 시크릿과 변수를 참조할 수 있다.
secrets.변수명
vars.변수명
레포지토리 수준에 등록된 시크릿과 변수는 워크플로우 내의 모든 job에서 참조할 수 있다. 접근 방법은 동일하다.
secrets.변수명
vars.변수명
⊙ ⊙ ⊙
멀티 환경 워크플로우 실행
if <custom>
- step의 실행 조건을 정의할 때 사용한다.
- 조건이 true일 때만 step이 실행된다.
name: Deploy Workflow
on:
push:
branches:
- develop
- main
jobs:
deploy-development:
runs-on: ubuntu-latest
# develop 브랜치에 push 된 경우
if: github.ref == 'refs/heads/develop'
# 개발 환경 정의
environment: development
steps:
- name: Deploy to Development
with:
build-args: |
API_URL=$
DB_HOST=$
NODE_ENV=development
env: |
RUNTIME_VAR1=$
RUNTIME_VAR2=$
deploy-production:
runs-on: ubuntu-latest
# main 브랜치에 push 된 경우
if: github.ref == 'refs/heads/main'
# 운영 환경 정의
environment: production
steps:
- name: Deploy to Production
with:
build-args: |
API_URL=$
DB_HOST=$
NODE_ENV=production
env: |
RUNTIME_VAR1=$
RUNTIME_VAR2=$
⊙ ⊙ ⊙
워크플로우 수동 실행
workflow_dispatch
workflow_dispatch는 GitHub Actions에서 사용자가 수동으로 워크플로우를 실행할 수 있도록 입력 파라미터를 제공하는 이벤트다. workflow_dispatch를 설정하면 Actions 페이지에서 워크플로우를 실행 할 때 environment 입력 값을 설정하는 UI를 표시할 수 있다. Actions 페이지에서 “Run workflow” 버튼을 통해 실행할 수 있다.
예를 들어 멀티 환경이 설정된 워크플로우(한 번에 모든 환경을 실행할 수 없게 설정된 경우)를 수동으로 실행할 경우에는 모든 환경에 배포되도록 설정할 수 있다. 아래 워크플로우는 다음과 같은 상황에 실행된다.
- develop 브랜치에 push 된 경우 deploy-development job이 실행된다.
- main 브랜치에 push 된 경우 deploy-production job이 실행된다.
- 워크플로우가 수동으로 실행될 때 입력된 파라미터가 development 인 경우 deploy-development job이 실행된다.
- 워크플로우가 수동으로 실행될 때 입력된 파라미터가 production 인 경우 deploy-production job이 실행된다.
- 워크플로우가 수동으로 실행될 때 입력된 파라미터가 all 인 경우 deploy-development job과 deploy-production job이 모두 실행된다.
name: Deploy
on:
push:
branches: ["develop", "main"]
workflow_dispatch:
inputs:
environment:
description: 'Deploy to environment'
required: true
default: 'all'
type: choice
options:
- all
- development
- production
jobs:
deploy-development:
if: >
github.ref == 'refs/heads/develop' ||
(github.event_name == 'workflow_dispatch' &&
(github.event.inputs.environment == 'development' || github.event.inputs.environment == 'all'))
runs-on: ubuntu-latest
environment: development
steps:
- name: Deploy to dev
run: echo "Deploying to development environment"
deploy-production:
if: >
github.ref == 'refs/heads/main' ||
(github.event_name == 'workflow_dispatch' &&
(github.event.inputs.environment == 'production' || github.event.inputs.environment == 'all'))
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to prod
run: echo "Deploying to production environment"
inputs
배포할 환경의 입력 파라미터를 정의하는 최상위 요소
environment <custom>
입력 파라미터를 식별하는 고유한 이름을 지정한다. 자유롭게 작성하면 된다.
required <ref>
입력 값의 필수 여부를 설정한다.
true
: 워크플로우 실행 시 반드시 값을 입력해야 한다.false
: 선택적으로 값을 입력할 수 있다.
description <custom>
어떤 환경인지 사용자가 인지할 수 있도록 자유롭게 설명을 작성한다.
default
최초 사용자에게 기본으로 보이는 값을 의미한다. 문자열, 숫자, boolean 등 type에 맞는 값을 사용할 수 있다.
type <ref>
입력 될 값의 형태를 지정한다.
choice | boolean | string | number | environment
choice
미리 정의된 옵션 중에서 선택 (options 필요)
type: choice
options:
- option1
- option2
boolean
true/false 선택
debug_mode:
type: boolean
default: false
string
자유 텍스트 입력
commit_message:
type: string
default: 'automated deployment'
number
숫자 입력
timeout_minutes:
type: number
default: 30
environment
GitHub Environments 중 선택
target_env:
type: environment
복합 예시
workflow_dispatch:
inputs:
deploy_target:
description: 'Deployment target'
required: true
type: choice
options:
- aws-prod
- aws-dev
- gcp-prod
- gcp-dev
default: 'aws-dev'
debug_enabled:
description: 'Enable debug mode'
required: false
type: boolean
default: false
release_version:
description: 'Version to deploy'
required: false
type: string
default: 'latest'
retry_attempts:
description: 'Number of retry attempts'
required: false
type: number
default: 3
workflow_dispatch 설정 값 사용
workflow_dispatch에 설정된 값을 job에 전달하여 사용할 수 있다. 입력 파라미터를 식별하기 위해 정의 이름으로 입력 값에 접근할 수 있다.
name: Manual Deployment Workflow
on:
workflow_dispatch:
inputs:
environment:
description: 'Choose deployment environment'
required: true
default: 'staging'
version:
description: 'Version to deploy'
required: true
default: 'latest'
- environment로 정의된 입력 파라미터의 입력된 값에 접근
github.event.inputs.environment
- version 정의된 입력 파라미터의 입력된 값에 접근
github.event.inputs.version
github.event_name
- workflow_dispatch 이벤트로 워크플로우가 실행된 경우 github.event_name의 값은 항상 workflow_dispatch이다.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Display selected options
env:
VERSION=#
run: |
echo "event name: $"
echo "Environment: $"
echo "Version: $"
- name: Deploy to environment
run: |
echo "Deploying version $ to $"
⊙ ⊙ ⊙
Actions 캐시 활용
GitHub Actions 캐시란?
GitHub Actions의 캐시 시스템은 워크플로우 실행 사이에 종속성이나 빌드 출력물을 저장하고 재사용할 수 있게 해주는 기능이다. 이를 통해 빌드 시간을 크게 단축할 수 있다.
캐시를 사용하면 빌드 시간 단축, 네트워크 대역폭 절약, 의존성 다운로드 최소화, 빌드 안정성 향상을 도모할 수 있다.
캐시 유형
1. actions/cache
GitHub에서 공식 제공하는 액션으로, 워크플로 내에서 특정 파일이나 디렉토리를 캐시하여 이후 실행 시 해당 데이터를 재사용함으로써 빌드 시간을 단축한다. actions/cache는 종속성 관리 및 빌드 최적화에 매우 유용하며, 적절한 키 관리와 설정으로 빌드 시간을 효과적으로 단축할 수 있다.
파일 시스템 레벨의 캐싱에 사용되며 주로 Node.js의 node_modules, Python의 venv 등 다양한 디렉토리나 파일을 캐시하는 데 사용된다.
- uses: actions/cache@v3
with:
path: ~/.npm
key: npm-$-$
동작 방식 1. 저장 단계:
- 사용자가 지정한 파일 경로나 디렉토리(path)를 기반으로 데이터를 압축하여 캐시한다.
- 캐시는 사용자가 정의한 키(key)를 사용하여 저장된다.
- 동일한 키로 캐시가 이미 존재하면 캐시가 업데이트되지 않는다.
2. 복원 단계:
- 동일한 키(key)를 사용하여 캐시를 복원한다.
- 키가 없거나 일치하지 않으면,
restore-keys
에 지정된 프리픽스 키를 사용하여 대체 캐시를 찾는다.
특징
- 캐시는 GitHub의 내부 캐시 저장소에 저장된다.
- 캐시는 같은 리포지토리 내에서만 공유 및 재사용할 수 있다.
- 각 리포지토리당 최대 10GB까지 캐시를 저장할 수 있다.
- 캐시가 오래되거나 공간이 부족하면 GitHub가 자동으로 제거한다.
- 캐시 키 및 무효화 전략을 사용자 정의해야 하므로, 적절한 키 관리가 필요하다.
2. GHA 캐시
Docker Buildx와 같은 도구에서 BuildKit의 캐시를 GitHub Actions의 내부 캐시 저장소에 저장하고 복원하는 기능을 제공한다.
# Dockerfile
RUN --mount=type=cache,target=/root/.npm \
npm install
# GitHub Actions workflow
- uses: docker/build-push-action@v5
with:
context: .
cache-from: type=gha
cache-to: type=gha,mode=max
GitHub Actions의 내부 캐시 서비스를 사용하여 BuildKit의 캐시 데이터를 저장하고 복원한다. 추가적인 설정 없이 GitHub 인프라를 통해 자동으로 관리된다.
캐시 저장 (cache-to)
type=gha
로 설정하면, BuildKit의 캐시 데이터가 GitHub Actions의 중앙 캐시 저장소로 전송되어 저장된다.- 이는 러너의 로컬 디스크에 저장되는 것이 아니기 때문에, 러너 세션이 종료되어도 캐시 데이터가 유지된다.
캐시 불러오기 (cache-from)
- 빌드 시, GitHub Actions의 중앙 캐시 저장소에서 캐시 데이터를 가져온다.
- 이 데이터는 워크플로우 내에서 BuildKit이 직접 사용한다.
특징
- type=gha 캐시는 동일한 리포지토리 내에서만 공유 및 재사용할 수 있다.
- 다른 리포지토리나 외부 프로젝트와는 캐시를 공유할 수 없다.
- GitHub Actions 환경에서 자동으로 인증되며, 추가적인 인증이나 구성 없이 바로 사용할 수 있다.
- 캐시는 GitHub Actions의 내부 인프라에 저장되며, 리포지토리당 10GB 제한이 적용된다.
- 캐시가 오래되거나 공간이 부족하면 GitHub가 자동으로 삭제할 수 있다.
3 레지스트리 캐시
레지스트리 캐시는 Docker 레지스트리를 사용한 캐싱 방식을 말한다.
- uses: docker/build-push-action@v5
with:
context: .
cache-from: type=registry,ref=user/app:cache
cache-to: type=registry,ref=user/app:cache,mode=max
특징
- Docker 레지스트리(예: Docker Hub, GCR, ECR)에 저장된다.
- 여러 저장소나 CI/CD 환경에서 공유 가능하다.
- 레지스트리 인증 필요하다.
- 레지스트리의 스토리지 제한과 비용 정책을 따른다.
- 캐시 이미지가 레지스트리에 별도로 저장되어 추가적인 관리가 필요하다.
예를 들어, 여러 저장소에서 공통으로 사용하는 베이스 이미지의 캐시를 공유하고 싶다면 레지스트리 캐시가 유용할 수 있다. 반면, 단일 저장소의 빌드 최적화만 필요하다면 GHA 캐시로 충분하다.
댓글남기기