GitHub PackagesでNode.jsのDockerイメージを管理する


早いもので1月もあと10日ほどで終わりですが、今年の冬は寒くリモートワークが有り難くも感じています。

節分の頃には、春に向けて期待が膨らませられる出来事が増えますように。

さて、
今回はこちら[Managing Node.js Docker images in GitHub Packages using GitHub Actions](https://snyk.io/blog/managing-node-js-docker-images-in-github-packages-using-github-actions/)を紹介します。

開発ですでにGithubは使っている方は多いと思いますが、node.jsのDockerイメージ管理についてのブログ記事の翻訳をご紹介いたします。


#GitHub Actionsを使ってGitHub PackagesでNode.jsのDockerイメージを管理する

リランタル
2021年7月13日
今日オープンソース開発を行っている場合は、GitHubコミュニティ内でアクティブになっている可能性が高く、オープンソースプロジェクトとそのリポジトリに参加しています。GitHubエコシステムに最近追加されたのは[GitHubパッケージ](https://github.com/features/packages)で、2019年に発表されたGitHub Packagesのコンテナレジストリが一般公開されたことで、さらにアップデートされています。これは、Dockerベースのイメージやその他のOCIに準拠したフォーマットを、完全にGitHubのエコシステム内で公開したりプルしたりできることを意味します。
この記事では、GitHub Actions のワークフローを順を追って説明していきます。[Node.jsプロジェクトをDockerイメージ](https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/)[<翻訳記事>](https://qiita.com/bricolageart/items/a509594a5b4c349e90b7)として公開し、それをGitHubパッケージコンテナーレジストリにプッシュする方法を学習します。
始める前に、GitHubサポートコミュニティと呼ばれるGitHubbers 専用のサポートフォーラムがあることをご存知でしょうか？何か困ったことがあったら、ぜひ訪れてみましょう。
この記事で紹介する Node.js プロジェクトは、[dockly](https://github.com/lirantal/dockly)です。dockly はオープンソースの Node.js コマンドラインツールで、docker コンテナやサービスを管理するための没入型ターミナルインターフェイスを提供します。

https://snyk.io/wp-content/uploads/blog-nodejs-docker-gh-dockly.png


###GitHub Actionワークフローの作成 
GitHub のオープンソースリポジトリを開き、Actions タブをクリックして New Workflow を選択し、次のようなワークフローを設定します：

https://snyk.io/wp-content/uploads/blog-nodejs-docker-gh-workflow.png
 


まず、ワークフローのファイル名を定義します。docker-publish.ymlまたはその他のお好みの命名規則で設定してください。
GitHub にはワークフローのコードがあらかじめ入力されていることがありますが、その場合はそれをすべて削除して以下のように貼り付けます。
 
```
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
  push:
    branches: [ main ]
    tags: [ 'v*.*.*' ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
```

上記のワークフローでは、以下のような規約を設定しています。

* ワークフローは、メインブランチへのコミット、あるいはメインブランチへのプルリクエストに対してのみ実行されます。
注意: リポジトリで master ブランチを使用している場合は、こことコードスニペットの残りの部分で名前を変更する必要があります。また、`<v*.*.*>`というsemver形式のタグがリポジトリにプッシュされた際にも実行されます。これは、各バージョンのDockerイメージを公開できるので便利です。

* 新しいDockerイメージが公開されると、GitHubリポジトリのタグも作成されるようになっています。
* また、ワークフローの他のジョブのために、GitHub Container Registry (ghcr.io)を指すグローバル環境変数を設定し、Dockerイメージの名前には、Docker Hubの`<user>/<repo>`のような標準的な規則、例えば`lirantal/nodejs-app`を使うように設定します。

次にジョブを定義します。このジョブでは、Dockerイメージをビルドしてから公開するまでのプロセスを確立します。


##GitHub Actions ワークフローの一環としての Docker イメージのビルド
DockerイメージをGitHub Packagesコンテナレジストリに（あるいはGitHubに）公開できるようにするには、まず有効なアカウントで認証する必要があります。そこで、ビルドと公開のジョブの最初のステップとして、ログインを行います。

先ほどのコード貼り付けの続きで、以下のコードをコピーします。
 
 ```jobs:
  build_and_publish:

    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Log into registry ${{ env.REGISTRY }}
        if: github.event_name != 'pull_request'
        uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
```

ここで紹介したジョブが実行するアクションを確認してみましょう。

1. 最初のステップは、リポジトリのソースコードをチェックアウトすることです。
2. 次に、GitHub Packages コンテナレジストリへの認証を行います。先ほど定義した環境変数 `REGISTRY` を再利用して、GitHub が提供するコンテナイメージのレジストリである `ghcr.io` を指定します。

認証するユーザー名はワークフローを開始したユーザーのもので、リポジトリのオーナーであるあなたのユーザーと一致するはずです。パスワードには `GITHUB_TOKEN` を使用します。これは GitHub Actions ワークフローで自動的に使用できるようになるもので、リポジトリのシークレットや環境変数として手動で追加する必要はありません。これがプルリクエストの場合、レジストリログインは発生しないことに気付くでしょう。これはいずれにせよ不要で、プルリクエストの CI やフォークに関する機密情報が漏えいする可能性があります。

3.上記のコードスニペットの最後のステップでは、イメージからメタデータを抽出し、Dockerイメージ構築プロセスで利用できるようにします（このワークフローの次の最後のステップです！）
メタデータは、Dockerビルドアクションで利用可能なタグやラベルに関する情報で構成されています。具体的には、渡された`images`の入力では、タグのベースネームとして使用するDockerイメージを定義します。

##DockerイメージのビルドとGitHub Packagesコンテナレジストリへの公開
最後のステップは、Dockerイメージをビルドして公開することです。これは、それをサポートするアクションを使用する統合ステップとして発生します。ただし、ワークフローのプッシュ入力を条件付きで設定し、プルリクエストでイベントがトリガーされなかった場合にのみイメージをレジストリに公開するようにしていることに気づくでしょう。
 
      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

これで終わりです。
ワークフローを（適切なインデントで！）保存し、このワークフローをメインブランチにマージしてトリガーすると、イメージがビルドされ、 GitHub Packages container registryに公開されます。
すべてがうまくいけば、私のように成功したジョブには待望の緑色のチェックマークが表示されるはずです。
これで終わりです。

https://snyk.io/wp-content/uploads/blog-nodejs-docker-gh-success.png

####DockerのイメージをGitHub Packagesのコンテナ・レジストリにプッシュするには？
GitHub Actions のワークフローファイルに Docker の公式 GitHub Action である `docker/build-push-action`を使用し、環境変数 `REGISTRY`に `ghcr.io` が設定されていることを確認します。
 
##GitHubパッケージコンテナレジストリからDockerイメージをプルする
プロジェクトのDockerイメージがパブリックレジストリに公開されたので、今度はローカル開発環境からプルしてテストしてみましょう。

```
$ docker pull ghcr.io/lirantal/my-nodejs-app
Using default tag: latest
latest: Pulling from lirantal/my-nodejs-app
b4d181a07f80: Pulling fs layer
de8ecf497b75: Pulling fs layer
69b92f9e5e70: Pulling fs layer
1f2b8e2c8ad8: Waiting
d0f4259cb643: Waiting
9ae47f3f99ba: Waiting
87270829eb60: Waiting
905fc634546c: Waiting
```

####プルするDockerバージョンイメージはどのように指定しますか？
docker pullコマンドは、`<registry>/<user>/<repo>:<image tag>`のスキームを持つ追加の引数を取ります。
例えば、GitHub Packages コンテナレジストリに登録されている `my-nodejs-app image` イメージから `docker pull ghcr.io/lirantal/my-nodejs-app` を引き出すには、次のようにコマンドを実行します。
成功しました！
今一度考えてみましょう。GitHub PackagesにプッシュしたDockerイメージを見るのに、もっといい方法はあるでしょうか？なさそうです。
 
 
##GitHubパッケージでDockerイメージを検索する 
GitHubプロファイルページ（私のhttps://github.com/lirantal?tab=packagesなど）
を参照すると、公開されているすべてのDockerイメージが表示されます。
このチュートリアルを実行して独自のDockerイメージを作成した場合、それを見つけることができますか？リポジトリGitHubActionsCIの一部としてGitHubパッケージにプッシュしたDockerイメージパッケージのページは次のとおりです。
 
https://snyk.io/wp-content/uploads/blog-nodejs-docker-gh-pushed.jpg

##公開されたDockerイメージに最新のタグがない？
使用しているメインブランチまたはマスターブランチのDockerイメージタグを指定せずに、名前でDockerイメージをプルしようとすると、一般的に使用されている最新のDockerイメージタグが利用できないことがあるかもしれません。semver（セマンティック・バージョニング）タグがプッシュされていない場合に起こるため、独自のリポジトリでそれらをプッシュして、使用できるようにします。
公開されたDockerイメージにDockerイメージタグの最新のエイリアスを適用する場合は、次のようにメタデータアクションを更新できます（追加の複数行フレーバーキーに注意してください）。
公開されたDockerイメージにDockerイメージタグlatestのエイリアスを強制したい場合は、以下のようにメタデータアクションを更新します（複数行のフレーバーキーが追加されていることに注目してください）。
 
     - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: |
            latest=true
            prefix=
            suffix=
 
ただし、メインブランチがCIジョブをトリガーする際に公開されるDockerイメージのエイリアスには、常に最新のイメージタグが設定されることになるので注意してください。
 
####Dockerイメージにlatestとタグ付けするには？
以前にビルドしたものからローカルにイメージをタグ付けするには、次のようなDocker tag imageコマンド構造を使用します： `dockertag <local image name> <new tag>`　例：`docker tag my-nodejs-app lirantal/my-nodejs-app:latest`

##タグ付きのDockerイメージを実行するにはどうすればよいですか？
イメージの実行時に特定のDockerイメージタグを使用するには、完全修飾されたイメージ名とタグをdocker runコマンドに指定するだけです。例えば：`docker run --rm -p 27017:27017 mongo:latest`

##GitHub Actions Marketplaceは、関連するDockerおよびContainer関連の統合機能がある
GitHub Actionsワークフローを探して作成するもう1つの方法は、[GitHub Actions Marketplace](https://github.com/marketplace?type=actions)で、コード品質、依存性管理、セキュリティなど、9000以上のワークフローが用意されています。[Snyk GitHub Action](https://github.com/marketplace/actions/snyk)は、オープンソースのライブラリに存在するサードパーティの脆弱性からプロジェクトの安全性を確保し、チームが[セキュアなコーディングプラクティス](https://snyk.io/learn/secure-coding-practices/)を実践するためのものです。
 
この記事の焦点である、Dockerイメージの構築、テスト、レジストリへの公開については、Marketplaceを閲覧するよりも簡単に始めることができます。リポジトリにすでに Dockerfile があれば、GitHub はそれを自動的に検出し、GitHub Actions に使用する関連ワークフローを提案します。つまり、[Actions]タブに移動するだけです。
 
https://snyk.io/wp-content/uploads/blog-nodejs-docker-gh-actions.png

最初に提案されたワークフロー「Publish Docker Container」では、すでに確認したものと同様のDockerイメージ公開およびDockerイメージ構築ワークフローが設定されます。
 
##まとめとフォローアップ
 
セキュアな開発手法に少しでも興味を持っていただけたら光栄です。あなたのチームでセキュリティ力を向上させるための、お勧めの資料をご紹介します:
 
1. サプライチェーン・セキュリティは重要なので[GitHubセキュリティのベストプラクティス10](https://snyk.io/blog/ten-git-hub-security-best-practices/)をご案内します。
2. あなたはNode.jsとnpmパッケージの構築にハマってますか？私もです。こちらの記事では、[GitHub Actions を使って npm パッケージを安全に公開する方法](https://snyk.io/blog/github-actions-to-securely-publish-npm-packages/)を紹介しています。
もしあなたがGitHubのエコシステムの中で多くの時間を使っているとしたら、ワークフローの中でより統合された体験を提供するSnykのコードスキャンをチェックしてみてください。[GitHub Security Code Scanning: あなたのオープンソースの依存関係を保護する](https://snyk.io/blog/github-security-code-scanning/)
 



######最後まで、お付き合いいただきありがとうございました！！！

---
Contents provided by:
Jesse Casman, Fumiko Doi, Content Strategists for Snyk, Japan, and Randell Degges, Community Manager for Snyk Global