CI/CD Github Actions

InSeok·2023년 1월 31일
0

TIL

목록 보기
46/51

**Github Actions**

  • Github가 공식적으로 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD 플랫폼
  • Github Actions는 Runner 위에서 실행이 되고, Runner는 가상 머신 위에서 실행이 됩니다.
  • Github에서 두 종류의 Runner를 제공합니다. Github-hosted Runner, Self-Hosted Runner(사용자가 직접 호스팅하는 환경)가 있습니다.
    • Azure의 가상 머신 위에서 돌아갑니다
      • 2-core CPU
      • 7GB of RAM memory
      • 14 GB of SSD disk space

비용

  • 공개 저장소 경우에는 무료이며, 비공개 저장소는 계정에 부여한 무료 사용량 이후에 과금이 됩니다. Workflow는 저장소마다 최대 20개까지 등록이 가능하며 Workflow의 Job이라는 단계마다 최대 6시간 동안 실행이 가능하며, 초과하면 자동으로 중지됩니다.공개 저장소 경우에는 무료입니다.
  • 레포지토리에서 Pull Requestpush같은 이벤트를 트리거로 GitHub 작업 워크플로(Workflow)를 구성할 수 있습니다.
  • 워크플로는 하나 이상의 작업이 실행되는 자동화 프로세스로, 각 작업은 자체 가상 머신 또는 컨테이너 내부에서 실행됩니다.
  • 워크플로는 .yml(혹은 .yaml) 파일에 의해 구성되며, 테스트, 배포 등 기능에 따라 여러개의 워크플로도 만들 수 있습니다.
  • 생성된 워크플로는 .github/workflows디렉토리 이하에 위치
  • 비공개 레포지토리의 경우 Github Actions가 작동할 때의 용량과 시간이 제한되어있으며 공개 레포지토리는 무료로 사용 가능

  • Github Actions는 설정 파일(.yml)에 따라 Github Repository에 특정 변동사항을 트리거로 작동됩니다
  • S3를 정적 웹 페이지 배포하는데에 사용하기도 하지만 ,이번 Github Actions를 통한 배포 자동화
    에서는 저장소로써 사용
  • Github Actions에서 빌드한 결과물이 압축되어 S3으로 전송되고, 버킷에 저장
  • workflow 설정시 제일 중요한건 actions/checkout 을 꼭 지정해야합니다.

하지 않는다면 해당 working-directory를 읽지 못하고 그냥 종료되기 때문에 꼭 적어야 합니다.

구성

Workflow

  • 레파지토리에 정의한 자동화된 프로세스 절차
  • 한개 이상의 job을 실행할 수 있는 자동화된 작업
  • Github에게 YAML파일로 정의한 자동화 동작을 전달하면, Github Actions는 해당 파일을 기반으로 그대로 실행시킨다.
  • .github/workflows디렉토리에 YAML 형태로 저장되며, event에 의해 실행 됩니다.

Event

  • workflow 실행을 발동시키는 특정한 활동
  • 깃허브에 소스코드를 푸시하면 발생하는 push event, pull request event, issue event 등 깃허브에서 발생하는 대부분의 작업을 event로 정의할 수 있습니다.
  • cron 으로 특정 시간대 반복
  • Repository Dispatch Webhook을 사용하면 Github 외부에서 발생한 이벤트에 의해서도 Workflow를 실행시킬 수 있습니다.

Jobs

  • 한가지 러너안에서 실행되는 여러가지 step들의 모음
  • 각각의 step들은 일종의 shell script 처럼 실행이 됩니다.
  • 작업마다 실행환경이 다르다
  • Step들은 순서에 따라 실행되며 Step 끼리 데이터들을 공유할 수 있습니다.
  • N개의 도커 이미지
    를 생성하여 하나의 작업을 수행시킵니다. 이것을 활용하여 서로다른 운영체제에서의 작업을 실행시킬 수 있습니다.
  • Job은 다른 Job에 의존관계를 가질 수 있으며, 병렬 실행도 가능합니다.
  • 서로다른 두 개의 작업은 선행관계를 지정할 수 있으며, 후행작업은 선행작업이 끝난 이후에야 실행될 수 있습니다. 만약 선행관계가 설정되지 않은 경우 병렬로 실행됩니다. 그리고 각각의 작업은 실패할 수 있으며, 선행작업이 실패한 경우 후행작업은 취소됩니다.

