ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื” ืฉืœ Python

ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื” ืฉืœ Python ื”ื™ื ื—ื‘ื™ืœืช ื”ืชื•ื›ื ื” ืฉืื—ืจืื™ืช ืœื”ืชืงื ืช ืงื•ื“ ื”ืืคืœื™ืงืฆื™ื” ื•ื”ืชืœื•ื™ื•ืช ืฉืœื”, ื•ืœืื—ืจ ืžื›ืŸ ืœื”ืจืฆืช ื”ืืคืœื™ืงืฆื™ื” ื‘ืกื‘ื™ื‘ื” ื”ื’ืžื™ืฉื”.

ื’ืจืกืื•ืช Python

โ€ซPython 3.14 ืžืฉืชืžืฉ ื‘-buildpacks. ื‘ืžืืžืจ ื”ื–ื” ืžืคื•ืจื˜ืช ืจืฉื™ืžื” ืžืœืื” ืฉืœ ื’ืจืกืื•ืช Python ื ืชืžื›ื•ืช ื•ื’ืจืกืื•ืช Ubuntu ื”ืชื•ืืžื•ืช ืœื”ืŸ.

ื›ื“ื™ ืœื”ืฉืชืžืฉ ื‘ื’ืจืกืช Python ื ืชืžื›ืช, ืฆืจื™ืš:

  • ื›ื“ื™ ืœืฆื™ื™ืŸ ืžืขืจื›ืช ื”ืคืขืœื”, ืฆืจื™ืš ืœื›ืœื•ืœ ืืช ื”ื”ื’ื“ืจื•ืช runtime_config ื•-operating_system ื‘ืงื•ื‘ืฅ app.yaml.

  • ืžืชืงื™ื ื™ื ืืช gcloud CLI ื‘ื’ืจืกื” 420.0.0 ื•ืื™ืœืš. ื›ื“ื™ ืœืขื“ื›ืŸ ืืช ื›ืœื™ ื”-CLI, ืžืจื™ืฆื™ื ืืช ื”ืคืงื•ื“ื” gcloud components update. ื›ื“ื™ ืœืจืื•ืช ืืช ื”ื’ืจืกื” ื”ืžื•ืชืงื ืช, ืžืจื™ืฆื™ื ืืช ื”ืคืงื•ื“ื” gcloud version.

  • ืืคืฉืจ ื’ื ืœืฆื™ื™ืŸ ื’ืจืกืช ื–ืžืŸ ืจื™ืฆื” ืขืœ ื™ื“ื™ ื”ื•ืกืคืช ื”ื”ื’ื“ืจื” runtime_version ืœืงื•ื‘ืฅ app.yaml. ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, ื ืขืฉื” ืฉื™ืžื•ืฉ ื‘ื’ืจืกื” ื”ืขื“ื›ื ื™ืช ื‘ื™ื•ืชืจ ืฉืœ Python ืื ืœื ืžืฆื™ื™ื ื™ื ืืช ื”ื”ื’ื“ืจื” runtime_version.

ื“ื•ื’ืžืื•ืช

  • ื›ื“ื™ ืœืฆื™ื™ืŸ Python 3.14 ื‘-Ubuntu 24:

    runtime: python
    env: flex
    entrypoint: gunicorn -b :$PORT main:app
    
    runtime_config:
        operating_system: "ubuntu24"
        runtime_version: "3.14"
    
  • ื›ื“ื™ ืœืฆื™ื™ืŸ ืืช ื’ืจืกืช Python ื”ื ืชืžื›ืช ื”ืื—ืจื•ื ื” ื‘-Ubuntu 24:

      runtime: python
      env: flex
      entrypoint: gunicorn -b :$PORT main:app
    
      runtime_config:
          operating_system: "ubuntu24"
    

ืžื™ื“ืข ื ื•ืกืฃ ื–ืžื™ืŸ ื‘ื“ืฃ ื”ืขื–ืจื” ืฉืœ app.yaml.

