在App Engine上将Django与Google Cloud结合使用的Ci / CD失败

时间:2019-12-27 02:01:01

标签: python django cloud gcloud google-cloud-build

背景:尝试在标准应用程序引擎上使用带有Django的新Google Cloud Build自动化我的构建过程。我从这里的好Google员工提供的Django民意调查示例开始: https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard_python37/django

环境:带有Django 3.0.1的Python3.7

对上述内容进行了一些更改,现在我的requirements.txt如下:

  

requirements.txt

coverage==5.0.1
Django==3.0.1
entrypoints==0.3
flake8==3.7.9
mccabe==0.6.1
mysqlclient==1.4.6
pycodestyle==2.5.0
pyflakes==2.1.1
pytz==2019.3
sqlparse==0.3.0
  

app.yaml

runtime: python37

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto

env_variables:
# the secret key used for the Django app (from PROJECT-DIRECTORY/settings.py)
  SECRET_KEY: 'DJANGO-SECRET-KEY'
  DEBUG: 'False' # always False for deployment

# everything after /cloudsql/ can be found by entering >> gcloud sql instances describe DATABASE-NAME << in your Terminal
# the DATABASE-NAME is the name you gave your project's PostgreSQL database
# the second line from the describe output called connectionName can be copied and pasted after /cloudsql/
  DB_HOST: '/cloudsql/annular-will-XXXX:asia-east2:XXXX'
  DB_PORT: '5432' # PostgreSQL port
  DB_NAME: 'XXX'
  DB_USER: 'XXX'
  DB_PASSWORD: 'XXXXX'

# [END django_app]
  

使用命令行进行部署的时间   gcloud app deploy app.yaml

     

行,是的!

     

是时候自动构建了,并按照这里的步骤进行操作:

https://cloud.google.com/source-repositories/docs/quickstart-triggering-builds-with-source-repositories

我将cloudbuild.yaml的名称进行了一些小的更改,将其更改为cloud-build.yaml

结果:在推送到分支机构时触发了构建!到目前为止,一切看起来都很好!

  

让我们看看cloud_build.yaml:   请注意,这是[cloud build] [1]

快速入门指南中提到的步骤的一部分。

https://cloud.google.com/source-repositories/docs/quickstart-triggering-builds-with-source-repositories

steps:
- name: "gcr.io/cloud-builders/gcloud"
  args: ["app", "deploy"]
timeout: "1600s"
  

