μ΅κ·Ό μμ±νλ νλ‘μ νΈλ€μ΄ λΉμ·ν νμμΌλ‘ ꡬμ±λμ΄ CI/CD λ₯Ό GitHub Actions λ₯Ό νμ©νκ³ μμ΅λλ€.
κ°λ¨ν λ¨κ³λ κΈ°λ³Έμ μΌλ‘ μ 곡λλ GitHub Actions ν¨ν€μ§λ₯Ό νμ©νκ³ , νμλ‘ νλ νΉμ κΈ°λ₯μ κ²μν΄λ³΄λ λλΆλΆ 곡κ°λ ν¨ν€μ§κ° μ‘΄μ¬ν©λλ€.
λͺλͺ μνμ°©μ€λ₯Ό κ±°μ³ .NET 5 λ°±μλ μμ©νλ‘κ·Έλ¨κ³Ό React νλ‘ νΈμλ μμ©νλ‘κ·Έλ¨μ λΉλνκ³ , νκ·Έν ν GitHub Release Draft λ₯Ό μμ±νκ³ , νκ·Έλ 컀λ°μ κΈ°μ€μΌλ‘ λ컀 μ΄λ―Έμ§λ₯Ό λΉλν΄μ λ μ§μ€νΈλ¦¬μ κ²μνκ² κ΅¬μ±λ GitHub Actions μ λλ€.
λμ νλ‘μ νΈ:
- λ°±μλ: .NET 5
- νλ‘ νΈμλ: React
- κ²μ: Docker registry
ꡬμ±λ μ μ₯μ:
π’ GitHub Actions
μλμ κ°μ΄ λκ°μ μν¬νλ‘μ°λ‘ λλ μ μμ±λμμΌλ©°, λ μν¬νλ‘μ°λ μλ‘ μμ‘΄νμ§ μμ΅λλ€.
Workflows:
- Build and tag
- 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>
λΉλ, νκ·Έ μ‘μ μ νλμ μμ μΌλ‘ ꡬμ±λμ΄ μκ³ , μμ μ μ¬λ¬ λ¨κ³λ‘ ꡬμ±λ©λλ€.
μ‘μ μ λ©μΈ λΈλμΉμ 컀λ°μ΄ μ μ‘λμμ λ μμλ©λλ€. λ©μΈ λΈλμΉμ νκ·Έκ° μ μ‘λ κ²½μ°μλ μμλμ§ μμ΅λλ€.
μμ μ μλ λ¨κ³κ° μμλλ‘ μ€νλ©λλ€.
- 체ν¬μμ λ©μΈ λΈλμΉμ λ΄μ©μ 볡μ ν©λλ€.
- .NET 5 λꡬλ₯Ό μ€μΉν©λλ€.
- Nodejs λꡬλ₯Ό μ€μΉν©λλ€.
- ν΄λΌμ΄μΈνΈ μμ©νλ‘κ·Έλ¨ λλ ν°λ¦¬μμ npm ν¨ν€μ§λ₯Ό μ€μΉνκ³ , npm run build μ€ν¬λ¦½νΈλ₯Ό μ€νν΄μ ν΄λΌμ΄μΈνΈ μμ©νλ‘κ·Έλ¨μ λ²λ€λ§ν©λλ€.
- dotnet μμ‘΄ ν¨ν€μ§λ₯Ό μ€μΉν©λλ€.
- dotnet νλ‘μ νΈλ₯Ό λΉλν©λλ€.
- λ°±μλ μμ νλ‘μ νΈμ λ²μ μ νκ²½λ³μμ μ μ₯ν©λλ€.
- νκ²½λ³μμ μ μ₯λ λ²μ κ°μΌλ‘ νκ·Έλ₯Ό μμ±ν©λλ€.
git tag
- μμ±λ νκ·Έμ μ°κ²°λ λ¦΄λ¦¬μ¦ μ΄μμ μμ±ν©λλ€.
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*.*.*
νμμ νκ·Έκ° μ μ‘λμμ λ μμλ©λλ€.
μμ μ μλ λ¨κ³κ° μμλλ‘ μ€νλ©λλ€.
- 체ν¬μμ λ©μΈ λΈλμΉμ λ΄μ©μ 볡μ ν©λλ€.
- λ컀 λ©νλ°μ΄ν°λ₯Ό μμ§ν©λλ€.
- λ컀 μ΄λ―Έμ§λ₯Ό λΉλνκΈ° μν΄ QEMU λꡬλ₯Ό μ€μΉν©λλ€.
- λ컀 μ΄λ―Έμ§λ₯Ό λΉλνκΈ° μν΄ Buildx λꡬλ₯Ό μ€μΉν©λλ€.
- λ μ§μ€νΈλ¦¬μ λ‘κ·ΈμΈν©λλ€.
- λ컀 μ΄λ―Έμ§λ₯Ό λΉλνκ³ , μΈμ¦λ λ μ§μ€νΈλ¦¬μ μ΄λ―Έμ§λ₯Ό κ²μν©λλ€.
π Conclusion
μ΄λ κ² κ΅¬μ±ν΄λλ©΄, λ²μ λ³ μΆμμ 보μ λ컀 μ΄λ―Έμ§λ₯Ό λ μ§μ€νΈλ¦¬μμ νμΈν μ μμ΅λλ€.