ืชืžื™ื›ื” ื‘ืกื‘ื™ื‘ื•ืช ื–ืžืŸ ืจื™ืฆื” ืื—ืจื•ืช ืฉืœ Python

ืื ืืชื ืฆืจื™ื›ื™ื ืœื”ืฉืชืžืฉ ื‘ื’ืจืกืช Python ืฉืœื ื ืชืžื›ืช, ืืชื ื™ื›ื•ืœื™ื ืœื™ืฆื•ืจ ืกื‘ื™ื‘ืช ืจื™ืฆื” ื‘ื”ืชืืžื” ืื™ืฉื™ืช ื•ืœื‘ื—ื•ืจ ืชืžื•ื ืช ื‘ืกื™ืก ืชืงื™ื ื” ืขื ื’ืจืกืช Python ืฉืืชื ืฆืจื™ื›ื™ื.

ืžื™ื“ืข ืขืœ ืชืžื•ื ื•ืช ื‘ืกื™ืก ืฉืกื•ืคืงื• ืขืœ ื™ื“ื™ Google ืื• ืขืœ ืชืžื•ื ื•ืช ื‘ืกื™ืก ืฉืœ Docker Python ื–ืžื™ืŸ ื‘ืžืืžืจ ื™ืฆื™ืจืช ืกื‘ื™ื‘ื•ืช ืจื™ืฆื” ื‘ื”ืชืืžื” ืื™ืฉื™ืช.

ื›ื“ื™ ืœื‘ื“ื•ืง ืœืขื•ืžืง ืืช ื”ืืคืฉืจื•ืช ืœื”ืขื‘ื™ืจ ืืคืœื™ืงืฆื™ื•ืช ืฉืœ App Engine ืœ-Cloud Run ื‘ืืžืฆืขื•ืช ืงื•ื ื˜ื™ื™ื ืจื™ื, ืืคืฉืจ ืœืขื™ื™ืŸ ื‘ืžื“ืจื™ืš ืœื”ืขื‘ืจืช ื ืชื•ื ื™ื.

ืชืœื•ื™ื•ืช

ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื” ืžื—ืคืฉืช ืงื•ื‘ืฅ requirements.txt ื‘ืกืคืจื™ื™ืช ืงื•ื‘ืฆื™ ื”ืžืงื•ืจ ืฉืœ ื”ืืคืœื™ืงืฆื™ื” ื•ืžืฉืชืžืฉืช ื‘-pip ื›ื“ื™ ืœื”ืชืงื™ืŸ ืืช ื›ืœ ื”ืชืœื•ื™ื•ืช ืœืคื ื™ ื”ืคืขืœืช ื”ืืคืœื™ืงืฆื™ื”. ืžื™ื“ืข ื ื•ืกืฃ ืขืœ ื”ืฆื”ืจื” ื•ื ื™ื”ื•ืœ ืฉืœ ื—ื‘ื™ืœื•ืช ื–ืžื™ืŸ ื‘ืžืืžืจ ืฉื™ืžื•ืฉ ื‘ืกืคืจื™ื•ืช Python.

ืื ื”ืืคืœื™ืงืฆื™ื” ืฉืœื›ื ื“ื•ืจืฉืช ืชืœื•ืช ืคืจื˜ื™ืช, ืืชื ืฆืจื™ื›ื™ื ืœื”ืฉืชืžืฉ ื‘ืกื‘ื™ื‘ืช ืจื™ืฆื” ื‘ื”ืชืืžื” ืื™ืฉื™ืช ืฉืžื‘ื•ืกืกืช ืขืœ ืกื‘ื™ื‘ืช ื”ืจื™ืฆื” ืฉืœ Python ื›ื“ื™ ืœื”ืชืงื™ืŸ ืืช ื”ื—ื‘ื™ืœื•ืช ื”ืžืชืื™ืžื•ืช.

