きり丸の技術日記 (original) (raw)
始めに
小ネタ。
PyCharm
にてrye
やuv
を直接指定することはまだできませんが、uv
から生成される.venv
は指定可能だということに気付いていなかったのでそれを記載するだけのメモです。
環境
- PyCharm Professional
- 2024.3
※ PyCharm Communityでもできるかもしれませんが検証してません。なお、IntelliJ IDEA Ultimateではだめでした。
実装
- Python Interpreterを開きます
- .venvのPythonを指定します
特に指定していない限り、uvを実行したディレクトリの.venv/bin/python
や.venv/bin/python3
等にバイナリファイルが配備されているので指定してください。
非表示になっているパターンもありますので、その場合は修正してください。
終わりに
ずーっとJavaの現場にいたこともあり、最近までJetBrainsのAll Products Pack
ではなく、IntelliJ IDEA Ultimate
を無理やり拡張して使用していました。IntelliJ IDEA Ultimate
ではあくまでJavaがメインだったので、.venv
をSDKに指定する等がうまくできなかったようなのですが、値上げをきっかけに購入したことでPythonを書く際のコーディング力が増しました。
All Products Pack
を使い倒せるように、可能であればプログラマとしての副業もしていきたいです。
始めに
弊社のシステムではECSを使用しているのですが、ここ最近Dockerイメージのビルド時間が大幅に延長されてしまっていました。そのうち、大幅な時間を占めているのがライブラリのインストール時間で、CPUの使用率が高くなって応答が非常に遅くなっていました。
uv.lock
等のロックファイルが取り扱われている環境であればインストールでは常に同じライブラリが使用されるものですし、ライブラリインストールが完了した状態のイメージをRepositoryにアップロードすることで短縮することを目指しました。
今回の記事では、Dockerのマルチステージビルドを扱って処理時間を短縮することを目指します。
環境
- Docker
- 21以降
- GitHub Actions
実装
Repositoryの作成
ライブラリをインストールしたイメージをアップロードするためのRepositoryを使用します。
dev-dependencies
ありのイメージと、なしのイメージをアップロードしたかったので、2つ用意しました。
- https://hub.docker.com/r/kirimaru/fastapi-practice_dev-runtime
- https://hub.docker.com/r/kirimaru/fastapi-practice_prod-runtime
マルチステージビルドができるDockerファイルの作成
マルチステージビルドができるDockerファイルを用意します。全体の内容については今回の解説には不要なので省きます。
今回の場合、次のステージを用意しました。
- base
- 一番基準になるステージです。本番とベースイメージを分けたい場合はdev_base, prod_baseが生まれます
- dev_runtime
- 開発用のイメージを作るためのステージ。4. testで流用する。
- dev
- ローカル用ステージ
- test
- 2.のdev_runtimeを使用してCIを高速で処理させる
- prod_runtime
- 本番用イメージ。
dev-dependencies
を抜いているだけ
- 本番用イメージ。
- prod
- 本番用ステージ
ARG RUNTIME_TAG=latest
ベースイメージ
FROM python:3.12-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 ENV UV_PROJECT_ENVIRONMENT="/usr/local/"
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
1. 開発用ランタイムのビルド
FROM base AS dev_runtime
COPY src /app/src COPY README.md pyproject.toml .python-version uv.lock ./ COPY tests /app/tests COPY alembic /app/alembic COPY alembic.ini .env ./ RUN uv sync --frozen --no-cache --dev
ローカルはあんまりここを分けるメリットがない
2. 開発用ランタイムを使用して起動
FROM dev_runtime AS dev
COPY src /app/src
CMD ["uv", "run", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--reload"]
3. test 用
FROM kirimaru/fastapi-practice_dev-runtime:${RUNTIME_TAG} AS test ARG RUNTIME_TAG
NOTE: compose ファイルでマウントするなら不要
COPY src /app/src
4. 本番用ランタイムのビルド
FROM base AS prod_runtime
COPY README.md pyproject.toml .python-version uv.lock ./
RUN uv sync --frozen --no-cache
5. 本番用ランタイムを使用して起動
FROM kirimaru/fastapi-practice_prod-runtime:${RUNTIME_TAG} AS prod ARG RUNTIME_TAG
COPY src /app/src COPY .env ./
CMD ["uv", "run", "uvicorn", "src.main:app", "--host", "0.0.0.0"]
ロックファイルのハッシュ取得
ロックファイルのハッシュを取得し、それをDockerのタグにします。そうすることで、ライブラリの更新がされたかどうかをチェックできます。また、念のためDockerのイメージ名と混ざらないようにpython-
等のprefixも付与しています。
export LOCK_HASH=python-$(sha1sum < uv.lock | cut -d' ' -f1)
Docker側でわかりやすい変数に変更
export RUNTIME_TAG=$LOCK_HASH
Dockerイメージのpull
過去に作成したイメージがあればそれを取得します。
docker pull kirimaru/fastapi-practice_dev-runtime:$RUNTIME_TAG
Dockerイメージのbuild and push
pullしたイメージが存在しない場合、イメージをビルドします。作成したイメージをRepositoryにpushします。
if [ $? -ne 0 ]; then docker buildx build --target dev_runtime -t kirimaru/fastapi-practice_prod-runtime:$RUNTIME_TAG . docker push kirimaru/fastapi-practice_dev-runtime:$RUNTIME_TAG fi
pullしたイメージを使用する
開発用ビルドイメージをもとにテストしたいので、compose.yml
のtargetに定義したtest
を指定します。また、タグをロックファイルのハッシュにしているので、パラメータとして渡してあげます。
services: api: build: context: . target: ${BUILD_TARGET:-dev} args: - RUNTIME_TAG=${RUNTIME_TAG}
export BUILD_TARGET=test docker compose up -d
ソースコード
- https://github.com/hirotoKirimaru/fastapi-practice/blob/cd935568cf52293c9cc2ce883694b607e402918b/Dockerfile
- https://github.com/hirotoKirimaru/fastapi-practice/blob/cd935568cf52293c9cc2ce883694b607e402918b/compose.yml
- https://github.com/hirotoKirimaru/fastapi-practice/blob/c095102aea311efb9b9e3e1ce6f4d6e6b8b519e7/.github/workflows/build.yml
- https://github.com/hirotoKirimaru/fastapi-practice/blob/c095102aea311efb9b9e3e1ce6f4d6e6b8b519e7/.github/workflows/test.yml
終わりに
1回あたり全体で20分くらいかかっていたのを10分弱まで省略できました。特にlint
するだけのCIでは、イメージのpullがなくなったことで10分弱かかっていたのを2分程度で完了するほど高速処理になっています。
CIが遅くて悩んでいる方はぜひ参考にしてみてください。
簡単にBasic認証を実装したり検証したりするためにNGINXを使用しつつ、ついでにBasic認証まで含めているDockerイメージがあったので素振りしました。
環境
- Docker
- 26.0.0
- beevelop/nginx-basic-auth
対応
localhost:80
にアクセスしたらBASIC認証がかかっており、認証成功したらlocalhost:8080
で公開しているサイトに対してリダイレクトしている例です。BASIC認証はデフォルトで次のパスワードになっています。
- id
- foo
- password
- bar
services: web: image: dockercloud/hello-world auth: image: beevelop/nginx-basic-auth ports: - 8080:80 links: - web:web
設定できる環境変数は少ないので、Docker ImageのGitHubを読むと確認できます。
備考
クラスメソッド株式会社様が公開しているページもあったのですが、記事で使用しているイメージのquay.io/dtan4/nginx-basic-auth-proxy
が古すぎるのでエラーで起動しませんでした。今回紹介したイメージは2023年10月19日に最新がプッシュされているので、イメージが古いということは無さそうです。
docker run -d -p 80:80 quay.io/dtan4/nginx-basic-auth-proxy Unable to find image 'quay.io/dtan4/nginx-basic-auth-proxy:latest' locally latest: Pulling from dtan4/nginx-basic-auth-proxy
docker: [DEPRECATION NOTICE] Docker Image Format v1 and Docker Image manifest version 2, schema 1 support is disabled by default and will be removed in an upcoming release. Suggest the author of quay.io/dtan4/nginx-basic-auth-proxy:latest to upgrade the image to the OCI Format or Docker Image manifest v2, schema 2. More information at https://docs.docker.com/go/deprecated-image-specs/. See 'docker run --help'
終わりに
BASIC認証を元に検証したい内容があったのですが、Dockerイメージで最初からBASIC認証がかかっているとありがたいですね。
普通に調べるとNGINXの設定を頑張って設定する記事しか見つかりませんでした。もちろん、正攻法なのでこちらの記事が多いことはいいことですが。
簡単に検証できる環境ができてうれしいです。