🐱 github actionsλ₯Ό ν™œμš©ν•œ ν…ŒμŠ€νŠΈ μžλ™ν™” λ„μž…κΈ°

κ°œμš”

ν˜„μž¬ νŒ€μ— ν•©λ₯˜ν•œ μ§€λŠ” 4κ°œμ›” 정도 λ˜μ—ˆλ‹€. λ‚˜λŠ” νŒ€μ—μ„œ 뽑은 첫 λ°±μ—”λ“œ κ°œλ°œμžμ˜€κ³ , κΈ°μ‘΄μ—λŠ” λΆ€λ¬Έμž₯λ‹˜ ν•œ λΆ„μ΄μ„œ λ°±μ—”λ“œ κ°œλ°œμ„ λͺ¨λ‘ λ‹΄λ‹Ήν•˜κ³  계셨닀. 개발 νŒ€μ›μ΄ 1λͺ…μ—μ„œ 2λͺ…이 λ˜λŠ” 건 λ‹¨μˆœνžˆ μˆ«μžκ°€ λŠ˜μ–΄λ‚˜λŠ” 것 뿐만 μ•„λ‹ˆλΌ ν˜‘μ—…μ΄ λΆˆν•„μš”ν–ˆλ˜ κ·Έλ™μ•ˆμ˜ 개발 ν”„λ‘œμ„ΈμŠ€μ™€ λ¬Έν™”λ₯Ό λͺ¨λ‘ ν†΅μ§Έλ‘œ λ“€μ–΄λ‚΄μ•Όν•˜λŠ” 혁λͺ…이 ν•„μš”ν•œ 일이라고 μƒκ°λœλ‹€.

μž…μ‚¬ μ΄ˆλ°˜μ—λŠ” μ‹ κ·œ μž…μ‚¬μžλ₯Ό μœ„ν•œ README μž‘μ„±λΆ€ν„° μ‹œμž‘ν•΄ 둜컬 ν™˜κ²½ μ…‹νŒ… 방법, git 브랜치 μ „λž΅ 수립 λ“± κ°œλ°œν•˜κΈ° 쒋은 ν™˜κ²½ λ§Œλ“€κΈ°!λ₯Ό μ£Όλ„μ μœΌλ‘œ μ§„ν–‰ν–ˆλ‹€. λ‚΄κ°€ 고생을 ν•˜λ”λΌλ„ λ‹€μŒ μ‚¬λžŒμ€ 고생을 덜 ν•  수 μžˆλ„λ‘ λ§Œλ“€μ–΄λ‘λ©΄ 쒋을 것 같단 생각을 ν–ˆκΈ° λ•Œλ¬Έμ— ν•˜λ‚˜μ”© μ°¨κ·Όμ°¨κ·Ό ν•΄λ‚˜κ°ˆ 수 μžˆμ—ˆλ‹€.

이후 이슈λ₯Ό ν• λ‹Ήλ°›κ³  API κ°œλ°œμ„ μ§„ν–‰ν•˜κ²Œ λ˜μ—ˆλŠ”λ°, 이미 λ§Žμ€ μœ μ €λ“€μ΄ μ‚¬μš©μ€‘μΈ μ„œλΉ„μŠ€λ₯Ό κ°œμ„ ν•΄λ‚˜κ°€λŠ” μž‘μ—…μ΄ μ‰½μ§€λ§Œμ€ μ•Šμ•˜λ‹€. νŠΉνžˆλ‚˜ 아직 μ΅μˆ™ν•˜μ§€ μ•Šμ€ κΈ°μ‘΄ μ½”λ“œλ“€ 사이에 λ‚΄ 피쳐λ₯Ό μ§‘μ–΄λ„£μœΌλ €λ‹ˆ μ‚¬μ΄λ“œμ΄νŽ™νŠΈλ₯Ό μ˜ˆμƒν•˜κΈ°κ°€ νž˜λ“€μ—ˆκ³ , κΆŒν•œ λ¬Έμ œκ°€ λ―Όκ°ν•œ λ„λ©”μΈμ΄λ‹€λ³΄λ‹ˆ μ—¬λŸ¬ κ³„μ •μœΌλ‘œ ν…ŒμŠ€νŠΈλ₯Ό ν•΄μ•Ό ν–ˆλŠ”λ° 이λ₯Ό λ°˜λ³΅ν•˜λŠ” μž‘μ—…μ΄ ꡉμž₯히 λ²ˆκ±°λ‘œμ› λ‹€. ν™€λ‘œ 개발>ν…ŒμŠ€νŠΈ>λ°°ν¬ν•˜λŠ” 사이클을 λŒλ©΄μ„œ μ˜ˆμƒμΉ˜λͺ»ν•œ μž₯μ• λ₯Ό λ§ˆμ£ΌμΉ˜λŠ” 일도 λΉˆλ²ˆν–ˆλ‹€. μ΄λ ‡κ²Œ κ°œλ°œν•˜λ‹€κ°„ λŠμž„μ—†λŠ” μž₯애와 CS에 μ‹œλ‹¬λ¦¬λŠ” μ–΄λ‘μš΄ λ―Έλž˜κ°€ 기닀릴 λΏπŸ˜­μ΄λΌλŠ” 생각이 λ“€μ—ˆκ³ , ν…ŒμŠ€νŠΈ/배포 κ·œμΉ™ λ…Όμ˜λ₯Ό μœ„ν•œ 자리λ₯Ό λ§Œλ“€μ–΄ νŒ€μ›λΆ„λ“€κ»˜ λ‚΄ 생각을 κ³΅μœ λ“œλ¦¬κ²Œ λ˜μ—ˆλ‹€.

κ·Έ 쀑 κ°€μž₯ 적극적으둜 μ–΄ν•„ν–ˆλ˜ 뢀뢄은 ν…ŒμŠ€νŠΈμ½”λ“œ μž‘μ„±κ³Ό ν…ŒμŠ€νŠΈ μžλ™ν™” ν”„λ‘œμ„ΈμŠ€ λ„μž…μ΄μ—ˆλ‹€. ν…ŒμŠ€νŠΈλ₯Ό 도와쀄 인λ ₯이 λΆ€μ‘±ν•˜λ‹€λ©΄ μ½”λ“œλΌλ„ λ‚  도와주도둝 λ§Œλ“€μ–΄μ•Όκ² λ‹¨ 생각이 λ“€μ—ˆκ³ , ν…ŒμŠ€νŠΈμ½”λ“œ μž‘μ„±μ„ ν•΄λ³΄μžλŠ” 결둠에 λ„λ‹¬ν–ˆλ‹€. ν…ŒμŠ€νŠΈμ½”λ“œκ°€ μŒ“μ΄λ©΄ 그만큼 λ‚΄κ°€ 반볡적으둜 ν•΄μ•Ό ν•  ν…ŒμŠ€νŠΈκ°€ 쀄어듀 것이고 λ‚˜λ³΄λ‹€ 더 μ •ν™•ν•˜κ²Œ 였λ₯˜λ₯Ό μ§šμ–΄μ€„ 수 μžˆμ„ 것이닀.

CI νˆ΄μ€ TravisCI, CircleCI λ“± μ—¬λŸ¬κ°€μ§€κ°€ μžˆλŠ”λ°, 버전 관리λ₯Ό Git/Github으둜 ν•˜κ³  μžˆμœΌλ‹ˆ github의 actions λ₯Ό ν™œμš©ν•΄ λ˜λ„λ‘μ΄λ©΄ μ‚¬μš© 쀑인 ν”Œλž«νΌ λ‚΄μ—μ„œ ν™˜κ²½μ„ κ΅¬μΆ•ν•˜κΈ°λ‘œ ν–ˆλ‹€.

DRF API ν…ŒμŠ€νŠΈμ½”λ“œ μž‘μ„±