ื”ืคืขืœืช ื”ืืคืœื™ืงืฆื™ื”

ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื” ืžืคืขื™ืœื” ืืช ื”ืืคืœื™ืงืฆื™ื” ื‘ืืžืฆืขื•ืช ื”ืคืงื•ื“ื” entrypoint ืฉืžื•ื’ื“ืจืช ื‘ืงื•ื‘ืฅ app.yaml. ื ืงื•ื“ืช ื”ื›ื ื™ืกื” ืฆืจื™ื›ื” ืœื”ืชื—ื™ืœ ืชื”ืœื™ืš ืฉืžื’ื™ื‘ ืœื‘ืงืฉื•ืช HTTP ื‘ื™ืฆื™ืื” ืฉืžื•ื’ื“ืจืช ืขืœ ื™ื“ื™ ืžืฉืชื ื” ื”ืกื‘ื™ื‘ื” PORT.

ืจื•ื‘ ืืคืœื™ืงืฆื™ื•ืช ื”ืื™ื ื˜ืจื ื˜ ืžืฉืชืžืฉื•ืช ื‘ืฉืจืช WSGI ื›ืžื• Gunicorn, โ€ uWSGI ืื• Waitress.

ื›ื“ื™ ืœื”ืฉืชืžืฉ ื‘ืื—ื“ ืžื”ืฉืจืชื™ื ื”ืืœื”, ืฆืจื™ืš ืœื”ื•ืกื™ืฃ ืื•ืชื ื›ืชืœื•ืช ื‘ืงื•ื‘ืฅ requirements.txt ืฉืœ ื”ืืคืœื™ืงืฆื™ื”. ืื ืืชื ืžืฉืชืžืฉื™ื ื‘-gunicorn ื‘ืืคืœื™ืงืฆื™ื™ืช Flask, ื•ื“ืื• ืฉื’ืจืกืช Python ืฉืœ ื”ืืคืœื™ืงืฆื™ื” ืชื•ืืžืช ืœ-gunicorn.

ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื” ืžื•ื•ื“ืืช ืฉื›ืœ ื™ื—ืกื™ ื”ืชืœื•ืช ืžื•ืชืงื ื™ื ืœืคื ื™ ืฉื ืงื•ื“ืช ื”ื›ื ื™ืกื” ื ืงืจืืช.

Flask==2.0.2
gunicorn==20.1.0

ื“ื•ื’ืžื” ืœื ืงื•ื“ืช ื›ื ื™ืกื” ื‘ืืžืฆืขื•ืช gunicorn ืœืืคืœื™ืงืฆื™ื™ืช Flask:

entrypoint: gunicorn -b :$PORT main:app

ื“ื•ื’ืžื” ืœื ืงื•ื“ืช ื›ื ื™ืกื” ื‘ืืžืฆืขื•ืช gunicorn ืœืืคืœื™ืงืฆื™ื™ืช Django:

entrypoint: gunicorn -b :$PORT mydjangoapp:wsgi

Gunicorn ื”ื•ื ืฉืจืช WSGI ื”ืžื•ืžืœืฅ, ืื‘ืœ ืืคืฉืจ ืœื”ืฉืชืžืฉ ื‘ื›ืœ ืฉืจืช WSGI ืื—ืจ. ืœื“ื•ื’ืžื”, ื”ื ื” ื ืงื•ื“ืช ื›ื ื™ืกื” ืฉืžืฉืชืžืฉืช ื‘-uWSGI ืขื Flask:

entrypoint: uwsgi --http :$PORT --wsgi-file main.py --callable app

ื‘ืืคืœื™ืงืฆื™ื•ืช ืฉื™ื›ื•ืœื•ืช ืœื˜ืคืœ ื‘ื‘ืงืฉื•ืช ื‘ืœื™ ืฉืจืช WSGI, ืืคืฉืจ ืคืฉื•ื˜ ืœื”ืจื™ืฅ ืกืงืจื™ืคื˜ Python:

