首页 文章

Google App Engine上的持续集成/部署/交付风险太大了?

提问于
浏览
3

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

在今天的日子里,我们唯一关心它的错误 . 但是昨天(2016年10月21日),发生了大规模的DNS中断,管道在部署步骤中失败了, breaking down the prod . 简单地重新运行管道已经完成了工作,但问题可以随时重现 .

我的问题是:

  • 在持续部署过程中,我们如何处理这类网络问题?

  • 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

1 回答

  • 4

    好坏?主观 - 因此SO的主题 . 假设问题是如何使连续部署可靠:)

    好吧,问题是您使用 app versions 作为您的CI环境,这意味着您无法避免因特定版本不良而导致的损坏 . 您只能希望通过重新部署版本(停机结束时)尽快恢复 - 这可以自动完成 .

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

    来自Deploying your program

    默认情况下,deploy命令会在您每次使用时自动生成新的版本ID,并将任何流量路由到新版本 . 要覆盖此行为,您可以使用版本标志指定版本ID:gcloud app deploy --version myID
    您还可以指定不使用--no-promote标志立即将所有流量发送到新版本:gcloud app deploy --no-promote

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

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

    当然,这假设网络问题只发生在你和GAE之间,如果它们也影响GAE的内部操作,所有的赌注都是关闭的(但我相信的应该是相当及时的固定) .

相关问题