Configurar e invocar funciones en la nube usando Python

Oh, la diversión que he tenido aprendiendo Cloud Functions. En realidad, ha sido divertido y también frustrante y definitivamente esclarecedor explorar los servicios sin servidor que se supone que facilitan las cosas. Es cierto que he estado lo suficiente como para saber que siempre hay un aumento, incluso cuando es simple.

Cloud Functions es un servicio que le permite ejecutar código en los servidores de Google Cloud sin necesidad de ocuparse de la configuración o el escalado del servidor. Es un enfoque de pago por uso que significa que paga por lo que usa y que puede ayudar a optimizar los costos. Comencé a usarlo para un par de funciones que necesito ejecutar varias veces y ahí es donde puede ser muy valioso. Hubo una curva de aprendizaje especialmente al conectar diferentes servicios y esta publicación cubre los aprendizajes clave sobre estos temas.

  • Probar código localmente antes de ejecutar en Cloud Functions
  • Configuración de funciones en la nube con un disparador HTTP y Python
  • Invocar funciones en la nube desde su computadora portátil
  • Solución de problemas de errores y autenticación
  • Costo

Esta publicación asume que ya tiene el SDK de gcloud instalado localmente y que tiene una configuración de proyecto de Google Cloud. Tengo publicaciones anteriores que cubren estos temas. Usé Python 3.7 en la función y una Mac para el desarrollo local.

Emulación de funciones en la nube localmente

Si desea probar su código antes de ejecutar en Cloud Functions, puede hacerlo con Functions Framework para Python .

Ejemplo simple | No se pasaron parámetros

Instale frameworks de funciones con pip en su máquina.

 pip install functions-framework 

Redacta un ejemplo simple que puedas probar como el siguiente y etiquétalo main.py.

 def my_function (solicitud): 
volver 'Hola mundo'

Para simular las funciones de la nube, ejecute el comando functions-framework en su terminal.

 funciones-marco --target my_function 

Hay banderas que puede pasar para realizar ajustes, como el nombre del archivo (- fuente) y el puerto al que apunta (- puerto), por ejemplo. Y use el indicador - debug para obtener ayuda más detallada al desarrollar.

Luego llame a curl para invocarlo localmente para ver cómo funciona el disparador HTTP o ejecutarlo en una ventana del navegador.

 curl http: // localhost: 8080 
 O para el navegador 
 http: // localhost: 8080 

La respuesta superior de desbordamiento de pila en el enlace es donde saqué el código anterior. Emular Cloud Functions es especialmente valioso cuando extrae paquetes y desea ver cómo esos paquetes funcionarán o no, así como verificar las conexiones a otros servicios. Además, este es un buen marco para usar para probar Cloud Run localmente también.

Parámetros de paso

El siguiente es un ejemplo de cómo pasar parámetros a Cloud Functions.

Use este código de inicio para experimentar y colóquelo en un archivo main.py.

 def hola (solicitud): 
request_json = request.get_json ()
if request.args y 'first' en request.args:
return f'Hello '+ request.args.get (' first ') + request.args.get (' last ') +' \ n '
elif request_json y 'mensaje' en request_json:
return f'Hello '+ request_json [' first '] + request_json [' last '] +' \ n '
más:
return f'Hola Mundo! '+' \ n '

Para probarlo puedes usar el comando curl.

 curl http: // localhost: 8080? first = My & last = Name 

O puede llamarlo en el navegador con la misma url.

 http: // localhost: 8080? first = My & last = Name 

Tenga en cuenta que el comando curl también debería funcionar pasando -d '{“first”: ”My”, “last”: ”Name”}' para Linux y Mac. Estaba teniendo dificultades para que esto funcione por alguna razón en mi terminal. No tengo una respuesta de por qué y si sabes enviarme un mensaje y lo compartiré aquí.

Configurar la función de la nube

Si desea ejecutar el código en una función de nube real, puede usar la consola de Google Cloud para configurar su función para que se ejecute. También puede publicar el código usando gcloud SDK. Para esta publicación, me quedo con la interfaz de usuario, pero no dude en consultar este enlace para obtener más información sobre el lanzamiento desde su terminal con gcloud.

