研究開発部 Architectグループ ML PlatformチームのKAZYこと新井です。ちなみに名古屋にある中部支店に所属です。
今回はPoetryでプライベートパッケージ(ライブラリ)を扱うテーマです。
追記(2022/11)
Poetry 1.2で新たに追加された機能をプライベートパッケージの観点からまとめました。 合わせて御覧ください。 buildersbox.corp-sansan.com
目次
はじめに
PoetryとはPython用パッケージ管理ツールです。
Poetryはインストールするライブラリ管理としてだけではなく、パッケージ化や公開機能も持っています。 公開パッケージであれば大体PyPIに普段お世話になっている事は知っています。 しかし社内専用のような公開できないパッケージを作ったり使ったりしたい場合はどうすればいいのかわからなかったので調べました。
興味があった以下の3パターンについて書きます。
No | コード管理の場所 | パッケージ管理の場所 |
---|---|---|
1 | GitHub | GitHub |
2 | GitHub | AWS CodeArtifact |
3 | GitHub | GCP Artifact Registry |
GitHubを使っていない方でもPoetry + AWS CodeArtifactとかPoetry + GCP Artifact Registryを検討されている方には役に立つ記事になっていると思います。
調査結果
はじめに調査結果です。
私見も入っていると思いますがご容赦ください。
詳細な使い方は以降で紹介します。
No | コード 管理 |
パッケージ管理 | ⭕ | △ | 動作確認 Poetry Ver |
---|---|---|---|---|---|
1 | GitHub | GitHub | - お手軽さ | - AccessToken期限の柔軟さ - バージョン管理 |
1.1.14 |
2 | GitHub | AWS CodeArtifact | - AccessToken期限の柔軟さ - パッケージっぽさ |
- 設定の一手間 | 1.1.14 |
3 | GitHub | GCP Artifact Registry | - AccessToken期限の柔軟さ - パッケージっぽさ |
- 設定の一手間 - Poetry1.2以降推奨*1 |
1.2.0b3 |
所感
GitHubでコード管理をしている場合はパッケージもGitHubで管理するのが圧倒的に楽かなと思いました。GitHubの認証ができている環境であればpyproject.tomlへの追記も必要がないのも嬉しいです。 パッケージのバージョンを指定したり、とにかく最新を持ってこられるようにしたりしたい場合はAWSのCodeArtifactやGCPのArtifact Registryに立てて利用するのが運用しやすそうです。GCPのArtifact Registryの場合はPoetryのバージョン1.2がリリースされた後に使うのが無難です。
Poetryでのパッケージ作成方法
そもそもどうやってPoetryを用いてパッケージを作るかという話をします。 すでにご存じの方は読み飛ばしてもらって結構です。
またほぼドキュメントからの引用になりますので詳しくは以下を参照ください。 python-poetry.org python-poetry.org
パッケージ作成
poetry new poetry-demo
poetry-demo ├── pyproject.toml ├── README.rst ├── poetry_demo │ └── __init__.py └── tests ├── __init__.py └── test_poetry_demo.py
パッケージのビルド
ビルドを行うとgz, whlと言ったファイルがdistというディレクトリととも作成されます。それらが次に紹介する公開の際に使用するファイルとなります。
poetry build
. ├── README.rst ├── dist │ ├── poetry-demo-0.1.0.tar.gz │ └── poetry_demo-0.1.0-py3-none-any.whl ├── poetry_demo │ └── __init__.py ├── pyproject.toml └── tests ├── __init__.py └── test_poetry_demo.py
パッケージの公開
ビルド時に作成されたdistディレクトリ以下の*.gz, *.whlファイルをリポジトリにアップロードします。デフォルトではPyPIに公開します。
poetry publish
プライベートパッケージへの公開
引数でリポジトリを指定することで独自に作成したリポジトリに公開することができます。プライベートリポジトリへの公開はこちらを使います。そしてAWSのCodeArtifactやGCPのArtifact Registryではこのリポジトリを建てることになります。
poetry publish --repository リポジトリ名
なるべく以上の流れで運用できることを目指します。
(おまけ) パッケージに含めたくないファイルの制御
パッケージする際に特定のファイルを含めたくないときは以下のような設定で制御できます。
特定のファイルをパッケージから除外したいとき。
[tool.poetry] exclude = ["my_package/excluded.py"]
パッケージのソースコードをgitで管理している場合は.gitignoreの設定がパッケージにも反映されます。
AWS CodeArtifact
パッケージ作成方法
パッケージの開発者は以下の流れを行うことになります。
- AWS CodeArtifactでプライベートリポジトリを作成
- pyproject.tomlにプライベートリポジトリの情報を記入
- Poetryのconfigに認証情報の設定
- パッケージのビルドとアップロード
順に説明します。
AWS CodeArtifactでプライベートリポジトリを作成
pypi-storeに設定します。 それ以外はよしなに設定ください。 特に迷うところはないと思います。
pyproject.tomlにプライベートリポジトリの情報を記入
先の章で説明した通りPoetryでパッケージを作成すると、pyproject.tomlというファイルができます。
公開予定のパッケージのpyproject.tomlに以下のCodeArtifactで作成したプライベートリポジトリの情報を追記することでプライベートリポジトリの場所をPoetryに教えます。
︙略 [[tool.poetry.source]] name = "<任意のリポジトリ名>" # Poetry内での管理用リポジトリ名(code artifactと一致しなくても良いですがpoetry configで設定するものを合わせる) url = "https://<Code Artifactで設定したドメイン>-<AWS account id>.d.codeartifact.<リージョン>.amazonaws.com/pypi/<CodeArtifactで設定したリポジトリ名>/simple" ︙略
Poetryのconfigに認証情報の設定
ここから先はAWSの認証ができる環境で行ってください。
Poetryのconfigにプライベートリポジトリへの認証のための情報を与えます。
コードアーティファクトのトークンは 15分から12時間
に設定できます(例では3600秒=1時間)。
# simpleがパスに入らないのがポイント poetry config repositories.<任意のリポジトリ名> https://<Code Artifactで設定したドメイン>-<aws account id>.d.codeartifact.<リージョン>.amazonaws.com/pypi/<CodeArtifactで設定したリポジトリ名> CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain <CodeArtifactで設定したドメイン> --domain-owner <AWS account id> --query authorizationToken --output text --duration-seconds 3600` poetry config http-basic.<任意のリポジトリ名> aws ${CODEARTIFACT_AUTH_TOKEN}
パッケージのビルドとアップロード
認証情報が正しくセットされていれば以下のコマンドでパッケージをアップロードできます。
poetry build poetry publish --repository <任意のリポジトリ名>
パッケージ追加方法
パッケージ作成と共通する部分が多いですが次のような流れになります。 1, 2はパッケージ作成時と全く同じです。
- pyproject.tomlにプライベートリポジトリの情報を記入
- Poetryのconfigに認証情報の設定
- パッケージの追加
pyproject.tomlにプライベートリポジトリの情報を記入
[[tool.poetry.source]] name = "<任意のリポジトリ名>" # poetry内での管理用リポジトリ名(code artifactと一致しなくても良いですがpoetry configで設定するものを合わせる) url = "https://<Code Artifactで設定したドメイン>-<AWS account id>.d.codeartifact.<リージョン>.amazonaws.com/pypi/<CodeArtifactで設定したリポジトリ名>/simple" #simpleを忘れないようにしてください。
Poetryのconfigに認証情報の設定
ここから先はAWSの認証ができる環境で行ってください。
# simpleがパスに入らないのがポイント poetry config repositories.<任意のリポジトリ名> https://<Code Artifactで設定したドメイン>-<aws account id>.d.codeartifact.<リージョン>.amazonaws.com/pypi/<CodeArtifactで設定したリポジトリ名> CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain <CodeArtifactで設定したドメイン> --domain-owner <AWS account id> --query authorizationToken --output text --duration-seconds 3600` poetry config http-basic.<任意のリポジトリ名> aws ${CODEARTIFACT_AUTH_TOKEN}
パッケージの追加
認証情報が正しくセットされていれば以下のコマンドでパッケージを追加できます。
# 追加時 poetry add <パッケージ名> # バージョン指定 poetry add <パッケージ名>==1.0.0 # インストール poetry install
Github Actionsなどでの利用
AWSの認証をしてCodeArtifactのアクセストークンを取得できればインストールができます。 以下を用いれば良いでしょう。
GitHub ActionsでDockerのビルドをする場合はマルチステージビルドやsecretオプションを使ってトークンがイメージに残らないように気をつけインストールすると良いでしょう。
GCP Artifact Registry
ほとんどAWS CodeArtifactと同じです。しかしPoetryのバージョンが1.2以降が必要なのでご注意ください。 github.com
パッケージ作成方法
パッケージの開発者は以下の流れを行うことになります。
- GCP Artifact Registryでプライベートリポジトリを作成
- Poetryのバージョン1.2のインストールとをkeyringsのライブラリをインストール
- pyproject.tomlにプライベートリポジトリの情報を記入
- Poetryのconfigに認証情報の設定
- パッケージのビルドとアップロード
順に説明します。
パッケージの追加方法
formatをPythonに設定します。 それ以外はよしなに設定ください。 特に迷うところはないと思います。
Poetryのバージョン1.2のインストールとをkeyringsのライブラリをインストール
poetry self addはバージョン1.2移行で使えるコマンドです。
curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.2.0b3 python - poetry self add keyrings.google-artifactregistry-auth==1.0.0
pyproject.tomlにプライベートリポジトリの情報を記入
[[tool.poetry.source]] name = "<任意のリポジトリ名>" url = "https://<リージョン>-python.pkg.dev/<プロジェクトID>/<Artifact Registoryのrepository名>/simple" #simpleを忘れないようにしてください。
Poetryのconfigに認証情報の設定
GOOGLE_APPLICATION_CREDENTIALSという環境変数を経由して認証のための情報を渡しているのがAWS CodeArtifactとの違いです。
export GOOGLE_APPLICATION_CREDENTIALS="<クレデンシャルのあるパス>/<ファイル名>.json" poetry config repositories.<任意のリポジトリ名> https://<リージョン>-python.pkg.dev/<プロジェクトID>/<Artifact Registoryのrepository名>
パッケージのビルドとアップロード
poetry build poetry publish --repository <任意のリポジトリ名>
パッケージ追加方法
パッケージ作成方法と2, 3, 4 は全く同じです。 その後以下のコマンドでパッケージを追加します。
# 追加時 poetry add <パッケージ名> # バージョン指定 poetry add <パッケージ名>==1.0.0 # インストール poetry install
GitHub Actionsなどでの利用
認証自体はこちらを使えば良いでしょう。 github.com
クレデンシャルはWorkload Identity連携などを用いて期限付きのものを発行するとよりセキュアかなと思います。
GitHub ActionsでDockerのビルドをする場合はマルチステージビルドやsecretオプションを使ってクレデンシャルがイメージに残らないように気をつけインストールすると良いでしょう。
GitHub
パッケージの作成方法
Poetryで作成したプロジェクトをそのままGitHubにプッシュします。pyproject.tomlがルートに来るようにしてください。 CodeArtifactやArtifact Registoryを用いた方法に比べて非常に簡単です。
パッケージの追加方法
対象リポジトリへの認証がされている環境下では以下のコマンドでインストールします。バージョンを指定するのではなく、ブランチやタグを指定する形
になります。特定のブランチの中でパッケージのバージョンが上がった場合はpoetry updateで更新できますがタグを指定している場合は更新の都度poetry addすることになると思います。
とりあえず最新を使いたい場合はXXXXブランチを使いましょうなど、規則を決めておくと使う側が困らなくて良さそうです。
# GitHubにログイン gh auth login poetry add git+https://github.com/<accountやorganization>/<リポジトリ>#<ブランチorタグorコミットハッシュ>
パーソナルアクセストークンを用いたパッケージ追加について
GitHubのパーソナルアクセストークンを用いればプライベートパッケージを以下のコマンドで追加できますがオススメしません。
# パーソナルアクセストークン PAT=gha_XXXXXXXXX poetry add git+https://${PAT}@github.com/<accountやorganization>/<リポジトリ>#<ブランチorタグorコミットハッシュ>
上記のコマンドでパッケージを追加するとパーソナルアクセストークンがpyproject.tomlとpoetry.lockのファイルに書き込まれてしまうからです。
特にpoetry.lockファイルはあまり見ていない人が多くうっかりアップロードしてしまう恐れがあります。
そのためGitHub Cliでログインするか、vscodeであればgithub拡張でログインするのが良いと思います。
# GitHub Cliでのログイン
gh auth login
GitHub Actionsでインストール方法
パッケージの作成や、認証済みの環境でのパッケージの追加は非常に簡単ですが、GitHub Actionsからパッケージのインストールを行う場合はひと手間必要です。
同一オーガニゼーション内であってもGitHub Actionsからは他のリポジトリにアクセスできません。 そのためアクセス権を持ったトークンを発行してからパッケージをインストールします。
トークンの発行にはGitHub Appを用いた方法とパーソナルアクセストークンを用いる方法があります。 次の観点からパーソナルアクセストークンは用いずGitHub Appを利用することをお勧めします。
- 個人に紐づくため退職時などアカウントがプライベートなスループから外れた際使えなくなる
- 期限付きのトークンを都度発行するのは運用コストが高い
- 期限なしのトークンをパッケージ利用者ごと渡すと漏洩時にリスクが高い
GitHub Appのトークンは8時間有効だそうです(期限なしに設定はできますが、細かい有効期限設定は見つけられませんでした)。
インストールまでの流れ
- GitHub App作成 (1度だけで良い)
- GitHub Appからパッケージのあるリポジトリへのアクセス権をもつトークンを取得
- 取得したトークンを使用する設定
- インストール
GitHub App作成
GitHub Appの作り方自体は他の記事に譲ります。
以下の権限を付与したAppを作成してください。
- Contentsにread-only権限
- パッケージのあるリポジトリへのアクセス権限
- パッケージを参照するリポジトリへのアクセス権限
- 発行するトークンは期限付き
そしてGitHub Appにidとプライベートキーがあるのでこれらをパッケージをインストールしたいリポジトリのsecretsにそれぞれ、secrets.APP_ID, secrets.PRIVATE_KEYとしてパッケージを利用するリポジトリに保存しておきます*2。
GitHub Actionsのyamlファイル
github-app-tokenを利用して先程secretsに保存したAPP_IDとPRIVATE_KEYからトークンを発行して、それをgitの設定に利用させるようにしてからインストールします。
︙略 - name: Generate github token id: generate_token uses: tibdex/github-app-token@v1 with: app_id: ${{ secrets.APP_ID }} private_key: ${{ secrets.PRIVATE_KEY }} - name: Install run: | git config --global url."https://x-access-token:${ACCESS_TOKEN}@github.com/organization名".InsteadOf https://github.com/organization名 poetry install env: ACCESS_TOKEN: ${{ steps.generate_token.outputs.token }} ︙略
Dockerfileをビルドしたい場合は次のように行います。
︙略 - name: Generate github token id: generate_token uses: tibdex/github-app-token@v1 with: app_id: ${{ secrets.APP_ID }} private_key: ${{ secrets.PRIVATE_KEY }} - name: docker build env: ACCESS_TOKEN: ${{ steps.generate_token.outputs.token }} DOCKER_BUILDKIT: 1 run: | docker build --secret id=ACCESS_TOKEN . ︙略
こちらがDockerfileです。 期限付きのトークンではありますが、マルチステージビルドやsecretオプションを使って情報をイメージに残さないようにしましょう。ここではsecretのオプションを使っています。
︙略 RUN --mount=type=secret,id=ACCESS_TOKEN \ git config --global url."https://x-access-token:${ACCESS_TOKEN}@github.com/organization名".InsteadOf https://github.com/organization名 ︙略
1リポジトリで複数のパッケージを管理する
プライベートで作るパッケージ群を一つのリポジトリにしたいこともあると思いますが現状のpoetry 1.1系ではできないようです。
先日対応させるためのPRがmasterにマージされたので今後使えるようになることを期待しましょう。
ちなみにpipではsubdirectoryを指定することで以下のように複数パッケージを1つのリポジトリで管理できます。
pip install "git+https://github.com/XXXX/XXXXXXX@BRANCH#subdirectory=パッケージのあるディレクトリ"
おわりに
Pythonでパッケージを公開しようと思ったことがなかったのでとても勉強になりました。GitHubでの運用が思った以上に便利でびっくりしました。
アナウンス
求人
私の所属するML Platformチームを含む、研究開発部Architectグループでは一緒に働く仲間を募集しています。最近募集の給与レンジが上がりました。私の所属する中部支社勤務も上がりましたのでオススメです。是非一緒に働きましょう。