standard - Integración/implementación/entrega continua en Google App Engine, ¿demasiado arriesgado?
google app engine memory limit (1)
Recientemente, hemos configurado la integración / implementación / entrega continua de una aplicación web de nodejs en Google App Engine. El servidor CI (GitLabCI) ejecuta la instalación, compilación, pruebas e implementación de dependencias para la integración / producción dependiendo de la rama (desarrollo / maestro).
En el día de hoy, los únicos errores que enfrentamos fue durante el paso de dependencias, por lo que no nos importó mucho. Pero ayer (21/10/16), hubo una interrupción del servicio de DNS a gran escala y la tubería falló en el medio del paso de despliegue, rompiendo el producto . Simplemente volver a ejecutar la tubería ha hecho el trabajo, pero el problema puede reproducirse en cualquier momento.
Mis preguntas son:
- ¿Cómo podemos manejar este tipo de problemas de red, en el proceso de implementación continua?
- ¿La implementación continua en Google App Engine es realmente una buena idea?
- Si es así, ¿cuál es el método de implementación de App Engine? No encuentro ningún documento relevante al respecto ...
Por el momento solo tenemos dos versiones "dev" y "prod" que se actualizan después de los commits, pero en momentos aleatorios pude observar comportamientos extraños.
Cualquier respuesta / sugerencia / retroalimentación es muy bienvenida!
Ejemplo de stacktrace sobre los problemas de red de los que estoy hablando:
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
¿Bueno malo? Subjetivo - por lo tanto fuera de tema para SO. Asumir que la pregunta es cómo hacer que la implementación continua sea confiable :)
Bueno, el problema es que está utilizando versiones de aplicaciones como sus entornos de CI, lo que significa que no puede evitar roturas debido a que una versión específica es mala. Solo puede esperar recuperarse lo más rápido posible al volver a implementar la versión (cuando finaliza la interrupción), esto puede automatizarse.
No debe tener su sitio de producción ejecutándose directamente fuera de la versión sobrescrita por la canalización de
production
CI, de lo contrario corre el riesgo de interrupción del sitio en una implementación incorrecta.
En su lugar, podría usar una versión nueva / única para cada ejecución de la canalización de
production
CI y solo después de que se complete con éxito, finalmente cambiará el tráfico del sitio a su versión utilizando el flujo descrito a continuación (que también se puede utilizar dentro de las canalizaciones de CI si se utilizan diferentes
aplicaciones
en lugar de
versiones
de
aplicaciones
como entornos de CI)
Desde la implementación de su programa :
Por defecto, el comando de despliegue genera automáticamente una nueva ID de versión cada vez que lo usa y enrutará cualquier tráfico a la nueva versión.
Para anular este comportamiento, puede especificar la ID de versión con el indicador de versión:
gcloud app deploy --version myID
También puede especificar no enviar todo el tráfico a la nueva versión inmediatamente con el indicador --no-promote:
gcloud app deploy --no-promote
Por lo tanto, asegúrese de nunca implementar una versión y hacer que esa versión sea el destino de tráfico predeterminado en el mismo paso (posiblemente no atómica si se maneja desde el lado del cliente). Especialmente para la aplicación de producción. En lugar:
-
implementar la nueva versión (
gcloud app deploy --no-promote --version ...
) -
inicie la nueva versión (
gcloud app versions ...
) y compruebe que funciona -
si funciona bien, cambie el tráfico real (
gcloud app services set-traffic ...
)
De esta manera, la única operación crítica es el cambio de tráfico, que (con suerte) es una operación atómica que tiene éxito o se revierte por completo en el lado GAE (si no es un error GAE). Si este paso falla, la aplicación debería seguir funcionando con la versión anterior.
Por supuesto, esto supone que los problemas de red solo se encuentran entre usted y GAE, si también están afectando las operaciones internas de GAE, todas las apuestas están canceladas (pero aquellos en los que confío deberían resolverse bastante oportunamente).