Steps

  • Job안에서 순차적으로 실행되는 프로세스 단위
  • 하나의 job에 여러 task를 넣을 수 있다.
  • step은 action이나 shell command로도 생성될 수 있다.
  • 하나의 job에 있는 step은 같은 runner에 의해 실행된다.
  • 하나의 Job 내에서 각각의 Step은 다양한 Task로 인해 생성된 데이터를 공유할 수 있습니다.

Actions

  • 재사용이 가능한workflow에서 가장 작은 개념으로 action은 독립된 실행할 명령
  • 하나의 작업 내에서 액션들은 항상 선행관계가 존재하며 선행액션이 실패한 경우 후행액션은 취소되고, 덧붙여서 해당 작업은 실패됩니다
  • 사용자가 직접 커스터마이징하거나, 깃허브 마켓플레이스를 통해 공용 Action 또는 다른 사람들이 만든 Action을 사용할 수 있습니다.
  1. 단일 스크립트 명령어
  2. 다중 스크립트 명령어
  3. 다른 사람이 배포한 액션 명령어

Runners

  • Job을 실행시키기 위한 애플리케이션
  • Github에 의해 호스팅 되고있는 서버이다. runner를 통해서 job을 실행시킨다고 생각하면 된다.

matrix build

  • Github Action에서는 여러 환경으로 동시에 빌드하게 할 수 있다
  • Github에서 호스팅하는 가상 환경 또는 직접 호스팅하는 가상 환경에서 실행 가능
  • 다양한 운영체제에서 다양한 노드 버전으로 돌려보는 것
jobs:
  build:
    runs-on: ubuntu-lastest

    strategy:
      matrix:
        os: [ubunutu-latest, windows-2016]
        node-version: [12.x, 14.x]
# 10분마다 실행 workflow
on:
  schedule:
    - cron: '*/10 * * * *'

# master, dev 브랜치에 push 된 경우에 실행
on:
  push:
    branches: [master, dev]

# master, dev 브랜치에 push 되었고,
# js파일의 변경이 있을 때에만 트리거,
# doc 디렉토리의 변경에는 트리거 하지 않게 하고싶은 경우
on:
  push:
    branches: [master, dev]
    paths:
      - "**.js"
    paths-ignore:
      - "doc/**"
  • jobs jobs에 등록된 job들은 기본적으로 병렬적으로 실행된다. job_id를 키값으로 하여 생성할 수 있다.
jobs:
  some-job-id: ...
  some-job-id-2: ...

**실행환경**

  • 깃허브 액션은 도커 컨테이너 위에서 작동한다
  • 구체적으로는 가상기계와 도커의 2단계로 나누어집니다. 즉 도커 이미지가 가상기계 위에서 수행되는 형태이므로 2개의 실행환경을 명시해야 합니다.
  • 가상기계 운영체제 - 필수
  • 깃허브 액션에서 제공하는 도커 이미지 (또는 이미지의 목록) - 선택

**Code Deploy**

  • Github Actions에서 배포 명령을 받은 Code Deploy는 S3에 저장되어있는 빌드 결과물을 EC2 인스턴스로 이동합니다.
  • 프로젝트 최상단에 위치한 appepec.yml설정 파일에 의해 쉘 스크립트 등 단계에 따라 특정 동작을 합니다.
  • Code Deploy가 S3 버킷에서 EC2 인스턴스로 프로젝트를 이동할 수 있도록 EC2 인스턴스에 Code Deploy Agent의 설치가 필요
  • Code Deploy에 의해 빌드 과정을 거친 프로젝트가 EC2 인스턴스로 전달되고, .yml (설정 파일)과 .sh(쉘 스크립트)에 의해 각 배포 결과를 로그로 저장하며 빌드 파일(.jar)을 실행

