졜근 μž‘μ„±ν•˜λŠ” ν”„λ‘œμ νŠΈλ“€μ΄ λΉ„μŠ·ν•œ ν˜•μ‹μœΌλ‘œ κ΅¬μ„±λ˜μ–΄ CI/CD λ₯Ό GitHub Actions λ₯Ό ν™œμš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

κ°„λ‹¨ν•œ λ‹¨κ³„λŠ” 기본적으둜 μ œκ³΅λ˜λŠ” GitHub Actions νŒ¨ν‚€μ§€λ₯Ό ν™œμš©ν•˜κ³ , ν•„μš”λ‘œ ν•˜λŠ” νŠΉμ • κΈ°λŠ₯은 κ²€μƒ‰ν•΄λ³΄λ‹ˆ λŒ€λΆ€λΆ„ 곡개된 νŒ¨ν‚€μ§€κ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

λͺ‡λͺ‡ μ‹œν–‰μ°©μ˜€λ₯Ό 거쳐 .NET 5 λ°±μ—”λ“œ μ‘μš©ν”„λ‘œκ·Έλž¨κ³Ό React ν”„λ‘ νŠΈμ—”λ“œ μ‘μš©ν”„λ‘œκ·Έλž¨μ„ λΉŒλ“œν•˜κ³ , νƒœκ·Έν•œ ν›„ GitHub Release Draft λ₯Ό μž‘μ„±ν•˜κ³ , νƒœκ·Έλœ 컀밋을 κΈ°μ€€μœΌλ‘œ 도컀 이미지λ₯Ό λΉŒλ“œν•΄μ„œ λ ˆμ§€μŠ€νŠΈλ¦¬μ— κ²Œμ‹œν•˜κ²Œ κ΅¬μ„±λœ GitHub Actions μž…λ‹ˆλ‹€.

λŒ€μƒ ν”„λ‘œμ νŠΈ:

  • λ°±μ—”λ“œ: .NET 5
  • ν”„λ‘ νŠΈμ—”λ“œ: React
  • κ²Œμ‹œ: Docker registry

κ΅¬μ„±λœ μ €μž₯μ†Œ:

πŸ“’ GitHub Actions

μ•„λž˜μ™€ 같이 λ‘κ°œμ˜ μ›Œν¬ν”Œλ‘œμš°λ‘œ λ‚˜λˆ μ„œ μž‘μ„±λ˜μ—ˆμœΌλ©°, 두 μ›Œν¬ν”Œλ‘œμš°λŠ” μ„œλ‘œ μ˜μ‘΄ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

Workflows:

  1. Build and tag
  2. Docker image

Build and Tag

name: Build and tag

on:
  push:
    branches:
      - main # Default release branch
    tags:
      - "!*"

jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 1

      - name: Setup dotnet
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x

      - name: setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '14'

      - name: build ClientApp
        run: |
          cd src/Sample.App/ClientApp
          npm install
          npm run build

      - name: Restore dependencies
        run: dotnet restore

      - name: Build
        run: dotnet build --no-restore

      - name: package-version
        run: grep '<Version>' < src/Sample.App/Sample.App.csproj | echo "::set-output name=version::$(sed 's/.*<Version>\(.*\)<\/Version>/\1/')"
        id: get_package_version

      - name: set-version  
        run: echo "PACKAGE_VERSION=${{ steps.get_package_version.outputs.version }}" >> $GITHUB_ENV

      - name: package-version-to-git-tag
        uses: pkgdeps/git-tag-action@v2
        with:
          github_token: ${{ secrets.GH_TOKEN }}
          github_repo: ${{ github.repository }}
          version: ${{ env.PACKAGE_VERSION }}
          git_commit_sha: ${{ github.sha }}
          git_tag_prefix: "v"
      - name: Release Drafter
        id: release_drafter
        uses: release-drafter/release-drafter@v5
        with:
          config-name: release-drafter.yml
          version: ${{ env.PACKAGE_VERSION }}
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

λΉŒλ“œλ₯Ό ν™•μΈν•˜κ³ , Semver ν˜•μ‹μ˜ νƒœκ·Έλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

νƒœκ·ΈλŠ” λ°±μ—”λ“œμ˜ μ‹œμž‘ν”„λ‘œμ νŠΈλ‘œ μ„€μ •λ˜λŠ” ν”„λ‘œμ νŠΈμ˜ 버전 Version μš”μ†Œλ₯Ό μ°Έμ‘°ν•©λ‹ˆλ‹€.

λ°±μ—”λ“œμ˜ μ‹œμž‘ ν”„λ‘œμ νŠΈλ‘œ μ„€μ •λ˜λŠ” ν”„λ‘œμ νŠΈ 파일(.csproj)에 λ°˜λ“œμ‹œ <Version> μš”μ†Œκ°€ μ‘΄μž¬ν•΄μ•Ό ν•©λ‹ˆλ‹€.

예)

<Version>1.0.0</Version>

λΉŒλ“œ, νƒœκ·Έ μ•‘μ…˜μ€ ν•˜λ‚˜μ˜ μž‘μ—…μœΌλ‘œ κ΅¬μ„±λ˜μ–΄ 있고, μž‘μ—…μ€ μ—¬λŸ¬ λ‹¨κ³„λ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.

