【CI/CD】 Github Actionsを使ってDocker ImageをGitHub Package Registry にpushする

Githubにもワークフローの実行ツールのGithub Actionsとパッケージの管理機能のGitHub Package Registryが追加されました。これらを使うことで、CIプロセスにおけるDockerのbuildやpushをGithubの機能で完結できます。ここでは、Docker imageをGithub Actions、GitHub Package Registry によって公開するまでの手順を解説します。

# 前準備
手順を進めて最終的に出来上がるリポジトリは[こちら](https://github.com/k8shiro/github_docker_push_example)です。

準備として、以下のような構成のリポジトリをGithubに作成します。

```
./
　┣ README.md
　┗　app/
　    ┗ Dockerfile
```

Dockerfileは3秒ごとに`echo hello`を実行するだけの単純なものです。



```Dockerfile
# ./app/Dockerfile 
FROM alpine:3.10.3
CMD while :; do echo hello; sleep 3; done
```

上記のリポジトリをpushしたら準備は完了です。

# Workflowを追加

GithubのUI上でベースとなるファイルを生成します。
上部のActionsからSet up a workflow yourselfをクリックします。

![スクリーンショット 2019-11-24 11.26.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/2ef65f5a-37b8-d988-f959-d6dc19bbd4d7.png)

編集画面が出ますが一旦このまま右上の緑のボタンからcommitしてください。

![スクリーンショット 2019-11-24 11.27.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/d648e961-f9d2-64b3-bf91-1e9eb7361bb5.png)

この操作で`.github/workflows/main.yml`が生成されました。ローカルで編集するため`git pull`して中身を確認すると以下のymlファイルが作成されています。

```
name: CI

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Run a one-line script
      run: echo Hello, world!
    - name: Run a multi-line script
      run: |
        echo Add other actions to build,
        echo test, and deploy your project.
```

リポジトリ全体はこのようになりました。

```
./
 ┣ README.md
 ┣ .github/
 ┃  ┗ workflows/
 ┃     ┗ main.yml
 ┗ app/
   ┗ Dockerfile
```

# Workflowが実行されていることを確認
この時点でmain.ymlがpushされているのでWorkflowが動くことを確認できます。

ActionsのCIをクリックすると実行結果画面になり`main.yml`でechoされたものが確認できます。

![スクリーンショット 2019-11-24 11.29.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/8dc10db3-82a3-3a00-cc72-2e556af003d5.png)

![スクリーンショット 2019-11-24 11.30.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/e76d8c09-ca88-e5b3-a19b-f8e2cf9e275f.png)

# secretsの設定
認証情報等の秘密情報はmain.ymlに埋め込むわけには行かないので、リポジトリのsecretsに設定する必要があります。今回は埋め込んでしまっても問題ないのですが、secretsにユーザー名を設定してみます。

Settings > Secrets > Add a new secret と進むと下のような画面になり、ここにsecretを追加しておきます。

![スクリーンショット 2019-11-24 12.50.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/739f22a5-1333-ffd6-1bc3-18af899da3e1.png)

一つは`GITHUB_DOCKER_USERNAME`でここはリポジトリのオーナー(自分のユーザ名)を指定します。今回は特にこれ以外の登録すべきものはありませんが、他にもパスワード等の情報が必要な場合はここに登録することでGithub Actionsの中で使用できます。

※ Gitlab CIだと`$CI_REGISTRY_USER`でregistryにloginできるのでGithub Actionsでもこれに相当するものがありそうな気がするが調べきれませんでした。そのうち見つかれば直します。

# Dockerfileをbuildしてpushするようにする。

`.github/workflows/main.yml`を編集してDockerのbuildとpushが行われるようにします。以下のように編集してください。test_containerというimageがブランチ名をタグとしてpushされるようになります。

```
name: CI

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: build Dockerfile and push image # userで外部ファイル or 定義済みの処理を実行できる。ここではリポジトリのcheckout
      run: |
        IMAGE_NAME=test_container:${GITHUB_REF#refs/heads/} # docer imageの名前とそのタグ、${GITHUB_REF#refs/heads/}でブランチ名を取得している
        docker build ./app --tag docker.pkg.github.com/${GITHUB_REPOSITORY}/${IMAGE_NAME}
        docker login docker.pkg.github.com --username ${DOCKER_USERNAME} --password ${DOCKER_PASSWORD}
        docker push docker.pkg.github.com/k8shiro/github_docker_push_example/${IMAGE_NAME}
      env:
          DOCKER_USERNAME: ${{ secrets.GITHUB_DOCKER_USERNAME }} # リポジトリのsecretsとして定義した値を環境変数に渡す
          DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
```

ファイルの内容の説明です。詳細や今回使用していないものは
https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
に記載されています。

```
name: CI # ワークフローの名前
```

```
on: [push] # ワークフローをトリガーするGitHubイベントの名前、ここではリポジトリへのpushでワークフローが実行される
```

トリガーはwikiの変更やissueに関するイベント等様々なものがあります。
参照: https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows

```
runs-on: ubuntu-latest # ワークフローの実行環境の指定
```

runs-onでワークフローの実行環境となるrunnerを指定します。Windows Server等も用意されているようです→[GitHub-hosted runners](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources)。
また自分でrunnerを用意することもできます。

- Self-hosted runners について: 
    - https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/hosting-your-own-runners
    - https://github.blog/2019-11-05-self-hosted-runners-for-github-actions-is-now-in-beta/


```
uses: actions/checkout@v1 # 既定のアクションを実行、ここではリポジトリのcheckoutのアクションを実行している
```

`uses`ではGithub既定のアクションの呼び出し、または自分で定義した別ファイルのアクションを呼び出せます。


```    
    - name: build Dockerfile and push image
      run: |
        IMAGE_NAME=test_container:${GITHUB_REF#refs/heads/} # docer imageの名前とそのタグ、${GITHUB_REF#refs/heads/}でブランチ名を取得している
        docker build ./app --tag docker.pkg.github.com/${GITHUB_REPOSITORY}/${IMAGE_NAME} # Dockerfileのbuild
        docker login docker.pkg.github.com --username ${DOCKER_USERNAME} --password ${DOCKER_PASSWORD} # GitHub Package Registryへのlogin
        docker push docker.pkg.github.com/k8shiro/github_docker_push_example/${IMAGE_NAME} # imageのpush
      env:
          DOCKER_USERNAME: ${{ secrets.GITHUB_DOCKER_USERNAME }} # リポジトリのsecretsとして定義した値を環境変数に渡す
          DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}           # Github Actionsで規定で定義されるGITHUB_TOKENを使用
```
Dockerのbuild・pushを行う処理です。まず、一番下の`env`ですが、ここで環境変数を設定しています。先ほど設定したsecretsが`secrets.*****`で読み込まれ、これが`DOCKER_USERNAME`として設定されています。また、`secrets.GITHUB_TOKEN`はデフォルトで定義されるTokenでPermissions等は[ここ](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#undefined)に記載されています。`GITHUB_REF`、`GITHUB_REPOSITORY`はデフォルトで定義されている環境変数です。その他の環境変数は[こちら](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/using-environment-variables#default-environment-variables)です。

ここまで編集が終了したら`.github/workflows/main.yml`をcommitとpushしてください。

# 動作確認
先ほどWorkflowの実行を確認した時と同様に動作確認してください。

![スクリーンショット 2019-11-24 14.07.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/46ab1168-eac2-d965-80cc-f16c8ad52535.png)

また、packageにimageがpushされているかも確認しておきます。packageをクリックすると以下のようにレジストリが作成されていることが確認できます。

![スクリーンショット 2019-11-24 14.10.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/c0a033c1-186e-64d5-fbf7-8fcbdc2ff754.png)

![スクリーンショット 2019-11-24 14.27.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/6eda3d48-d9f6-e2f7-ab8a-4754626398b6.png)

これでdocker pullできます。pullする時には先ほどのToken(or 同等の権限を持つもの)でdocker loginする必要があります。pullコマンドは以下のように表示されています。

![スクリーンショット 2019-11-24 14.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/681e7c8b-da98-3c66-d913-4bd10ce1ed9b.png)

# ImageをPullする

自分の開発環境に作成されたdocker imageを落としてくるには、上記画像の通り`docker pull`コマンドを実行すればよいのですが、pullの前に`docker login`コマンドを実行する必要があります。

```
docker login docker.pkg.github.com　-u <username> -p <personal access token>
docker pull docker.pkg.github.com/k8shiro/github_docker_push_example/test_container:master
```

ここで<username>は自分のユーザー名でよいのですが、<personal access token>はGithubのパスワードではだめで、Personal Access Tokenを取得する必要があります。

## personal access token
GitHub Package Registryへのloginには、personal access tokenを使用する必要があります。

自分のアカウントのSettingsから

![スクリーンショット 2019-11-24 13.37.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/12620574-df8e-1439-3dbb-76a0a3c1d65a.png)

Developer settingsに移動し![スクリーンショット 2019-11-24 13.41.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/c89c3e36-c627-dab0-dd1f-028b84dac090.png)


![スクリーンショット 2019-11-24 13.39.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/da2ac5a6-c550-41b4-53b2-9ddf76fcdedd.png)

Generate new tokenから新しいTokenを作成します。

![スクリーンショット 2019-11-24 13.41.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/c5a88ded-3e5c-c477-9b21-4fd677edac42.png)

まずNoteの部分にこのTokenの説明(他のTokenと区別がつくように、今回はリポジトリ名を記載)を設定し、その下のScopeを設定していきます。必要なScopeは

- repo
- write:packages
- read:packages

あたりになります。

![スクリーンショット 2019-11-24 12.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86684/164973b8-7aa1-85fa-289b-b7dbf0378bdf.png)

これでページ下部のGenerate TokenをクリックするとTokenが表示されます。
Tokenは`11aaaa1aba999951abca2406b92a66665d3cb22`のような文字列でこのタイミング以外では二度と表示されないのでからなず確認し、また流出等扱いには気をつけてください。

# まとめ
Github Actionsを使ってDocker ImageをGitHub Package Registry にpushする一連の操作を説明しました。CI/CDツールとしての利用は多くの場合、Github ActionsとGitHub Package Registryを利用することで完結できるのではないかと思います。また、課金プランによって[使用制限](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/about-github-actions#usage-limits)があるようですが無料アカウントでも個人レベルでの使用では問題なさそうです。ただし、[使用制限](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/about-github-actions#usage-limits)下部に記載がある通り、仮想通貨の採掘やサーバーレスコンピューティングを目的とする場合等、コード開発プロセスの自動化以外の目的に使うことは制限されているようなので注意しましょう。