반응형

이번 주 학습 주제는 Github Actions다.

이를 사용하여 CI/CD로 모든 소프트웨어 워크플로우를 자동화할 수 있다. 워크플로우란 코드를 빌드, 테스트, 배포 등의 작업들을 말한다.

Github Ations는 CI/CD의 종류 중 하나이다. 나 같은 경우 CI/CD 종류인 Jenkins, CircleCI 등을 한 번도 접해본 적이 없기 때문에 이번이 처음이었다.

먼저 CI와 CD의 정의에 대해서 요약해보자면,

-CI(Continuous Integration) 지속적인 통합은 빌드와 테스트까지의 과정을 자동화하는 것을 일컫는다. 이는 CI/CD파이프라인을 구현하는 첫 번째 단계이기도 하며, 여러 개발자들이 코드 작업 중 충돌을 막아줄 수 있고, 동일한 작업 기반을 제공해준다.

-CD는 배포를 자동화하는 과정으로, 두 가지의 의미가 담겨있다.

1.지속적인 서비스 제공(Continuous Delivery)

2.지속적인 배포(Continuous Deployment)

두 가지 모두 자동화 과정이지만 간단하게 설명하자면 1번의 CD는 프로덕션에 업데이트에 대한 수동 승인이 필요하고, 2번의 CD는 승인 없이 자동으로 프로덕션이 일어난다.

 

추가적으로 Github Actions에 설명을 덧붙이자면, 코드를 push했을 때 자동으로 빌드, 테스트, 배포만 하는 것이 아니다.

예를 들어, pull request를 날렸을 때, 그것을 보고 자동으로 체크하는 기능, 이슈 생성했을 경우, 누군가 pull request에 comment를 날렸을 때 등 어떤 event냐에 따라 그에 맞게 다양하게 Github Actions를 실행시켜 사용할 수 있다.

 

실습을 진행하기에 앞서 두 가지 확장 프로그램을 설치해야 한다.(github actions, yaml)

https://marketplace.visualstudio.com/items?itemName=cschleiden.vscode-github-actions

https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml

 

yaml이라는 것은 처음봐서 검색해서 찾아봤다. yaml은 구성파일 작성에 자주 사용되는 데이터 직렬화 언어이며, 기존의 json, xml파일과 같이 데이타 전송 파일로 생각하면된다. 실제 예시 코드를 비교해봤을 때 yaml이 가장 간단하게 구성되어 있는 것을 볼 수 있었다.

-실습

1.사용할 프로젝트 작업 폴더에 .github/workflows폴더 생성(폴더명은 중요하지 않고, 해당 폴더 안에 깃허브 액션과 관련된 소스 코드들이 다 들어간다. 다른 곳에서 하면 인식을 하지 못한다.)

2.해당 폴더 안에 main.yaml파일을 생성한다.

3.해당 파일 안에 필요한 코드를 작성한다.

해당 파일에 코드를 작성하기에 앞서 깃허브 액션은 크게 3가지 필수요소가 존재한다.(기본적인 워크플로우)

  • name: "aaaa" => 워크플로우의 이름이 들어간다.
  • on: push=> 이 깃허브액션 워크플로우는 코드가 깃허브로 푸쉬됐을 때 작동한다는 뜻이다. 즉, 작동하기 위한 트리거이벤트라고 생각하면 된다.
  • jobs: => on에 작성된 이벤트를 실행했을 때 어떤 일을 할 것인지 정의하는 곳이다.

-첫 번째 실습 코드

해당 코드에서 runs-on은 실행할 운영체제를 뜻하며 steps에 각 name은 순서에 상관없이 빌드가 먼저 잡히는 쪽이 먼저 실행된다.  (첫 번째가 실패해도 뒤를 강제로 실행시킬 수 있는 방법도 존재한다.)

오른쪽 사진을 보면 깃허브 저장소에 Actions 카테고리 log에 각 name과 echo문이 제대로 실행된 것을 확인할 수 있다. 원리는 코드가 push되는 순간 Actions가 작동한다.

하지만, 이러한 코드들은 지금 다 하드코딩되어 있다. 이것을 해결하려면 변수 값을 지정해주면 된다. on밑에도 가능하고, runs-on, shell밑을 통해서도 할 수 있다.