μ•‘μ…˜μ€ 메인 λΈŒλžœμΉ˜μ— 컀밋이 μ „μ†‘λ˜μ—ˆμ„ λ•Œ μ‹œμž‘λ©λ‹ˆλ‹€. 메인 λΈŒλžœμΉ˜μ— νƒœκ·Έκ°€ μ „μ†‘λœ κ²½μš°μ—λŠ” μ‹œμž‘λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μž‘μ—…μ€ μ•„λž˜ 단계가 μˆœμ„œλŒ€λ‘œ μ‹€ν–‰λ©λ‹ˆλ‹€.

  1. 체크아웃 메인 브랜치의 λ‚΄μš©μ„ λ³΅μ œν•©λ‹ˆλ‹€.
  2. .NET 5 도ꡬλ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.
  3. Nodejs 도ꡬλ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.
  4. ν΄λΌμ΄μ–ΈνŠΈ μ‘μš©ν”„λ‘œκ·Έλž¨ λ””λ ‰ν„°λ¦¬μ—μ„œ npm νŒ¨ν‚€μ§€λ₯Ό μ„€μΉ˜ν•˜κ³ , npm run build 슀크립트λ₯Ό μ‹€ν–‰ν•΄μ„œ ν΄λΌμ΄μ–ΈνŠΈ μ‘μš©ν”„λ‘œκ·Έλž¨μ„ λ²ˆλ“€λ§ν•©λ‹ˆλ‹€.
  5. dotnet 의쑴 νŒ¨ν‚€μ§€λ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.
  6. dotnet ν”„λ‘œμ νŠΈλ₯Ό λΉŒλ“œν•©λ‹ˆλ‹€.
  7. λ°±μ—”λ“œ μ‹œμž‘ ν”„λ‘œμ νŠΈμ˜ 버전을 ν™˜κ²½λ³€μˆ˜μ— μ €μž₯ν•©λ‹ˆλ‹€.
  8. ν™˜κ²½λ³€μˆ˜μ— μ €μž₯된 λ²„μ „κ°’μœΌλ‘œ νƒœκ·Έλ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€. git tag
  9. μž‘μ„±λœ νƒœκ·Έμ™€ μ—°κ²°λœ 릴리즈 μ΄ˆμ•ˆμ„ μž‘μ„±ν•©λ‹ˆλ‹€.

Docker image

name: docker image

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 1
      -
        name: Docker meta
        id: meta
        uses: docker/metadata-action@v3
        with:
          # list of Docker images to use as base name for tags
          images: |
            ${{ secrets.DOCKER_REGISTRY_URI }}/${{ github.repository }}
          # generate Docker tags based on the following events/attributes
          tags: |
            type=schedule
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
            type=sha
          labels: |
            org.opencontainers.image.title=Sample File Share
            org.opencontainers.image.description=File sharing sample web app
            org.opencontainers.image.vendor=bbonkr

      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1

      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      -
        name: Login to Registry
        uses: docker/login-action@v1 
        with:
          registry: ${{ secrets.DOCKER_REGISTRY_URI }}
          username: ${{ secrets.DOCKER_REGISTRY_USERNAME }}
          password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
      -
        name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

메인 λΈŒλžœμΉ˜μ— νƒœκ·Έκ°€ μ „μ†‘λ˜λ©΄ 도컀 이미지λ₯Ό λΉŒλ“œν•œ ν›„ λ ˆμ§€μŠ€νŠΈλ¦¬μ— μƒˆ 이미지λ₯Ό μ „μ†‘ν•©λ‹ˆλ‹€.

도컀 μ΄λ―Έμ§€μ˜ 버전은 μ•‘μ…˜ 트리거인 νƒœκ·Έκ°€ μ‚¬μš©λ©λ‹ˆλ‹€.

λΉŒλ“œ, νƒœκ·Έ μ•‘μ…˜μ€ ν•˜λ‚˜μ˜ μž‘μ—…μœΌλ‘œ κ΅¬μ„±λ˜μ–΄ 있고, μž‘μ—…μ€ μ—¬λŸ¬ λ‹¨κ³„λ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.

μ•‘μ…˜μ€ μ €μž₯μ†Œμ— v*.*.* ν˜•μ‹μ˜ νƒœκ·Έκ°€ μ „μ†‘λ˜μ—ˆμ„ λ•Œ μ‹œμž‘λ©λ‹ˆλ‹€.

μž‘μ—…μ€ μ•„λž˜ 단계가 μˆœμ„œλŒ€λ‘œ μ‹€ν–‰λ©λ‹ˆλ‹€.

  1. 체크아웃 메인 브랜치의 λ‚΄μš©μ„ λ³΅μ œν•©λ‹ˆλ‹€.
  2. 도컀 메타데이터λ₯Ό μˆ˜μ§‘ν•©λ‹ˆλ‹€.
  3. 도컀 이미지λ₯Ό λΉŒλ“œν•˜κΈ° μœ„ν•΄ QEMU 도ꡬλ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.
  4. 도컀 이미지λ₯Ό λΉŒλ“œν•˜κΈ° μœ„ν•΄ Buildx 도ꡬλ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.
  5. λ ˆμ§€μŠ€νŠΈλ¦¬μ— λ‘œκ·ΈμΈν•©λ‹ˆλ‹€.
  6. 도컀 이미지λ₯Ό λΉŒλ“œν•˜κ³ , 인증된 λ ˆμ§€μŠ€νŠΈλ¦¬μ— 이미지λ₯Ό κ²Œμ‹œν•©λ‹ˆλ‹€.

πŸ‘ Conclusion

μ΄λ ‡κ²Œ ꡬ성해두면, 버전별 μΆœμ‹œμ •λ³΄μ™€ 도컀 이미지λ₯Ό λ ˆμ§€μŠ€νŠΈλ¦¬μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.