AWS CDKでLambda関数の依存ライブラリにプライベートリポジトリを指定したい話
ECシステム開発チームのいまづです。
みなさん cdk で deploy してますか?
社内でAWSでなんやかんや作るときは、CDK使おうねということにしています。
便利ですよね。わけわからなくて不便なときもありますけれども。
Lambda関数(Python多め)+何か、みたいなものを作るのに手軽なので細々と作って(しまって)います。
共通で使いたいモジュールをまとめようとしてGitHubにプライベートリポジトリを作ったはいいのですが、割とこれがめんどくさかったですよ、というお話です。
もっと良い方法があれば知りたいところです。
「作ってしまって」というのは、「Python3.8のサポート終わるぞ」などという場合に数が多いとメンテナンスが大変で… 😅
pip installとプライベートリポジトリ
Lambda関数はPythonで書くことが多い(またはGo)ので、ここで挙げているのはPythonのお話です。
依存ライブラリのインストールについては、基本的に公式の Bundling Asset Codeの例にあるように、requirements.txt
を用意するところまでやっておいて、pip install -r requirements.txt
しています。
Bundling Asset Codeから引用:
new lambda.Function(this, 'Function', {
code: lambda.Code.fromAsset(path.join(__dirname, 'my-python-handler'), {
bundling: {
image: lambda.Runtime.PYTHON_3_9.bundlingImage,
command: [
'bash', '-c',
'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output'
],
},
}),
runtime: lambda.Runtime.PYTHON_3_9,
handler: 'index.handler',
});
プライベートリポジトリを単にローカルで pip install
するなら良いのですが(GitHub CLI使って認証済ませておくとかありますし)、CDKでLambdaのイメージをビルドするときや、GitHub Actions上で使いたい場合には、デプロイキーやアクセストークンを使う必要があります。
鍵管理はやりたくないので、今回はアクセストークンを使うことにしました。
アクセストークンを使うにあたって、気にしたいのは以下の点です。
- 依存ライブラリ自体はどこかに書きたい。
- 認証情報はリポジトリのファイルには書きたくない。
1つ目は、pip install
する直前に動的に認証情報付きのURLをrequirements.txt
などに差し込む方法が考えられますが、そうなると「依存ライブラリの一覧」に載ってないことになるので、それは避けたい、というところから。
2つ目は当然ですよね。
requirements.txt
だけを考えるなら、環境変数にトークンが格納されている前提であれば次のように書けますので、実行時に環境変数が与えられることさえ守れば上記の条件は満たせそうです。
(例です。このリポジトリは存在しません。)
git+https://${GITHUB_TOKEN}@github.com/SWITCHSCIENCE/ss-private-repo.git
が、依存管理は pip freezeして作られたであろう requirements.txt をどうにか整理する話 でも書きましたが、poetryや最近はryeでやりたいのです。
poetryやryeとプライベートリポジトリ
(当然なのですが)poetryの場合、
poetry add git+https://${GITHUB_TOKEN}@github.com/SWITCHSCIENCE/ss-private-repo.git
とすると、pyproject.toml
には環境変数が展開された状態で記録されます。
[tool.poetry.dependencies]
python = "^3.11"
ss-private-repo = {git = "https://github_pat_XXXXXXXXXXXXX@github.com/SWITCHSCIENCE/ss-private-repo.git"}
これはトークンが丸見えなのでうれしくないですね。
ここを環境変数に書き直したらどうかと思いましたが、
[tool.poetry.dependencies]
python = "^3.11"
ss-private-repo = {git = "https://${GITHUB_TOKEN}@github.com/SWITCHSCIENCE/ss-private-repo.git"}
これだと、poetry export ...
を実行したときに Invalid git url ...
とエラーになってしまいます。
ryeでも同様に試してみましたが、pyproject.toml
に環境変数を書いてそのまま requirements.lock
等に出力されることはありません。
ということで、いずれを使うにしても pyproject.toml
には単にHTTPSのURLを書くしかなさそうです。
それならば、GitHub CLI でログインした状態にしておけば、add自体はできます。
poetry add git+https://github.com/SWITCHSCIENCE/ss-private-repo.git
rye add ss-private-repo --git https://github.com/SWITCHSCIENCE/ss-private-repo.git
ここで、さてトークンはどうしましょう、となりました。
Gitの認証情報の仕組みにのっかる
事例を探すと、いろんなところで紹介されていたのが7.14 Git のさまざまなツール - 認証情報の保存の「$HOME/.git-credentials
にトークンを保存して、 git config --global credential.helper store
する」というものでした。
これならトークンをファイルに書き出すところまで引き回してやれば良さそうです。
GitHub Actionsでの方法は割と紹介されていたのですが、Lambda関数のイメージを作る例は見つけられなかったので、こんな風にすることで期待した動作になりました。
// GitHubのPersonal Access Tokenを環境変数から得る
const github_token = process.env.TOKEN_GITHUB_SS_UTILS;
new lambda.Function(this, "Function", {
code: lambda.Code.fromAsset("lambda", {
bundling: {
image: lambda.Runtime.PYTHON_3_11.bundlingImage,
command: [
"bash",
"-c",
[
`export HOME=/asset-input`, // $HOME=/だと `git config --global ...`実行時にファイルの書き込みができない
`echo 'https://${github_token}:@github.com' > /asset-input/.git-credentials`, // pip installで使用される認証情報
`git config --global credential.helper 'store --file /asset-input/.git-credentials'`,
`pip install -r requirements.lock -t /asset-output`,
`cp -au . /asset-output`,
`rm -rf /asset-output/.mypy_cache /asset-output/__pycache__`,
`rm /asset-input/.git-credentials`,
].join(` && `),
]
}
}),
runtime: lambda.Runtime.PYTHON_3_11,
handler: 'index.handler',
...
このイメージを使う場合、環境変数 HOME=/
に設定されており、git config --global ...
を実行すると /.gitconfig
を書き込もうとしてpermission errorになります。
これを回避するために HOME=/asset-input
に指定しています。.git-credentials
も同じディレクトリに書き出しています。
これであれば、cdk
コマンドを実行する環境の環境変数にトークンを設定すれば良いですし、GitHub Actionsで実行するのであれば、GitHubの設定「Actions secrets and variables」の「Repository secrets」に設定してやればよさそうです。
最初に挙げた気にしたい点もOKですね。
- 依存ライブラリ自体はどこかに書きたい。
- 認証情報はリポジトリのファイルには書きたくない。
もうちょっと他にやり方がないのかなあ、とは思いますが、これで社内用の共通ライブラリをまとめやすくなりそうです。
こういうやり方もあるよ、と思ったそこのあなた
スイッチサイエンスでは開発者を募集しています。
ぜひカジュアル面談で教えてください。
システムエンジニア募集中です!
興味のある方はぜひカジュアル面談へ!お待ちしています。