Github Actions 설정

  • 공개 리포지토리 설정
    • 레포지토리의 Owner는 개인 계정이어야 한다.
  • Github Actions탭에선 워크플로를 어떻게 생성할지 선택할 수 있습니다
  • [set up a workflow yourself] 를 클릭하여 빈 yml 설정파일로 워크플로를 설정할 수 있고, 추천 워크플로 구성을 선택하여 진행할 수 있습니다.
    • Gradle 빌드가 기본으로 설정되어있는 추천 구성을 사용하여 시작
  • gradle.yml 파일이 생성됨과 동시에 워크플로에 작성되어있는 트리거(main 브랜치에 push)로 인해 Github Actions가 실행됩니다.
  • 진행 / 성공 / 실패 여부는 레포지토리에서 최근 커밋 내역과 함께 표시
  • S3 버킷에 프로젝트 빌드한 결과물을 전송
  • Github Actions에서 워크플로를 실행하는 과정에서 액세스 키가 필요
    • 공개되면 보안 이슈가 발생
    • Github Secret을 이용해 액세스 키 값을 저장한 후 사용
    • 레포지토리의 Settings > Secrets > Actions 탭으로 이동한 후 [New repository secret] 버튼클릭
    • Name에는 변수 이름을, Value엔 변수의 값을 저장
    • IAM User를 생성할 때 볼 수 있는 액세스 키 ID 값과, 비밀 액세스 키 값을 각각 저장
  • 워크플로가 성공적으로 완료되면 S3 버킷에 압축파일이 전송된다.
  • 도커 이미지 명세
    • strategy:와 matrix:
      를 사용하면 간단하게 도커 이미지를 명세할 수 있습니다. 아래는 4개의 운영체제에서 각각 8, 10, 12
      버전의 노드를 이용한 실행환경을 생성합니다. 즉, 12개의 실행환경이 만들어집니다.

      jobs:
      build_and_test:
      runs-on: ubuntu-latest
      strategy:
      matrix:
      node-version: [8.x, 10.x, 12.x]
      container:
      [
      "ubuntu-latest",
      "centos-latest",
      "windows-latest",
      "macos-latest",
      ]
    • 커스텀 도커 이미지를 사용하고 싶다면 matrix:를 사용하면 안됩니다.

    • jobs:
      build_and_test:
      runs-on: ubuntu-latest
      strategy:
      container:
      image: node:10.16-jessie
      env:
      NODE_ENV: development
      ports:
    • 80
      volumes:

    • my_docker_volume:/volume_mount
      options: --cpus 1

선행관계 설정

후행작업에서 needs:를 사용하면 해당 작업들이 끝날때까지 대기합니다. 즉, 아래의 작업들은 1 → 2 → 3 순서로 수행됩니다.

#선행 관계 설정
jobs:
job1:
....
job2:
needs: job1
job3:
needs: [job1, job2]
# 병렬
...
jobs:
   job1:
   job2:
   job3:

환경변수 설정

**env**:
**ENV_KEY1**: xxx
**ENV_KEY2:**  xxx

선택적 실행 설정

  • if:에 넣어진 표현식의 결과가 참이 아니라면 수행되지 않습니다
jobs:
nofity_to_slack:
if: github.event_name == 'push'

스텝

각 작업의 steps:에 적으며, 새로운 스텝마다 -를 앞에 적어야 합니다.

steps:
- action1:
- action2:
...
- actionN:

단일 스크립트

  • run:
    에 실행할 스크립트를 적습니다.

다중 스크립트

run:에 |으로 시작하여 적고싶은 만큼 적습니다.

다른 사람이 배포한 스크립트

use:를 사용하면 됩니다. 필요한 경우 with:과 env:를 사용하여 추가적인 데이터를 보낼 수 있습니다.

jobs:
build_and_test:
...
steps:
- name: Execute test.
run: npm test
- name: Install dependencies.
            run: |
              npm cl 
              npm install
- use: 8398a7/action-slack@v3
            with:
                ...
            env:
                ...
name: Java CI with Gradle 

on:
  push:
    branches: [ "main" ]

permissions:
  contents: read

env:
  S3_BUCKET_NAME: be-0-name

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - 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

    # build한 후 프로젝트를 압축합니다.
    - name: Make zip file
      run: zip -r ./practice-deploy.zip .
      shell: bash

    # Access Key와 Secret Access Key를 통해 권한을 확인합니다.
    # 아래 코드에 Access Key와 Secret Key를 직접 작성하지 않습니다.
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} # 등록한 Github Secret이 자동으로 불려옵니다.
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # 등록한 Github Secret이 자동으로 불려옵니다.
        aws-region: ap-northeast-2

    # 압축한 프로젝트를 S3로 전송합니다.
    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./practice-deploy.zip s3://$S3_BUCKET_NAME/practice-deploy.zip

Checkout은 현재 상태의 소스코드를 가상의 컨테이너 안으로 Checkout해주는 역할

name

  • workflow의 name을 정의(공백 허용X)
  • 선택사항이며 깃허브 저장소의 깃허브 액션 탭에서 workflow의 이름을 보여 줍니다.

on

  • 해당 workflow를 실행시키는 이벤트를 정의
  • push 이벤트가 발생했을 때 workflow가 실행되도록 정의

branches

  • 감지할 브랜치, 태그 범위를 좁힐 수 있다.
on:	
	branches:
# 단일 브랜치
	- master      
# 다중 브랜치
      - [master, dev]

      # * 또는 ** 정규식 매칭
      # refs/heads/releases/ 하위의 브랜치에 적용됩니다.
      - 'releases/**'
# branches-ignore를 위처럼 사용하면 특정 브랜치를 제외할 수 있습니다.

#태그 범위 제한
	tags: 
          # 단일 태그
          - v1

          # 다중 태그
          - [v1, v2]

          # * 또는 ** 정규식 매칭
          # v1.1, v1.2 ... v1.9 까지 매칭됩니다.
          - v1.*
#크론식 
on:
  schedule:
    - cron:  '*/15 * * * *'

jobs

  • check-bats-version - job의 이름을 정의
  • runs-on : 어떤 호스트에서 실행될지 정의 - ubuntu 가상 머신에서 실행 되도록 정의

Steps

  • uses: actions/checkout@v2 - 해당 레포지토리를 pull 받고 이동하는 action 대부분의 workflow에서 사용
  • uses: actions/setup-node@v2 - 노드를 설치하는 action으로 가상머신안에는 대부분의 프로그래밍 언어가 설치되어 있지 않기 때문에 프로젝트 실행에 필요한 언어들을 action을 통해 다운
  • run: npm install -g bats - run 키워드를 통해 러너가 실행되는 서버에서 명령어를 실행

Secret 환경 변수 등록하기

  • 깃허브에서는 organization, Repository에 Secret 변수를 등록
  • 해당 변수를 workflow에서 사용하면 workflow의 로그에서는 환경변수로 나오며 해당 값을 노출 시키지 않습니다.
  • paths로 특정 패턴을 설정하여, 해당 패턴에 일치하는 파일이 변경되었을 때 워크플로가 실행되도록 설정할 수 있다.paths와 반대로paths-ignore로는 무시할 패턴을 설정할 수 있다. (paths 의 값의 앞에!를 붙여 paths-ignore와 같이 사용할 수도 있다.)

빌드파일 배포 및 실행

  • S3에 저장된 빌드 파일을 EC2 인스턴스로 전달하기 위해 CodeDeploy 설정
  • 개발자 도구 CodeDeploy의 배포 > 애플리케이션 생성
  • 컴퓨팅 플랫폼은 EC2/온프레미스를 선택 하고 이름 설정
  • 애플리케이션 이름의 경우 Github Actions 워크플로에 작성이 필요
  • 애플리케이션이 생성되면 해당 애플리케이션 내에 배포 그룹을 생성
  • 배포 그룹 이름 역시 Github Actions 워크플로에 작성이 필요
  • 애플리케이션과 구분할 수 있도록 규칙에 맞게 네이밍
  • 서비스 역할에는 IAM Role을 연결합니다.
  • EC2 인스턴스의 태그를 이용해 배포 그룹 환경을 구성
  • 최하단의 로드밸런서 설정에서 [로드 밸런싱 활성화] 체크를 해제
  • Code Deploy의 작동을 모아놓은 appspec.yml 파일을 설정
  • 최상위 디렉토리 구조에 appspec.yml 파일을 생성합니다
    • appspec.yml
