Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

GitHub Actions에서 GitHub Container Registry에 이미지 푸시하기

GitHub Container Registry 사용하기에서 GitHub에서 제공하는 Container Registry의 사용 방법을 살펴봤다.

Container Registry를 살펴본 원래 이유는 Docker Hub에서 운영하던 도커 이미지를 GitHub으로 배포하기 위함이었고 기존에는 Docker Hub의 Automated Build를 이용해서 릴리스할 때마다 자동으로 Docker 이미지를 빌드하게 해두었는데 GitHub Container Registry에는 이런 기능이 없기 때문에 GitHub Actions를 이용해서 자동으로 컨테이너 이미지를 릴리스하도록 하기 위함이었다.

GitHub Actions 워크플로우 작성

GitHub에 Publishing Docker images 문서가 있지만, 아직 GitHub Packages 기준으로 문서가 작성되어 있다. 그리고 Docker에서 만든 docker/build-push-action 액션을 사용하고 있지만 2020년 10월에 v2가 나왔음에도 아직 v1을 기준으로 설명하고 있다.

그래서 docker/build-push-action@v2를 가지고 새로 테스트했다. Docker에서 만들었다 보니 GitHub Container Registry 예제는 따로 구성되어 있지 않아서 Docker Hub와 같이 푸시하는 Push to multi-registries 예제를 참고했다.

name: ci

on:
  push:
    tags:
      - 'v*'

도커 이미지는 릴리스할 때만 레지스트리에 등록할 것이므로 v로 시작하는 태그가 푸시 될 때만 실행되도록 했다.

jobs:
  image-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set env
        run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV

저장소의 코드를 체크아웃한 다음에 태그를 나중에 사용하기 위해서 환경변수를 지정했다. Set env 부분은 GitHub 액션에서 환경 변수를 지정하는 방법이다. 여기서 v1.2.3이란 태그를 푸시한다면 GITHUB_REF에는 refs/tags/v1.2.3가 저장되어 있으므로 앞부분을 잘라내고 1.2.3RELEASE_VERSION라는 환경 변수에 저장한다. 이 값은 나중에 도커 이미지 태그에 사용할 것이다. 이 방법은 Stackoverflow를 참고했다.

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

YAML을 나누어서 설명하다 보니 들여쓰기를 없앴지만 jobs.image-push.steps에 이어진 부분이다.

docker/build-push-action@v2는 사전에 필요한 작업을 여러 액션으로 나누어 두었는데 그중 하나인 docker/setup-buildx-action이다. 이 액션은 BuildKit을 이용하는 Docker CLI의 플러그인인 buildx를 설정한다. BuildKit는 아직 공부를 안해서 자세히 모르는데 뒤에서 Docker 이미지를 빌드하고 푸시할 때 이 buildx를 사용한다.

관련 액션의 문서를 보면 setup-qemu-action도 나오는데 내 용도에서는 필요가 없어서 사용하지 않았다. 이번에 처음 본 건데 QEMU라는 프로세스 에뮬레이터를 이용해서 여러 아키텍처의 컨테이너를 사용할 수 있도록 qemu-user-static 바이너리를 설치해 주는 액션이다.

- name: Login to GitHub Container Registry
  uses: docker/login-action@v1
  with:
    registry: ghcr.io
    username: ${{ github.repository_owner }}
    password: ${{ secrets.CR_PAT }}

docker/login-action 액션으로 GitHub Container Registry에 로그인한다. registry: ghcr.io로 저장소를 지정하고(ghcr은 GitHub Container Registry의 약자이다.) 사용자 이름은 직접 지정해도 되지만 저장소 소유자를 따라가도록 github.repository_owner로 지정했다.

비밀번호는 엑세스 토큰을 사용해야 하므로 secrets.CR_PAT이라고 지정했다.(CR_PAT은 Container Registry Personal Acccess Token이다.) GitHub Container Registry 사용하기에서 엑세스 토큰을 설명한 것처럼 packages의 권한을 가진 토큰을 만들어서 저장소의 Secrets에서 CR_PAT이라는 이름으로 등록하면 secrets.CR_PAT으로 가져다 사용할 수 있다.

저장소 설정의 Secrets에서 CR_PAT 시크릿 설정

제대로 설정했으면 GitHub Actions의 로그에서 로그인이 성공하는 것을 볼 수 있다.

GitHub Actions 로그에 출력된 Login Succeeded

- name: Build and push
  uses: docker/build-push-action@v2
  id: docker_build
  with:
    context: .
    file: ./Dockerfile
    push: true
    tags: |
      ghcr.io/${{ github.repository_owner }}/my-container-test:latest
      ghcr.io/${{ github.repository_owner }}/my-container-test:${{ env.RELEASE_VERSION }}

이제 실제로 Docker 이미지를 빌드하고 레지스트리에 푸시하는 단계다. 앞에서 계속 설명한 docker/build-push-action@v2를 사용했고 Dockerfile 등을 지정했고 ghcr.io/outsideris/my-container-test:latest같은 태그가 생성되도록 설정했다. 현재 릴리스한 버전과 latest를 같이 푸시하도록 했고 앞에서 설정한 RELEASE_VERSION 환경 변수를 여기서 사용하고 있다.

앞에서 설정한 buildx를 사용해서 빌드하는데 실행되는 명령어는 다음과 같다.(여기서는 buildx 0.4.2 버전이 사용되었다.)

$ /usr/bin/docker buildx build \
  --tag ghcr.io/outsideris/my-container-test:latest \
  --tag ghcr.io/outsideris/my-container-test:0.9 \
  --iidfile /tmp/docker-build-push-1zbDtO/iidfile \
  --file ./Dockerfile \
  --push .

저장소에서 릴리스할 때 git tag v0.9처럼 태그를 붙인 뒤 git push origin main --tags로 태그를 같이 푸시하면 지금까지 설정한 액션이 실행된다. 성공적으로 이미지가 푸시되면 나면 GitHub Container Registry에 등록된 것을 확인할 수 있다.

GitHub Container Registry에 푸시된 이미지

이제 태그만 붙여서 푸시하면 된다.

지금까지 설명한 YAML의 전체 내용은 다음과 같다.

name: ci

on:
  push:
    tags:
      - 'v*'

jobs:
  image-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set env
        run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: |
            ghcr.io/${{ github.repository_owner }}/my-container-test:latest
            ghcr.io/${{ github.repository_owner }}/my-container-test:${{ env.RELEASE_VERSION }}
2021/01/27 02:43 2021/01/27 02:43