皆さんはGitHub ActionsやGitHub Registryを利用していますか?
まだGAになっていないので使っていない方もいるかもしれませんが、来週の11/13(水)にGAとなるので今のうちにお試しで使ってみることをお勧めします。
それでは本題ですが、GitHub ActionsでビルドしたDockerイメージを後続のjobで使い回したい時にどのようにしていますか?
元々パブリックなリポジトリならDocker Hubにプッシュしたりできますが、プライベートリポジトリではそうできません。プライベートレジストリをもっていれば全て解決しますが、自前で立てたり、課金しなくてはならないので少し大変です。
ちなみに私は以前書いた記事にあるように毎回ビルドしていました
これでは同じイメージではないので、よろしくありません。せっかくTrivyやDockleを使ってスキャンをしているのに...
そこで今回は、GitHub Package Registryを利用してGitHub Actionsのworkflowの中で1度ビルドしたDockerイメージを使いまわす方法を説明していきたいと思います。workflowは以前書いた記事を使用します。
GitHub Package Registryとは?
GitHub Package Registryとはソフトウェアパッケージのホスティングサービスです。Docker HubやPyPIなどをイメージしてもらえれば分かりやすいと思います。
以下が公式ドキュメントの冒頭の説明文です。
GitHub Package Registry is a software package hosting service, similar to npmjs.org, rubygems.org, or hub.docker.com, that allows you to host your packages and code in one place. You can host software packages privately or publicly and use them as dependencies in your projects.
GitHub Package Registry使用方法
セットアップ
こちらのリンクへ飛んでボタンを二回程クリックすればすぐに使うことができます。めっちゃ簡単
Dockerイメージのプッシュ
GitHubのDocker Registryにプッシュする方法はとても簡単です。他のプライベートレジストリやサードパーティーレジストリへのプッシュ方法と基本的に同じです。
ただ、GitHubへのログインに二段階認証を有効にしている場合は、Registryへログインする際にアクセストークンが必要になります。こちらを参考にトークンを取得してください。
# DockerのRegistryにログイン
docker login docker.pkg.github.com -u owner -p password
# DockerfileはCWDにあるとする
docker build -t docker.pkg.github.com/owner/repository_name/sample .
# GitHub Package Registryへプッシュ
docker push docker.pkg.github.com/owner/repository_name/sample
イメージ名は後から変更可能なので以下のようにしてもOKです。
docker build -t sample .
docker tag sample docker.pkg.github.com/owner/repository_name/sample
Dockerイメージのプル
# DockerのRegistryにログイン
docker login docker.pkg.github.com -u owner -p password
docker pull docker.pkg.github.com/owner/repository_name/sample
とりわけ難しい部分もないのでGitHub Actionsでやってみましょう
GitHub Actions
GitHub ActionsからGitHub Package Registryを利用するTipsは、docker login
パスワードに環境変GITHUB_TOKEN
の指定することです。GitHub Actionsが自動生成してくれるので、わざわざボタンをポチポチしてトークンを生成して管理する必要はなくなります。
処理の流れ
+-----------------+
| ① |
| build |
| Dockerイメージを |
/| ビルドしてプッシュ |\
/ | | \
/ +-----------------+ \
/ \
+-----------------+ +-----------------+
| ② | | ②' |
| Trivy | | Dockle |
| | | |
+-----------------+ +-----------------+
\ /
\ /
\ /
\ /
+-----------------+
| ③ |
| Push to ECR |
| |
+-----------------+
Workflow例
name: Push Docker image to ECR
# リモートブランチにプッシュされたらWorkflowが起動
on: push
env:
# BuildKitを有効化
DOCKER_BUILDKIT: 1
IMAGE_NAME: sample
IMAGE_TAG: test
jobs:
build:
name: Build image
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@master
- name: Login GitHub Registry
# 自動生成されるGITHUB_TOKENを使用する
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u owner --password-stdin
- name: Build image
# `github.repository`で`owner/repository_name`が取得できる
run: docker build -t docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG} --file Dockerfile .
- name: Push image to GitHub Registry
run: docker push docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG}
- name: Notify Result to Slack
uses: homoluctus/slatify@master
if: always()
with:
type: ${{ job.status }}
job_name: ':docker: *Build image*'
channel: '#general'
url: ${{ secrets.SLACK_WEBHOOK }}
trivy:
name: Trivy Scan Vulnerability
runs-on: ubuntu-18.04
needs: build
steps:
- uses: actions/checkout@master
- name: Login GitHub Registry
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u owner --password-stdin
- name: Pull image from GitHub Registry
run: docker pull docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG}
- name: Install trivy
run: |
sudo apt-get install --no-install-recommends apt-transport-https gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install --no-install-recommends trivy
- name: Vulnerability Scan with Trivy
run: |
trivy -q --severity HIGH,CRITICAL \
--exit-code 1 docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG}
- name: Notify Result to Slack
uses: homoluctus/slatify@master
if: always()
with:
type: ${{ job.status }}
job_name: ':trivy: *Trivy*'
channel: '#general'
url: ${{ secrets.SLACK_WEBHOOK }}
dockle:
name: Dockle
runs-on: ubuntu-18.04
needs: build
steps:
- uses: actions/checkout@master
- name: Login GitHub Registry
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u owner --password-stdin
- name: Pull image from GitHub Registry
run: docker pull docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG}
- name: Install dockle
run: |
VERSION=$(curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/' \
)
curl -L -o dockle.deb https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.deb
sudo dpkg -i dockle.deb
rm dockle.deb
- name: Check image with dockle
run: dockle docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG}
- name: Notify Result to Slack
uses: homoluctus/slatify@master
if: always()
with:
type: ${{ job.status }}
job_name: ':docker: *Dockle*'
channel: '#general'
url: ${{ secrets.SLACK_WEBHOOK }}
push:
name: Push Docker Image to ECR
runs-on: ubuntu-18.04
needs: [trivy, dockle]
steps:
- uses: actions/checkout@master
- uses: actions/setup-go@master
with:
go-version: '1.13'
- name: Install ecs-cli
run: go get github.com/aws/amazon-ecs-cli/ecs-cli
- name: Login GitHub Registry
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u owner --password-stdin
- name: Pull image from GitHub Registry
run: |
docker pull docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG}
# Change docker image name
docker tag docker.pkg.github.com/${{ github.repository }}/${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:${IMAGE_TAG}
- name: Push image to ECR
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ap-northeast-1
# GOPATH bug [reference](https://github.com/actions/setup-go/issues/14)
run: $(go env GOPATH)/bin/ecs-cli push ${IMAGE_NAME}:${IMAGE_TAG}
- name: Notify Result to Slack
uses: homoluctus/slatify@master
if: always()
with:
type: ${{ job.status }}
job_name: ':rocket: *Push to ECR*'
channel: '#general'
url: ${{ secrets.SLACK_WEBHOOK }}
これで一回のDockerイメージビルドで後続のJobでもそのイメージを使いまわせるようになりました