entrypoint: python main.py

ื”ื“ื•ื’ืžืื•ืช ื”ื‘ืกื™ืกื™ื•ืช ืœื ืงื•ื“ื•ืช ื›ื ื™ืกื” ืฉืžื•ืฆื’ื•ืช ืœืžืขืœื” ื ื•ืขื“ื• ืœืฉืžืฉ ื›ื ืงื•ื“ื•ืช ื”ืชื—ืœื”, ื•ื™ื›ื•ืœ ืœื”ื™ื•ืช ืฉื”ืŸ ื™ืชืื™ืžื• ืœืืคืœื™ืงืฆื™ื•ืช ื”ืื™ื ื˜ืจื ื˜ ืฉืœื›ื. ืขื ื–ืืช, ื‘ืจื•ื‘ ื”ืืคืœื™ืงืฆื™ื•ืช ื™ื”ื™ื” ืฆื•ืจืš ืœื”ื’ื“ื™ืจ ืขื•ื“ ืืช ืฉืจืช ื”-WSGI. ื‘ืžืงื•ื ืœืฆื™ื™ืŸ ืืช ื›ืœ ื”ื”ื’ื“ืจื•ืช ื‘ื ืงื•ื“ืช ื”ื›ื ื™ืกื”, ื™ื•ืฆืจื™ื ืงื•ื‘ืฅ gunicorn.conf.py ื‘ืกืคืจื™ื™ืช ื”ื‘ืกื™ืก ืฉืœ ื”ืคืจื•ื™ืงื˜, ืฉื‘ื” ื ืžืฆื ื”ืงื•ื‘ืฅ app.yaml, ื•ืžืฆื™ื™ื ื™ื ืื•ืชื• ื‘ื ืงื•ื“ืช ื”ื›ื ื™ืกื”:

entrypoint: gunicorn -c gunicorn.conf.py -b :$PORT main:app

ื‘ืชื™ืขื•ื“ ืฉืœ Gunicorn ืืคืฉืจ ืœืงืจื•ื ืขืœ ื›ืœ ืขืจื›ื™ ื”ื”ื’ื“ืจื” ืฉืœื•.

ืขื•ื‘ื“ื™ื

โ€ซGunicorn ืžืฉืชืžืฉ ื‘ืชื”ืœื™ื›ื™ worker ื›ื“ื™ ืœื˜ืคืœ ื‘ื‘ืงืฉื•ืช. ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, Gunicorn ืžืฉืชืžืฉ ื‘-sync workers. ื”ืกื•ื’ ื”ื–ื” ืฉืœ Worker ืชื•ืื ืœื›ืœ ืืคืœื™ืงืฆื™ื•ืช ื”ืื™ื ื˜ืจื ื˜, ืื‘ืœ ื›ืœ Worker ื™ื›ื•ืœ ืœื˜ืคืœ ืจืง ื‘ื‘ืงืฉื” ืื—ืช ื‘ื›ืœ ืคืขื. ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, gunicorn ืžืฉืชืžืฉ ืจืง ื‘ืื—ื“ ืžื”ืขื•ื‘ื“ื™ื ื”ืืœื”. ื‘ืžืงืจื™ื ื›ืืœื”, ื™ื›ื•ืœ ืœื”ื™ื•ืช ืฉื”ืฉื™ืžื•ืฉ ื‘ืžื•ืคืขื™ื ืœื ื™ื”ื™ื” ื™ืขื™ืœ, ื•ื”ื”ืฉื”ื™ื” ื‘ืืคืœื™ืงืฆื™ื•ืช ืชื’ื“ืœ ื›ืฉื”ืขื•ืžืก ืขืœื™ื”ืŸ ื™ื”ื™ื” ื’ื‘ื•ื”.

