1

Wir haben kürzlich die kontinuierliche Integration/Bereitstellung/Bereitstellung einer Nodejs-Webapp in Google App Engine eingerichtet. Der CI-Server (GitLabCI) führt abhängig von der Verzweigung (develop/master) die Abhängigkeiten Installation, Build, Tests und Deployment zu integration/prod aus.Kontinuierliche Integration/Bereitstellung/Bereitstellung in Google App Engine, zu riskant?

Am heutigen Tag waren die einzigen Fehler, mit denen wir zu tun hatten, während des Schritts Abhängigkeiten, und darum haben wir uns nicht viel darum gekümmert. Aber gestern (21.10.16) gab es einen großflächigen DNS-Ausfall, und die Pipeline fiel mitten in dem Bereitstellungsschritt , der den Prod auflöste. Einfach die Pipeline erneut ausführen lassen hat den Job erledigt, aber das Problem kann sich jederzeit reproduzieren.

Meine Fragen sind:

  • Wie können wir diese Art von Netzwerkproblemen in dem kontinuierlichen Bereitstellungsprozess umgehen?
  • Ist die kontinuierliche Bereitstellung in Google App Engine wirklich eine gute Idee?
  • Wenn ja, wie lautet die App Engine-Bereitstellungsmethode? Ich finde keine relevanten doc darüber ...

Im Moment haben wir nur zwei Versionen „dev“ und „prod“, die nach Commits aktualisiert werden, aber zu zufälligen Zeiten konnte ich seltsames Verhalten beobachten .

Jede Antwort/Vorschläge/Feedback ist sehr willkommen!

Beispiel stacktrace die Vernetzung Fragen im Zusammenhang mit dem ich spreche:

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 

Antwort

2

Gut/schlecht? Subjektiv - also off-topic für SO. Angenommen, die Frage ist, wie man eine kontinuierliche Bereitstellung zuverlässig macht :)

Nun, das Problem ist, dass Sie App-Versionen als Ihre CI-Umgebungen verwenden, was bedeutet, dass Sie Brüche aufgrund einer bestimmten Version nicht vermeiden können . Sie können nur hoffen, sich so schnell wie möglich zu erholen, indem Sie die Version (wenn der Ausfall aufhört) erneut bereitstellen - dies kann automatisiert werden.

Die Produktionsumgebung sollte nicht direkt von der durch die CI production-Pipeline überschriebenen Version ausgeführt werden, da andernfalls bei einer fehlerhaften Bereitstellung ein Site-Ausfall droht. Stattdessen können Sie für jede Ausführung der CI production-Pipeline eine neue/eindeutige Version verwenden. Erst danach wird der Site-Datenverkehr schließlich mithilfe des unten beschriebenen Ablaufs auf die Version umgestellt (die auch innerhalb der CI-Pipelines verwendet werden kann, wenn verschiedene verwendet werden Apps statt App-Versionen als CI-Umgebungen)

von Deploying your program:

Standardmäßig ist der Befehl deploy eine neue Version ID jedes Mal, wenn Sie es automatisch erzeugt verwenden und leitet keinen Verkehr auf der neu Version.

dieses Verhalten zu überschreiben, können Sie die Version-ID mit der Version Flag angeben:

gcloud app deploy --version myID 

Sie auch nicht den gesamten Verkehr auf den neuen Version immediatey mit der schicken angeben --no-Förderung Flagge:

gcloud app deploy --no-promote 

So stellen Sie sicher, dass Sie nie eine Version bereitstellen und diese Version das Standard-Verkehrsziel machen ein im gleichen Schritt (möglicherweise nicht atomar, wenn von der Kundenseite getrieben). Speziell für die Produktions-App. Statt dessen:

arbeitet

Auf diese Weise ist der einzige kritische Vorgang der Verkehrswechsel, der (hoffentlich) eine atomare Operation ist, die entweder erfolgreich ist oder auf der GAE-Seite vollständig zurückgesetzt wird (wenn es nicht ein GAE-Fehler ist). Wenn dieser Schritt fehlschlägt, sollte die App weiterhin mit der alten Version arbeiten.

Natürlich geht dies davon aus, dass die Netzwerkprobleme nur zwischen Ihnen und GAE liegen, wenn sie auch GAEs interne Ops betreffen, sind alle Wetten aus (aber die, denen ich vertraue, sollten eher zeitnah behoben werden).

+0

Vielen Dank für Ihre sehr detaillierte Antwort. Sie haben wahrscheinlich recht, wenn Sie verschiedene Apps als CI-Umgebungen verwenden. Das ist eine bessere Idee und könnte die verschiedenen Probleme lösen, mit denen wir konfrontiert sind. Ich habe eine letzte Frage: Die App ist automatisch skaliert und ich kann daher keine Versionen starten/stoppen ([gemäß dem Dokument] (https://cloud.google.com/sdk/gcloud/reference/app/versions/start)). Wenn ein Build eine Version erstellt, wird der Traffic berechnet, sollte ich die Basisskala einrichten? Oder sollte ich vorherige Version löschen, wenn neu erstellt wird? – Loheek

+1

Es ist nicht erforderlich, die neue Version mit Autoscaling explizit zu starten. Verwenden Sie einfach die URLs der jeweiligen Version, um zu testen, ob die Version funktioniert, und GAE startet die Instanzen selbst: https://cloud.google.com/appengine/docs/flexible/python/how-requests-are-routed#routing_via_url –