🦁

gcloud python27 runtime dev_appserver.py が動かなくなった場合の対処

10 min read

google としては python37 への移行を強く推奨しているが、あまりにもsdkの互換性がないため、移植しあぐねてる案件も少なくないと思われる。
小生は、ただの一つの案件しかないのだが、 webapp2 の機能にガッツリと頼ってしまってる上に予算も時間もないため、python27ランタイムの利用を継続してる。

が、どうもグーグル側のpython27環境の検証も甘いのか、python27特有の不具合もあるようだ。

ImportError: No module named google.appengine.dist27.threading

先々月(2020.2)は動いてたはずなのだが、唐突に動かなくなった。
次の通りのエラーが出るため、初期化に失敗して、サービスが起動しない。

$ python2.7 -s -u /opt/google-cloud-sdk/bin/dev_appserver.py --port=8100 --host=127.0.0.1 --api_port=8101 --admin_port=8102 --require_indexes=no -- app
/
/usr/lib/python2.7/site-packages/OpenSSL/crypto.py:14: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in the next release.
  from cryptography import utils, x509
INFO     2021-04-18 18:21:58,287 devappserver2.py:289] Skipping SDK update check.
WARNING  2021-04-18 18:21:58,533 simple_search_stub.py:1203] Could not read indexes from /home/honda/WORK/gae-kuro-tsubasa-kiti-reservate/.web/search_indexes. Try running with the --clear_search_index flag. Cause:
IOError(13, 'Permission denied')
INFO     2021-04-18 18:21:58,535 api_server.py:282] Starting API server at: http://localhost:8101
INFO     2021-04-18 18:21:58,628 dispatcher.py:267] Starting module "default" running at: http://127.0.0.1:8100
INFO     2021-04-18 18:21:58,629 admin_server.py:150] Starting admin server at: http://localhost:8102
Traceback (most recent call last):
  File "/opt/google-cloud-sdk/platform/google_appengine/_python_runtime.py", line 96, in <module>
    _run_file(__file__, globals())
  File "/opt/google-cloud-sdk/platform/google_appengine/_python_runtime.py", line 90, in _run_file
    execfile(_PATHS.script_file(script_name), globals_)
  File "/opt/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/runtime/runtime.py", line 206, in <module>
    main()
  File "/opt/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/runtime/runtime.py", line 177, in main
    sandbox.enable_sandbox(config)
  File "/opt/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/runtime/sandbox.py", line 347, in enable_sandbox
    __import__('%s.threading' % dist27.__name__)
  File "/opt/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/runtime/sandbox.py", line 1168, in load_module
    raise ImportError('No module named %s' % fullname)
ImportError: No module named google.appengine.dist27.threading
ERROR    2021-04-18 18:22:00,751 instance.py:284] Cannot connect to the instance on localhost:15701

メッセージの通りで、google.appengine.dist27.threading が読めないと言ってる。
のだが、これは、/opt/google-cloud-sdk/platform/google_appengine/google/appengine/dist27/threading.py に存在してる。

ソースを探検してみると、この dist27.threading に限って特殊なやりかたをしてるようで、それがかなり環境にたいしてデリケートな挙動を起こすらしい。

検索してみる

ImportErrorの通りに検索してみると、2019年等、最近でないものが引っかかる。どうやら既知のトラブルのようだ。
ただ残念ながら、小生の環境ではいずれも動かなかった。

virtualenvを使えと言ってるもの。

2019年

No module named google.appengine.dist27.threading when run python butler.py run_server · Issue #232 · google/clusterfuzz · GitHub

virtualenv --no-site-packages /tmp/googleapps
source /tmp/googleapps/bin/activate
dev_appserver.py path_to_google_app

最近のvirtualenvには、このno-site-packageオプションが使えないようだ。このため、site-packagesを除外することができない。

7年前

python - App Engine dev server: bad runtime process port [''] No module named google.appengine.dist27.threading - Stack Overflow

2016年

Fixing "No module named google.appengine.dist27.threading" for App Engine

yamlに記述を書き足せと言ってるもの。

2015年

Google App Engine: ImportError: No module named google.appengine.dist27.threading - eshlox (Przemysław Kołodziejczyk)

Google App Engine: ImportError: No module named google.appengine.dist27.threading - pl.python.org/planeta

skip_files:
  - lib/google_appengine

この通りに app.yaml に書き足してもなんの変化もなかった。

dockerでpython2 dev_appserver.py専用環境を作る

どうやらこれが最も確実らしい。

まずは docker alpine に google-cloud-sdk を展開する。

alpineじゃなくても良いんだが、docker pullが圧倒的に早いので、設置時間が大幅に減る。
小生の環境では、2分もかからない。

FROM alpine:latest
ENV PYTHONUNBUFFERED=1
ENV GCLOUD_VER=335.0.0
RUN apk add python2 python3 bash \
&& cd /opt \
&& wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${GCLOUD_VER}-linux-x86_64.tar.gz \
&& tar xfz google-cloud-sdk-${GCLOUD_VER}-linux-x86_64.tar.gz \
&& ./google-cloud-sdk/install.sh \
&& /opt/google-cloud-sdk/bin/gcloud components install app-engine-python app-engine-python-extras

#CMD /bin/bash
WORKDIR /app
#CMD /bin/bash
##CMD /bin/ls /app/
COPY run.sh /root/
ENTRYPOINT [ "/bin/sh","/root/run.sh"]

