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: 527
pushした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 hoge
Dockerfile
の修正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
に乗り換えていこうと思う.