结果:应用已部署,但请等待,静态资产未加载:(   让我们只在我们的cloud-build.yaml中添加步骤,现在看起来像这样:

- name: 'python:3.7'
  entrypoint: python3
  args: ['-m', 'pip', 'install', '-t', '.', '-r', 'requirements.txt']
- name: 'python:3.7'
  entrypoint: python3
  args: ['./manage.py', 'collectstatic', '--noinput']
- name: "gcr.io/cloud-builders/gcloud"
  args: ["app", "deploy"]
timeout: "1600s"

我们需要安装Requirements.txt,因为collectstatic需要安装Django和其他依赖项。 注意传递给pip install的-t参数。之所以通过,是因为google cloud-build.yaml的每个步骤都在单独的docker映像中运行,并且唯一常见的是/ workspace目录。因此,将所有内容安装在工作空间中是有意义的。在此步骤之后,静电消除器起作用!

查看Cloud Build的历史看起来都是绿色的: [![在此处输入图片描述] [2]] [2]

但是该应用拒绝启动,该实例死于以下错误:

2019-12-27 01:10:49 default[20191227t010033]  [2019-12-27 01:10:49 +0000] [7] [INFO] Starting gunicorn 20.0.4
2019-12-27 01:10:49 default[20191227t010033]  [2019-12-27 01:10:49 +0000] [7] [INFO] Listening at: http://0.0.0.0:8081 (7)
2019-12-27 01:10:49 default[20191227t010033]  [2019-12-27 01:10:49 +0000] [7] [INFO] Using worker: threads
2019-12-27 01:10:49 default[20191227t010033]  [2019-12-27 01:10:49 +0000] [18] [INFO] Booting worker with pid: 18
2019-12-27 01:10:49 default[20191227t010033]  [2019-12-27 01:10:49 +0000] [22] [INFO] Booting worker with pid: 22
2019-12-27 01:10:51 default[20191227t010033]  [2019-12-27 01:10:51 +0000] [22] [ERROR] Exception in worker process
2019-12-27 01:10:51 default[20191227t010033]  Traceback (most recent call last):    File "/srv/django/db/backends/mysql/base.py", line 16, in <module>      import MySQLdb as Database    File "/srv/MySQLdb/__init__.py", line 18, in <module>      from . import _mysql  ImportError: libmariadb.so.3: cannot open shared object file: No such file or directory
2019-12-27 01:10:51 default[20191227t010033]
2019-12-27 01:10:51 default[20191227t010033]  The above exception was the direct cause of the following exception:
2019-12-27 01:10:51 default[20191227t010033]
2019-12-27 01:10:51 default[20191227t010033]  Traceback (most recent call last):    File "/env/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker      worker.init_process()    File "/env/lib/python3.7/site-packages/gunicorn/workers/gthread.py", line 92, in init_process      super().init_process()    File "/env/lib/python3.7/site-packages/gunicorn/workers/base.py", line 119, in init_process      self.load_wsgi()    File "/env/lib/python3.7/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi      self.wsgi = self.app.wsgi()    File "/env/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi      self.callable = self.load()    File "/env/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load      return self.load_wsgiapp()    File "/env/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp      return util.import_app(self.app_uri)    File "/env/lib/python3.7/site-packages/gunicorn/util.py", line 358, in import_app      mod = importlib.import_module(module)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "<frozen importlib._bootstrap>", line 1006, in _gcd_import    File "<frozen importlib._bootstrap>", line 983, in _find_and_load    File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked    File "<frozen importlib._bootstrap>", line 677, in _load_unlocked    File "<frozen importlib._bootstrap_external>", line 728, in exec_module    File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed    File "/srv/main.py", line 1, in <module>      from mysite.wsgi import application    File "/srv/mysite/wsgi.py", line 16, in <module>      application = get_wsgi_application()    File "/srv/django/core/wsgi.py", line 12, in get_wsgi_application      django.setup(set_prefix=False)    File "/srv/django/__init__.py", line 24, in setup      apps.populate(settings.INSTALLED_APPS)    File "/srv/django/apps/registry.py", line 114, in populate      app_config.import_models()    File "/srv/django/apps/config.py", line 211, in import_models      self.models_module = import_module(models_module_name)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "/srv/polls/models.py", line 7, in <module>      class Question(models.Model):    File "/srv/django/db/models/base.py", line 121, in __new__      new_class.add_to_class('_meta', Options(meta, app_label))    File "/srv/django/db/models/base.py", line 325, in add_to_class      value.contribute_to_class(cls, name)    File "/srv/django/db/models/options.py", line 208, in contribute_to_class      self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())    File "/srv/django/db/__init__.py", line 28, in __getattr__      return getattr(connections[DEFAULT_DB_ALIAS], item)    File "/srv/django/db/utils.py", line 207, in __getitem__      backend = load_backend(db['ENGINE'])    File "/srv/django/db/utils.py", line 111, in load_backend      return import_module('%s.base' % backend_name)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "/srv/django/db/backends/mysql/base.py", line 21, in <module>      ) from err  django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
2019-12-27 01:10:51 default[20191227t010033]  Did you install mysqlclient?
2019-12-27 01:10:51 default[20191227t010033]  [2019-12-27 01:10:51 +0000] [22] [INFO] Worker exiting (pid: 22)
2019-12-27 01:10:51 default[20191227t010033]  [2019-12-27 01:10:51 +0000] [18] [ERROR] Exception in worker process
2019-12-27 01:10:51 default[20191227t010033]  Traceback (most recent call last):    File "/srv/django/db/backends/mysql/base.py", line 16, in <module>      import MySQLdb as Database    File "/srv/MySQLdb/__init__.py", line 18, in <module>      from . import _mysql  ImportError: libmariadb.so.3: cannot open shared object file: No such file or directory
2019-12-27 01:10:51 default[20191227t010033]
2019-12-27 01:10:51 default[20191227t010033]  The above exception was the direct cause of the following exception:
2019-12-27 01:10:51 default[20191227t010033]
2019-12-27 01:10:51 default[20191227t010033]  Traceback (most recent call last):    File "/env/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker      worker.init_process()    File "/env/lib/python3.7/site-packages/gunicorn/workers/gthread.py", line 92, in init_process      super().init_process()    File "/env/lib/python3.7/site-packages/gunicorn/workers/base.py", line 119, in init_process      self.load_wsgi()    File "/env/lib/python3.7/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi      self.wsgi = self.app.wsgi()    File "/env/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi      self.callable = self.load()    File "/env/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load      return self.load_wsgiapp()    File "/env/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp      return util.import_app(self.app_uri)    File "/env/lib/python3.7/site-packages/gunicorn/util.py", line 358, in import_app      mod = importlib.import_module(module)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "<frozen importlib._bootstrap>", line 1006, in _gcd_import    File "<frozen importlib._bootstrap>", line 983, in _find_and_load    File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked    File "<frozen importlib._bootstrap>", line 677, in _load_unlocked    File "<frozen importlib._bootstrap_external>", line 728, in exec_module    File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed    File "/srv/main.py", line 1, in <module>      from mysite.wsgi import application    File "/srv/mysite/wsgi.py", line 16, in <module>      application = get_wsgi_application()    File "/srv/django/core/wsgi.py", line 12, in get_wsgi_application      django.setup(set_prefix=False)    File "/srv/django/__init__.py", line 24, in setup      apps.populate(settings.INSTALLED_APPS)    File "/srv/django/apps/registry.py", line 114, in populate      app_config.import_models()    File "/srv/django/apps/config.py", line 211, in import_models      self.models_module = import_module(models_module_name)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "/srv/polls/models.py", line 7, in <module>      class Question(models.Model):    File "/srv/django/db/models/base.py", line 121, in __new__      new_class.add_to_class('_meta', Options(meta, app_label))    File "/srv/django/db/models/base.py", line 325, in add_to_class      value.contribute_to_class(cls, name)    File "/srv/django/db/models/options.py", line 208, in contribute_to_class      self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())    File "/srv/django/db/__init__.py", line 28, in __getattr__      return getattr(connections[DEFAULT_DB_ALIAS], item)    File "/srv/django/db/utils.py", line 207, in __getitem__      backend = load_backend(db['ENGINE'])    File "/srv/django/db/utils.py", line 111, in load_backend      return import_module('%s.base' % backend_name)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "/srv/django/db/backends/mysql/base.py", line 21, in <module>      ) from err  django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
2019-12-27 01:10:51 default[20191227t010033]  Did you install mysqlclient?
2019-12-27 01:10:51 default[20191227t010033]  [2019-12-27 01:10:51 +0000] [18] [INFO] Worker exiting (pid: 18)
2019-12-27 01:10:51 default[20191227t010033]  [2019-12-27 01:10:51 +0000] [7] [INFO] Shutting down: Master
2019-12-27 01:10:51 default[20191227t010033]  [2019-12-27 01:10:51 +0000] [7] [INFO] Reason: Worker failed to boot.

如果有帮助,我在调试过程中看到了另一个奇怪的错误:

2019-12-27 01:31:35 default[20191227t092757]  Traceback (most recent call last):    File "/env/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker      worker.init_process()    File "/env/lib/python3.7/site-packages/gunicorn/workers/gthread.py", line 92, in init_process      super().init_process()    File "/env/lib/python3.7/site-packages/gunicorn/workers/base.py", line 119, in init_process      self.load_wsgi()    File "/env/lib/python3.7/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi      self.wsgi = self.app.wsgi()    File "/env/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi      self.callable = self.load()    File "/env/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load      return self.load_wsgiapp()    File "/env/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp      return util.import_app(self.app_uri)    File "/env/lib/python3.7/site-packages/gunicorn/util.py", line 358, in import_app      mod = importlib.import_module(module)    File "/opt/python3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module      return _bootstrap._gcd_import(name[level:], package, level)    File "<frozen importlib._bootstrap>", line 1006, in _gcd_import    File "<frozen importlib._bootstrap>", line 983, in _find_and_load    File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked    File "<frozen importlib._bootstrap>", line 677, in _load_unlocked    File "<frozen importlib._bootstrap_external>", line 728, in exec_module    File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed    File "/srv/main.py", line 1, in <module>      from mysite.wsgi import application    File "/srv/mysite/wsgi.py", line 12, in <module>      from django.core.wsgi import get_wsgi_application  ModuleNotFoundError: No module named 'django'```


At this point, i have almost given up on google cloud CD. If you have any working example of how to CI/CD on google app engine with Django, pls let me know.

further debugging:

 - Switched to gcloud app deploy --version 1 and it still works. Note that this happens from the command line from my project and my static directory in settings:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_ROOT = 'static'
STATIC_URL = '/static/'

Before the app deploy, i run python collectstatic thus creating the static directory. Hence i assume when i do app deploy, the image already has the static directory created. However, during cloud build, we had to explicitly make it as a step. Just thought of mentioning it.

-rw-r--r--    1 amit  staff   868B Dec 26 13:53 README.md
-rw-r--r--    1 amit  staff   1.1K Dec 27 09:21 app.yaml
-rw-r--r--    1 amit  staff    88B Dec 27 09:43 cloud-build.yaml
-rw-r--r--    1 amit  staff   492B Dec 26 14:34 main.py
-rwxr-xr-x    1 amit  staff   538B Dec 26 13:53 manage.py*
drwxr-xr-x    7 amit  staff   224B Dec 26 14:15 mysite/
drwxr-xr-x   12 amit  staff   384B Dec 27 00:27 polls/
-rwxr-xr-x    1 amit  staff   108B Dec 26 13:53 proxy.sh*
-rw-r--r--    1 amit  staff   173B Dec 27 09:43 requirements.txt
drwxr-xr-x    3 amit  staff    96B Dec 26 13:57 static/
drwxr-xr-x    6 amit  staff   192B Dec 26 15:27 venv/


  [1]: https://cloud.google.com/source-repositories/docs/quickstart-triggering-builds-with-source-repositories
  [2]: https://i.stack.imgur.com/aalUR.png

1 个答案:

答案 0 :(得分:0)

我接受了@methkal Khalawi的评论 为了避免mysqlclient的所有麻烦,建议您使用pymysql,它更稳定地包含在需求文件中。

但是,PyMySQL存在一个现有问题,因此它不适用于Django3.x。这是链接https://github.com/PyMySQL/PyMySQL/issues/790

为了避免上述情况,请在您的设置文件中执行以下操作:

import pymysql
# Hack to make PyMySql work with Django 3.x
# #https://github.com/PyMySQL/PyMySQL/issues/790
pymysql.version_info = (1, 4, 6, 'final', 0)  # change mysqlclient version
pymysql.install_as_MySQLdb()

现在,从requirements.txt中删除mysqlclient并获取PyMySql:

Django==3.0.2
PyMySQL==0.9.3

现在,cloud-build.yaml看起来像这样:

steps:
- name: 'python:3.7'
  entrypoint: python3
  args: ['-m', 'pip', 'install', '-t', '.', '-r', 'requirements.txt']
- name: 'python:3.7'
  entrypoint: python3
  args: ['./manage.py', 'collectstatic', '--noinput']
- name: "gcr.io/cloud-builders/gcloud"
  args: ["app", "deploy"]
timeout: "1600s"

而且有效!