컨텐츠로 건너뛰기

GitHub Actions 도커 이미지 자동 빌드

코드베이스를 지속해서 업데이트하고 최신 버전을 유지하는 것은 프로젝트의 중요한 측면 중 하나입니다. GitHub Actions를 활용하여 다른 레포지토리의 업데이트를 주기적으로 확인하고 필요할 때마다 나의 레포지토리에 자동으로 업데이트하는 방법을 소개합니다. 본 예시에서는 제가 개인적으로 사용하기 위해 오픈소스 프로젝트 트래킹 Planka에 사용된 실제 코드를 기반으로 설명합니다.

TL;DR

name: Check for updates
on:
schedule:
- cron: '*/5 * * * *'
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
- run: |
LOCAL_VER=$(git -c 'versionsort.suffix=-' \
ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/NavyStack/planka-ns.git \
| tail --lines=1 \
| cut --delimiter='/' --fields=3)
RELEASE_VER=$(git -c 'versionsort.suffix=-' \
ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/plankanban/planka.git 'v*.*.*' \
| tail --lines=1 \
| cut --delimiter='/' --fields=3)
if [[ $RELEASE_VER != $LOCAL_VER ]]; then
echo "Local version: $LOCAL_VER"
echo "Latest upstream version: $RELEASE_VER"
echo "Updating to latest version..."
git tag ${RELEASE_VER}
git push origin ${RELEASE_VER}
else
echo "No updates available..."
fi
name: Docker Image CI
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Dockerfile
uses: actions/checkout@v4
- name: Set version based on tag
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Checkout planka Server
uses: actions/checkout@v4
with:
repository: plankanban/planka
ref: ${{ env.RELEASE_VERSION }}
path: planka
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: navystack/planka
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
flavor: |
latest=true
#- name: Set up QEMU
# uses: docker/setup-qemu-action@v3
#- name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v3
- name: Set up SSH
uses: MrSquaare/ssh-setup-action@v3
with:
host: ${{ secrets.SSH_ARM64_RUNNER }}
private-key: ${{ secrets.SSH_PRIVATE_KEY_ARM64_RUNNER }}
- name: Set up Buildx
uses: docker/setup-buildx-action@v3
with:
endpoint: ${{ secrets.AMD64_RUNNER_ENDPOINT }}
append: |
- endpoint: ${{ secrets.ARM64_RUNNER_ENDPOINT }}
platforms: linux/arm64
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
#- name: Build and push
# uses: docker/build-push-action@v5
# with:
# context: ./planka/
# file: ./planka/Dockerfile
# tags: ${{ steps.meta.outputs.tags }}
# labels: ${{ steps.meta.outputs.labels }}
# platforms: linux/amd64,linux/arm64,linux/arm/v7
# push: ${{ github.event_name != 'pull_request' }}
- name: Build and push
uses: docker/build-push-action@v5
with:
file: Dockerfile
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: ${{ github.event_name != 'pull_request' }}

1. GitHub Actions로 레포지토리 업데이트 자동화하기

1-1. Workflow 설정

먼저, 코드에서 사용된 GitHub Actions workflow에 대한 설정을 살펴봅시다. 아래의 코드 조각은 5분마다 또는 수동으로 실행될 수 있는 작업을 정의한 것입니다.

on:
schedule:
- cron: '*/5 * * * *'
workflow_dispatch:
  • schedule: 크론 표현식을 사용하여 주기적으로 workflow를 실행합니다. 현재 설정은 매 5분마다 실행하도록 되어있습니다.

  • workflow_dispatch: 수동으로 workflow를 실행할 수 있는 트리거입니다.

1-2. Jobs 및 Steps

아래 코드는 주요 작업(publish)과 해당 작업이 실행될 때 수행되는 단계(steps)를 정의합니다.

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
  • publish: 이 작업은 최신 업데이트를 확인하고 필요한 경우 나의 레포지토리를 업데이트합니다. Ubuntu 최신 버전에서 실행됩니다.

  • Checkout Code: 나의 레포지토리의 코드를 체크아웃하는 단계입니다. GitHub API 토큰(GH_PAT)을 사용하여 인증합니다. (태그를 기록하기 때문에 관련된 권한 역시 필요합니다.)

- run: |
LOCAL_VER=$(git -c 'versionsort.suffix=-' \
ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/NavyStack/planka-ns.git \
| tail --lines=1 \
| cut --delimiter='/' --fields=3)
RELEASE_VER=$(git -c 'versionsort.suffix=-' \
ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/plankanban/planka.git 'v*.*.*' \
| tail --lines=1 \
| cut --delimiter='/' --fields=3)
if [[ $RELEASE_VER != $LOCAL_VER ]]; then
echo "Local version: $LOCAL_VER"
echo "Latest upstream version: $RELEASE_VER"
echo "Updating to latest version..."
git tag ${RELEASE_VER}
git push origin ${RELEASE_VER}
else
echo "No updates available..."
fi
  • run: 실제로 업데이트를 확인하고 적용하는 스크립트가 실행되는 단계입니다. 이 스크립트는 두 프로젝트의 최신 태그를 비교하여 업데이트가 필요한 경우 자동으로 레포지토리를 업데이트합니다.