ν”„λ‘œμ νŠΈλŠ” Django 기반이며 APIλŠ” 주둜 Django Rest Framework둜 μž‘μ„±λ˜μ—ˆλ‹€. 우리 ν”„λ‘œμ νŠΈμ˜ μ½”λ“œ κ³³κ³³μ—λŠ” μ„±λŠ₯ ν–₯상을 μœ„ν•΄ replica DBλ₯Ό λͺ…μ‹œμ μœΌλ‘œ 바라보도둝 ν•˜λŠ” 뢀뢄이 μžˆλŠ”λ°, 이λ₯Ό ν…ŒμŠ€νŠΈν•˜λ €λ‹ˆ replica DBλ₯Ό 찾을 수 μ—†λ‹€λŠ” 였λ₯˜κ°€ λ°œμƒν–ˆλ‹€. 이λ₯Ό ν•΄κ²°ν•˜λ €λ©΄ ν…ŒμŠ€νŠΈμ½”λ“œμ˜ databases에 μ‚¬μš©ν•  DBλ₯Ό λͺ…μ‹œμ μœΌλ‘œ μž‘μ„±ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.

class ExampleAPITest(APITransactionTestCase):
    databases = ["default", "replica"] # ν˜Ήμ€ databases = "__all__"

λ˜ν•œ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ΄μš©ν•΄ ν…ŒμŠ€νŠΈν•  λͺ©μ μ΄λΌλ©΄ APISimpleTestCaseλ‚˜ APITestCaseλŠ” 취지에 λ§žμ§€ μ•ŠλŠ”λ‹€. λŒ€μ‹  APITransactionTestCaseλ₯Ό μ‚¬μš©ν•˜μž. μ΄λŠ” νŠΈλžœμž­μ…˜μ—μ„œ ν…ŒμŠ€νŠΈλ₯Ό λž˜ν•‘ν•˜κ³  각 ν…ŒμŠ€νŠΈλ₯Ό μ‹œμž‘ν•  λ•Œ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό λ‘€λ°±ν•  수 μžˆλ„λ‘ ν•œλ‹€.

actions workflows λ§Œλ“€κΈ°

λ‚΄κ°€ κ΅¬μΆ•ν•˜λ € ν•œ ν”„λ‘œμ„ΈμŠ€λŠ” κ°„λ‹¨ν•˜λ‹€. λˆ„κ΅°κ°€ PR(Pull Request)을 μ˜¬λ¦¬κ±°λ‚˜ μ˜€ν”ˆλœ PR에 Pushλ₯Ό ν•˜λ©΄ actions workflowsλ₯Ό 톡해 슀크립트λ₯Ό 돌고 ν…ŒμŠ€νŠΈκ°€ μ„±κ³΅ν•˜λ©΄ μŠ¬λž™μœΌλ‘œ μ„±κ³΅ν–ˆλ‹€λŠ” λ©”μ‹œμ§€λ₯Ό 보내고 머지 λ²„νŠΌμ„ ν™œμ„±ν™”μ‹œν‚€λŠ” 방식이닀.

μš°μ„  ν”„λ‘œμ νŠΈ root ν•˜μœ„μ— .github 폴더λ₯Ό λ§Œλ“€κ³  κ·Έ ν•˜μœ„μ— workflows 폴더λ₯Ό λ§Œλ“ λ‹€. CI μ½”λ“œ 외에도 actionsλ₯Ό ν™œμš©ν•œ μžλ™ν™” μŠ€ν¬λ¦½νŠΈκ°€ 좔가될 수 μžˆμœΌλ‹ˆ pull-request.yml ν˜Ήμ€ ci.yml 와 같은 μ΄λ¦„μœΌλ‘œ νŒŒμΌμ„ ν•˜λ‚˜ λ§Œλ“ λ‹€.

.github/workflows/pull-request.yml

name: Pull request

on:
  pull_request:
    branches:
      - "**"

actions의 이름을 μ •ν•˜κ³  μ–΄λ–€ μ•‘μ…˜μ΄ μ–΄λ–€ λΈŒλžœμΉ˜μ— λ°œμƒν–ˆμ„ λ•Œ ν•΄λ‹Ή 슀크립트λ₯Ό 돌릴 지에 λŒ€ν•œ κ·œμΉ™μ„ μ λŠ”λ‹€. λ‚˜λŠ” λͺ¨λ“  λΈŒλžœμΉ˜μ— λŒ€ν•΄ PR이 λ°œμƒν•˜λ©΄ ν…ŒμŠ€νŠΈλ₯Ό 돌릴 κ³„νšμ΄μ—ˆκΈ° λ•Œλ¬Έμ— μœ„μ™€ 같이 μž‘μ„±ν–ˆλ‹€.