Vaya a Google Cloud Console y al panel de Cloud Functions. Seleccione Crear función .

Complete el nombre de la función que se utilizará en la URL para el disparador HTTP . También elija el disparador para usar. Hay otras opciones de activación, pero para este ejemplo me quedé con HTTP .

La url para invocar la función se publicará bajo URL en la imagen de arriba. Puede probarlo directamente en la interfaz de usuario, rizarlo en su terminal local, ejecutarlo a través de un navegador o publicar una solicitud a través del código.

El cuadro de autenticación es un poco complicado. Si se selecciona, cualquiera puede hacer una llamada a la función. Esta es una forma de probarlo y no lidiar con la autenticación, pero tenga cuidado porque está abierto para que cualquiera que encuentre la url (incluidos los bots) lo llame y eso puede ser costoso ya que es de pago por uso. Tenga en cuenta que automáticamente no está seleccionado y, si lo olvida, puede ir por el agujero del conejo que intenté averiguar por qué no podía invocar sin autenticación.

En Runtime, seleccione el idioma que desea codificar para la función y codifique su función en consecuencia en MAIN.PY. Al usar HTTP y Python, debe aceptar un objeto de solicitud para poder pasar los parámetros. También debe completar la pestaña REQUISITOS.TXT con los requisitos que importe que aún no forman parte del paquete estándar de Python.

En Función para ejecutar, ingrese el nombre de la función en su código que el programa necesita ejecutar cuando se ejecuta. Ya hay un código de muestra para ayudarlo a comenzar.

Cuando expande las Variables de entorno, Redes, Tiempos de espera y más, encontrará en Redes la configuración de Ingreso que indica Permitir todo el tráfico . Si no marca la casilla de arriba para Permitir invocaciones no autenticadas, pero asegúrese de que Permitir todo el tráfico esté seleccionado (que es el valor predeterminado), seguirá requiriendo autenticación. Esto me sorprendió un poco, lo que reitero a continuación.

También una nota sobre los tiempos de espera es que el programa está predeterminado en 60 segundos, y puede obtener como máximo 9 minutos antes de que la función agote el tiempo si está esperando una respuesta para finalizar el procesamiento.

Una vez que la función está configurada, elija Crear y espere unos minutos para que la función se inicie en un servidor. Cuando hay un círculo verde marcado, está listo para ejecutarse.

Siempre puede regresar y editar la función e implementarla nuevamente si hay errores.

Invocar función de nube

Después de configurar la función, puede invocar / ejecutar la función. Este paso fue más desafiante para mí de lo que debía ser debido a la casilla de verificación Autenticación como se mencionó y cómo las solicitudes de Python manejan los términos de datos vs json .

Acceso de todos los usuarios

Al otorgar acceso a cualquier persona a la función de nube, puede dejar pasar parámetros de autenticación en su código y lo siguiente proporciona ejemplos de invocación.

Terminal
Enrollar una función de nube existente sin parámetros.

 curl https: // [ MYPROJECT ] .cloudfunctions.net / [ FUNC NAME ] 

Riza una función de nube existente que toma parámetros.

 curl https: // [ MYPROJECT ] .cloudfunctions.net / [ NOMBRE FUNC ] -H "Tipo de contenido: application / json" -d '{"first": "Mae Carol", "last": "Jemison"}' 

Reemplace MYPROJECT con su identificación de proyecto de Google Cloud y FUNC NAME con el nombre de la función de nube como se indica en la configuración.

Código de Python
Cuando llamé a la url dentro de una función de Python, utilicé el paquete de solicitudes para aplicar el disparador HTTP y pasar parámetros a través de la solicitud.

Crea estas variables.

 url = " https: // [ MYPROJECT ] .cloudfunctions.net / [ NOMBRE FUNC ] 
