GitHub Actions는 무엇이고
CI/CD 파이프라인을 어떻게 구현할까?
GitHub Actions
--
GitHub에서는 파이프라인을 구성하고 자동화할 수 있는 GitHub Actions라는 도구를 제공해 준다.
GitHub Actions를 사용하면
GitHub의 소스 코드를 Push했을 때 자동으로 CI / CD 파이프라인을 실행시켜 준다.
CI 파이프라인을 (빌드단계) 수행하기 위해서는 빌드를 하기 위해 컴퓨터가 필요하다.
(도커 이미지 빌드를 하려면 도커가 설치된 컴퓨터가 필요)
하지만 GitHub Actions를 사용하면
GitHub가 빌드용 서버를 임시로 빌려주기 때문에
GitHub가 제공하는 서버에서 파이프라인을 실행할 수 있다.
GitHub Actions 무료 버전은
하단에 500MB의 공간과 2,000분을 사용할 수 있다.
500MB의 공간은
소스코드를 담는 것이 아닌 빌드 결과의 아티팩트와 테스트 결과 및 로그를 담는 공간이다.
(러너로 체크아웃은 포함 x / 데이터를 업로드, 다운로드하는 용량 (ex 도커허브에 이미지 업로드 등))
2,000분은
워크플로우가 실행되는 동안의 시간을 의미한다.
[ -- GitHub의 공개 Repository는 무제한 무료이며 위에 작성한 무료 버전은 비공개 Repository 기준이다. -- ]
--
GitHub Actions에서 사용되는 용어
--
- 러너 : 파이프라인이 실제로 실행되는 서버
- 워크플로우 : 파이프라인의 실제 작업
- 트리거 : 워크플로우를 자동으로 실행시켜 주는 조건
워크플로우는 파이프라인과 동일한 개념이라고 생각하면 된다.
하나의 워크플로우는
여러 개의 작업(Jobs)으로 구성되어 있으며
하나의 작업(Job)은 여러 개의 스텝(Steps)으로 구성되어 있다.
작업들(Jobs)은 워크플로우 파일 안에서 코드 형태로 작성되어 있다.
--
워크플로우 파일 작성 방법
--
워크플로우 파일은 yaml 파일이다.
워크플로우는 크게 3가지 파트로 구성되어 있다.
- name : 파일이 만드는 워크플로우의 이름을 지정
- on : 워크플로우가 실행되는 조건인 트리거를 지정
- jobs : 실제 워크플로우의 동작 내용을 작성
러너는 특별한 경우가 아니라면 최신 버전의 ubuntu를 지정하는 것을 권장한다. (ubuntu-latest)
작업 이름은 사용자가 원하는 명칭으로 지정한다.
트리거 지정 방법
트리거를 지정할 때
스케쥴러를 이용하여 시간을 기준으로 트리거를 발생하는 방법(schedule)과
소스코드의 변경사항이 push 되었을 때 트리거를 발생하는 방법(push)이 존재한다.
- branches : 특정 브랜치에 대한 push가 일어날 때마다 트리거 발생
- paths : 특정 디렉터리에 대한 변경사항이 일어날 때만 트리거 발생
- tags : 특정 태그가 붙은 커밋이 추가될 때만 트리거 발생
원하는 트리거에 맞게 "branches", "paths", "tags" 를 조합하여 트리거를 지정해 주면 된다.
스텝(steps) 지정 방법
모든 스탭(작업)은 러너에서 실행된다.
러너는 GitHub에서 제공하는 서버를 임시로 빌려오는 서버(PC)이기 때문에
많이 사용되는 Docker나 Git 같은 도구만 설치되어 있다.
스텝(step)에서 사용하는 필드 종류
- name : 해당 step의 이름 (선택사항)
- uses : GitHub Actions 또는 GitHub Actions 커뮤니티에서 제공하는 액션(동작)
- with : 해당 액션(동작)에 전달할 인수(변수, 값)
- run : 터미널(셀)에서 실행할 명령어
- env : 환경 변수 정의
step0
현재 워크플로우 파일이 존재하고 있는 GitHub reposigory에 존재하는 소스코드를
러너에 다운로드하여서 저장한다.
step1
도커에서 제공하는 고급 빌드 도구를 러너에 설치한다.
step2
러너 내부에서 도커에 로그인한다.
이때 도커 로그인 정보를 직접 입력해도 되지만
현재 워크플로우 파일은 GitHub에 업로드되어야 하기 때문에 개인정보가 유출될 위험이 있다.
이를 방지하기 위해 GitHub Actions에서는 Secrets이라는 기능을 제공한다.
step3
러너에 다운로드한 소스코드와 도커를 이용해서
이미지 빌드 후 도커허브에 업로드한다.
이렇게 결과적으로 CI 파이프라인이 구현되었다.
예시 CI 파이프라인 워크플로우 파일
platforms 필드에는 CPU 아키텍처를 정의해야 한다. (운영체제 유형)
리눅스 OS에서 빌드하는 이미지는 기본적으로 linux/amd64 로 되어 있는 이미지 실행이 가능하고
mac OS에서는 linux/arm64로 되어 있는 이미지만 실행할 수 있다.
그래서 환경에서든 이미지 빌드를 할 수 있도록 둘 다 명시해 준다.
+
윈도우같은 경우에는 도커 데스크탑으로 도커를 실행하면
실제로는 리눅스 가상환경으로 도커가 실행되기 때문에
윈도우의 도커 데스크탑에서 이미지를 실행할 때는 linux/amd64를 사용한다.
예시 CD 파이프라인 워크플로우
on:
push:
에서 트리거 발생 조건을 정의할 때
여러 개를 정의해도 그중에 하나만 동작하게 되면 트리거 발생
script: 필드에서 앞에 "|" 기호를 사용했는데
"|" (파이프) 문자는 YAML 파일에서 멀티라인 문자열을 나타내기 위해 사용된다.
즉, 여러 줄로 구성되어 있는 텍스트를 한 번에 정의할 때 유용하다.
(엔터(\n) 개행 문자를 포함)
예시
script: |
test 1
test 2
test 3
-> "line 1\nline 2\nline 3\n"
">" 문자는 개행 문자를 공백으로 변환해 준다.
예시
script: >
test 1
test 2
test 3
-> "line 1 line 2 line 3"
${{ github.sha }} 는 GitHub Actions에서 기본으로 제공해 주는 변수 (내장 변수)로
현재 워크플로우가 실행되는 커밋의 SHA-1 해시 값을 나타내서
커밋의 해시 값 (ex d6fde92930d4715a2b49857d24b940956b26d2d3)을 제공해 준다.
즉, 이미지 태그에 1:0:0 이런 식의 태그를 작성하지 않고
Git 커밋 해시 값을 가지고 태그를 지정해 주어서
해당 이미지가 어느 커밋 때 빌드되었는지 구분하기 편하게 구성했다.
docker stop rm-db || true
docker rm rm-db || true
"rm-db"라는 컨테이너를 정지하고 지우는 명령어다.
"||"는 쉘 스크립트에서 해당 명령어가 실패했을 때 스크립트의 실행을 이어서 계속 동작할지 여부를 정의한다.
"|| true"는 해당 명령어가 실패하더라도 명령의 종료 상태를 0으로 설정하여 스크립트가 중단되지 않도록 한다.
즉, 해당 명령이 실패해도 스크립트는 계속 실행된다.
위 예시 CI/CD 파이프라인 워크플로우는 파일을 따로 구성했지만
하나의 워크플로우 파일에 CI와 CD 파이프라인을 모두 구현할 수 있다.
이때 CI 파이프라인을 먼저 수행 후 CD 파이프라인을 수행하도록 해야 하는데
작업(jobs)의 순서를 지정하는 방법이 필요하다.
jobs:
deploy:
runs-on: ubuntu-latest
needs: build-and-push
이렇게 needs: 필드에 특정 jobs 이름을 지정해 주면
지정한 jobs 작업이 완료되면 현재 jobs를 동작시킨다.
즉, deploy 작업은 build-and-push 작업이 먼저 완료 후 동작하게 된다.
각 필요 변수 값 설명
- username: ${{ secrets.DOCKERHUB_USERNAME }}
Docker Hub 계정의 사용자 이름 - password: ${{ secrets.DOCKERHUB_TOKEN }}
Docker Hub 계정의 액세스 토큰 or 비밀번호 - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS IAM 사용자의 엑세스 키 - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS IAM 사용자의 비밀 엑세스 키 - host: ${{ secrets.EC2_HOST }}
SSH를 통해 접속할 EC2 인스턴스의 공용 IP 주소 or 호스트 이름 - username: ${{ secrets.EC2_USERNAME }}
EC2 인스턴스에 SSH로 접속할 때 사용하는 사용자 이름
(일반적으로 Amazon Linux AMI일 경우 "ec2-user", Ubuntu일 경우 "ubuntu") - key: ${{ secrets.EC2_SSH_KEY }}
EC2 인스턴스에 SSH로 접속할 때 사용하는 개인 키
(인스턴스에 사용한 키 페어의 내용 [.pem 파일의 내용])
--
GitHub Actions에서 제공하는 Secrets 기능
--
위 그림처럼
워크플로우 파일에 개인정보를 직접 작성하면 유출 위험이 존재하기 때문에
이를 방지하기 위해 GitHub Actions에서 제공하는 Secrets 기능을 사용하는 것이 좋다.
GitHub Secrets에 특정 변수를 저장하고
워크플로우 파일에서는 "${{ ... }}"로 GitHub Secrets에 저장된 시크릿 키값을 지정하면
해당 값을 Secrets에서 값을 불러와서 사용할 수 있다.
GitHub에서 Secrets 값 정의하기
1. 현재 GitHub repository -> Settings -> Actions -> New repository secret 버튼 클릭
2. secret 값 정의하기
GitHub Actions의 Secrets은
특정 repository에 고유한 secrets다.
즉, "Real_Momnet"라는 repository에서 정의한 secrets 값은
다른 repository에서 사용이 불가능하다.
+ 도커 토큰 발급받는 방법
1. My Account 이동
2. Security -> New Access Token 버튼 클릭
3. 새로 발급할 토큰의 정보를 작성 후 생성한다.
Access Token Description에는 해당 토큰명을 작성
Access permissions에는 해당 토큰의 권한을 작성
보통 Read, Write, Delete 인 기본값을 사용
4. 토큰 발급 완료
--
워크플로우 파일 위치
--
워크플로우 파일은
".github/workflows"라는 디렉토리 안에 워크플로우 파일을 담아야 한다.
GitHub에서 워크플로우를 실행하게 되면
".github/workflows" 디렉터리에 존재하는 워크플로우 파일들을 동작시키게 된다.
이제 트리거에 정의한 이벤트가 발생하면 자동으로 워크플로우가 동작하게 된다.
--
참고 및 출처