yml 파일 μž‘μ„±

μœ„ νŒŒμΌμ— μ΄μ–΄μ„œ μž‘μ„±ν•˜λ©΄ λœλ‹€.

jobs:
  test:
    timeout-minutes: 20
    runs-on: ubuntu-latest
    env:
	  example: ${{ secrets.example }}

ν•˜λ‚˜μ˜ workflow에 λŒ€ν•΄ μ—¬λŸ¬ job을 등둝할 수 μžˆλ‹€. λ‚˜λŠ” testλΌλŠ” μ΄λ¦„μ˜ job을 μž‘μ„±ν–ˆκ³ , timeout-minutesλŠ” 20λΆ„μœΌλ‘œ μž‘μ„±ν–ˆλ‹€. ν•΄λ‹Ή μ•‘μ…˜μ΄ μ‹€ν–‰ν•˜λŠ”λ° 20뢄이 초과되면 μžλ™ fail이 λ˜λŠ” 쑰건이닀. runs-on에 ν•΄λ‹Ήν•˜λŠ” 뢀뢄은 μ–΄λ–€ μ„œλ²„ 버전 μœ„μ—μ„œ λ™μž‘ν•˜λ„λ‘ 할지 μ§€μ •ν•˜λŠ” 뢀뢄이닀. envλŠ” job λ‚΄μ—μ„œ μ‚¬μš©λ  ν™˜κ²½λ³€μˆ˜λ₯Ό μ €μž₯ν•˜λŠ” 곡간이닀. μŠ€ν¬λ¦½νŠΈμ— 직접 μž‘μ„±ν•˜κΈ°μ—λŠ” λ―Όκ°ν•œ ν‚€ μ •λ³΄λ‚˜ 계정 μ •λ³΄λŠ” Github repository의 Settings > Secrets > Actions에 등둝해두고 secretsλ₯Ό 톡해 λ³€μˆ˜λ‘œμ„œ 가져와 μ“Έ 수 μžˆλ„λ‘ μ„€μ •ν–ˆλ‹€.

steps:
  - name: Checkout
    uses: actions/checkout@v2

steps ν•˜μœ„μ—λŠ” ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ ν•„μš”ν•œ 것듀을 ν•˜λ‚˜μ”© μž‘μ„±ν•΄μ£Όλ©΄ λœλ‹€. usesμ—λŠ” λ‹€μ–‘ν•œ μ˜€ν”ˆμ†ŒμŠ€λ₯Ό μž‘μ„±ν•˜μ—¬ ν™œμš©ν•  수 μžˆλŠ”λ°, checkout@v2 λŠ” ${{ github.workspace }} ν•˜μœ„μ— μ²΄ν¬μ•„μ›ƒν•˜λŠ” action으둜 μŠ€ν¬λ¦½νŠΈμ—μ„œ μ ‘κ·Όν•  수 μžˆλ„λ‘ ν•œλ‹€.

- name: Build containers
  run: docker-compose -f docker-compose.test.yml build

ν”„λ‘œμ νŠΈλŠ” docker-compose둜 μ»¨ν…Œμ΄λ„ˆλ₯Ό λΉŒλ“œν•˜κ³  μ‹€ν–‰ν•  수 μžˆλ„λ‘ κ΅¬μ„±λ˜μ–΄μžˆλ‹€. ν”„λ‘œλ•μ…˜/개발 ν™˜κ²½κ³Ό λ‹€λ₯΄κ²Œ test ν™˜κ²½μ—μ„œλŠ” AWS RDSλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  직접 PostgreSQL μ»¨ν…Œμ΄λ„ˆλ₯Ό λ”°λ‘œ λ„μ›Œ μ—°κ²°ν•˜μ—¬ μ‚¬μš©ν•˜λ„λ‘ κ΅¬μ„±ν–ˆμœΌλ―€λ‘œ 이에 λ”°λ₯Έ docker-compose.test.yml νŒŒμΌμ„ λ§Œλ“€μ—ˆλ‹€.