ex)
환경변수 설정과 scoping

 

왼쪽 사진에서 빨간 밑줄은 그은 곳이 각 환경변수를 설정해준 부분이다. 오른쪽 그림은 액션을 실행했을 때의 결과 화면인데, 이 실습은 scoping(범위)을 연습하는 것도 포함되어있다. workflow의 변수는 전역변수로 사용이 가능하다는 것을 보이며, 각각의 job이나 step은 독립적으로 작동하기 때문에 step level 변수 부분이 자신의 것만 로그에 출력되는 것을 볼 수 있다.

그리고 run 부분에서 배쉬쉘, 파워쉘, 깃허브 액션 문법 총 3가지가 다른 것을 확인할 수 있다. 즉, 환경변수를 저장, 접근하는 방법이 3가지라는 뜻이며, 이것을 자유자재로 활용할 수 있으면 굉장히 유용하다.

주의할 점으로는 scoping은 최소한으로 지정하는 게 좋다. 왜냐하면 원하지 않는 결과값이 나올 수 있기 때문이다.

환경변수를 런타임에서 만드는 방식

해당 실습은 환경변수를 런타임에서 만드는 방식이다. 밑줄친 $GITHUB_ENV는 환경변수가 지정된 파일경로를 뜻한다.

파워쉘 문법은 | Out-File FilePath $env:GITHUB_ENV Encoding utf-8 Append 이며, 파일 맨 마지막에 추가 시켜라는 뜻이다.

 
output test

아까 한 번 설명했듯이 각 job, name마다 독립적이라고 했고, 환경변수 설정과 scoping 실습 부분에서 보면 자신과 해당하는 부분만 로그에 출력하는 것을 볼 수 있었는데, 이 output실습은 각 steps마다 작성한 값을 아웃풋으로 빼는 방법이다.

"::set-output name-first_value::$first_value" 이 구문을 보면 해당 아웃풋 설정 이름에 넣을 원하는 변수(first_value)를 설정해주고, 아웃풋으로 뺄 때 사용할 변수명을 지정(::$first_value)해준다는 뜻이다. 이렇게 설정을하면, 다른 steps에서 빼올 수 있다.

ex)echo "first value: ${{ steps.first.outputs.first_value}}"

오른쪽 그림을 보면 Check output value 스텝에 다른 스텝의 변수값을 가져온 것을 확인할 수 있다.

 

output value mask

이 실습은 마스킹하는 방법이다. 예를 들어, apikey같은 것을 호출해서 가져와야할 때 민감한 정보니까 값을 숨겨야하는 방식이 필요할 때 사용하면 된다. 왼쪽 사진과 같이 ::add-mask::$first-value를 해주면 로그에만 값이 보이지 않게 해준다.

=> 오른쪽 그림과 같이 first value: ***로 표시가 된다.

github actions secrets

해당 실습은 직접 secret을 설정할 수 있다. 깃허브에서 settings => Actions 카테고리 => new repository secret을 들어가서 name값과 value값을 설정하면 된다.

왼쪽 사진에서 secrets.SECRET_1을 보면 SECRET_1은 name값을 뜻하므로, secrets개체 안에 있다는 뜻이다. value값에는 OCA World라는 단어를 넣어놨기 때문에 if문을 통해 해당 name에 있는 value값이 내가 설정한 value값과 동일할 경우 yes, 다를 경우 no를 출력하게 해준다. 오른쪽 사진을보면 동일하기 때문에 YES가 출력된 것을 볼 수 있다.(해당 if문은 파워쉘 문법으로, bash 문법도 따로 있다.)

Matrix

해당 실습은 matrix를 이용한 방법으로,runs on을가동할 운영체제는 하나밖에 사용못하는데 배열로 가능하게 한다. 이러한 방법이 필요한 이유는 예를 들어, 내가 만든 앱이 윈도우,,리눅스 등에서 다 돌아가야할 때가 있다. 또 다른 방법으로 first, second job 등 모두 runs-on을 다르게 해주는 방법이 있는데, 이것은 수정할 곳이 생기면 여러 군데에서 모두 수정해야하기 때문에 문제가 될 수 있다.(보통 우분투=>윈도우=>맥 순으로 빌드가 빨리 잡혀서 끝남)

