概要
チュートリアルをやってみたものの、読むべきドキュメントが多くて、行ったり来たりで大変だったので、手順をまとめてみました。
一部どハマりしてスキップした箇所がありますが、デプロイまでできる手順となります。
チュートリアルは下記になります。
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 インスタンス名
- '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
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
-STATIC_URL = '/static/'
+STATIC_URL = 'https://storage.googleapis.com/静的コンテンツ用のバケット名/static/'
App Engineの設定を変更します。
> vi app.yaml
既存のプロジェクトを利用する場合、service
を指定しないと、default
にデプロイされてしまうので、ご注意ください。
# 新しいプロジェクトなら追加は不要
+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
にアクセスしてみましょう。
やったぜ。
これでチュートリアルは終了ですが、もうちょっとだけ続くんじゃ。
デプロイ先でマイグレーションする
先程、ローカル環境から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