- name: Copy files
  run: echo "${{ secrets.file_name }}" > ${{ github.workspace }}/file_name.yml

κΈ°μ‘΄ μ„œλ²„μ—μ„œ scpλ₯Ό 톡해 νŠΉμ • νŒŒμΌμ„ 가져와야 ν•˜λŠ” μ΄μŠˆκ°€ μžˆμ–΄ actions의 μ˜€ν”ˆμ†ŒμŠ€λ₯Ό μ°Ύμ•„μ„œ μ μš©ν•΄λ³΄λ˜ 와쀑에 vpn λ“± μΆ”κ°€λ‘œ μ„€μ •ν•΄μ£Όμ–΄μ•Ό ν•˜λŠ” 것듀이 λ§Žμ•„μ Έ ν•΄λ‹Ή 파일의 정보도 github secrets에 μ €μž₯해두고 λ³΅μ‚¬ν•˜μ—¬ 쓰도둝 ν–ˆλ‹€.

- name: Start containers
  run: docker-compose -f docker-compose.test.yml up -d

- name: Check docker status
  run: docker-compose -f docker-compose.test.yml logs --tail=100 && docker-compose ps

- name: Migration
  run: docker-compose -f docker-compose.test.yml exec -T web python manage.py migrate

- name: Run tests
  run: docker-compose -f docker-compose.test.yml exec -T web python manage.py test

- name: Stop containers
  if: always()
  run: docker-compose -f docker-compose.test.yml down

도컀 μ»¨ν…Œμ΄λ„ˆλ₯Ό λ„μš°κ³  DBλ₯Ό λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ν•˜κ³  ν…ŒμŠ€νŠΈλ₯Ό λŒλ¦¬λŠ” 뢀뢄이닀. ν…ŒμŠ€νŠΈκ°€ λλ‚˜λ©΄ μ»¨ν…Œμ΄λ„ˆλ₯Ό μ’…λ£Œμ‹œν‚€λ„λ‘ ν–ˆλ‹€.

- name: Send result to slack
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    author_name: Github Action Test
    fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
  if: always()

action-slack@v3 λ₯Ό 톡해 workflowκ°€ λλ‚˜λ©΄ ν…ŒμŠ€νŠΈ κ²°κ³Όλ₯Ό μŠ¬λž™ μ±„λ„λ‘œ λ°›μ•„λ³Ό 수 μžˆλ„λ‘ μ„€μ •ν–ˆλ‹€. fieldsμ—λŠ” λ°›κ³  싢은 정보듀(λ ˆνŒŒμ§€ν† λ¦¬λͺ…, λ©”μ‹œμ§€, 컀밋, μ €μž λ“±)을 μž…λ§›μ— 맞게 μ„€μ •ν•΄μ£Όλ©΄ λœλ‹€.

workflows

슀크립트 μž‘μ„±μ„ μ™„λ£Œν•˜κ³ , PR을 올렀보면 actions에 μ•„λ¦„λ‹€μš΄ workflow 결과물이 μŒ“μΈλ‹€.

slack alert

μŠ¬λž™ μ±„λ„λ‘œ ν…ŒμŠ€νŠΈ κ²°κ³Ό λ˜ν•œ μ •μƒμ μœΌλ‘œ μ˜€λŠ” 것을 확인할 수 μžˆλ‹€.

μ°Έκ³ 

github plan

