every Tech Blog Advent Calendar 3日目の記事になります!
こんにちは 開発本部データ&AIチームでデータエンジニアを担当している塚田です。
今回は、挑戦WEEK中にGitHub Packagesを利用したnpmパッケージの社内利用を行いましたのでその内容についてご紹介します。
挑戦WEEKとは 開発メンバーが通常の各事業部のロードマップから離れ、技術的に何かに集中して挑戦する1週間 としており、 弊社CTOの今井がTech Blogにて説明しておりますので、よろしければ併せてご覧ください。
エブリーで利用している画像について
エブリーではDELISH KITCHEN、トモニテ、TIMELINEの3つのメディアを運営しています。 どのメディアも画像を多数利用して構成しており、画像配信基盤はシステムを構成する重要な一機能となっています。
画像配信基盤の問題点
それぞれのメディアで画像処理 → 画像返却 → 配信という処理の流れは共通しています。
ただし、画像処理の部分で画像変換はほぼ共通しているのですが、変換前処理がそれぞれ独自実装されている状況でした。
改善方針
独自処理が発生してしまうのは避けられない部分ではありますが、画像変換に関しては統一できる処理であるため共通化する方針となりました。
前置きが長くなりましたが、画像変換の共通処理のみを行うnpmパッケージとして切り出しGitHub Packagesで社内利用する流れを整備したので、事例として紹介します。
前提
- GitHub Organizationを利用している
- Organizationでなくても実行可能ですが、今回はOrganizationを利用した場合の説明となります
- 開発端末でNode.jsの実行環境が整備されている
- 執筆時はNode.js 20.9.0を利用しています
package.jsonの作成(初期化)
それでは実際にGitHub Packagesに登録するパッケージを作成します。
npm init -y
後述の手順でpackage.json
の変更を行いますのでデフォルトのままで問題ありません。
S3からファイル名を取得する処理を実装
今回はサンプルとして、Amazon S3に保存しているファイルを取得しデータ返却する を実装します。
パッケージのインストール
npm i -D typescript @types/node npm i -S @aws-sdk/client-s3
今回は上記のパッケージをインストールします。
用途に合わせて他のパッケージもインストールしてください。
tsconfig.jsonの作成
npx tsc --init
作成されたtsconfig.json
を以下のように修正します。
(自動的に作成されたものや今回の説明に必要ないものは削除しています)
{ "compilerOptions": { "target": "es2022", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
S3ファイル情報の取得ロジック
以下のサンプルプログラムをsrc/index.ts
として作成します。
import { GetObjectCommand, GetObjectCommandOutput, S3Client } from '@aws-sdk/client-s3' export async function getObject(bucket: string, key: string) { const params = { Bucket: bucket, Key: key } const command = new GetObjectCommand(params) const response = await new S3Client().send(command) const str = await response.Body?.transformToString(); return str }
package.jsonの変更
GitHub Packagesに登録できるようpackage.json
を以下のように変更します。
今回はs3-file-getter
というパッケージ名にしています。
GitHubの環境に合わせて{Organization名}
と{リポジトリ名}
を変更してください。
{ "name": "@{Organization名}/s3-file-getter", "version": "0.1.0", "description": "", "main": "dist/index.js", "files": [ "dist" ], "scripts": { "prepublishOnly": "npm run build", "build": "tsc -d" }, "author": "", "license": "", "repository": { "type": "git", "url": "https://github.com/{Organization名}/{リポジトリ名}.git" }, "dependencies": { "@aws-sdk/client-s3": "^3.450.0" }, "devDependencies": { "@types/node": "^20.9.0", "typescript": "^5.2.2" } }
ここで重要なのはname
とrepository
となっており、それ以外は環境によって適宜変更してください。
GitHub Packagesへ登録
GitHub ActionsワークフローYAMLファイルの作成
自動的にGitHub Packagesへ登録させたいので、GitHub Actionsの設定を行います。
GitHubクイックスタートが用意されているので、それを流用し以下の設定を.github/workflows/publish.yml
として作成します。
name: npm package publish on: release: types: [created] jobs: publish-gpr: runs-on: ubuntu-latest permissions: packages: write contents: read steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 20 registry-url: https://npm.pkg.github.com/ - run: npm ci - run: npm publish env: NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
リリースの作成
作成したpublish.yml
はリリースが新規作成された際に実行される設定となっているため、GitHubでリリースを作成します。
この時package.jsonのversion
が既にGitHub Packagesで登録されている場合エラーとなるため、導入するプロジェクトのリリースフローによって柔軟に変更してください。
今回はリリース前にversionの更新を行なっているものとして運用します。
GitHub Packagesの確認
GitHub Actionsの処理が完了すると以下のように対象リポジトリTOPの右下のPackagesに今回作成したかったnpm packageが登録されています。
今回作成したs3-file-getter
のリンクを選択するとパッケージのバージョンなどのサマリーが確認できます。
GitHub Packagesの利用
登録だけしても利用できないと意味がないので利用するために必要な手順を記載します。
ローカルの場合
Personal Access Token (Classic)を作成
GitHub Packagesへの認証を行うドキュメントが用意されているので、これに従いAccess Tokenを作成します。
パッケージの読み込みができれば良いので、今回Scopeはread:packages
のみを選択します。
.npmrc
の作成
以下の設定を.npmrc
として作成します。
{Organization名}
と{作成したAccess Token}
を環境に合わせて置換してください。
registry=https://npm.pkg.github.com/{Organization名} //npm.pkg.github.com/:_authToken={作成したAccess Token}
注意:.npmrc
にAccess Tokenを直書きしているので、.gitignore
で管理対象外にするなど誤って公開される状況にならないよう防御策を取るようにしてください。
GitHub Packagesからパッケージのインストール
.npmrc
の設定をしていてもGitHub Packages以外のパッケージは今まで通りインストール可能です。
GitHubの環境に合わせて{Organization名}
を変更してください。
npm i -D typescript @types/node npm i -S @{Organization名}/s3-file-getter
パッケージの利用
他のパッケージと同様にimportすることで利用できます。
import { getObject } from '@{Organization名}/s3-file-getter'; const data = async () => { console.log(await getObject('{bucketName}', '{key}')) } data()
GitHub Actionsの場合
GitHub Packagesにアクセスできるリポジトリを設定
パッケージのサマリー画面にPackage settings
のリンクがあるので、クリックします。
パッケージを利用したいリポジトリを以下の機能から追加することで参照可能な権限を付与できます。
GitHub ActionsのWorkFlowを設定する
パッケージを利用するための設定のみ記載しています。
環境に合わせて適宜変更してください。
jobs: sample: steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 20 registry-url: https://npm.pkg.github.com/ - run: npm ci env: NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
おわりに
GitHub Packagesを利用した、社内でのみ参照可能なnpmパッケージの作成方法と利用方法について一連の流れを紹介しました。
今回のサンプルは公開しても問題ないものですが、共通の処理をパッケージにして利用したいけどロジックは外部に公開したくないなどのシチュエーションで利用できると感じています。
画像配信基盤の改善はデータエンジニアとして関わるのはあまりないことだと思うのですが、挑戦WEEKが良いきっかけとなりました。
この後のAdvent Calendarでも挑戦WEEKに関連する投稿を予定していますので、ぜひチェックしてみてください。