param = {“first”: ”Mae Carol”, “last”: ”Jemison"}

Realice la solicitud de llamada a la URL de Cloud Functions.

 r = request.post (url, json = param) 

Si recibe un error como "Su cliente no tiene permiso para la URL solicitada" , puede que no sea necesariamente la autorización a pesar de lo que dice el error. Descubrí que el problema real anterior era que estaba usando los datos de palabras clave y no convertía mi parámetro en formato json . Cuando cambié el parámetro de entrada de datos a json funcionó.

Este es el código en el que estaba atascado que NO funcionaba antes de cambiar a json.

 r = request.post (url, data = param) 

Acceso autorizado

Como se mencionó, pasé una buena parte del tiempo por la madriguera del conejo auténtico porque pensé que por un tiempo no tenía permiso. Un par de cosas sobre este punto es que en realidad no tenía permiso inicialmente ya que perdí esa autenticación casilla de verificación pero también tuve algunos desafíos para cargar el token en mi código de Python.

Terminal
Encontré bastante rápido el siguiente código de ejemplo que funciona para invocar mi función de nube desde mi computadora portátil y extrae mi token de identidad predeterminado desde que configuré gcloud .

 curl -H "Autorización: Bearer $ (gcloud auth print-identity-token)" https: // [ MYPROJECT ] .cloudfunctions.net / [ NOMBRE FUNC ] -H "Tipo de contenido: aplicación / json" -d '{" primero ”:” Mae Carol ”,“ último ”:” Jemison "} ' 

Código de Python
Cuando fui a probar esto en Python, ahí es donde se puso difícil. Como mi comando bash funcionó, me ayudó a identificar que cargar el token en mi código era parte del desafío.

Experimenté con los paquetes google-auth y google-oauth. Incluso usé os y paquetes de subprocesos para simplemente extraer el token directamente de la llamada bash. Lo que aprendí al probar todas estas cosas fue que no pude obtener un token para cargar con google-auth y google-oauth, lo cual es un problema para otro momento.

Uno de los errores que recibí como se señaló anteriormente fue porque necesitaba intercambiar datos con json en la llamada de solicitud o corregir cómo se configuraron mis parámetros.

Pude analizar mi token con os y subprocess, y este es el comando de subproceso que terminé usando.

 subproceso de importación 
 token = '{}'. format (subprocess.Popen (args = "gcloud auth print-identity-token", stdout = subprocess.PIPE, shell = True) .communicate () [0]) [2: -3] 

¿Es esta una buena forma de hacerlo? Debatible y muy probablemente no. Pero funcionó y necesitaba seguir adelante para hacer otras cosas. Los comentarios siempre son bienvenidos y si encuentro una mejor manera, intentaré volver aquí y actualizar.

Use este código para realizar una solicitud a la URL de la función de nube sin parámetros.

 r = request.post (url, encabezados = {"Autorización": "Portador {}". formato (token)}) 

Use este código para realizar una solicitud a la URL de la función de nube con params.

 r = request.post (url, json = param, encabezados = {"Autorización": "Portador {}". formato (token)}) 

Después de que se ejecuten las solicitudes, puede verificar cómo lo hizo. Los siguientes comandos brindan información sobre si el token es incorrecto y si la solicitud respondió con 200 o 500 o algo en los códigos de rango 400.

 r.haders 
r.status_code

Notas al margen de resolución de problemas

Autenticación | Acceso de todos los usuarios

Si omitió esa casilla de verificación Autenticación la primera vez que configuró su función, use estas instrucciones de Gestión de acceso a través de IAM para que esté disponible para que cualquiera la use. Recuerde tener cuidado con este acceso y considere usarlo en casos como probar la integración.

  1. Ir a Google Cloud Console
  2. Haga clic en la casilla de verificación junto a la función a la que desea otorgar acceso.
  3. Haga clic en Mostrar panel de información en la esquina superior derecha para mostrar la pestaña Permisos .
  4. Haz clic en Agregar miembro .
  5. En el campo Nuevos miembros , escriba allUsers.
  6. Seleccione el rol Funciones de nube> Invocador de funciones de nube en el menú desplegable Seleccionar un rol .
  7. Haz clic en Guardar .

Autenticación | Fichas de metadatos

Si está ejecutando solicitudes de Cloud Functions de un servicio de Google Cloud, hay instrucciones que muestran cómo obtener un token llamando a un servicio de metadatos. Los documentos en Autenticación de desarrolladores, funciones y usuarios finales se detallan más. A continuación se muestra una muestra de algún código que puede usar en Python.

 REGION = 'us-central1' 
PROJECT_ID = [ID DEL PROYECTO]
RECEIVING_FUNCTION = [NOMBRE FUNC]
 function_url = f ' https: // {REGIÓN} - {PROYECTO_ID} .cloudfunctions.net / {RECEIVING_FUNCTION}' 
metadata_server_url = \
' http: // metadata / computeMetadata / v1 / instance / service-accounts / default / identity? audiencia ='
token_full_url = metadata_server_url + function_url
token_headers = {'Metadata-Flavor': 'Google'}
 token_response = request.get (token_full_url, headers = token_headers) 
jwt = token_response.text
function_headers = {'Autorización': f'bearer {jwt} '}
r = request.get (function_url, headers = function_headers)

Cuando estaba tratando de descubrir el token localmente, probé los metadatos y tuve otros errores que me hicieron perder el control. "Reintentos máximos excedidos con url" y "Error al establecer una nueva conexión". Esto me llevó por un camino confuso pensando que necesitaba cambiar una configuración en Cloud Functions. En pocas palabras, debe estar en un servicio desde el que pueda llamarlo como Cloud Compute.

Solución de problemas y registro

Al construir algo con múltiples servicios integrados, es bueno desglosar los componentes y probarlos directamente en cada servicio individual cuando pueda. He compartido anteriormente que Cloud Functions permite realizar pruebas directamente en la interfaz de usuario o desde la línea de comandos. Úselo si obtiene errores que no están claros. Además, use el registro donde pueda. Google Cloud proporciona registro y puede ver más sobre cómo configurarlo para grabar en el Servicio de registro de operaciones de la plataforma. El registro detallado es tu amigo y puede ayudar a localizar errores extraños.

Si ha leído alguna de mis publicaciones anteriores, puede saber que me gusta comenzar poco a poco y expandirme y hacer una pequeña prueba de integración local siempre que sea posible. Eso puede ser un desafío cuando se trata de autenticación, diferencias en las configuraciones y detalles de registro insuficientes. Comience con poco, agregue registros, pruebe cada servicio individualmente y crezca.

Reducir tiempo y costos

Por último, pero no menos importante, recuerde usar return en su función de nube cuando use el disparador HTTP. Esto asegurará que la función finalice frente a la ejecución hasta que finalice el tiempo de espera. No desea pagar por el tiempo de espera si puede finalizar la función más rápidamente.

Costo

El costo total de usar Cloud Functions incluye cuántas veces se llama, cuánto tiempo se ejecuta, cuántos recursos se aprovisionan y si se realizan solicitudes de red salientes. Entonces la ecuación es invocaciones + tiempo de cómputo + trabajo en red. El nivel gratuito ofrece invocaciones de 2 millones por mes, 1 millón de segundos de cómputo gratuito por mes y 5 GB de tráfico de salida de Internet gratis por mes. Después de eso, la invocación es una tarifa plana de $ 0.4 por millón, la red es una tarifa plana de $ 0.12 por GB y el tiempo de cómputo está en niveles de $ 0.0000025 por GB-segundo o $ 0.00001 por GHz-segundo para el nivel 1. Para obtener más información, puede pagar los documentos de precios que proporcionan un ejemplo más específico y el desglose de los costos.

Envolver

Pasé por configurar e invocar una función de nube usando Python 3.7. Compartí las trampas que experimenté con la esperanza de que otras personas que puedan encontrar estos errores puedan encontrar esto y ver cómo salir del problema más rápido que yo al buscar. Las cosas clave a tener en cuenta al usar las Funciones de nube son buenas para usar cuando necesita hacer muchas, muchas llamadas a esa función y la función puede completarse en menos de 9 minutos; de lo contrario, debería mirar algo como Cloud Run.

Diviértete explorando. norte


Configurar e invocar funciones en la nube usando Python se publicó originalmente en Google Cloud - Community on Medium, donde las personas continúan la conversación resaltando y respondiendo a esta historia.