Profile picture

[Github Actions] Github Action의 유용한 작업 설정

JaehyoJJAng2023년 04월 14일

작업의 독립성

Github Actions에서 작업 설정을 할 때 염두해야하는 가장 중요한 부분은 바로 하나의 워크플로우 상에서 각각의 작업이 완전히 격리돤 환경에서 실행된다는 것이다.

쉽게 말해 2개의 작업을 실행하면 각 작업은 서로 CI 서버, 다른 컴퓨터에서 돌아간다는 뜻이다.

이러한 작업은 Github Actions에서 의도한 설계라고 볼 수 있다. 우선 이렇게 작업들이 완전히 격리되면 병렬 처리가 가능해져 성능 측면에서 유리해진다고 한다.

또한 하나의 워크플로우를 다양한 실행 환경에서 실행할 수 있게된다는 뜻이다.

즉, 일부 작업은 리눅스에서 실행하고 일부 작업은 윈도우즈 환경에서 돌릴 수 있는 것이다.

예를 들어보자, 다음과 같이 하나의 파일을 두 개의 작업을 통해서 쓰고 읽는 워크플로우를 생각해보자.

name: my Jobs
on:
  push:
    branches:
      - main
jobs:
  ddong1:
    name: write file
    runs-on: ubuntu-latest
    steps:
      - run: echo "hello I'm Ddong" > log.txt
  ddong2:
    name: read file
    runs-on: ubuntu-latest
    steps:
      - run: cat log.txt

위 YAML 파일이 어떻게 보이는가? 정상적으로 Actions가 빌드 될 것인가?

하지만 결과는 아래와 같다.

image

파일을 찾을 수 없다는 에러가 발생하였다.

ddong1 작업과 ddong2 작업은 엄밀히 애기해서 서로 다른 CI 서버에서 돌아가게 된다. 그러므로 첫 번째 작업인 ddong1에서 생성한 log.txt를 ddong2 작업이 접근하는 것은 불가능하다 이거다.


따라서 위의 경우에는 job을 따로 나누지 말고 하나의 작업에서 여러 단계(step)로 처리해야한다.

아래처럼 바꿔보자

name: my Jobs
on:
  push:
    branches:
      - main
jobs:
  ddong1:
    name: write file
    runs-on: ubuntu-latest
    steps:
      - run: echo "hello I'm Ddong" > log.txt
      - run: cat log.txt

작업 간에 실행 순서 제어하기

간단한 실습을 위해 작업 식별자(ID)를 콘솔에 출력하기 위한 동일한 작업 3개로 이루어진 워크플로우를 작성해보자


.github/workflows/jobs.yml

name: My Three jobs
on:
  push:
    branches:
      - main
jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - run: echo ${{ github.job }}
  job2:
    runs-on: ubuntu-latest
    steps:
      - run: echo ${{ github.job }}
  job3:
    runs-on: ubuntu-latest
    steps:
      - run: echo ${{ github.job }}

이제 Github의 Actions 탭에서 My Three jobs 워크플로우를 선택해보면 다음과 같이 3개의 작업이 병렬로 처리되는 것을 확인할 수 있다.

image


여기서 문제는 언제나 병렬 처리를 원하는 것은 아니다라는 것이다

이럴 때는 작업의 needs 속성을 사용해서 작업 간에 의존 관계를 설정해줄 수 있다.

예를 들어 job2가 실행되기 전에 job2이 먼저 완료되야 하고, job3가 실행되기 전에 job1job2가 먼저 완료되도록 실습 워크플로우를 수정해보자


.github/workflows/jobs.yml

name: My Three jobs
on:
  push:
    branches:
      - main
jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - run: echo ${{ github.job }}
  job2:
    runs-on: ubuntu-latest
    needs: job
    steps:
      - run: echo ${{ github.job }}
  job3:
    runs-on: ubuntu-latest
    needs: [job1,job2]
    steps:
      - run: echo ${{ github.job }}

특정 작업을 선택적으로 실행하기

간혹 각각의 작업 수준에서 추가적으로 실행 여부를 결정해야하는 경우가 있을 수도 있다. 그런 경우에는 해당 작업의 if 속성을 명시해주면 된다

예를 들면, 다음과 같이 3개의 작업으로 이루어진 워크플로우가 있다고 생각해보자

name: My Three jobs
on:
  push:
    branches:
      - main
jobs:
  echo:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Ddong!"
  echo-if:
    runs-on: ubuntu-latest
    if: github.ref_name == 'main'
    steps:
      - run: echo "Ddong, main!"
  skip-if:
    runs-on: ubuntu-latest
    if: ${{ !contains(github.event.head_commit.message,'skip ci') }}
    steps:
      - run: echo "Ddong, Skip CI!"
  1. 첫 번쨰 echo 작업은 무조건 실행된다
  2. 두 번쨰 echo-if 작업은 push 이벤트가 main 브랜치에서 발생했을 때만 실행된다
  3. 세 번쨰 skip-if 작업은 마지막 커밋 메시지에 skip ci가 포함되지 않았을 경우에만 실행된다

동일 작업을 다양한 실행 환경에서 실행하기

동일한 작업을 다양한 실행 환경에서 돌리고 싶을 때는 어떻게 해야할까?

보통 범용 라이브러리 프로젝트에서는 특정 운영체제에서만 발생하는 문제를 잡기 위해서 여러 운영체제에서 테스트를 돌리기도 한다.

예시로 간단하게 날짜를 출력하는 작업을 여러 운영체제에서 실행하고 싶다고 가정해보자.

가장 쉽게 생각해낼 수 있는 접근 방법을 사용해보자


.github/workflows/jobs.yml

name: my jobs
on: push
jobs:
  date1:
    runs-on: ubuntu-latest
    steps:
      - run: date
  date2:
    runs-on: windows-latest
    steps:
      - run: date
  date3:
    runs-on: macos-latest
    steps:
      - run: date

이 방법은 아마 의도한대로 작동은 할거다.

하지만 같은 내용이 중복되기 때문에 좋은 방법은 아닐것 같다.

위 작업을 해소할 수 있는 방법이 존재하는데 그건 작업의 strategy 속성의 matrix 옵션을 활용하면 이러한 중복없이 훨씬 더 간단하게,깔끔하게 목적 달성이 가능하다


.github/workflows/jobs.yml

name: my jobs
on: push
jobs:
  date:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
          - macos-latest
    steps:
      - run: date

image


Loading script...