起動スクリプトは次の通り。

  • 環境変数 MYPRJ でプロジェクト名を設定する。 docker の -eとか、docker-composerの environmentにて。
  • サーバソースを /app に 展開|mount
  • データディレクトリは必要なら /webdb に展開|mount

dev_appserverの指定では、単に host=0.0.0.0 にするだけではだめで、接続もとのホワイトリストを設定する必要があるらしい。

gcloud-inline_1  | + exec python2 /opt/google-cloud-sdk/platform/google_appengine/dev_appserver.py --port 8110 --host 0.0.0.0 --admin_port 8112 --admin_host 0.0.0.0 --skip_sdk_update_check -A $MYPRJ --storage_path /webdb/ /app/
gcloud-inline_1  | INFO     2021-04-19 02:49:06,089 devappserver2.py:289] Skipping SDK update check.
gcloud-inline_1  | INFO     2021-04-19 02:49:06,451 api_server.py:282] Starting API server at: http://localhost:34903
gcloud-inline_1  | INFO     2021-04-19 02:49:06,496 dispatcher.py:267] Starting module "default" running at: http://0.0.0.0:8110
gcloud-inline_1  | INFO     2021-04-19 02:49:06,497 admin_server.py:150] Starting admin server at: http://0.0.0.0:8112
gcloud-inline_1  | INFO     2021-04-19 02:49:08,658 instance.py:294] Instance PID: 14
gcloud-inline_1  | ERROR    2021-04-19 02:49:32,384 wsgi_server.py:340] Request Host 172.24.0.2 not whitelisted. Enabled hosts are set(['0.0.0.0'])

末尾の行に注目。

リクエストには次の通りのレスポンスが戻る。

Request host is not whitelist enabled for this server. Please use the --host command-line flag to whitelist a specific host (recommended) or use --enable_host_checking to disable host checking. See the command-line flags help text for more information.

ただこの説明では --enable_host_checkingをつければよいとあるが、それを指定しても解決しない。

port forwardを使えば動作する。 127.0.0.1/localhostだと言い張ればいいということらしい。

だが、それは小生の主義に合わないので、docker が /etc/hostsに書き込んでくれている IPアドレス情報を引っ張ることにした。

#!/bin/bash -x
MYIP=$( awk '$2 ~/^[0-9a-f]{12}$/{print $1}' /etc/hosts )
exec python2 /opt/google-cloud-sdk/platform/google_appengine/dev_appserver.py \
--port 8110 --host $MYIP \
--admin_port 8112 --admin_host $MYIP \
−--skip_sdk_update_check -A $MYPRJ --storage_path /webdb/ /app/

次はdocker-composeで/appにmountしてる(記述は割愛)してる例である

# docker-compose up --build
Building gcloud-inline
Sending build context to Docker daemon  46.08kB

Step 1/7 : FROM alpine:latest
 ---> 6dbb9cc54074
Step 2/7 : ENV PYTHONUNBUFFERED=1
 ---> Using cache
 ---> 044c23972aa1
Step 3/7 : ENV GCLOUD_VER=335.0.0
 ---> Using cache
 ---> c86d43915fb2
Step 4/7 : RUN apk add python2 python3 bash && cd /opt && wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${GCLOUD_VER}-linux-x86_64.tar.gz && tar xfz google-cloud-sdk-${GCLOUD_VER}-linux-x86_64.tar.gz && ./google-cloud-sdk/install.sh && /opt/google-cloud-sdk/bin/gcloud components install app-engine-python app-engine-python-extras
 ---> Using cache
 ---> e7f54c724029
Step 5/7 : WORKDIR /app
 ---> Using cache
 ---> 47356e843c3c
Step 6/7 : COPY run.sh /root/
 ---> Using cache
 ---> 0134b14b750d
Step 7/7 : ENTRYPOINT [ "/bin/sh","/root/run.sh"]
 ---> Using cache
 ---> 7058884c6cde
Successfully built 7058884c6cde
Successfully tagged gclouddocker_gcloud-inline:latest
Starting gclouddocker_gcloud-inline_1 ... done
Attaching to gclouddocker_gcloud-inline_1
gcloud-inline_1  | + awk '$2 ~/^[0-9a-f]{12}$/{print $1}' /etc/hosts
gcloud-inline_1  | + MYIP=172.24.0.2
gcloud-inline_1  | + exec python2 /opt/google-cloud-sdk/platform/google_appengine/dev_appserver.py --port 8110 --host 172.24.0.2 --admin_port 8112 --admin_host 172.24.0.2 --skip_sdk_update_check -A $MYPRJ --storage_path /webdb/ /app/
gcloud-inline_1  | INFO     2021-04-18 18:38:19,880 devappserver2.py:289] Skipping SDK update check.
gcloud-inline_1  | INFO     2021-04-18 18:38:20,020 api_server.py:282] Starting API server at: http://localhost:33909
gcloud-inline_1  | INFO     2021-04-18 18:38:20,053 dispatcher.py:267] Starting module "default" running at: http://172.24.0.2:8110
gcloud-inline_1  | INFO     2021-04-18 18:38:20,054 admin_server.py:150] Starting admin server at: http://172.24.0.2:8112
gcloud-inline_1  | INFO     2021-04-18 18:38:22,153 instance.py:294] Instance PID

ようやく仕事ができそうだ。

Discussion

ログインするとコメントできます