GitHub Actions
앱당 세 개의 워크플로우, 각각 하나의 작업으로 구성됩니다. 템플릿의 .github/workflows/{pr,main,release}.yaml이 진실의 원천(source of truth)이며, references/workflows.md에 설명과 함께 재현되어 있습니다.
pull request ──► pr.yaml 검사만 수행, 아무것도 퍼블리시하지 않음
merge to main ─► main.yaml 이미지 한 번 빌드 → ghcr.io/nuvraxis/<app>:sha-<short>, :main
tag vX.Y.Z ────► release.yaml 동일한 이미지 리태깅 :vX.Y.Z, :latest · 차트 X.Y.Z → OCI · GitHub Release
모든 워크플로우를 위한 규칙
-
상단에
permissions: contents: read를 설정하고, 필요한 작업에만 권한을 확장합니다.packages: write는 GHCR에 푸시하는 작업에,contents: write는 릴리스를 생성하는 작업에만 사용합니다.id-token: write또는attestations: write는 사용하지 않습니다. provenance 및 SBOM은 BuildKit에서 제공되며,actions/attest*(프라이빗 리포지토리에서 GitHub Enterprise 필요)가 아닙니다. -
GITHUB_TOKEN만 사용합니다. GHCR 로그인은${{ github.actor }}/${{ secrets.GITHUB_TOKEN }}을 사용하고,gh는GH_TOKEN: ${{ github.token }}을 사용합니다. CI에 개인 액세스 토큰을 사용하지 마십시오. (클러스터에서 프라이빗 패키지를 가져오는 것은 다른 자격 증명입니다.helm-nextjs참조.) -
액션 메이저 버전(
@v7)을 고정하고 SHA 테이블을 최신 상태로 유지합니다. 템플릿은 가독성을 위해 메이저 태그를 사용합니다. 조직에서 SHA 고정을 요구하는 경우 각@vN을 references/action-pins.md의 SHA로 바꾸고# vN.M.P주석을 유지하십시오. 현재 메이저 버전: checkout v7, setup-node v7, pnpm/action-setup v6, setup-qemu v4, setup-buildx v4, login v4, metadata v6, build-push v7, azure/setup-helm v5. -
도구 체인:
pnpm/action-setup을actions/setup-node보다 먼저 실행합니다. action-setup은packageManager에서 pnpm 버전을 읽고, setup-node는.node-version을 읽고 pnpm 스토어를 캐시합니다(cache: pnpm은 PATH에 pnpm이 먼저 있어야 함). 그런 다음pnpm install --frozen-lockfile을 실행합니다.npm ci는 절대 사용하지 마십시오. -
워크플로우 및 ref별
concurrency를 설정하고, PR에서만 진행 중인 실행을 취소합니다. PR에 새 푸시가 발생하면 이전 실행이 취소됩니다. main 및 태그에서는 실행이 항상 완료됩니다. release.yaml은 해당 정확한 커밋의 이미지가 필요합니다. -
비밀을 절대 echo하거나 신뢰할 수 없는 입력을
run:에 직접 삽입하지 마십시오. 값을env:를 통해 전달하고 따옴표로 감싸십시오("${APP}").${{ github.event.pull_request.title }}과 같은 값은 스크립트 내부에 절대 넣지 마십시오. git에 푸시하지 않는 작업에서는persist-credentials: false로 설정하십시오. -
모든 작업에는
timeout-minutes가 설정되어야 합니다. 그렇지 않으면 중단된 Docker 빌드가 6시간 동안 실행될 수 있습니다. -
이름은 소문자로 사용합니다. GHCR은 대문자 리포지토리를 거부합니다.
IMAGE: ghcr.io/nuvraxis/<app>은env에 소문자로 작성되며, 스캐폴드가 앱 이름을 소문자로 변환합니다.
pr.yaml
-
on: pull_request에types: [opened, synchronize, reopened, ready_for_review]를 사용하고branches필터를 설정하지 않습니다. 따라서 기능 브랜치에 대한 스택형 PR도 검사됩니다. 모든 작업에는if: ${{ !github.event.pull_request.draft }}가 있으며, 준비 완료로 표시하면 실행이 트리거됩니다. -
네 개의 병렬 작업:
quality(biome ci --reporter=github, stylelint,turbo run typecheck test --affected,pnpm audit --audit-level high),build(turbo run build --affected),docker(하나의 플랫폼을load: true로 빌드하고, 기능을 제거한 읽기 전용 모드로 실행한 후/api/health에 curl 실행),helm(helm lint --strict및 두 values 파일에 대해 kubeconform 실행).--affected는fetch-depth: 0이 필요합니다. -
PR에서는 아무것도 푸시되지 않습니다.
push: false, 캐시는 읽기 전용(cache-from만), 레지스트리 로그인 없음.
main.yaml
-
on: push: branches: [main]은 이미지를 한 번 빌드하여 두 아키텍처 모두를 푸시합니다.docker/metadata-action의 태그:type=sha,format=short,prefix=sha-및type=raw,value=main,flavor: latest=false.latest는 릴리스용입니다. -
provenance: mode=max,sbom: true,cache-from/to: type=gha,scope=<app>,mode=max. Provenance 및 SBOM은 이미지 인덱스에 첨부되며, release.yaml에서 리태깅 시 함께 전달됩니다.NEXT_DEPLOYMENT_ID=${{ github.sha }}는 스큐 보호를 위한 빌드 인자입니다. -
main.yaml은 차트를 퍼블리시하지 않으며 PR 검사를 다시 실행하지 않습니다. 브랜치 보호는 pr.yaml을 요구하며, main은 아티팩트만 생성합니다.
release.yaml
-
on: push: tags: ['v*.*.*'], 그런 다음 순서대로:- 태그가 정확히
vMAJOR.MINOR.PATCH형식이고 해당 커밋이origin/main의 조상이어야 합니다. 그렇지 않으면 실패합니다. - 재빌드하지 않습니다.
ghcr.io/nuvraxis/<app>:sha-<short>가 존재하지 않으면 "main.yaml이 완료될 때까지 기다린 후 다시 실행" 메시지와 함께 실패합니다. 대체 빌드는 없습니다. docker buildx imagetools create --tag :vX.Y.Z --tag :latest <sha-image>: 두 아키텍처, provenance 및 SBOM을 동일한 다이제스트로 유지하는 매니페스트 수준 복사입니다.helm package --version X.Y.Z --app-version vX.Y.Z,helm pushtooci://ghcr.io/nuvraxis/charts.gh release create vX.Y.Z --verify-tag --generate-notes명령으로 차트.tgz,image-digest.txt및sbom.spdx.json을 첨부합니다.
- 태그가 정확히
-
릴리스 절차: main에 병합 → main.yaml이 초록색이 될 때까지 기다림 →
git tag vX.Y.Z && git push origin vX.Y.Z. main.yaml이 완료되기 전에 태깅하면 2단계에서 의도적으로 실패합니다. 이미지가 존재하면 릴리스 작업을 다시 실행하십시오. 잘못된 릴리스는 태그를 이동하는 것이 아니라 새 패치 태그로 수정합니다.
속도 향상 (필요할 때만)
- arm64에서 QEMU는 main.yaml의 느린 부분입니다.
ubuntu-24.04-arm+ubuntu-latest를 활용한 매트릭스로 대체하고, 다이제스트로 푸시한 다음imagetools create로 병합 작업을 수행하십시오. 태그와 단일 인덱스를 유지하십시오. - pr.yaml을 위한 Turborepo 원격 캐시:
pnpm-turborepo참조.
검증
docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:latest # 모든 워크플로우 린트
gh workflow list && gh run list --limit 5
gh run view <run-id> --log-failed
릴리스 후: docker buildx imagetools inspect ghcr.io/nuvraxis/<app>:vX.Y.Z는 두 플랫폼을 모두 보여주고, helm show chart oci://ghcr.io/nuvraxis/charts/<app> --version X.Y.Z는 appVersion: vX.Y.Z를 보여줍니다.
출처
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
- https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
- https://github.com/pnpm/action-setup
- https://github.com/actions/setup-node
- https://github.com/docker/metadata-action
- https://github.com/docker/build-push-action
- https://docs.docker.com/build/ci/github-actions/cache/#github-cache
- https://docs.docker.com/build/metadata/attestations/
- https://docs.docker.com/reference/cli/docker/buildx/imagetools/create/
- https://helm.sh/docs/topics/registries/
- https://cli.github.com/manual/gh_release_create
- https://turborepo.dev/docs/reference/run#--affected