Git Flow
나의 경우 아래와 같이 깃 플로우를 설정하고 개발을 해왔었다.
- Main 브랜치는 출시 가능한 프로덕션 코드를 모아두는 브랜치이며, 배포된 각 버전을 Tag를 이용해 표시한다.
- Develop 브랜치는 다음 버전 개발을 위한 코드를 모아두는 브랜치로 개발이 완료되면 Main 브랜치로 merge된다.
- Feature 브랜치는 하나의 기능을 개발하기 위한 브랜치로, Develop 브랜치에서 분기되며, 기능이 개발 완료되면 다시 Develop 브랜치로 merge된다.
- Release 브랜치는 소프트웨어 배포를 준비하기 위한 브랜치 Develop 브랜치에서 배포될 준비가 됐다면 Release 브랜치로 merge된다.
Release Tag 자동화 하기
내가 선택한 과정을 다음과 같다!
- Dev barnch가 release로 merge될때 CI 작동
- Release branch가 main으로 merge될때 CD 작동
- merge commit 으로부터 버전 정보 추출하여 추출된 버전 정보를 통해 release/tag 생성
- Helm chart의 버전 정보를 변경하여 ArgoCD에서 버전 정보를 탐지하도록
CI
CI.yaml 전체 코드
name: CI
on:
workflow_dispatch:
pull_request:
branches:
- "release"
types:
- closed
env:
IMAGE: ${{ secrets.NCP_CONTAINER_REGISTRY }}/del-app
IMAGE_TAG: ${{ secrets.NCP_CONTAINER_REGISTRY }}/del-app:latest
jobs:
lint:
name: Check lint (black)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install black
run: pip install black
- name: Check black
run: black --check app
build_push_to_ncp:
needs: lint
name: Build Image
runs-on: ubuntu-latest
outputs:
NEW_TAG: ${{ steps.check_tag.outputs.NEW_TAG }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v2
- name: Login to NCR
uses: docker/login-action@v2
with:
registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
username: ${{ secrets.NCP_ACCESS_KEY }}
password: ${{ secrets.NCP_SECRET_KEY }}
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.1
with:
github_token: ${{ secrets.DEL_APP }}
default_bump: false
release_branches: release
# fix: - patch, feat: - minor, BREAKING CHANGE: - major
- name: Check if new_tag exists
id: check_tag
run: |
echo "NEW_TAG=${{ steps.tag_version.outputs.new_tag }}" >> $GITHUB_ENV
- name: Create a GitHub release
if: ${{ env.NEW_TAG != '' }}
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.DEL_APP }}
tag: ${{ steps.tag_version.outputs.new_tag }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
- name: create TAG
id: created_tag
run: |
if [[ "${{ env.NEW_TAG }}" != "" ]]; then
echo "Using version tag: ${{ env.NEW_TAG }}"
echo "TAG=${{ env.NEW_TAG }}" >> $GITHUB_ENV
else
TIMESTAMP=$(date '+%s')
echo "Using timestamp tag: $TIMESTAMP"
echo "TAG=$TIMESTAMP" >> $GITHUB_ENV
fi
- name: Build and Push
if: ${{ env.NEW_TAG != '' }}
uses: docker/build-push-action@v4
with:
context: app
push: true
tags: ${{ env.IMAGE_TAG }},"${{ env.IMAGE }}:${{ env.TAG }}"
platforms: linux/amd64,linux/arm64
name: CI
on:
workflow_dispatch:
pull_request:
branches:
- "release"
types:
- closed
env:
IMAGE: ${{ secrets.NCP_CONTAINER_REGISTRY }}/app
IMAGE_TAG: ${{ secrets.NCP_CONTAINER_REGISTRY }}/app:latest
우선, workflow_dispatch를 통해 워크플로우를 수동으로 실행할 수 있도록 허용하도록 해주었다. 또한, release 브랜치에 pull_request가 closed 되었을 때 CI가 작동하도록 설정해주었다.
https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
공식문서를 잘 살펴보면 workflow에 대한 내용이 자세히 나와있다.
event가 pull_request에서 사용할 수 있는 activity 유형들 중에서 closed를 설정해주었다. 자신의 프로젝트 상황에 맞게 설정해주면 된다.
jobs:
lint:
name: Check lint (black)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install black
run: pip install black
- name: Check black
run: black --check app
먼저 actions/checkout@v3를 사용하여 GitHub 리포지토리의 코드를 가져온 후 파이썬 환경을 설정해준다. 이후 Python 코드 포맷터인 Black을 설치하여 코드 스타일을 검사해주었다. run: black --check ${APP_NAME}을 실행하여 해당 디렉토리 내의 코드를 검사하고 코드가 Black 스타일 가이드를 따르는지 확인한다.
jobs:
...
build_push_to_ncp:
needs: lint
name: Build Image
runs-on: ubuntu-latest
outputs:
NEW_TAG: ${{ steps.check_tag.outputs.NEW_TAG }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v2
- name: Login to NCR
uses: docker/login-action@v2
uses: actions/checkout@v3를 사용하여 코드를 가져온 후, uses: docker/setup-buildx-action@v2를 사용하여 Docker Buildx를 설정한다. 이후 NCR에 로그인한다.
Docker Buildx란?
docker/setup-buildx-action@v2를 사용하여 Docker Buildx를 설정하는 이유 중 하나는 크로스 플랫폼 호환성을 보장하기 위해서이다. Docker Buildx는 다중 아키텍처 빌드 및 푸시를 지원하므로 macOS에서 빌드한 이미지가 Windows나 Linux와 같은 다른 플랫폼에서도 정상적으로 실행될 수 있도록 도와준다.
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.1
with:
github_token: ${{ secrets.APP }}
default_bump: false
release_branches: release
# fix: - patch, feat: - minor, BREAKING CHANGE: - major
- name: Check if new_tag exists
id: check_tag
run: |
echo "NEW_TAG=${{ steps.tag_version.outputs.new_tag }}" >> $GITHUB_ENV
- name: Create a GitHub release
if: ${{ env.NEW_TAG != '' }}
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.DEL_APP }}
tag: ${{ steps.tag_version.outputs.new_tag }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
- name: create TAG
id: created_tag
run: |
if [[ "${{ env.NEW_TAG }}" != "" ]]; then
echo "Using version tag: ${{ env.NEW_TAG }}"
echo "TAG=${{ env.NEW_TAG }}" >> $GITHUB_ENV
else
TIMESTAMP=$(date '+%s')
echo "Using timestamp tag: $TIMESTAMP"
echo "TAG=$TIMESTAMP" >> $GITHUB_ENV
fi
- name: Build and Push
if: ${{ env.NEW_TAG != '' }}
uses: docker/build-push-action@v4
with:
context: app
push: true
tags: ${{ env.IMAGE_TAG }},"${{ env.IMAGE }}:${{ env.TAG }}"
platforms: linux/amd64,linux/arm64
1. Bump version and push tag
GitHub 리포지토리의 버전 태그를 업데이트하고 새 버전을 생성하는 부분이다. mathieudutour/github-tag-action@v6.1를 사용하여 "release" 브랜치에서 변경 사항을 감지하고 버전을 업데이트한다. 예를 들어 버전이 0.1.0 인 경우에 fix를 사용한다면 0.1.1이 되고, feat을 사용하면 0.2.0이 된다.
https://github.com/mathieudutour/github-tag-action
해당 내용은 이 표에서 확인 가능하다. 커밋 메세지에 fix:, feat:, perf: 처럼 지정을 해줘야 github tag 버전에 정상적으로 배포로그가 남게된다. 주의할 점은 반드시 ':'를 넣어주어야 한다! (문서를 잘 읽는게 정말 중요한 것 같다..)
또한, release_branches를 release로 설정해주었다. 이 설정을 해주지 않는다면, release 버전뒤에 -release.0과 같은 suffix가 붙게 된다. 이게 문제가 되는 이유는 이후 CD과정에서 해당 버전을 가지고 helm chart의 appVersion을 업데이트 해줄거고, 이 버전을 가진 이미지를 ArgoCD가 자동 배포과정 중에 가져와서 자동으로 클러스터에 배포를 해주게된다. 하지만 버전 정보가 잘못되어있다면 .. 새로운 태그 정보를 container registry에서 찾을 수 없기 떄문에 당연히 파드가 죽는 등의 에러가 발생할 것이다. 또한 위의 사진을 살펴보면, 내가 원했던 것은 0.0.1 에서의 버전 정보가 변경되길 원했는데, 오히려 suffix에 붙어있는 숫자가 변경되고 있는 것이었다.
따라서 해당 레포의 이슈를 엄청나게 찾아본 결과..
release_branches 옵션에 나의 브랜치를 넣어주어야 해당 suffix가 사라진다는 것을 알게 되었다!
2. Check if new_tag exists
이전 작업에서 생성한 새로운 버전 태그가 있는지 확인하고, 태그가 생성되었다면 환경 변수에 저장한다.
3. Create a GitHub release
새 버전 태그를 기반으로 GitHub 릴리스를 만들고, 릴리스의 이름과 내용을 설정한다.
4. Create TAG
이전 작업에서 생성한 새로운 버전 태그를 사용하거나, 새로운 버전 태그가 없는 경우 타임스탬프 기반의 태그를 생성한다. 이는 환경 변수에 저장되며, 이미지 태그로 사용된다.
5. Build and Push
새 버전 태그가 존재할 때 Docker 이미지를 빌드하고 지정한 Docker 레지스트리로 푸시한다
CD
CD.yaml 전체 코드
name: CD
on:
workflow_dispatch:
pull_request:
branches:
- "main"
types:
- closed
env:
IMAGE: ${{ secrets.NCP_CONTAINER_REGISTRY }}/app
IMAGE_TAG: ${{ secrets.NCP_CONTAINER_REGISTRY }}/app:latest
jobs:
deploy:
name: deploy new version
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
ref: main
token: ${{ secrets.DEL_APP }}
- name: Get Latest Tag
id: get-latest-tag
run: |
LATEST_TAG=$(curl -s -H "Authorization: token ${{ secrets.APP }}" https://api.github.com/repos/{$자신의레포명}/tags | jq -r '.[0].name')
echo "Latest Tag is $LATEST_TAG"
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
- name: Update appVersion in Chart.yaml
if: ${{ env.LATEST_TAG != ''}}
run: |
echo "Using version tag: ${{ env.LATEST_TAG }}"
sed -ie 's/appVersion: ".*"/appVersion: "'${{ env.LATEST_TAG }}'"/g' helm-chart/Chart.yaml
- name: Commit files
if: ${{ env.LATEST_TAG != ''}}
run: |
git add .
git config --local user.email "이메일@gmail.com"
git config --local user.name "github-actions[bot]"
git commit -a -m "update chart tag"
- name: Push changes
if: ${{ env.LATEST_TAG != ''}}
uses: ad-m/github-push-action@master
with:
branch: main
github_token: ${{ secrets.APP }}
name: CD
on:
workflow_dispatch:
pull_request:
branches:
- "main"
types:
- closed
env:
IMAGE: ${{ secrets.NCP_CONTAINER_REGISTRY }}/app
IMAGE_TAG: ${{ secrets.NCP_CONTAINER_REGISTRY }}/app:latest
- main 브랜치에서 pull request가 closed 된 경우에 CD가 작동한다.
- name: Get Latest Tag
id: get-latest-tag
run: |
LATEST_TAG=$(curl -s -H "Authorization: token ${{ secrets.APP }}" https://api.github.com/repos/{$자신의레포명}/tags | jq -r '.[0].name')
echo "Latest Tag is $LATEST_TAG"
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
- name: Update appVersion in Chart.yaml
if: ${{ env.LATEST_TAG != ''}}
run: |
echo "Using version tag: ${{ env.LATEST_TAG }}"
sed -ie 's/appVersion: ".*"/appVersion: "'${{ env.LATEST_TAG }}'"/g' helm-chart/Chart.yaml
- name: Commit files
if: ${{ env.LATEST_TAG != ''}}
run: |
git add .
git config --local user.email "이메일@gmail.com"
git config --local user.name "github-actions[bot]"
git commit -a -m "update chart tag"
- name: Push changes
if: ${{ env.LATEST_TAG != ''}}
uses: ad-m/github-push-action@master
with:
branch: main
github_token: ${{ secrets.APP }}
- 깃허브 레포지토리로부터 가장 최근의 태그를 가져온다. CD가 작동하려면 CI가 작동하고, 완료되었어야하기 때문에 태그값이 업데이트 되어있을 것이다. 따라서 이 태그를 가지고 helm의 Chart.yaml에 변경을 해주게 되는데, 이 변경 사항은 main브랜치에 커밋을 남기고 푸쉬가 되는 과정을 거친다.
이런식으로 Release가 되어있고, 이 태그를 가져와서 ...
위의 사진처럼 Chart.yaml의 appVersion을 업데이트해준다. 그렇게 되면 ArgoCD가 이 버전 정보를 가지고 이미지를 가져와서 자동적으로 클러스터를 업데이트 한다.
'Git' 카테고리의 다른 글
[Git] 원격 저장소 연결 및 끊기 (0) | 2022.09.01 |
---|---|
[Git] 커밋 후 푸쉬한 내역을 되돌리는 방법 (0) | 2022.06.28 |
댓글