=>왼쪽 사진에 나온 코드 matrix.os는 first job이 3번 실행된다는 뜻으로 os배열 순서 상관없이 실행이 된다.

Matrix2

nodejs버전 같은 것들도 지정할 수 있으며, os, nodejs를 합쳐 3x2 = 6번 실행이 되는 것을 볼 수 있다. 이러한 매트릭스를 잘 활용하면 작업을 좀 더 효과적으로 단순화시킬 수 있는 장점이 있다.

참고로 이러한 작업들은 오픈소스 프로젝트(public repository)로 진행되기 때문에 따로 요금을 청구하지 않는 장점이 있으나, 깃허브의 코파일럿 같은 곳에서 머신러닝 등으로 사용될 수 있다는 점을 유의해야 한다. 예를 들어, 회사에서 깃허브 엔터프라이즈(깃허브 액션포함)를 사용할 경우 회사에서 요금을 다 지불한다.(우리가 생각해야 할 부분은 아님)

추가적으로, 이러한 점을 악용하여 프로세스 해커들이 블록체인으로 깃허브 액션에 아무것도 없는데 돌려서 채굴하는 경우가 있다고 한다. 완벽하게 막을 방법은 없어서(선의로 사용하는 사람들은 사용해야하기 때문에) 요즘은 모니터링하여 알아서 걸러내고 있다고 한다. 

Conditions on Jobs

해당 실습은 각각의 운영체제마다 특화된 액션이 있을 때(맥 기반에서 nodejs빌드할 경우에는 되는데, 윈도우에서는 안될 경우) 그것을 각각 체크해서 conditions를 주는 방법이다. 이것은 job level에서 if문으로 condition을 주는 방법을 보여준다.

왼쪽 사진에서 첫 번째 if문을 보면 github.event_name == 'push' 즉, push가 실행되었을 때는 first-job을 실행하라는 뜻이고, 두 번째는 pr이 실행되었을 때는 second job을 실행하라는 뜻이다. 오른쪽 사진을 보면 push를 해서 Actions를 실행해보면 First Job만 실행된 것을 볼 수 있다.

Conditions on steps

해당 실습은 steps level에서 condition을 걸어주는 방법이다. 왼쪽 사진 밑에 if문을 보면 운영체제가 windows일 때만 해당 name이 실행된다. 그러므로 오른쪽 사진을 보면 OCA Power from windows-latest 2도 실행된 것을 볼 수 있다. 다른 운영체제는 저게 실행되지 않는다.

Actions Chaining

해당 실습은 체이닝하는 방법이다. needs라는 것을 사용하면 되고, 먼저 실행시키고 싶은 job을 넣어주면 된다. 예를 들어 needs: first-job 이라고 작성한다면 first-job이 빌드가 끝나야만 해당 job이 실행된다.

연습이라 체이닝이 간단하지만, 굉장히 대형 어플리케이션이라면 체이닝이 아주 많이 사용될 수 있다.

 

Events – push, pull_request
events(pull, pr 등)마다 실행되는 코드를 작성한다.  아마도 CI(?)부분을 작성한 코드인 듯 하다. 해당 코드를 실행 성공시키는 데에 있어 굉장히 많은 시간이 걸렸다. 해당 사진에는 안나와있지만 첫 번째 오류로,  MSBUILD : error MSB1009: Project file does not exist.를 직면했다. 해당 프로젝트 파일이 존재하지 않는다는 뜻이었고, dotnet restore ./api <=이렇게 닷넷을 restore하는 경로를 바꿔야되었다. 수많은 구글링 끝에 .csporj파일의 경로를 넣어주면 되었다.(이유는 아직 모름) 
하지만 이게 끝이 아니었고, 오류가 하나 더 있었다. The parameter "automatic_release_tag" was not set and this does not appear to be a GitHub tag event. (Event: refs/heads/master) 이 오류는 해당 문법 tag세팅이 제대로 되어있지 않다는 뜻이었다. 사진에도 나와있듯이 uses에는 다른 사람의 코드를 봐도 동일했고, 버전을 latest가 아닌 1.2.1, 1.1.1을 해도 상관이 없었다. 문제는 atomatic_release_tag라는 것을 따로 설정을 해주어야했다. 결국 설정을 해주고 액션을 성공적으로 했지만, 아직 의문점은 tag에 master가 아닌 latest를 하면 워크플로우가 끝도없이 계속 돌아갔다. 추후 알아볼 것.
 