ืžื•ืžืœืฅ ืœื”ื’ื“ื™ืจ ืืช ืžืกืคืจ ื”ืขื•ื‘ื“ื™ื ื›ืš ืฉื™ื”ื™ื” ื’ื“ื•ืœ ืคื™ 2 ืขื“ 4 ืžืžืกืคืจ ืœื™ื‘ื•ืช ื”-CPU ื‘ืžื•ืคืข, ื•ืขื•ื“ ืื—ื“. ืืคืฉืจ ืœืฆื™ื™ืŸ ืืช ื–ื” ื‘-gunicorn.conf.py ื‘ืื•ืคืŸ ื”ื‘ื:

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1

ื‘ื ื•ืกืฃ, ื—ืœืง ืžืืคืœื™ืงืฆื™ื•ืช ื”ืื™ื ื˜ืจื ื˜ ืฉืžื•ื’ื‘ืœื•ืช ื‘ืขื™ืงืจ ืขืœ ื™ื“ื™ ืงืœื˜/ืคืœื˜ ื™ื›ื•ืœื•ืช ืœื™ื”ื ื•ืช ืžืฉื™ืคื•ืจ ื‘ื‘ื™ืฆื•ืขื™ื ื‘ืืžืฆืขื•ืช ืกื•ื’ ืื—ืจ ืฉืœ ืชื”ืœื™ืš ืขื‘ื•ื“ื”. ืื ืžื—ืœืงืช ื”ืขื•ื‘ื“ื™ื ืฉืœื›ื ื“ื•ืจืฉืช ื™ื—ืกื™ ืชืœื•ืช ื ื•ืกืคื™ื, ื›ืžื• gevent ืื• tornado, ืชืฆื˜ืจื›ื• ืœื”ืฆื”ื™ืจ ืขืœ ื™ื—ืกื™ ื”ืชืœื•ืช ื”ืืœื” ื‘ืงื•ื‘ืฅ requirements.txt ืฉืœ ื”ืืคืœื™ืงืฆื™ื”.

ืคืจื•ื˜ื•ืงื•ืœ HTTPS ื•ืฉืจืชื™ proxy ืœื”ืขื‘ืจื”

โ€ซApp Engine ืžืคืกื™ืง ืืช ื—ื™ื‘ื•ืจ ื”-HTTPS ื‘ืžืื–ืŸ ื”ืขื•ืžืกื™ื ื•ืžืขื‘ื™ืจ ืืช ื”ื‘ืงืฉื” ืœืืคืœื™ืงืฆื™ื”. ืœืจื•ื‘ ื”ืืคืœื™ืงืฆื™ื•ืช ืœื ืฆืจื™ืš ืœื“ืขืช ืื ื”ื‘ืงืฉื” ื ืฉืœื—ื” ื‘ืืžืฆืขื•ืช HTTPS ืื• ืœื, ืื‘ืœ ืืคืœื™ืงืฆื™ื•ืช ืฉืฆืจื™ื›ื•ืช ืืช ื”ืžื™ื“ืข ื”ื–ื” ืฆืจื™ื›ื•ืช ืœื”ื’ื“ื™ืจ ืืช Gunicorn ื›ืš ืฉื™ืกืžื•ืš ืขืœ ื”-proxy ืฉืœ App Engine ื‘-gunicorn.conf.py:

forwarded_allow_ips = '*'
secure_scheme_headers = {'X-FORWARDED-PROTO': 'https'}

โ€ซGunicorn ื™ื•ื•ื“ื ืขื›ืฉื™ื• ืฉ-wsgi.url_scheme ืขื“ 'https', ืฉืจื•ื‘ ืžืกื’ืจื•ืช ื”ืื™ื ื˜ืจื ื˜ ื™ืฉืชืžืฉื• ื‘ื”ืŸ ื›ืื™ื ื“ื™ืงืฆื™ื” ืœื›ืš ืฉื”ื‘ืงืฉื” ืžืื•ื‘ื˜ื—ืช. ืื ืฉืจืช ื”-WSGI ืื• ื”ืžืกื’ืจืช ืœื ืชื•ืžื›ื™ื ื‘ื–ื”, ืคืฉื•ื˜ ื‘ื•ื“ืงื™ื ืืช ื”ืขืจืš ืฉืœ ื”ื›ื•ืชืจืช X-Forwarded-Proto ื‘ืื•ืคืŸ ื™ื“ื ื™.

ื—ืœืง ืžื”ืืคืœื™ืงืฆื™ื•ืช ืฆืจื™ื›ื•ืช ื’ื ืœืงื‘ื•ืข ืืช ื›ืชื•ื‘ืช ื”-IP ืฉืœ ื”ืžืฉืชืžืฉ. ื”ืืคืฉืจื•ืช ื”ื–ื• ื–ืžื™ื ื” ื‘ื›ื•ืชืจืช X-Forwarded-For.

ืฉื™ืžื• ืœื‘ ืฉื”ื”ื’ื“ืจื” secure_scheme_headers ื‘-gunicorn.conf.py ืฆืจื™ื›ื” ืœื”ื™ื•ืช ื‘ืื•ืชื™ื•ืช ืจื™ืฉื™ื•ืช, ื›ืžื• X-FORWARDED-PROTO, ืื‘ืœ ื”ื›ื•ืชืจื•ืช ืฉื”ืงื•ื“ ื™ื›ื•ืœ ืœืงืจื•ื ื™ื”ื™ื• ื‘ืื•ืชื™ื•ืช ืžืขื•ืจื‘ื•ืช, ื›ืžื• X-Forwarded-Proto.

ื”ืืจื›ืช ื–ืžืŸ ื”ืจื™ืฆื”

ืืคืฉืจ ืœื”ืฉืชืžืฉ ื‘ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื” ื”ื’ืžื™ืฉื” ืฉืœ Python ื›ื“ื™ ืœื™ืฆื•ืจ ื–ืžืŸ ืจื™ืฆื” ื‘ื”ืชืืžื” ืื™ืฉื™ืช. ืžื™ื“ืข ื ื•ืกืฃ ื–ืžื™ืŸ ื‘ืžืืžืจ ื‘ื ื•ืฉื ื”ืชืืžื” ืื™ืฉื™ืช ืฉืœ Python.

ืžืฉืชื ื™ ืกื‘ื™ื‘ื”

ืžืฉืชื ื™ ื”ืกื‘ื™ื‘ื” ื”ื‘ืื™ื ืžื•ื’ื“ืจื™ื ืขืœ ื™ื“ื™ ืกื‘ื™ื‘ืช ื–ืžืŸ ื”ืจื™ืฆื”:

ืžืฉืชื ื” ืกื‘ื™ื‘ื” ืชื™ืื•ืจ
GAE_INSTANCE ื”ืฉื ืฉืœ ื”ืžื›ื•ื ื” ื”ื ื•ื›ื—ื™ืช.
GAE_MEMORY_MB ื ืคื— ื”ื–ื™ื›ืจื•ืŸ ืฉื–ืžื™ืŸ ืœืชื”ืœื™ืš ื”ืืคืœื™ืงืฆื™ื”.
GAE_SERVICE ืฉื ื”ืฉื™ืจื•ืช ืฉืฆื•ื™ืŸ ื‘ืงื•ื‘ืฅ app.yaml ืฉืœ ื”ืืคืœื™ืงืฆื™ื”, ืื• ืื ืœื ืฆื•ื™ืŸ ืฉื ืฉื™ืจื•ืช, ื”ืฉื ืฉืžื•ื’ื“ืจ ื”ื•ื default.
GAE_VERSION ืชื•ื•ื™ืช ื”ื’ืจืกื” ืฉืœ ื”ืืคืœื™ืงืฆื™ื” ื”ื ื•ื›ื—ื™ืช.
GOOGLE_CLOUD_PROJECT ืžื–ื”ื” ื”ืคืจื•ื™ืงื˜ ืฉืžืฉื•ื™ืš ืœืืคืœื™ืงืฆื™ื”, ืฉืžื•ืคื™ืข ื‘ืžืกื•ืฃ Google Cloud
PORT ื”ื™ืฆื™ืื” ืฉืชืงื‘ืœ ื‘ืงืฉื•ืช HTTP.

ืืคืฉืจ ืœื”ื’ื“ื™ืจ ืžืฉืชื ื™ ืกื‘ื™ื‘ื” ื ื•ืกืคื™ื ื‘ืงื•ื‘ืฅ app.yaml.

ืฉืจืช ืžื˜ื-ื ืชื•ื ื™ื

ื›ืœ ืžื•ืคืข ืฉืœ ื”ืืคืœื™ืงืฆื™ื” ื™ื›ื•ืœ ืœื”ืฉืชืžืฉ ื‘ืฉืจืช ื”ืžื˜ื-ื ืชื•ื ื™ื ืฉืœ Compute Engine ื›ื“ื™ ืœืฉืœื•ื— ืฉืื™ืœืชื•ืช ืœื’ื‘ื™ ืžื™ื“ืข ืขืœ ื”ืžื•ืคืข, ื›ื•ืœืœ ืฉื ื”ืžืืจื—, ื›ืชื•ื‘ืช ื”-IP ื”ื—ื™ืฆื•ื ื™ืช, ืžื–ื”ื” ื”ืžื•ืคืข, ืžื˜ื-ื ืชื•ื ื™ื ืžื•ืชืืžื™ื ืื™ืฉื™ืช ื•ืคืจื˜ื™ ื—ืฉื‘ื•ืŸ ื”ืฉื™ืจื•ืช. ื‘-App Engine ืื™ ืืคืฉืจ ืœื”ื’ื“ื™ืจ ืžื˜ื-ื ืชื•ื ื™ื ืžื•ืชืืžื™ื ืื™ืฉื™ืช ืœื›ืœ ืžื•ืคืข, ืื‘ืœ ืืคืฉืจ ืœื”ื’ื“ื™ืจ ืžื˜ื-ื ืชื•ื ื™ื ืžื•ืชืืžื™ื ืื™ืฉื™ืช ื‘ืจืžืช ื”ืคืจื•ื™ืงื˜ ื•ืœืงืจื•ื ืื•ืชื ืžื”ืžื•ืคืขื™ื ืฉืœ App Engine ื•-Compute Engine.

ื”ืคื•ื ืงืฆื™ื” ื‘ื“ื•ื’ืžื” ื”ื–ื• ืžืฉืชืžืฉืช ื‘ืฉืจืช ื”ืžื˜ื-ื ืชื•ื ื™ื ื›ื“ื™ ืœืงื‘ืœ ืืช ื›ืชื•ื‘ืช ื”-IP ื”ื—ื™ืฆื•ื ื™ืช ืฉืœ ื”ืžื•ืคืข:

METADATA_NETWORK_INTERFACE_URL = (
    "http://metadata/computeMetadata/v1/instance/network-interfaces/0/"
    "access-configs/0/external-ip"
)


def get_external_ip():
    """Gets the instance's external IP address from the Compute Engine metadata
    server.

    If the metadata server is unavailable, it assumes that the application is running locally.

    Returns:
        The instance's external IP address, or the string 'localhost' if the IP address
        is not available.
    """
    try:
        r = requests.get(
            METADATA_NETWORK_INTERFACE_URL,
            headers={"Metadata-Flavor": "Google"},
            timeout=2,
        )
        return r.text
    except requests.RequestException:
        logging.info("Metadata server could not be reached, assuming local.")
        return "localhost"