νŒ€μ΄ Github Free ν”Œλžœμ„ μ‚¬μš©μ€‘μ΄κ³  ν•΄λ‹Ή ν”„λ‘œμ νŠΈκ°€ μ˜€ν”ˆμ†ŒμŠ€ ν”„λ‘œμ νŠΈκ°€ μ•„λ‹ˆλΌλ©΄ actions μ†Œμš”μ‹œκ°„μ΄ μ›” 2,000λΆ„μœΌλ‘œ μ œν•œλ˜μ–΄ μžˆλŠ” 것을 μ°Έκ³ ν•˜μ‹œλ©΄ 쒋을 것 κ°™λ‹€. (우리 νŒ€μ€ νŒ€ ν”Œλžœ μ—…κ·Έλ ˆμ΄λ“œλ₯Ό ν–ˆλ‹€.)

κ²°λ‘ 

ν…ŒμŠ€νŠΈμ½”λ“œ μž‘μ„±μ΄ λͺ¨λ“  버그λ₯Ό ν”Όν•  수 μžˆλ„λ‘ ν•΄μ£Όμ§€λŠ” μ•ŠλŠ”λ‹€. κ°œλ°œμžκ°€ ν…ŒμŠ€νŠΈμ½”λ“œ 자체λ₯Ό 잘λͺ» μž‘μ„±ν–ˆλ‹€λ˜μ§€, ν•„μš”ν•œ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜μ§€ λͺ»ν–ˆλ‹€λ˜μ§€ ν•˜λŠ” μ΄μœ μ—μ„œ λ°œμƒν•˜λŠ” 버그듀도 생긴닀.

고민을 ν•΄κ²°ν•˜μž 또 λ‹€λ₯Έ 고민듀이 생겨났닀.

  1. ν…ŒμŠ€νŠΈμ½”λ“œλ₯Ό μ–΄λ–»κ²Œ 더 유의미있게 μž‘μ„±ν•  수 μžˆμ„κΉŒ? λΆˆν•„μš”ν•œ ν…ŒμŠ€νŠΈμ½”λ“œλŠ” 무엇이고 ν•„μš”ν•œ ν…ŒμŠ€νŠΈμ½”λ“œλŠ” λ¬΄μ—‡μΌκΉŒ?
  2. ν…ŒμŠ€νŠΈμ½”λ“œκ°€ λŠ˜μ–΄λ‚  수둝 workflowλ₯Ό ν•œ 번 λ„λŠ” 데 κ±Έλ¦¬λŠ” μ‹œκ°„λ„ λŠ˜μ–΄λ‚˜κ³  μžˆλ‹€. 이λ₯Ό 더 λ‹¨μΆ•μ‹œν‚€λŠ” 방법이 μžˆμ„κΉŒ?
  3. …

이처럼 고민의 고민이 끝없이 μƒκ²¨λ‚˜κ³  μžˆμ§€λ§Œ, κ·Έλž˜λ„ 결둠은 λ„μž…ν•˜κΈΈ μž˜ν–ˆλ‹€ 이닀. 사전에 버그λ₯Ό 찾은 κ²½ν—˜λ„ λ§Žμ•„μ§€κ³ μžˆκ³ , λ°©λŒ€ν•œ ν…ŒμŠ€νŠΈλ₯Ό pushν•  λ•Œλ§ˆλ‹€ μžλ™μœΌλ‘œ λŒλ €μ£Όλ‹ˆ μ΄λ ‡κ²Œ νŽΈν•  수 μ—†λ‹€. νŒ€μ›μ΄ 2λͺ…μ—μ„œ 3λͺ…이 λ˜μ—ˆμ„ λ•ŒλŠ” 더 빛을 λ°œν•  수 μžˆλŠ” λ¬Έν™”κ°€ λ˜μ§€ μ•Šμ„κΉŒ μ‹Άλ‹€.

아직은 μ•„μ£Ό κ°„λ‹¨ν•œ ν”„λ‘œμ„ΈμŠ€μ΄μ§€λ§Œ, μ•žμœΌλ‘œ μžλ™ν™”κ°€ ν•„μš”ν•œ 뢀뢄은 κ³Όκ°ν•˜κ²Œ μ²˜λ¦¬ν•˜μ—¬ 훨씬 더 생산성 μžˆλŠ” νŒ€μ„ λ§Œλ“€κ³  μ‹Άλ‹€.


Written by@ugaemi
Record things I want to remember

🐱 GitHubπŸ“š Reading Space