Skip to main content

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

著者
blog hero github actions docker push

2021年7月13日

0 分で読めます

現在、オープンソース開発に取り組んでいる方の多くは、GitHubコミュニティで活動し、オープンソースプロジェクトやそのリポジトリに参加していることでしょう。GitHubエコシステムに最近加わったのがGitHub Packagesです。2019年に発表され、現在はGitHub Packagesのコンテナレジストリが一般提供されるなど、さらにアップデートが進んでいます。これにより、Dockerベースのイメージや、OCI準拠のその他の形式をGitHubエコシステム内だけで公開したりプルしたりできるようになりました。

この記事では、GitHub Actionsのワークフローを一つずつ解説します。Node.jsプロジェクトをDockerイメージとして公開し、GitHub Packagesのコンテナレジストリにプッシュする方法を紹介します。

始める前に、GitHubユーザー向けの専用サポートフォーラム、GitHub Support Communityをご存じですか?困ったことがあれば、ぜひチェックしてみてください。

この記事で取り上げるNode.jsプロジェクトはdocklyです。Dockerコンテナやサービスを管理するための、臨場感のあるターミナルインターフェースを提供するオープンソースのNode.jsコマンドラインツールです。

DocklyのREADME。コンテナ一覧、ステータスチャート、ログを表示する、Dockerコンテナ管理用のターミナルインターフェース。

GitHub Actionsワークフローを作成する

GitHubでオープンソースリポジトリを開き、Actionsタブ、続いてNew Workflow、set up a workflow yourselfの順にクリックします。次のような画面が表示されます。

「ワークフローテンプレートを選択」見出しと、ワークフローを選択または設定するオプションが表示されたGitHub Actionsのページ

まず、ワークフローファイル名を定義します。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 }}

上記のワークフローでは、次の規則を設定しています。

  • このワークフローは、mainブランチへのコミット、またはmainブランチ宛てのプルリクエストでのみ実行されます。注:以前の規則に従ってリポジトリで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イメージをビルドして公開します。これらの処理に対応するアクションを使い、1つのステップとして実行します。ただし、ワークフローのpush入力には条件を設定し、プルリクエストでイベントが発生した場合はイメージをレジストリに公開しないようにしています。

      - 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 }}

これで完了です。

インデントを正しく設定してワークフローを保存し、mainブランチにマージして実行すると、イメージがビルドされ、GitHub Packagesのコンテナレジストリに公開されます。

すべてうまくいけば、私の場合のように、ジョブが成功したことを示す待望の緑色のチェックマークが表示されます。

masterブランチでイメージのビルドとGHCRへのプッシュが成功したことを示すGitHub Actionsワークフロー

DockerイメージをGitHub Packagesのコンテナレジストリにプッシュするには?

GitHub Actionsのワークフローファイルで、公式Docker GitHub Actionのdocker/build-push-actionを使用し、環境変数REGISTRYにghcr.ioを設定してください。

GitHub Packagesのコンテナレジストリから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の「latest」タグをプルするには、次のコマンドを使います。docker pull ghcr.io/lirantal/my-nodejs-app

やった、成功です!

でも、ちょっと待ってください。GitHub PackagesにプッシュしたDockerイメージを、もっと簡単に確認する方法はないでしょうか?こちらをご覧ください。

GitHub PackagesでDockerイメージを見つける

GitHubプロフィールページ(私の場合はhttps://github.com/lirantal?tab=packages)を開くと、公開中のDockerイメージをすべて確認できます。

このチュートリアルに沿ってDockerイメージをビルドした方は、自分のイメージを見つけられるでしょうか?こちらが、リポジトリのGitHub Actions CIを使ってGitHub PackagesにプッシュしたDockerイメージパッケージのページです。

docklyのGitHub Container Registryページ。Dockerのpullコマンド、タグ付きイメージのバージョン、READMEが表示されています。

公開したDockerイメージにlatestタグがない場合

使用中のmainまたはmasterブランチのDockerイメージを、タグを指定せず名前だけでプルしようとして、よく使われるDockerイメージタグlatestがないことに気づいたかもしれません。これは、semver(セマンティックバージョニング)タグがプッシュされていない場合に発生します。自分のリポジトリでタグをプッシュしていれば、利用できる可能性があります。

公開するDockerイメージにlatestエイリアスを必ず設定するには、次のようにメタデータアクションを更新します(複数行のflavorキーが追加されている点に注目してください)。

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: |
            latest=true
            prefix=
            suffix=

ただし、この設定では、mainブランチをトリガーとしてCIジョブが実行されるたびに、公開するDockerイメージのエイリアスとしてlatestタグが必ず設定されます。

Dockerイメージにlatestタグを付けるには?

ビルド済みのイメージにローカルでタグを付けるには、次のDocker tagコマンドの形式を使用します。docker tag <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やコンテナ関連の便利なインテグレーション

GitHub Actionsワークフローを見つけて作成するもう一つの方法は、GitHub Actions Marketplaceを利用することです。コード品質、依存関係管理、セキュリティなど、9,000以上のワークフローが揃っています。オープンソースライブラリに潜むサードパーティの脆弱性からプロジェクトを守り、チームがセキュアコーディングのプラクティスに従っていることを確認できるSnyk GitHub Actionsもあります。

この記事では、Dockerイメージをビルド、テストし、レジストリに公開する方法を取り上げています。Marketplaceを探し回るよりも簡単に始める方法があります。リポジトリにDockerfileがあれば、GitHubが自動的に検出し、GitHub Actionsで使える関連ワークフローを提案してくれます。Actionsタブを開くだけです。

Dockerコンテナの公開またはDockerイメージのビルドにおすすめのDockerfileワークフローが表示されたGitHub Actionsのセットアップページ

最初に提案されるワークフローPublish Docker Containerを使えば、先ほど確認したものと同様のDockerイメージのビルド・公開ワークフローを設定できます。

まとめと次のステップ

セキュアな開発プラクティスに興味が湧いてきましたか?すばらしいですね!学習を始めて、チームからセキュリティの評価を得るのに役立つ資料をいくつか紹介します。

  1. サプライチェーンセキュリティは重要です。GitHubのセキュリティに関するベストプラクティス10選を確認し、同じ過ちを繰り返さないようにしましょう。

  2. Node.jsやnpmパッケージの開発に興味がありますか?私もです!GitHub Actionsを使ってnpmパッケージを安全に公開する方法を紹介する記事を書きました。

  3. GitHubエコシステムをよく利用する方は、ワークフローとより緊密に統合できるSnykのコードスキャンもぜひご覧ください。GitHub Security Code Scanning:オープンソースの依存関係を保護する

キャプチャー・ザ・フラッグを始めよう

オンデマンドのバーチャル入門ワークショップを視聴して、キャプチャー・ザ・フラッグの課題の解き方を学びましょう。

カテゴリー: