Github Actions Matrix 사용법과 예제


환경

  • Github Actions


배경


사용법

  • 문서에 나온대로 아래와 같은 방법으로 사용할 수 있다.
  • jobs.<job_id>.strategy.matrix에 행렬의 변수와 값을 정의해주면 된다.
  • 아래 예제의 경우 version에 해당하는 값들이 [10, 12, 14]이며 os도 마찬가지이다.
jobs:
  example_matrix:
    strategy:
      matrix:
        version: [10, 12, 14]
        os: [ubuntu-latest, windows-latest]


예시

Jekyll 빌드를 여러 OS에서 실행하고 싶은 경우 아래처럼 작성할 수 있다. 실제로 이 블로그에 사용하는 workflow 예제다.

코드

  • 문서에 나온대로 적용했으며 다른 부분들도 포함되어 있지만 jobs에 있는 build job의 strategy를 보면된다.
  • os: [ubuntu-22.04, ubuntu-20.04, macos-latest]를 통해 사용할 os를 목록으로 정의했고 runs-on: ${{ matrix.os }}에서 해당 os들을 사용하도록 작성했다.
  • jobs.<job_id>.strategy.fail-fast 설정이 true이거나 해당 식이 true로 평가되면, matrix의 어떤 job이라도 실패할 경우 matrix에서 진행 중인 job과 대기 중인 job을 모두 취소한다고 문서에 나와 있다. 여러개의 job에서 하나가 실패하더라도 나머지 job들은 계속 진행하도록 하고 싶어서 false로 적용했다.
name: Jekyll Build CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:
    inputs:
      ruby-version:
        required: true
        type: string
        default: "3.2.2"
        
jobs:
  build:
    name: jekyll build
    strategy:
      matrix:
        os: [ubuntu-22.04, ubuntu-20.04, macos-latest]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Setup Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ github.event.inputs.ruby-version }}
    - name: Install Bundler
      run: |
        gem install bundler
    - name: Install Dependencies
      run: |
        bundle install
    - name: Build Jekyll Site
      run: |
        bundle exec jekyll build

결과

  • 실행한 결과를 이미지로 보여주는게 이해하기 편해 이미지를 첨부한다


참고자료

Usage and example of github actions matrix


Environment and Prerequisite

  • Github Actions


Background


Usage

  • According to the document, you can use it as shown below.
  • jobs.<job_id>.strategy.matrix is where you define the variables and values for the matrix.
  • In the example below, the values corresponding to version are [10, 12, 14] and the same applies to os.
jobs:
  example_matrix:
    strategy:
      matrix:
        version: [10, 12, 14]
        os: [ubuntu-latest, windows-latest]


Example

If you want to run Jekyll builds on multiple OS, you can write it as shown below. This is a workflow example actually used in this blog.

Code

  • This include other steps but just look on strategy in jobs’s build.
  • Define os on statement os: [ubuntu-22.04, ubuntu-20.04, macos-latest] and use it on runs-on: ${{ matrix.os }}.
  • The documentation states that if jobs.<job_id>.strategy.fail-fast is set to true or its expression evaluates to true, GitHub will cancel all in-progress and queued jobs in the matrix if any job in the matrix fails. To allow remaining jobs to continue even if one job fails, I’ve set this to false.
name: Jekyll Build CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:
    inputs:
      ruby-version:
        required: true
        type: string
        default: "3.2.2"
        
jobs:
  build:
    name: jekyll build
    strategy:
      matrix:
        os: [ubuntu-22.04, ubuntu-20.04, macos-latest]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Setup Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ github.event.inputs.ruby-version }}
    - name: Install Bundler
      run: |
        gem install bundler
    - name: Install Dependencies
      run: |
        bundle install
    - name: Build Jekyll Site
      run: |
        bundle exec jekyll build

Result

  • To make it easier to understand, I’m attaching an image that shows the results of the execution.


Reference

PyYAML 사용 시 키 이름 “on”이 True로 바뀌는 사례


환경

  • Github Actions
  • Python
  • PyYAML


