Django 製アプリを Cloud Run で動かすまで

thumbnail

ベースとなるイメージ作成

とりあえずローカルにあるもの全部コンテナにつっこんでいます。

FROM python:3
EXPOSE 8080
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt

ADD . /code/

CMD ["python3", "manage.py", "runserver", "0.0.0.0:8080"]

不要なものは適宜 dockerignore などで除けておいてください。

python3 manage.py runserver は引数でホストやポートを指定できます。インターネットに公開する + Cloud Run のデフォルト指定を使いたいのでここは 0.0.0.0:8080 にします。

ワークフローの定義

GitHub Actions からデプロイ

今回は GHA からデプロイします。その手続き自体はGitHub Actions から CloudRun にデプロイするに書いたものと同じ通りにします。

name: docker_build

on:
  push:
    branches:
      - "*"
      - "*/*"
      - "**"
      - "!main"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v2
      - id: "auth"
        uses: "google-github-actions/auth@v0"
        with:
          credentials_json: ${{ env.GCP_SERVICE_ACCOUNT_KEY }}
      - name: Configure docker to use the gcloud cli
        run: gcloud auth configure-docker --quiet
      - name: Build a docker image
        run: docker build -t ${{ env.IMAGE }} -f docker/dev/Dockerfile .
      - name: Push the docker image
        run: docker push ${{ env.IMAGE }}
      - name: Deploy to Cloud Run
        id: deploy
        uses: google-github-actions/deploy-cloudrun@v0
        with:
          service: ${{ env.SERVICE_NAME }}
          image: ${{ env.IMAGE }}
          region: ${{ env.GCP_REGION }}

Database の設定

migration は GHA でしようと思います。起動時、手元、ワークフロー、Docker ビルド時などいくつか方法はありますが、今回はワークフローでの実行をします。

今回は Django は Cloud SQL に接続させます。登録時のパスワード、設定画面で表示されるホストは setting.py で使わせます。

DATABASES = {
    'default': {
        'ENGINE': env('ENGINE'),
        'NAME': env('DB_NAME'),
        'USER': env('DB_USER'),
        'PASSWORD': env('DB_PASSWORD'),
        'HOST': env('DB_HOST'),
        'PORT': env('DB_PORT'),
  },
}

こうしておくことで python3 manage.py migratepython3 manage.py createsuperuser が通るようになります。しかし Cloud SQL を手順通りに設定している場合はうまくいかないかもしれません。もし Cloud SQL に IP 制限をしているのであれば、GHA から migrate することができません。これを解決するためにはワークフロー内で自分の IP を調べて(これは action.ipv4 みたいな変数に入っているのですぐ調べられる)、gcloud コマンドなり terraform 経由で CloudSQL の IP 穴あけをすれば実現できますが、めんどくさいので別の方法を考えます。

それは IP 制限をなくしてしまうことです。とはいえ GCP の設定上はなんらかの IP 値を入れないといけないので 0.0.0.0:0 を指定します。これは任意の IP アドレスとして認識されます。危険と思うかもしれませんが planetscale など他のサービスではデフォルトが IP 制限なしなので危険ではないと認識しています。(インターネットから隔離するのは常とされてはいるが、DB 然り SSH 先然り)

FYI: https://stackoverflow.com/questions/28339849/google-cloud-sql-authorize-all-ips

ワークフローから一連のコマンド実行

マイグレーションを行うpython3 manage.py migrate、admin 情報を登録する python3 manage.py createsuperuser、seed の追加をする python3 manage.py loaddata src/fixtures/rule.json を行います。

name: docker_build

on:
  push:
    branches:
      - "*"
      - "*/*"
      - "**"
      - "!main"

env:
  GCP_REGION: asia-northeast1
  SERVICE_NAME: splatoon3-hansei-server-dev
  IMAGE: asia.gcr.io/${{ secrets.GCP_PROJECT_ID_DEV }}/hoge:${{ github.sha }}
  GCP_SERVICE_ACCOUNT_KEY: ${{ secrets.GCP_SERVICE_ACCOUNT_KEY_DEV }}
  ENGINE: django.db.backends.mysql
  DB_NAME: ${{ secrets.CLOUD_SQL_DB_NAME_DEV }}
  DB_USER: ${{ secrets.CLOUD_SQL_USER_DEV }}
  DB_PASSWORD: ${{ secrets.CLOUD_SQL_PASSWORD_DEV }}
  DB_HOST: ${{ secrets.CLOUD_SQL_HOST_DEV }}
  DB_PORT: 3306
  DJANGO_SUPERUSER_USERNAME: ${{ secrets.DJANGO_ADMIN_NAME_DEV }}
  DJANGO_SUPERUSER_EMAIL: ${{ secrets.DJANGO_ADMIN_EMAIL_DEV }}
  DJANGO_SUPERUSER_PASSWORD: ${{ secrets.DJANGO_ADMIN_PASSWORD_DEV }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v2
      - id: "auth"
        uses: "google-github-actions/auth@v0"
        with:
          credentials_json: ${{ env.GCP_SERVICE_ACCOUNT_KEY }}
      - name: Configure docker to use the gcloud cli
        run: gcloud auth configure-docker --quiet
      - name: Build a docker image
        run: docker build -t ${{ env.IMAGE }} -f docker/dev/Dockerfile .
      - name: Push the docker image
        run: docker push ${{ env.IMAGE }}
      - name: install python lib
        run: pip install -r requirements.txt
      - name: migration
        run: python3 manage.py migrate
      - name: create admin account
        continue-on-error: true
        run: python3 manage.py createsuperuser --noinput
      - name: load seed
        run: python3 manage.py loaddata src/fixtures/rule.json && python3 manage.py loaddata src/fixtures/buki.json
      - name: Deploy to Cloud Run
        id: deploy
        uses: google-github-actions/deploy-cloudrun@v0
        with:
          service: ${{ env.SERVICE_NAME }}
          image: ${{ env.IMAGE }}
          region: ${{ env.GCP_REGION }}

面白いのは create admin account の continue-on-error: true です。admin 情報の登録は 1 度しかできず繰り返し実行すると失敗します。そこでこれは失敗してもいいようにcontinue-on-error: trueを設定しました。ちなみにあまり知られていませんが、管理画面の管理ユーザーは DJANGO_SUPERUSER_USERNAME,DJANGO_SUPERUSER_EMAIL,DJANGO_SUPERUSER_PASSWORD という環境変数があれば python3 manage.py createsuperuser --noinput コマンドで宣言的に実行できます。