version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ubuntu/action #왼쪽의 디렉토리 내에 배포가 진행됨
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

hooks:
  ApplicationStart:
    - location: scripts/deploy.sh #최상위 디렉토리에 scripts 폴더내의 쉘 스크립트가 실행됨
      timeout: 60
      runas: ubuntu
  • scripts 폴더를 생성한 후 디렉토리 내부에 deploy.sh 파일을 생성합니다
    • EC2 배포 진행 상황 별 로그를 기록하고 새로 배포된 빌드 파일을 실행한다.
#!/bin/bash# 빌드 파일의 이름이 콘텐츠와 다르다면 다음 줄의 .jar 파일 이름을 수정하시기 바랍니다.
BUILD_JAR=$(ls /home/ubuntu/action/build/libs/practice-githubAction-deploy-0.0.1-SNAPSHOT.jar)JAR_NAME=$(basename $BUILD_JAR)echo "> 현재 시간: $(date)" >> /home/ubuntu/action/deploy.log

echo "> build 파일명: $JAR_NAME" >> /home/ubuntu/action/deploy.log

echo "> build 파일 복사" >> /home/ubuntu/action/deploy.log
DEPLOY_PATH=/home/ubuntu/action/
cp $BUILD_JAR $DEPLOY_PATH

echo "> 현재 실행중인 애플리케이션 pid 확인" >> /home/ubuntu/action/deploy.log
CURRENT_PID=$(pgrep -f $JAR_NAME)if [ -z $CURRENT_PID ]
then
  echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ubuntu/action/deploy.log
else
  echo "> kill -9 $CURRENT_PID" >> /home/ubuntu/action/deploy.log
  sudo kill -9 $CURRENT_PID
  sleep 5
fi

DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo "> DEPLOY_JAR 배포"    >> /home/ubuntu/action/deploy.log
sudo nohup java -jar $DEPLOY_JAR >> /home/ubuntu/deploy.log2>/home/ubuntu/action/deploy_err.log &
  • 워크플로의 하단에 Code Deploy 배포 명령을 추가
  • gradle.yml에 아래 코드 추가
# CodeDeploy에게 배포 명령을 내립니다.
    - name: Code Deploy
      run: >
        aws deploy create-deployment --application-name be-0-name #code Deploy 애플리케이션 이름 
        --deployment-config-name CodeDeployDefault.AllAtOnce
        --deployment-group-name be-0-name-group #배포 그룹 이름
        --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=practice-deploy.zip
  • 배포에 성공하면 EC2 인스턴스에서 배포및 프로젝트 실행여부 확인가능
    • action 디렉토리 내에 빌드 파일이 이동했고, 실행중인 프로세스 검색 결과 해당 빌드 파일이 실행중입니다.
  • 배포를 마치면 action 디렉토리 내에 두 개의 로그 파일이 생성됩니다.
    • EC2 인스턴스에서의 빌드 과정은 deploy.log 파일에,
    • 빌드 파일을 정상적으로 실행하지 못한다면 deploy_err.log 파일에 기록됩니다.
    • 에디터 혹은 cat 명령어로 로그를 확인할 수 있습니다.

AWS 콘솔에서 리소스가 변화된 경우에는(e.g. 파라미터 스토어 변수값 변경, Code Deploy 설정 변경 등) 코드의 변화가 아니기 때문에 파이프라인이나 Github Actions가 자동으로 실행되지 않습니다.

1. 파이프라인 다시실행하기 : 변경 사항 릴리스 버튼 클릭
2. Github Actions 다시 실행하기 : 가장 최근에 실행된 workflow 선택
3. Re-run all jobs 버튼을 클릭하여 workflow 재실행

profile
백엔드 개발자

0개의 댓글