CI/CDっぽいことがしたい
GitHub公式のCI/CDサービスGitHub Actionsを使って, リポジトリ上のDockerfileからimageをbuildしてpushする手順を試した.
まとめ
GitHubのPAT(個人アクセストークン)をリポジトリのSecretsにCR_PATとして登録した状態で以下のような.github/workflows/docker-publish.ymlを作成すると,
masterブランチへのcommitやrelease(tag)の作成時にDocker imageをGitHub ActionでGitHub Container Registryにpushすることができる.
pushしたimage : https://github.com/users/uzimihsr/packages/container/package/echo
# ghcr.io/<GitHubアカウント>/<image名>:<タグ>のimageをGitHub Packagesにpushするworkflow
name: Docker
on:
# masterブランチまたはvから始まるtag(例:`v1.2.3`)のpushでjobsを実行する
push:
branches:
- master
tags:
- v*
# 全ブランチのPRに対してもjobsを実行
pull_request:
env:
# <image名>を指定
IMAGE_NAME: echo
jobs:
# テスト用のjob
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
if [ -f docker-compose.test.yml ]; then
docker-compose --file docker-compose.test.yml build
docker-compose --file docker-compose.test.yml run sut
else
docker build . --file Dockerfile
fi
# imageをpushする
push:
# test jobが成功した場合のみトリガーされる
needs: test
runs-on: ubuntu-latest
# pushイベント以外(PRなど)では実行されない
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME
- name: Log into GitHub Container Registry
# `read:packages`と`write:packages`の権限を持つPAT(個人アクセストークン)をSecretに`CR_PAT`として登録しておく
# PATの作成手順 : https://docs.github.com/ja/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image to GitHub Container Registry
run: |
# <GitHubアカウント>が自動で選択される
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# git tagの値を<タグ>として付与
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# masterブランチへのcommitでトリガーされている場合はlatestを<タグ>として使う
[ "$VERSION" == "master" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION https://github.com/uzimihsr/echo-image/blob/master/.github/workflows/docker-publish.yml
環境
- macOS Mojave 10.14
- GitHub
- GitHub Packages
- Git
- git version 2.20.1 (Apple Git-117)
- Docker Desktop for Mac
- Version 2.1.0.3
- Docker Engine 19.03.13
やりかた
PATの発行とログイン
まずは公式ドキュメント1を参考に, GitHub Container Registryの認証に必要なPAT(個人アクセストークン)を発行する.
GitHubにログインした状態で
https://github.com/settings/tokens
を開き, Generate new tokenをクリック.
PATの権限設定画面ではwrite:packages, read:packagesにのみチェックを入れてGenetate tokenをクリック.
PATが発行される.
発行されたPATを使って, コマンドラインからGitHub Container Registryにログインする.
# GitHub Container Registryにログイン
$ echo <PAT> | docker login ghcr.io -u <GitHubアカウント> --password-stdin
Login Succeededこれでログインは成功.
手動でpush
上記の手順でGitHub Container Registryにログインした状態で, まずはコマンドラインからimageをpushしてみる.
適当なimageを作成.
# 適当なディレクトリで適当なDockerfileを作成
$ cd /path/to/workspace
$ touch Dockerfile
# Docker imageをビルド, 動作確認
$ docker image build -t echo:latest .
$ docker container run --rm echo:latest
hello, world!次にこのimageにGitHub Container Registry用のタグをつけ, pushする.
# imageのタグをつけ直す
$ docker image tag echo:latest ghcr.io/uzimihsr/echo:latest
# Docker imageをpush
$ docker image push ghcr.io/uzimihsr/echo:latest
The push refers to repository [ghcr.io/uzimihsr/echo]
be8b8b42328a: Pushed
latest: digest: sha256:c7926eae1c1aef6291e5eef1673c9815b5644fa9c417bfab65a4baba50c046a2 size: 527pushしたimageの情報はGitHub PackagesのUIから確認できる.
https://github.com/users/uzimihsr/packages/container/package/echo

もちろんこのimageをpullして使うこともできる.
# ローカルのimageを削除
$ docker image rm ghcr.io/uzimihsr/echo:latest
# imageをpull
$ docker image pull ghcr.io/uzimihsr/echo:latest
latest: Pulling from uzimihsr/echo
Digest: sha256:c7926eae1c1aef6291e5eef1673c9815b5644fa9c417bfab65a4baba50c046a2
Status: Downloaded newer image for ghcr.io/uzimihsr/echo:latest
ghcr.io/uzimihsr/echo:latest
# 動作確認
$ docker container run --rm ghcr.io/uzimihsr/echo:latest
hello, world!これでGitHub Container Registryを使ったimageのpush/pullができるようになった.
GitHub Actionsでpush
次にGitHub Actionsを使ってimageをGitHub Container Registryにpushしてみる.
新たにGitHubリポジトリを作成し, 先程作成したDockerfileをgit pushする.
作ったリポジトリ : https://github.com/uzimihsr/echo-image
# Dockerfileが存在する状態
$ ls
Dockerfile
# git initからpushまで
$ git init
$ git remote add origin https://github.com/uzimihsr/echo-image.git
$ git add .
$ git commit -m "initial commit"
$ git push origin masterリポジトリのActionsタブを開き, Publish Docker ContainerアクションのSet up this workflowをクリック.
workflowの定義ファイルdocker-publish.ymlを編集する画面が開く.
このままでも動くけど, 自分用にenv.IMAGE_NAMEだけ任意のimage名に修正する.
docker-publish.yml
# ghcr.io/<GitHubアカウント>/<image名>:<タグ>のimageをGitHub Packagesにpushするworkflow
name: Docker
on:
# masterブランチまたはvから始まるtag(例:`v1.2.3`)のpushでjobsを実行する
push:
branches:
- master
tags:
- v*
# 全ブランチのPRに対してもjobsを実行
pull_request:
env:
# <image名>を指定
IMAGE_NAME: echo
jobs:
# テスト用のjob
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
if [ -f docker-compose.test.yml ]; then
docker-compose --file docker-compose.test.yml build
docker-compose --file docker-compose.test.yml run sut
else
docker build . --file Dockerfile
fi
# imageをpushする
push:
# test jobが成功した場合のみトリガーされる
needs: test
runs-on: ubuntu-latest
# pushイベント以外(PRなど)では実行されない
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME
- name: Log into GitHub Container Registry
# `read:packages`と`write:packages`の権限を持つPAT(個人アクセストークン)をSecretに`CR_PAT`として登録しておく
# PATの作成手順 : https://docs.github.com/ja/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image to GitHub Container Registry
run: |
# <GitHubアカウント>が自動で選択される
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# git tagの値を<タグ>として付与
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# masterブランチへのcommitでトリガーされている場合はlatestを<タグ>として使う
[ "$VERSION" == "master" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION https://github.com/uzimihsr/echo-image/blob/master/.github/workflows/docker-publish.yml
docker-publish.ymlの編集が終わったら, Start commit -> Commit new fileと進みworkflowを作成する.
次にこのworkflowでGitHub Container Registryの認証を行うためのSecretsの設定をする.
リポジトリのSettingsタブを開き, New sectetをクリック.
Secretの作成画面ではNameをCR_PAT(docker-publish.yml内で参照している名前)に設定し, Valueには先程作成したPATを貼り付けてAdd secretをクリック.
Secretが作成された.
Secretを作成した状態でリポジトリのActionsタブを開くと,
先程のdocker-publish.yml作成時のcommitで起動したworkflowが失敗している.
(CR_PAT のSecretを作る前に実行されたため, 認証部分でコケている)
Re-run all jobsから再度workflowを実行してみる.
今度はCR_PATが作成済みなのでworkflowが正常に終了し, imageがghcr.io/uzimihsr/echo:latestにpushされた.
再度GitHub Packageの画面
https://github.com/users/uzimihsr/packages/container/package/echo
を開くと, 確かにLast publishedが更新されている.
以上でGitHub Actionsを使ってimageをGitHub Container Registryにpushする設定ができたので, 試しにimageを更新してみる.
# masterからhogeブランチを切る
$ git checkout master
$ git pull origin master
$ git checkout -b hoge
# Dockerfileを修正
$ vim Dockerfile
$ cat Dockerfile
FROM busybox
ENTRYPOINT [ "echo" ]
CMD [ "good morning!" ] # CMDを変更した
# commitしてhogeブランチをpush
$ git add ./Dockerfile
$ git commit -m "fixed Dockerfile: CMD"
$ git push origin hogeDockerfileの修正commitを積んだhogeブランチがpushされた状態でPR(master <- hoge)を作成すると, PRにトリガーされたworkflowが実行される.
testのjobのみが実行されpushのjobがスキップされているが, これは今回作成したdocker-publish.ymlでGitHub eventがpushの場合にのみ実行するよう設定しているため.
if: github.event_name == 'push'

このPRをmergeすると今度はmasterブランチへのpushが行われるので, それにトリガーされたworkflowでtestとpushのjobが実行される.
以降のimageがpushされるまでの流れは先程試した流れと同じで, latestタグのimageがpushされる.
latestタグだけではimageのバージョン管理が不便なので,
最新版のimageにバージョンタグを付与してみる.
やり方としては最新のcommitにgit tagをつけてpushするだけ.
# masterブランチで作業
$ git checkout master
$ git pull origin master
# masterブランチの最新のcommitにvから始まるtagをつけてpushする
$ git tag -a v0.0.1 -m "hogehoge"
$ git push origin v0.0.1するとtagのpushにトリガーされてworkflowが実行される.
今度はtagで指定したvからはじまる文字列がimageのタグとして付与されていることがわかる.
再度Packagesの画面を開くと確かにgit tagで指定した0.0.1のimageがpushされている.
今回はコマンドラインでtagをつけたけど, UIからreleaseを作っても同様にimageのpushができる.
最後にimageの動作確認を行う.
# 動作確認
$ docker container run --rm ghcr.io/uzimihsr/echo:0.0.1
good morning! # CMDの変更が反映されているやったぜ.GitHub Actionsを使ってGitHub Container Registryにimageをタグ付けしてpushできるようになった.
おわり
GitHubリポジトリ上のDockerfileからimageを作れるようになった.GitHub Actionsを使うのも初めてだったので, 練習にもなってよかった.Docker Hubが無料プランだといろいろ制限が厳しくなってきてるので2, (今のところは無料の)GitHub Container Registryに乗り換えていこうと思う.
おまけ