현재 https://github.com/NavyStack/planka-ns.githttps://github.com/plankanban/planka.git 를 비교하고 있습니다.
https://github.com/plankanban/planka.git가 업데이트 되면, https://github.com/NavyStack/planka-ns.git에 반영하는 구조입니다.

위의 설정에 따라서 https://github.com/NavyStack/planka-ns/tags 여기에 새로운 태그가 기록되고 아래의 설정을 통해서 Docker 이미지를 빌드하고 푸시 합니다.

2. GitHub Actions로 Docker 이미지 CI 설정하기

이 GitHub Actions workflow는 태그가 푸시되거나 수동으로 실행될 때 Docker 이미지를 빌드하고 푸시하는 작업을 수행합니다.

2-1. Workflow 설정

name: Docker Image CI
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
  • push: 태그가 푸시되면 workflow가 실행됩니다. 태그는 “v*..” 형식을 따라야 합니다.

  • workflow_dispatch: 수동으로 workflow를 실행할 수 있는 트리거입니다.

2-2. Jobs 및 Steps

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Dockerfile
uses: actions/checkout@v4
- name: Set version based on tag
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
  • build: Docker 이미지 빌드 작업을 정의합니다. Ubuntu 최신 버전에서 실행됩니다.

  • Checkout Dockerfile: Dockerfile을 체크아웃하는 단계입니다.

  • Set version based on tag: 현재 태그에서 버전을 추출하고 $GITHUB_ENV에 저장합니다.

- name: Checkout planka Server
uses: actions/checkout@v4
with:
repository: plankanban/planka
ref: ${{ env.RELEASE_VERSION }}
path: planka
  • Checkout planka Server: 레포지토리의 특정 버전을 체크아웃하는 단계입니다.
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: navystack/planka
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
flavor: |
latest=true
  • Docker meta: Docker 이미지의 메타데이터를 생성하는 단계입니다. Semantic versioning 및 이미지 플레이버를 설정합니다.
- name: Set up SSH
uses: MrSquaare/ssh-setup-action@v3
with:
host: ${{ secrets.SSH_ARM64_RUNNER }}
private-key: ${{ secrets.SSH_PRIVATE_KEY_ARM64_RUNNER }}
  • Set up SSH: SSH 연결을 설정하여 원격 환경에서 빌드를 실행할 수 있도록 합니다.

SSH 연결을 하는 가장 큰 이유는 멀티 아키텍쳐용 이미지를 만들기 때문이고, 가끔 Qemu에서 컴파일 오류가 나기 때문에 node를 append 해서 빌드합니다.

- name: Set up Buildx
uses: docker/setup-buildx-action@v3
with:
endpoint: ${{ secrets.AMD64_RUNNER_ENDPOINT }}
append: |
- endpoint: ${{ secrets.ARM64_RUNNER_ENDPOINT }}
platforms: linux/arm64
  • Set up Buildx: Docker Buildx를 설정하여 여러 플랫폼에서 빌드할 수 있도록 합니다.

기본 endpoint는 Github Runner입니다. append는 SSH를 통해서 접속하는 Self-host Arm 인스턴스 입니다.
위의 설정으로 기본적으로 amd64용 그리고 arm64용 이미지가 만들어집니다.

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
  • Login to Docker Hub: Docker Hub에 로그인합니다.

password: ${{ secrets.DOCKER_PASSWORD }} 라고 사용했지만 실제로는 토큰입니다. 코드를 재사용하다보니 DOCKER_PASSWORD로 되어 있네요 ㅎㅎ..

- name: Build and push
uses: docker/build-push-action@v5
with:
file: Dockerfile
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: ${{ github.event_name != 'pull_request' }}
  • Build and push: Docker 이미지를 빌드하고 푸시하는 단계입니다. 여러 플랫폼에서 빌드하고 푸시하며, 풀 리퀘스트 이벤트가 아닐 때만 푸시합니다.

이제 이 GitHub Actions workflow를 사용하여 태그가 푸시될 때마다 Docker 이미지를 빌드하고 푸시할 수 있습니다. 필요한 경우 이 예시를 참고하여 자신의 프로젝트에 맞게 설정할 수 있습니다.

Dockerhub에서 바로 확인해 보실래요? 바로가기

수고 많으셨습니다. 감사합니다.


Askfront.com (에스크프론트)

기존의 댓글 대신, 초보자도 자유롭게 질문할 수 있는 포럼을 만들었습니다.
에스크프론트에서는 가이드뿐만 아니라 모든 종류의 질문을 하실 수 있습니다.
검색해도 오래된 정보나 도움이 되지 않는 정보만 나오는 것 같고, 주화입마에 빠진 것 같은 기분이 들 때가 있습니다.
그럴 때, 부담 없이 질문해 주세요 :) 같이 의논하며 생각해봅시다.
가능하다면, 제가 답변 드리겠습니다. 고맙습니다.