1

我們最近在Google App Engine上設置了一個nodejs webapp的持續集成/部署/交付。 CI服務器(GitLabCI)根據分支(develop/master)運行依賴關係安裝,構建,測試和部署到集成/產品。Google App Engine上的持續集成/部署/交付風險太大?

在今天的日子裏,我們遇到的唯一的錯誤是在依賴項步驟中,所以我們並不關心它。但昨天(2016年10月21日),在部署步驟中發生了大範圍的DNS中斷,管道故障,分解了產品。只需重新運行管道就可以完成這項工作,但問題可隨時重現。

我的問題是:

  • 我們如何處理這樣的網絡問題,在連續部署過程?
  • 在Google App Engine上持續部署真的是一個好主意嗎?
  • 如果是這樣,那麼App Engine部署方法是什麼?我沒有找到任何關於它的相關文檔...

就目前而言,我們只有兩個版本的「開發」和那些後 提交更新的「刺」,但在隨機時間我所觀察到異常行爲。

任何回覆/建議/反饋非常歡迎!

關於我講的是網絡問題堆棧跟蹤的例子:

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 

回答

2

好/壞?主觀的 - 因此不屬於SO。假設的問題是如何使持續部署可靠的:)

好了,問題是,你正在使用應用版本爲您的CI環境中,這意味着你無法避免破損,由於特定的版本是壞。您只能希望通過重新部署版本(當中斷結束時)儘快恢復 - 這可以自動完成。

您不應讓您的生產站點直接從CI production管道覆蓋的版本運行,否則可能會導致網站因不良部署而停機。相反,您可以使用一個新/唯一版本來執行CI production管道的每次執行,並且只有在成功完成後,才能使用下面描述的流程將站點流量切換到其版本(如果使用不同的,也可以在CI管道內使用該流程應用代替應用版本爲CI環境)

Deploying your program

默認情況下,部署命令自動生成每一個使用它的時候一個新版本ID 和將路由的任何信息給新的 版本。

要覆蓋此行爲,你可以用 版本標記指定版本ID:

gcloud app deploy --version myID 

你也可以指定不所有流量發送到新版本 immediatey用--no-促進標誌:

gcloud app deploy --no-promote 

所以一定要確保你永遠不會部署的版本,使該版本的默認流量目的地在同一個步驟(可能不是原子的,如果從客戶端驅動)。特別是對於生產應用程序。相反:

這種方式唯一關鍵的操作是流量切換,它(希望)是一個原子操作,它要麼成功,要麼完全在GAE側回滾(如果不是GAE的話)。如果此步驟失敗,應用程序仍應繼續使用舊版本。

。當然,這是假設的網絡問題只在您和GAE之間,如果他們也影響到GAE的內部OPS所有的賭注都 關閉(但這些我相信應該是固定的,而及時)。

+0

非常感謝您的詳細回覆。你可能使用不同的應用程序作爲CI環境,這是一個更好的主意,它可以解決我們面臨的不同問題。我有最後一個問題:應用程序是自動調整的,所以我無法啓動/停止版本([根據文檔](https://cloud.google.com/sdk/gcloud/reference/app/versions/start) )。當一個版本創建一個版本時,我應該設置基本的規模,流量將被收取費用?或者我應該刪除以前的版本,當新創建? – Loheek

+1

無需使用自動縮放顯式啓動新版本。只需使用相應版本的網址即可測試該版本的效果,GAE將自行啓動實例:https://cloud.google.com/appengine/docs/flexible/python/how-requests-are-routed#routing_via_url –