배경

  • Github Actions Workflow 파일을 동적으로 Python을 통해 수정하는데 YAML 파일 파싱시 on이라는 키가 True로 바뀌는 상황이 발생해서 정리.


예시

아래와 같이 Python에서 yaml을 통해 파일을 읽어서 출력하면 on이 사라지고 True가 들어가 있는걸 볼 수 있다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

결과

{'name': 'Workflow Complete Event Test', True: {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


이유

검색해보니 PyYAML의 경우 YAML 1.1 버전을 지원하고 있으며 1.1 버전의경우 "on"은 boolean으로 간주되며 그렇기에 True로 바뀌는게 맞다고 한다. YAML 1.2를 아직 지원하지 않다고 하기에 의도된 동작이며 방법을 따로 찾아야한다.


해결 방법

여러가지 방식이 있다.

  • Loader의 코드를 변경해서 설정
  • Key에 따옴표("" 또는 '')를 사용
  • 다른 Python 모듈 사용

따옴표가 눈에 띄어서 없애고 싶은 마음이 들지만 두번째 방식이 가장 간단해보이고 기존 yaml 모듈 변경이 없어서 해당 방식을 적용했다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

'on':
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

결과

{'name': 'Workflow Complete Event Test', 'on': {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


기타

True를 키 이름으로 사용

  • 키가 True로 잡히는데 Python에서 True를 사용하니 접근이 가능했다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content[True])

결과

{'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}


YAML 파일 생성 시 생성되는 키 이름

  • 여기서 yaml.dump를 통해 파일을 만들면 키는 true로 들어간다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

with open('example.yaml', 'w') as file:
    yaml.dump(yaml_content, file)

결과

$ cat example.yaml
name: Workflow Complete Event Test
true:
  workflow_run:
    types:
    - completed
    workflows:
    - Push Main Branch
key:
  true: test


참고자료

Case of converting key name “on” to True when using PyYAML


Environment and Prerequisite

  • Github Actions
  • Python
  • PyYAML


Background

  • on key was automatically changed to True when modifying Github Actions Workflow file dynmically using Python.


Example

When reading and outputting a file using yaml in Python as shown below, you’ll notice that on is replaced with True.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

Result

{'name': 'Workflow Complete Event Test', True: {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


Reason

According to searching, PyYAML supports YAML 1.1 and in version 1.1, "on" is considered as a boolean value which is why it gets converted to True. Since YAML 1.2 is not yet supported, this behavior is intentional, and you will need to find an alternative solution.


Solution

There are many ways to solve it.

  • Modify Loader code
  • Use quote("" or '') to key
  • Use another Python module

Although I was tempted to remove the quotation marks, the second method seemed the simplest and didn’t require changes to the existing YAML module, so I applied that approach.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

'on':
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

Result

{'name': 'Workflow Complete Event Test', 'on': {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


Others

Use True as key name

  • Key is set to True and it can be accessed via True in Python.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content[True])

Result

{'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}


Key name after YAML file created

  • Key is set to true if make file via yaml.dump.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

with open('example.yaml', 'w') as file:
    yaml.dump(yaml_content, file)

Result

$ cat example.yaml
name: Workflow Complete Event Test
true:
  workflow_run:
    types:
    - completed
    workflows:
    - Push Main Branch
key:
  true: test


Reference

DynamoDB Throttling 발생 사례 정리


환경

  • AWS
  • DynamoDB


배경

  • DynamoDB 프로비저닝된 모드에서 Auto Scaling 사용 시 Throttling이 발생해서 이유를 조사해서 정리함.


이슈

  • DynamoDB 프로비저닝된 모드에서 Auto Scaling 설정을 사용했음에도 Throttling이 발생함.


이유

DynamoDB 관련 개념과 용어 정리

  • 내용을 정리하기 앞서서 몇 가지 개념과 용어가 새로 나와서 정리한다.

온디맨드 모드와 프로비저닝된 모드

  • 온디맨드 모드: 용량 계획 없이 초당 수백만 개의 요청을 처리할 수 있는 서버리스 청구 옵션으로 사용한만큼 지불하는 방식으로 보면 된다.
  • 프로비저닝된 모드: 애플리케이션에 필요한 초당 읽기 및 쓰기 횟수를 지정할 수 있으며 Auto Scaling을 사용하여 트래픽 변경에 따라 테이블의 프로비저닝된 용량을 자동으로 조정할 수 있다.
  • 관련 링크: https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/capacity-mode.html

WCU와 RCU

  • 프로비저닝된 용량 모드에서 애플리케이션에 필요한 초당 데이터 읽기 및 쓰기 단위이다.
  • WCU: 테이블에서 데이터를 쓰는 각 API 호출이 쓰기 요청이다.
  • RCU: 테이블에서 데이터를 읽는 각 API 호출이 읽기 요청이다.
  • 각 WCU 및 RCU에 대한 용량은 공식 문서에 나와있다.
  • 관련 링크: https://aws.amazon.com/ko/dynamodb/pricing/provisioned/

Auto Scaling

  • 위에 설명한 용량 단위의 최솟값 및 최댓값 그리고 목표 사용률 설정할 수 있다.
  • 목표 사용률에 따라 최솟값 및 최댓값 사이에서 용량을 조절한다. 간단하게 예를 들어 목표 사용률이 70% 이고 700 RCU를 사용한다면 1000 RCU를 프로비저닝 해둔다. 아래 정리하겠지만 남은 300 RCU를 패딩(Padding)이라 한다.
  • 관련 링크: https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/AutoScaling.html

패딩(Padding), 버스트 용량 그리고 Spike


Spike 발생 시 Throttling 발생 이유

  • 프로비저닝된 용량을 훨씬 넘어서는 Spike(갑작스러운 데이터 요청) 발생 시 아래와 같은 순서로 요청이 처리될 수 있다고 한다.
목표 사용률 이하 RCU 사용
-> 모든 RCU(목표 사용률 이하 RCU + Padding)를 통해 처리
-> 버스트 용량에서 처리
  • Spike에 대해 그래프에서와 같이 처음에는 버스트 용량에서 처리되다가 버스트 용량을 다 소진하면서 Throttling이 발생한다. 이후 Auto Scaling이 완료된 이후에는 Throttling이 사라진다.
  • 문서에 따르면 “Auto scaling triggers when your consumed capacity breaches the configured target utilization for two consecutive minutes. CloudWatch alarms might have a short delay of up to a few minutes before triggering auto scaling.”라고 나와있다.
  • DynamoDB의 경우 Auto Scaling이 일어나려면 CloudWatch에 1분간 연속해서 사용된 값이 목표 사용률을 넘어야 한다고 했다. 그렇기에 아래와 같은 이유로 지연이 생기게 되며 이게 순간적인 많은 요청에 대해 Throttling을 발생 시킨다.
    • CloudWatch에 표시되려면 약간의 시간 지연이 필요하다.
    • CloudWatch에 연속된 1분동안 목표 사용률을 넘는 상황이 발생하면 Auto Scaling을 시작한다.
    • Auto Scaling이 되는 과정에서 위에서 언급한 “목표 사용률 이하 RCU 사용 → 모든 RCU(목표 사용률 이하 RCU + Padding)를 통해 처리 → 버스트 용량에서 처리”를 넘어서는 요청에 대해서는 Throttling이 발생한다.
  • 관련 링크: https://aws.amazon.com/ko/blogs/database/handle-traffic-spikes-with-amazon-dynamodb-provisioned-capacity/
  • 관련 링크: https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/AutoScaling.html


작가의 생각

  • Auto Scaling에서도 급격한 요청에 대해서는 Scaling을 탐지하는 부분과 조정하는 시간이 필요하기에 앞으로 설계시 이에 대한 고려도 하면 좋을거 같다.
  • 관련 조사를 진행하면서 DynamoDB Auto Scaling에 대해 많이 배웠다.
  • 예상하지 못한 급격한 트래픽 요청에 대해서는 알람이 오게 해야하며 트랙픽 증가가 예정된 부분이 있다면 점검하는 습관을 만들어야겠다.


참고자료