Help us understand the problem. What is going on with this article?

Google App Engine フレキシブル環境でのDjangoの実行チュートリアルでハマった

More than 1 year has passed since last update.

概要

チュートリアルをやってみたものの、読むべきドキュメントが多くて、行ったり来たりで大変だったので、手順をまとめてみました。
一部どハマりしてスキップした箇所がありますが、デプロイまでできる手順となります。

チュートリアルは下記になります。

App Engine フレキシブル環境での Django の実行
https://cloud.google.com/python/django/flexible-environment?hl=ja

前提

上記記事の「始める前に」を読んで、以下の準備が完了している前提です。

  • GCPプロジェクトがある
  • プロジェクトの課金が有効
  • Google Cloud SDKがインストール済み。gcloudコマンドが利用できる
  • プロジェクトでApp EngineとCloud SQLのAPIが有効になっている

また、Python3系がインストール済みであることも前提です。
環境がない方は以下をご参考ください。

Macでanyenvをつかってpython環境構築(bash、fish対応)
https://qiita.com/kai_kou/items/f54931991a781b96bb9c

手順

サンプルアプリのダウンロード

> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
> cd python_sample_doc/appengine/flexible/django_cloudsql/

Cloud SQLにインスタンスを作成する

下記を参考にDjangoアプリが利用するデータベースを用意します。

インスタンスを作成する
https://cloud.google.com/sql/docs/postgres/create-instance

Cloud SDK を使用してインスタンスを管理する
https://cloud.google.com/sql/docs/cloud-sdk?hl=ja

先にGCPのプロジェクトを選択しておきます。

> gcloud config list

[compute]
region = asia-northeast1
zone = asia-northeast1-a
[core]
account = xxx@xxxxx.xxx
disable_usage_reporting = True
project = プロジェクトID

> gcloud config set project プロジェクトID

とりあえず、お試しなので、最小スペックでインスタンスを作成します。
立ち上がるのに少々お時間がかかります。

> gcloud sql instances create インスタンス名 \
    --database-version=POSTGRES_9_6 \
    --cpu=1 \
    --region=asia-northeast1 \
    --memory=3840MiB

インスタンスが作成されたか確認します。

> gcloud sql instances list

NAME         DATABASE_VERSION  LOCATION           TIER              ADDRESS         STATUS
インスタンス名  POSTGRES_9_6      asia-northeast1-b  db-custom-1-3840  xx.xxx.xxx.xxx  RUNNABLE

はい。

インスタンス情報を取得します。

> gcloud sql instances describe インスタンス名

()
connectionName: プロジェクトID:asia-northeast1:インスタンス名
databaseVersion: POSTGRES_9_6
()
serviceAccountEmailAddress: xxxx@xxx-xxxx-xx-x.iam.gserviceaccount.com
()

PostgreSQLユーザーのパスワード設定

下記を参考にしてpostgres ユーザーにパスワードを設定します。

PostgreSQL ユーザーを作成、管理する
https://cloud.google.com/sql/docs/postgres/create-manage-users?hl=ja

> gcloud sql users set-password postgres no-host \
   --instance インスタンス名 \
   --password パスワード

WARNING: Positional argument deprecated_host is deprecated. Use --host instead.
Updating Cloud SQL user...done.

データベースの作成

下記を参考にしてデータベースを作成します。

データベースを作成する
https://cloud.google.com/sql/docs/postgres/create-manage-databases?hl=ja#create

> gcloud sql databases create データベース名 --instance=インスタンス名

Creating Cloud SQL database...done.
Created database [データベース名].
instance: インスタンス名
name: データベース名
project: プロジェクトID

データベースが作成されたか確認します。

> gcloud sql databases list --instance=インスタンス名

NAME         CHARSET  COLLATION
postgres     UTF8     en_US.UTF8
django-test  UTF8     en_US.UTF8

はい。

Djangoアプリの設定

Djangoアプリがデータベースへアクセスできるように設定ファイルを編集します。

vi mysite/settings.py

HOST には先程gcloud sql instances describe インスタンス名 で取得した、connectionName を指定します。
gcloud sql instances describe インスタンス名

mysite/settings.py
-       'NAME': 'polls',
-       'USER': '<your-database-user>',
-       'PASSWORD': '<your-database-password>',
+       'NAME': 'データベース名',
+       'USER': 'postgres',
+       'PASSWORD': 'パスワード',

-DATABASES['default']['HOST'] = '/cloudsql/<your-cloudsql-connection-string>'
+DATABASES['default']['HOST'] = '/cloudsql/プロジェクトID:asia-northeast1:インスタンス名'

Djangoアプリの準備

Pythonの仮想環境を作成して、必要なパッケージをインストールします。
が、その前にrequirements.txtを編集しておきます。
Postgresqlを利用するチュートリアルなのに、不要でかつ、インストールできないライブラリが指定されていました。
あと、マイグレーションするとライブラリが足りないと怒られるので、先に追加しておきます。
(2018/08/10現在)

> vi requirements.txt
requirements.txt
Django==2.0.3
-mysqlclient==1.3.12
wheel==0.31.0
gunicorn==19.7.1
psycopg2==2.7.4
+psycopg2-binary==2.7.5
> python -m venv venv
> . venv/bin/activate
# fishはこちら
> . venv/bin/activate.fish

> pip install -r requirements.txt
()

Djangoアプリのマイグレーション

アプリの設定とライブラリがインストールできたらマイグレーションを行います。
ローカル環境でCloud SQLへアクセスできるプロキシアプリが提供されているので、新しいターミナルを開いて作業します。

新しいターミナル
> cd 任意のディレクトリ/python_sample_doc/appengine/flexible/django_cloudsql/
> curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
> chmod +x cloud_sql_proxy
> ./cloud_sql_proxy -instances="プロジェクトID:asia-northeast1:インスタンス名"=tcp:5432

2018/08/10 15:55:10 Listening on 127.0.0.1:5432 for プロジェクトID:asia-northeast1:インスタンス名
2018/08/10 15:55:10 Ready for new connections

もとのターミナルに戻ってマイグレーションを実行します。

> python manage.py makemigrations


Error during createEphemeral for プロジェクトID:asia-northeast1:インスタンス名: googleapi: Error 403: The client is not authorized to make this request., notAuthorized

はい。
権限がないと怒られました。

調べたところ、Cloud SQLのインスタンスに関連するサービスアカウントに権限付与しないといけなさそう?
先程実行したgcloud sql instances describe インスタンス名 で取得できたserviceAccountEmailAddress をGCP管理コンソールのIAMに編集者として追加してあげたら良いのかな?

Google Compute Engine(GCE)からCloud SQL接続でハマった
https://qiita.com/NagaokaKenichi/items/b54952e977c13f098bf5

申し訳ありませんが、諸般の都合で、IAM権限が低いため、ここではローカルでの実行をスキップして、Google App Engineへのデプロイへ進みます。
m(_ _)m

ちなみにCloud SQLへアクセスできないので、ローカルでアプリは起動できませんでした。

> python manage.py runserver

だめだった。

App Engineへのデプロイ

さて、ローカルでの実行もできたので(大嘘)
いよいよ、App Engineへのデプロイとなります。

まずは、静的コンテンツをCloud Storageへアップします。
バケットを一般読み取り可能にするので、専用のバケットにしたほうが安全です。

# バケットの作成
> gsutil mb gs://静的コンテンツ用のバケット名

Creating gs://静的コンテンツ用のバケット名/...

# バケットを一貫読み取り可能にする
> gsutil defacl set public-read gs://静的コンテンツ用のバケット名

Setting default object ACL on gs://静的コンテンツ用のバケット名/...

# 静的コンテンツを1フォルダにまとめる
> python manage.py collectstatic

# バケットにコピーする
> gsutil rsync -R static/ gs://静的コンテンツ用のバケット名/static

Djangoアプリ設定にアップロードしたフォルダのURLを設定します。

> vi mysite/settings.py
mysite/settings.py
-STATIC_URL = '/static/'
+STATIC_URL = 'https://storage.googleapis.com/静的コンテンツ用のバケット名/static/'

App Engineの設定を変更します。

> vi app.yaml

既存のプロジェクトを利用する場合、serviceを指定しないと、default にデプロイされてしまうので、ご注意ください。

app.yaml
# 新しいプロジェクトなら追加は不要
+service: サービス名

-   cloud_sql_instances: <your-cloudsql-connection-string>
+   cloud_sql_instances: プロジェクトID:asia-northeast1:インスタンス名

準備ができたので、デプロイします。

> gcloud app deploy

Services to deploy:

descriptor:      [/任意のディレクトリ/gcp/python-docs-samples/appengine/flexible/django_cloudsql/app.yaml]
source:          [/任意のディレクトリ/gcp/python-docs-samples/appengine/flexible/django_cloudsql]
target project:  [プロジェクトID]
target service:  [サービス名]
target version:  [バーション]
target url:      [https://サービス名-dot-プロジェクトID.appspot.com]

Do you want to continue (Y/n)?  Y
()

DONE
()  

デプロイが完了したら上記のtarget url にアクセスしてみましょう。

hello_-django.png

やったぜ。

これでチュートリアルは終了ですが、もうちょっとだけ続くんじゃ。


デプロイ先でマイグレーションする

先程、ローカル環境からCloud SQLにアクセスできないままで、マイグレーションができていないので、ここではデプロイ先のインスタンスに入ってマイグレーションしてみます。

下記を参考にして進めます。

インスタンスをデバッグする
https://cloud.google.com/appengine/docs/flexible/python/debugging-an-instance

gcloud app instances enable-debug
https://cloud.google.com/sdk/gcloud/reference/app/instances/enable-debug

インスタンスのデバッグができるように有効化します。
インスタンスが複数ある場合、どのインスタンスで有効化するか聞かれます。
スケールしているだけなので、どれを選んでも問題ありません。

> gcloud app --project プロジェクトID \
    instances enable-debug \
    --service=サービス名 \
    --version バーション

Which instance?
 [1] サービス名/バージョン/aef-xxxxx-バージョン-bqrz
 [2] サービス名/バージョン/aef-xxxxx-バージョン-zlqb

Please enter your numeric choice: 1
Waiting for operation 
()
...done.

デバッグが有効化されたらインスタンスにログインします。
初回はインスタンスへの接続に利用するrsa keyが生成されます。パスフレーズを忘れないようにしましょう。

> gcloud beta app instances \
    --project プロジェクトID \
    ssh aef-xxxxx-バーション-zlqb \
    --service サービス名 \
    --version バーション

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
()
Are you sure you want to continue connecting (yes/no)? 
()
Enter passphrase for key '/Users/xxx/.ssh/google_compute_engine':

インスタンスにログインできたらさらにDockerコンテナに入ります。
コンテナプロセスを確認するとどうやらgaeapp がDjangoアプリのコンテナのようです。

インスタンス内
> sudo docker ps

CONTAINER ID        IMAGE                                                         COMMAND                  CREATED             STATUS       PORTS                                        NAMES
212d1c1528be        us.gcr.io/プロジェクトID/appengine/サービス名.バーション@sha256:xxxx   "/bin/sh -c 'exec ..."   18 minutes ago      Up 18 minutes       172.17.0.1:8080->8080/tcp                    gaeapp
269598f6f28c        gcr.io/google-appengine/cloud-sql-proxy                                                         "/cloud_sql_proxy ..."   19 minutes ago      Up 18 minutes                                                    cloudsql
9629a8176717        gcr.io/google-appengine/api-proxy                                                         "/proxy"                 19 minutes ago      Up 19 minutes                                                    api
dae95a724b34        gcr.io/google-appengine/nginx-proxy                                                         "/var/lib/nginx/bi..."   19 minutes ago      Up 19 minutes       8080/tcp, 8090/tcp, 0.0.0.0:8443->8443/tcp   nginx_proxy
b3a1a85a156b        gcr.io/google-appengine/iap-watcher                                                         "./iap_watcher.py ..."   19 minutes ago      Up 19 minutes                                                    iap_watcher
3d45ca9828db        gcr.io/google-appengine/fluentd-logger                                                         "/opt/google-fluen..."   20 minutes ago      Up 20 minutes                                                    fluentd_logger

Dockerコンテナに入ります。

インスタンス内
> docker exec -it gaeapp /bin/bash

root@25f63590347e:/home/vmagent/app# ll
total 7320
drwxr-xr-x 1 root root    4096 Aug 10 07:37 ./
drwxr-xr-x 1 root root    4096 Jul  9 20:36 ../
-rw-r--r-- 1 root root     988 Aug  9 07:51 README.md
-rw-r--r-- 1 root root     271 Aug 10 07:36 app.yaml
-rwxr-xr-x 1 root root 7448368 Aug 10 06:39 cloud_sql_proxy*
-rwxr-xr-x 1 root root     825 Aug  9 07:51 manage.py*
drwxr-xr-x 1 root root    4096 Aug 10 07:41 mysite/
drwxr-xr-x 1 root root    4096 Aug 10 07:41 polls/
-rw-r--r-- 1 root root      83 Aug 10 07:11 requirements.txt
-rw-r--r-- 1 root root     136 Jan  1  1970 source-context.json
drwxr-xr-x 3 root root    4096 Aug 10 07:37 static

あってました^^

ではコンテナ内でマイグレーションします。

コンテナ内
> python manage.py makemigrations

No changes detected

> python manage.py makemigrations polls

Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Choice
    - Create model Question
    - Add field question to choice

> python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying polls.0001_initial... OK
  Applying sessions.0001_initial... OK

やったぜ。

無事に終わったら、コンテナとインスタンスから抜け出しましょう。

> exit
> exit

インスタンスでの作業が終わったら、デバッグモードを無効化します。

多分これを忘れると、インスタンスが起動しっぱなしで課金される?(未調査)

> gcloud app --project プロジェクトID \
    instances disable-debug \
    --service=サービス名 \
    --version バーション

どハマりもありましたが、なんとかApp Engine上でDjangoが実行できることが確認できました。
最後に、チュートリアルで作成した、Cloud SQLのインスタンスやApp Engineのサービスは不要であれば削除しておきましょう。

間違って削除してしまわないように、
ほんとうに、
ほんとうに、
ご注意ください。

# App Engineのサービス削除
> gcloud app services delete サービス名

# Cloud SQLインスタンスのデータベース削除
> gcloud sql databases delete データベース名 \
    --instance=インスタンス名

# Cloud SQLインスタンス削除
> gcloud sql instances delete インスタンス名

# Cloud Storageのバケット削除
> gsutil rm -r gs://静的コンテンツ用のバケット名

それでは、良きApp Engine上でのDjangoライフを^^

参考

App Engine フレキシブル環境での Django の実行
https://cloud.google.com/python/django/flexible-environment?hl=ja

インスタンスを作成する
https://cloud.google.com/sql/docs/postgres/create-instance

Cloud SDK を使用してインスタンスを管理する
https://cloud.google.com/sql/docs/cloud-sdk?hl=ja

PostgreSQL ユーザーを作成、管理する
https://cloud.google.com/sql/docs/postgres/create-manage-users?hl=ja

データベースを作成する
https://cloud.google.com/sql/docs/postgres/create-manage-databases?hl=ja#create

Google Compute Engine(GCE)からCloud SQL接続でハマった
https://qiita.com/NagaokaKenichi/items/b54952e977c13f098bf5

インスタンスをデバッグする
https://cloud.google.com/appengine/docs/flexible/python/debugging-an-instance

gcloud app instances enable-debug
https://cloud.google.com/sdk/gcloud/reference/app/instances/enable-debug

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした