🤸‍♀️

(Python)Cloud Functionsプライベート共通モジュールのデプロイ方法を試す

2022/01/10に公開

Cloud Functions (Python) にてプライベートなライブラリを含むデプロイ方法
公式ドキュメントの以下内容を試した際のメモ。

Cloud Functions - Python での依存関係の指定 - プライベート依存関係を使用する

モチベーション

マイクロサービスにて同じようなソースコードをできるだけコピーするのを避けてソースコード管理を一元化したい。

検証アプリについて

foobar1, foobar2というモジュールを複数のFunctions func1, func2で共通利用するというシナリオ。

ディレクトリ構成

$ tree
.
├── functions
│   ├── func1
│   │   ├── main.py
│   │   └── requirements.txt
│   └── func2
│       ├── main.py
│       └── requirements.txt
└── shared_libs
    ├── package_foobar1
    │   ├── foobar1
    │   │   └── __init__.py
    │   └── setup.py
    └── package_foobar2
        ├── foobar2
        │   └── __init__.py
        └── setup.py

func1 (httpトリガー)

functions/func1/main.py

from libs import foobar1
from libs import foobar2

def main(request):
    return f"name:func1, foobar1:{foobar1.main()}, foobar2:{foobar2.main()}"

func2 (httpトリガー)

functions/func2/main.py

from libs import foobar1
from libs import foobar2

def main(request):
    return f"name:func2, foobar1:{foobar1.main()}, foobar2:{foobar2.main()}"

foobar1 モジュール

shared_libs/package_foobar1/setup.py

from setuptools import setup, find_packages
setup(
      name='foobar1',
      version='0.0.1',
      packages=find_packages()
)

shared_libs/package_foobar1/foobar1/__init__.py

def main():
    return 'foobar1'

foobar2 モジュール

shared_libs/package_foobar2/setup.py

from setuptools import setup, find_packages
setup(
      name='foobar2',
      version='0.0.1',
      packages=find_packages()
)

shared_libs/package_foobar2/foobar2/__init__.py

def main():
    return 'foobar2'

デプロイコマンド例

func1用のデプロイコマンド例

func_name='func1'
func_path="./functions/${func_name}"

rm -rf ${func_path}/libs
pip install -t ${func_path}/libs shared_libs/package_foobar1
pip install -t ${func_path}/libs shared_libs/package_foobar2

gcloud functions deploy ${func_name} \
  --entry-point main \
  --runtime python39 \
  --trigger-http \
  --allow-unauthenticated \
  --region asia-northeast1 \
  --source $func_path

ポイントはデプロイ前に pip install -t (target_path) (package_source) でfunctionのデプロイ対象のディレクトリに共通ライブラリをコピーしているところ。

これで、.gitignore でデプロイ毎にコピーするディレクトリを無視設定をすれば、やりたかったソース管理の一元化に光が見えてきた。

参考: pip --version, pip install --help

$ pip --version
pip 21.3.1 from /opt/homebrew/lib/python3.9/site-packages/pip (python 3.9)

$ pip install --help                                      

Usage:   
  pip install [options] [-e] <local project path> ...

...

  -t, --target <dir>          Install packages into <dir>. By default this will not replace existing
                              files/folders in <dir>. Use --upgrade to replace existing packages in
                              <dir> with new versions.

追記)Artifact Registryを用いた方式も以下で検証しました

https://zenn.dev/koshilife/articles/887d8aa53c2332

Discussion