PythonプロジェクトをGoogle Cloud Runにデプロイする

## gcloudコマンドのインストール

下記を参考に
https://cloud.google.com/sdk/docs/install?hl=ja 

```
./google-cloud-sdk/install.sh
```

途中で色々と聞いてくるが基本yesで答える。
ただ、python3.12を入れてもいいか? という質問にはNo. 
私はpyenvを使っているので、環境を汚したくない。
```
Google Cloud CLI works best with Python 3.12 and certain modules.

Download and run Python 3.12 installer? (Y/n)?  n
```

3.12は別途インストールした。
```
pyenv install 3.12
pyenv global 3.12.9
```

確認。OK。
```
python --version
Python 3.12.9
```

## プロジェクトの作成

事前準備として、
Google cloudでプロジェクトをあらかじめ作成しておく。
https://console.cloud.google.com/

左メニュープロジェクトの概要から、プロジェクトIDをメモしておく。

gcloudインストール時に永続化用にPATHを入れてくれたが、
未反映なので実行しておく。
macなので `.zshrc` 。ここは環境によって異なるため注意。
```
source ~/.zshrc
```

コンソールから初期コマンド入力。
```
./google-cloud-sdk/bin/gcloud init

Pick cloud project to use:
 [1] xxxxxx #←すでにあった別のプロジェクト名
 [2] Enter a project ID
 [3] Create a new project
```

2を選択し、先ほどメモしておいたプロジェクトIDを入力。

バージョン確認。うん、できたっぽい。
```
gcloud --version
Google Cloud SDK 514.0.0
bq 2.1.14
core 2025.03.07
gcloud-crc32c 1.0.0
gsutil 5.33
```

## 課金、サービスの有効化
### 課金の有効化
事前準備として、アカウントの課金を有効化する。
cloud runには課金が必要なのでプロジェクトの課金を有効化する。
webからやってもいいけど、せっかくなのでコマンドで。

課金有効アカウントリストを取得
```
gcloud billing accounts list
```

出てきたACCOUNT_IDをメモし、下記を実行
```
gcloud billing projects link PROJECT_ID --billing-account=ACCOUNT_ID
```

### サービスの有効化
cloud runに必要なサービスを有効化していく。
```
gcloud services enable run.googleapis.com
gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com
```

## プロジェクト作成
中身は後で色々いじるとして、一旦シンプルなpythonのWebアプリを作成する。

```
my-python-app/ # 仮名。各々好みで
│── app.py
│── requirements.txt
│── Dockerfile
└── .dockerignore
```

app.py
```py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, Cloud Run!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)
```

requirements.txt
flaskの最新バージョンを下記で確認。
https://github.com/pallets/flask
```
Flask==3.1.0
```

Dockerfile
```docker
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
```

.dockerignore
```
__pycache__/
*.pyc
*.pyo
.env
.git
```

各自分のgithubリポジトリにアップしたりしておくとよき。

## いよいよデプロイ

プロジェクトのセット
```
gcloud config set project PROJECT_ID
```

Artifact Registryにリポジトリを作成する。
MY_REPOのところは好きに名前を設定すること
```
gcloud artifacts repositories create MY_REPO \
  --repository-format=docker \
  --location=us-central1  
```

そういえば、前はContainer Registryだったはず。
調べてみるとContainer Registryは非推奨になり、Artifact Registryを使うと良いらしい。
色々細かく知りたい方は以下。
https://cloud.google.com/artifact-registry/docs/transition/gcr-repositories?hl=ja

Artifact Registryのdocker認証。リージョンに合わせて設定。
```
gcloud auth configure-docker us-central1-docker.pkg.dev
```

Dockerイメージビルド。
PROJECT_ID, MY_REPO, COMMIT_HASHは各々設定すること。
この `us-central1-docker.pkg.dev/PROJECT_ID/MY_REPO/COMMIT_HASH` がイメージ名となる。
```
docker build -t us-central1-docker.pkg.dev/PROJECT_ID/MY_REPO/COMMIT_HASH .
```

作ったイメージをpush。
IMAGEはビルド時に設定した名前。
```
docker push IMAGE
```

デプロイコマンド。
MY_APPはcloud runのアプリ名なので好きに設定すること。
```
gcloud run deploy MY_APP \
  --image=IMAGE \
  --platform=managed \
  --region=us-central1 \
  --allow-unauthenticated #← これがあると認証なしアクセスを許可する。私は一旦いらないので外した。
```

### ※エラーが出てデプロイできないとき
下記エラーが出てデプロイできなかった。
```
X Deploying...
  - Creating Revision...
  . Routing traffic...
Deployment failed
ERROR: (gcloud.run.deploy) Revision 'プロジェクト名' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable within the allocated timeout. This can happen when the container port is misconfigured or if the timeout is too short. The health check timeout can be extended. Logs for this revision might contain more information.

Logs URL: https://console.cloud.google.com/logs/viewer?project=...(省略)...
For more troubleshooting guidance, see https://cloud.google.com/run/docs/troubleshooting#container-failed-to-start
```

どうやら、m系macとdocker環境のアーキテクチャ不一致で起こるエラーらしい。 `--platform linux/amd64` をビルド時に追加して解決した。
ちなみに、一度失敗したコンテナは上書きするのではなく新しい名前をつけてあげた方が無難そう。
```
docker build --platform linux/amd64 -t us-central1-docker.pkg.dev/PROJECT_ID/MY_REPO/COMMIT_HASH .
```

参考:
https://zenn.dev/msksgm/scraps/d667e2b2eecf4e

## デプロイ確認
```
gcloud run services describe MY_APP --region us-central1 --format 'value(status.url)'
```

これで返却されたURLにアクセスして、帰ってきたらクリア!
![スクリーンショット 2025-03-17 15.12.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164351/832ba05e-3c32-4b54-bf87-591df8add371.png)
お疲れ様でした。

次はcloud schedulerから今回デプロイしたcloud runアプリを定期的に呼ぶまでやりたい。

あと、どこかで余裕があったらgithubのmainブランチにpushされたら自動でデプロイするようにしたい