[CI/CD] GithubActions 적용기
개요
멋쟁이사자처럼 개인 프로젝트 진행에 GitLab을 사용하여 CI/CD를 구축했다. CI/CD를 구축하는 데는 전혀 문제가 없었지만, GitLab 무료 버전에는 Reviewers, Assignees를 한 명 밖에 등록하지 못하고 PR rule도 깃랩에서는 유료라고 한다. GitHub에서는 무료로 가능한데…
그래서 GitHub의 GithubActions으로 이주하기 위해 내가 필요한 기능들을 정리해 보았다.
필요한 기능
깃랩에서 깃액션으로 넘어가기 위해서는 아래와 같은 기능들이 필요했다.
- Gradle 빌드
- Docker 이미지 빌드
- Container Registry (Docker 이미지 Push & Pull)
깃랩의 경우 Container Registry에 도커 이미지를 push 하고 ec2에서 pull 받아와 컨테이너를 실행시켰다.
깃액션에서는 package라는 이름으로 같은 기능을 지원한다.
사용방법
1. Workflows 작성
워크플로우를 구성할 리포지토리에서 Actions 탭으로 들어간다.
아직 워크플로우를 작성하기 전이라면 위와 같은 화면을 마주친다.
현재 리포지토리에 올라와있는 파일을 참고해서 기본적인 템플릿을 제안해 준다.
만약, 스크립트를 직접 작성한다면 set up a workflow yourself를 클릭하고 작성하면 되고 기본 템플릿을 참고하여 작성해도 된다.
워크플로우 스크립트 파일은 .github/workflows 하위에 작성해야 한다.
파일이름은 무관하고 yaml파일[*.yml]로 작성하면 된다.
2. 기본문법
name:
워크플로우의 이름. 리포지토리의 Actions탭에 들어왔을 때 왼쪽 목록에 보이는 이름이다.
on:
워크플로우가 동작되는 특정 이벤트를 정의한다.
uses:
이 step에서 특정 actions을 사용함을 나타낸다.
라이브러리를 추가해 사용한다고 이해하면 될 것 같다.
run:
echo, mkdir 등의 커맨드를 실행시키기 위한 스크립트이다.
3. 스크립트
워크플로우 이름, 트리거 이벤트 설정
name: CI PipeLine
on:
pull_request:
branches:
- main
workflow_dispatch:
env:
REGISTRY: ghcr.io
워크플로우 이름은 CI PipeLine으로 지정했다.
워크플로우 동작 이벤트 조건은 main 브랜치에 pr이 발생하거나 수동으로 동작할 수 있도록 설정했다.
더 많은 조건들은 아래 공식문서에서 찾아볼 수 있다.
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
Workflow syntax for GitHub Actions - GitHub Docs
About YAML syntax for workflows Workflow files use YAML syntax, and must have either a .yml or .yaml file extension. If you're new to YAML and want to learn more, see "Learn YAML in Y minutes." You must store workflow files in the .github/workflows directo
docs.github.com
env는 환경변수를 설정하는 부분으로 ${{ env.REGISTRY }} 로 값을 가져와 사용할 수 있다.
jobs:
gradle-build: # Gradle 빌드
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: build
- name: Upload Gradle Build Artifact
uses: actions/upload-artifact@v3.1.2
with:
name: build-artifact
path: build/libs/*-SNAPSHOT.jar
여기서 주의 깊게 볼 부분은 Upload Gradle Build Artifact이다.
job 사이에는 파일을 공유하지 못하기 때문에 빌드하고 나온 jar파일을 업로드해 주고 다른 job에서 다운로드해줘야 한다.
with.name 옵션에는 다운로드할 때 어떤 artifact를 다운로드할지 지칭하는 변수로 생각하면 이해가 쉬울 것 같다.
path는 말 그대로 어떤 파일을 업로드할 것이냐를 나타낸다. 파일뿐만 아니라 폴더로도 지정할 수 있고 와일드카드도 사용할 수 있다.
https://github.com/marketplace/actions/upload-a-build-artifact
Upload a Build Artifact - GitHub Marketplace
Upload a build artifact that can be used by subsequent workflow steps
github.com
docker-push:
needs: gradle-build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs 옵션이 없다면 job이 모두 동시에 작동한다. 하지만 docker-push job은 gradle-build job이 완료되어야만 하기 때문에 needs 옵션에 gradle-build를 추가해 주었다.
워크플로우 안에서 github token이 기본적으로 생성되고 환경변수 GITHUB_TOKEN으로 사용할 수 있기 때문에 직접 생성한 access token을 직접 환경변수에 등록하고 사용할 필요가 없다.
이때 github token의 권한을 permissions 옵션 설정해 줄 수 있다.
가장 높은 레벨에 설정 시 워크플로우안에 모든 job들에 적용된다.
특정 job 안에 작성하면 그 job에만 적용할 수 도 있다.
모든 권한을 열어주면 가장 편하지만 보안이 약해지기 때문에 최소한의 권한을 찾아보고자 공식문서를 참고했다.
GitHub Package를 사용하기 위한 최소 권한은 content read, package write이기 때문에 이에 맞게 설정해 주었다.
steps:
- uses: actions/checkout@v3
- name: Docker Login
uses: docker/login-action@v1.12.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download Gradle Build Artifact
uses: actions/download-artifact@v3
with:
name: build-artifact
- name: Docker Build
run: docker build -t ${{ env.REGISTRY }}/${{ github.repository }} .
- name: Docker push
run: docker push ${{ env.REGISTRY }}/${{ github.repository }}
Docker image를 빌드하고 GitHub Package에 푸시하기 위해 GitHub Token을 활용해서 Docker 로그인을 한다.
그리고 도커 이미지를 빌드하고 푸시했다.
도커 빌드, 푸시를 한 번에 할 수 있는 Actions도 있었지만 사용방법을 터득하지 못해 직접 명령어를 작성해서 진행했다.
Build and push Docker images : https://github.com/marketplace/actions/build-and-push-docker-images
Build and push Docker images - GitHub Marketplace
Build and push Docker images with Buildx
github.com
마무리
내가 필요한 기능들이 아주 기초적인 부분들이었기 때문에 성공적으로 이주할 수 있었다.
도커 빌드, 푸시를 한 번에 진행해 주는 액션을 사용하지 못했다는 것이 아쉬웠고, 다음에는 AWS에서 컨테이너 소프트웨어를 배포하고 공유할 수 있는 ECR(Elastic Container Registry)도 한 번 사용해 봐야겠다.
전체 스크립트
name: CI PipeLine
on:
pull_request:
branches:
- main
workflow_dispatch:
env:
REGISTRY: ghcr.io
jobs:
gradle-build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: build
- name: Upload Gradle Build Artifact
uses: actions/upload-artifact@v3.1.2
with:
name: build-artifact
path: build/libs/*-SNAPSHOT.jar
docker-push:
needs: gradle-build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- name: Docker Login
uses: docker/login-action@v1.12.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download Gradle Build Artifact
uses: actions/download-artifact@v3
with:
name: build-artifact
- name: Docker Build
run: docker build -t ${{ env.REGISTRY }}/${{ github.repository }} .
- name: Docker push
run: docker push ${{ env.REGISTRY }}/${{ github.repository }}