【问题标题】:Continuous integration/deployment/delivery on Google App Engine, too risky?在 Google App Engine 上持续集成/部署/交付,风险太大?
【发布时间】:2017-03-04 16:54:09
【问题描述】:

我们最近在 Google App Engine 上设置了 nodejs webapp 的持续集成/部署/交付。 CI 服务器 (GitLabCI) 根据分支 (develop/master) 运行依赖项安装、构建、测试和部署到集成/产品。

今天,我们遇到的唯一错误是在依赖关系步骤中,因此我们并不太关心它。但是昨天(16 年 10 月 21 日),发生了大规模的 DNS 中断,并且管道在部署步骤的中间失败,破坏了产品。只需重新运行管道即可完成工作,但问题随时可能重现。

我的问题是:

  • 在持续部署过程中,我们如何处理此类网络问题?
  • 在 Google App Engine 上持续部署真的是个好主意吗?
  • 如果是这样,App Engine 部署方法是什么?我没有找到任何相关的文档...

目前我们只有两个版本“dev”和“prod”在之后更新 提交,但在随机时间我可以观察到奇怪的行为。

非常欢迎任何回应/建议/反馈!

关于我正在谈论的网络问题的堆栈跟踪示例:

DEBUG: Error sending result: 'MetadataServerException(HTTPError(),)'. Reason: 'PicklingError("Can't pickle <type 'cStringIO.StringO'>: attribute lookup cStringIO.StringO failed",)'
Traceback (most recent call last):
  File "/google-cloud-sdk/lib/googlecloudsdk/calliope/cli.py", line 733, in Execute
    resources = args.calliope_command.Run(cli=self, args=args)
  File "/google-cloud-sdk/lib/googlecloudsdk/calliope/backend.py", line 1630, in Run
    resources = command_instance.Run(args)
  File "/google-cloud-sdk/lib/surface/app/deploy.py", line 53, in Run
    return deploy_util.RunDeploy(self, args)
  File "/google-cloud-sdk/lib/googlecloudsdk/command_lib/app/deploy_util.py", line 387, in RunDeploy
    all_services)
  File "/google-cloud-sdk/lib/googlecloudsdk/command_lib/app/deploy_util.py", line 247, in Deploy
    manifest = _UploadFiles(service, code_bucket_ref)
  File "/google-cloud-sdk/lib/googlecloudsdk/command_lib/app/deploy_util.py", line 115, in _UploadFiles
    service, code_bucket_ref)
  File "/google-cloud-sdk/lib/googlecloudsdk/api_lib/app/deploy_app_command_util.py", line 277, in CopyFilesToCodeBucketNoGsUtil
    _UploadFiles(files_to_upload, bucket_ref)
  File "/google-cloud-sdk/lib/googlecloudsdk/api_lib/app/deploy_app_command_util.py", line 219, in _UploadFiles
    results = pool.map(_UploadFile, tasks)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 251, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 558, in get
    raise self._value
MaybeEncodingError: Error sending result: 'MetadataServerException(HTTPError(),)'. Reason: 'PicklingError("Can't pickle <type 'cStringIO.StringO'>: attribute lookup cStringIO.StringO failed",)'
DEBUG: Exception captured in Error
Traceback (most recent call last):
  File "/google-cloud-sdk/lib/googlecloudsdk/core/metrics.py", line 411, in Wrapper
    return func(*args, **kwds)
TypeError: Error() takes exactly 3 arguments (1 given)
ERROR: gcloud crashed (MaybeEncodingError): Error sending result: 'MetadataServerException(HTTPError(),)'. Reason: 'PicklingError("Can't pickle <type 'cStringIO.StringO'>: attribute lookup cStringIO.StringO failed",)'
Traceback (most recent call last):
  File "/google-cloud-sdk/lib/gcloud.py", line 65, in <module>
    main()
  File "/google-cloud-sdk/lib/gcloud.py", line 61, in main
    sys.exit(googlecloudsdk.gcloud_main.main())
  File "/google-cloud-sdk/lib/googlecloudsdk/gcloud_main.py", line 145, in main
    crash_handling.HandleGcloudCrash(err)
  File "/google-cloud-sdk/lib/googlecloudsdk/command_lib/crash_handling.py", line 107, in HandleGcloudCrash
    _ReportError(err)
  File "/google-cloud-sdk/lib/googlecloudsdk/command_lib/crash_handling.py", line 86, in _ReportError
    util.ErrorReporting().ReportEvent(error_message=stacktrace,
  File "/google-cloud-sdk/lib/googlecloudsdk/api_lib/error_reporting/util.py", line 28, in __init__
    self._API_NAME, self._API_VERSION)
  File "/google-cloud-sdk/lib/googlecloudsdk/core/apis.py", line 254, in GetClientInstance
    http_client = http.Http()
  File "/google-cloud-sdk/lib/googlecloudsdk/core/credentials/http.py", line 60, in Http
    creds = store.Load()
  File "/google-cloud-sdk/lib/googlecloudsdk/core/credentials/store.py", line 282, in Load
    if account in c_gce.Metadata().Accounts():
  File "/google-cloud-sdk/lib/googlecloudsdk/core/credentials/gce.py", line 122, in Accounts
    gce_read.GOOGLE_GCE_METADATA_ACCOUNTS_URI + '/')
  File "/google-cloud-sdk/lib/googlecloudsdk/core/util/retry.py", line 160, in TryFunc
    return func(*args, **kwargs), None
  File "/google-cloud-sdk/lib/googlecloudsdk/core/credentials/gce.py", line 45, in _ReadNoProxyWithCleanFailures
    raise MetadataServerException(e)
googlecloudsdk.core.credentials.gce.MetadataServerException: HTTP Error 503: Service Unavailable
DEBUG: Uploading [/builds/apps/webapp/lib/jinja2/defaults.pyc] to [151c77b4e5bdd2c38b6a2bf914fffa3a6ffa71a6]
INFO: Uploading [/builds/apps/webapp/lib/jinja2/defaults.pyc] to [151c77b4e5bdd2c38b6a2bf914fffa3a6ffa71a6]
INFO: Refreshing access_token

【问题讨论】:

    标签: google-app-engine continuous-integration continuous-deployment gitlab-ci continuous-delivery


    【解决方案1】:

    好/坏?主观的 - 因此对于 SO 来说是题外话。假设问题是如何使持续部署可靠:)

    好吧,问题在于您使用应用程序版本作为您的 CI 环境,这意味着您无法避免由于特定版本不好而导致的损坏。您只能希望通过重新部署版本(当中断结束时)尽快恢复 - 这可以自动化。

    您不应该让您的生产站点直接在 CI production 管道覆盖的版本上运行,否则您可能会因部署不当而导致站点中断。相反,您可以为 CI production 管道的每次执行使用一个新的/唯一版本,并且只有在成功完成之后,您才最终使用下面描述的流程将站点流量切换到其版本(如果使用,也可以在 CI 管道内使用不同的 应用程序 而不是 应用程序版本 作为 CI 环境)

    来自Deploying your program

    默认情况下,deploy 命令会自动生成一个新的版本 ID 每次您使用它并将任何流量路由到新的 版本。

    要覆盖此行为,您可以使用 版本标志:

    gcloud app deploy --version myID
    

    您还可以指定不将所有流量发送到新版本 立即使用 --no-promote 标志:

    gcloud app deploy --no-promote
    

    因此,请确保您从不部署版本,并在同一步骤中将该版本设置为默认流量目标(如果从客户端驱动,则可能不是原子的)。特别是对于生产应用程序。而是:

    这样,唯一的关键操作是流量切换,它(希望)是一个原子操作,要么成功,要么在 GAE 端完全回滚(如果不是,那就是 GAE 错误)。如果此步骤失败,应用仍应继续使用旧版本。

    当然,这是假设网络问题仅存在于您和 GAE 之间,如果它们也影响 GAE 的内部运营 已关闭(但我信任的应该及时修复)。

    【讨论】:

    • 感谢您非常详细的回复。使用不同的应用程序作为 CI 环境你可能是对的,这是一个更好的主意,它可以解决我们面临的不同问题。我有最后一个问题:该应用程序是自动缩放的,因此我无法启动/停止版本 (according to the doc)。构建创建版本时,会收取流量,我应该设置基本规模吗?还是应该在创建新版本时删除以前的版本?
    • 无需通过自动缩放显式启动新版本。只需使用相应版本的 URL 来测试版本是否有效,GAE 将自行启动实例:cloud.google.com/appengine/docs/flexible/python/…
    • +1000000 很好的答案,因为它就在那里@DanCornilescu
    • 如果命令中不包含版本ID,gcloud app deploy --no-promote是否会生成版本ID?
    • @GeekGuy 是的,它应该 - 部署需要一个版本 ID。这是默认行为。
    猜你喜欢
    • 2015-04-20
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 2023-03-02
    相关资源
    最近更新 更多