추가적으로 secriets.GITHUB_TOKEN을 따로 만들어야하는 줄 알고 토큰을 생성했는데, 없어도 실행에 문제가 없는 것 같다. 그리고 해당 명으로 토큰이 생성되지도 않았는데 이러한 이유도 알아봐야겠다.( => 알아보니 workflow에서 사용할 고유 비밀을 자동으로 생성해주는 것이다. workflow 실행에서 인증할 때 사용된다. GITHUB_TOKEN은 Github 앱 설치 액세스 토큰이다.) : 깃허브 공식문서 출처: https://docs.github.com/en/actions/security-guides/automatic-token-authentication
 
events - workflow_dispatch를 이용한 github action 수동 트리거

해당 실습 workflow_dispatch는 POST Request를 이용해 event를 발생시킬 수 있는 event occurs다. 이것을 사용하면 2번 사진에서 manual버튼이 생겨 push같은 특정 상황에서 트리거되던 workflow를 수동으로 실행시킬 수 있다. 3번 사진이 실행 했을 때 성공한 워크플로우. 

첫 번째 사진은 push 등과 같이 on아래에 작성하며 내부 값 inputs로 메뉴얼에 테스트 시 사용할 값을 받을 수 있다.

 

workflow_call

workflow_call : 재사용 가능한 workflow. 입력 및 비밀을 사용. call_build job에는 CI를, call_release job에는 CD를.

즉, uses 를 사용해 재사용 가능한 workflow를 호출할 수 있다. with작업을 통해 명명된 입력을 호출된 workflow에 전달할 수 있으며, secrets의 inherit으로 비밀을 암시적으로 전달할 수 있다.

-정리를 하면, 다른 workflows를 사용하는 workflow(해당 왼쪽사진)를 호출자(caller) workflow라고 하며, 재사용 가능한 workflow는 호출된(called) workflow라고 한다. 그러므로 하나의 호출자에 여러 호출된 workflow를 사용할 수 있다.

 

multi-stage deployment

다단계 배포 : 이 기능은 배포 프로세스를 단계별로 구분하여 여러 프로젝트에 재사용할 수 있는 장점이 있다.

왼쪽 사진을 보면 같은 파일 cd.yaml을 참조하는 2개의 job이 있다. 실습 초중반에 사용했던 needs를 써서  먼저 실행될 job을 정해줄 수 있고, cd마다 각 환경(env)을 다르게 설정해준 것을 볼 수 있다.

env:DEV는 서버 개발 환경으로, 각 개발자들이 만든 소스 코드를 통합하여 테스트를 해볼 수 있는 환경이다.

env:PROD는 Production으로 운영 환경(live server)을 뜻한다. 실제 서비스를 위한 운영 환경이다.

 

  • 궁금한 점

1.on: 에서 push, pr이 아닌  branches: main을 사용할 경우 푸쉬는 되는데 actions에 뜨지 않는다. 그 이유는? 브랜치가 master였기 때문이다. master로 바꿔 사용하면 가능. 그렇다면 왜 on: ['push', 'pull_request'] 배열을 사용하지 않고 저런식으로 설정해주었나? tags는 무엇?

2.call_release job level에서 uses 경로가 workflows가 아닌 다른 경로였는데 일부러 다른 경로에서 사용되는지 실험해보려고한 것 인지??

3.dotnet restore, build, publish 등을 할 때 설정할 경로가 .api여서 oca.csproj의 경로로 바꾸니 워크플로우 실행이 성공되었는데, 이러한 경로가 올바른지?? ===> 멘토님의 파일에 api폴더가 있었어서 해당 폴더를 다운해주는 것이었다!

4.automatic_release_tag: "master" 를 작성하지 않으면 오류가 나는데 꼭 넣어야 하는지?? latest를 값으로 넣으면 왜 무한 반복 workflow가 실행되는지?? ===> 멘티님의 피드백을 듣고 해당 문제가 아닌 것 같아서 다시 latest로 수정해서 봤더니 잘 돌아갔다!

+ Recent posts