Lors de la Google IO 2022, Google a dévoilé le service Cloud Run Jobs.
Sortie en 2019, Cloud Run est un service serverless spécialisé dans la mise en place de workloads de serveurs Web scalables de zéro à l’infini. L’idée principale est de rester concentré sur la valeur du code plutôt que les problématiques sous-jacentes à son hébergement. Avec Cloud Run Jobs, Google nous propose une offre qui reste la même sur le fond mais change de cible de workload en nous faisant sortir du paradigme web serveur. Il est désormais possible de faire tourner des batchs, ce qui ouvre l’audience de Cloud Run à d’autres types de profils que les seuls développeurs Web.

Rappels sur Cloud Run

Sorti en 2019, Cloud Run s’est imposé comme LE service GCP représentatif d’une certaine approche du serverless.

Beaucoup a été écrit sur le sujet et l’on retiendra les points suivants :

  • C’est le service de référence de la GCP en ce qui concerne le paradigme serverless
    Cloud Run est précédé par AppEngine et Cloud Function dans l’ordre chronologique de sortie. Il est cependant celui qui a émergé comme le service sur lequel mise la GCP au point que la nouvelle version des Cloud Function n’est en réalité qu’une version déguisée de Cloud Run.

  • Cloud Run est adapté à l'approche micro-service
    Cloud Run expose ses traitements à travers des instances de services versionnés.
    Ce que vous déployez sont donc des services dont la logique est portée par des images Docker. Vous pouvez les faire communiquer de manière synchrone via des appels direct à leur FQDN (fourni par Google ou custom) ou de manière asynchrone en utilisant par exemple Cloud Tasks ou Google Pub/Sub.

  • C’est un service très intégré dans l’écosystème GCP
    En tant que service serverless phare de la GCP, il est important d’en faciliter l’intégration avec les autres services. Par exemple avec EventArc qui accepte des services Cloud Run en tant que cible d'événements se produisant sur votre projet GCP.

  • Des contraintes de runtime sont imposées
    Cloud run repose sur la technologie des containers pour exposer des logiques liés à votre business. Par exemple, retourner une page Web.
    Les promesses de scalabilité offertes par Cloud Run ne sont pas sans concession car la runtime du container associé doit respecter des contraintes.
    Globalement, la runtime représente un serveur Web écoutant sur un port et ayant un temps d’allocation CPU limité au traitement de la requête.
    Cette dernière contrainte s’est dernièrement vue atténuée avec la possibilité de dépasser cette allocation, et ainsi permettre aux processus en arrière-plan de perdurer au-delà de la requête (agents d’observabilité, traitements asynchrones, …)

Nous restons cependant fondamentalement dans le même paradigme de request/response HTTP pour déclencher un processus, qui doit donc en adopter les codes en passant par exemple par des framework type Flask ou SpringBoot.

C’est sur le point des contraintes runtime que Cloud Run Jobs s’inscrit comme une évolution majeure de Cloud Run.

Note: Pour aller plus loin dans la compréhension de Cloud Run nous vous dirigeons vers cet excellent FAQ issu de la communauté GCP.

Qu’est ce que Cloud Run Jobs ?

Cloud Run Jobs permet de s’affranchir d’une runtime orientée web server. Le Job vient remplacer le service. Il n’est plus question d’exposer un point d'entrée HTTP particulier pour traiter une requête et il y est possible de lancer le code suivant:


if __name__ == "__main__":
    print("Hello World")

plutôt que


from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

Pour autant, nous gardons les mêmes promesses de scalabilité que Cloud Run Services.  Cloud Run Jobs concurrencera directement des approches de lancement de scripts sur une VM, non scalable et dont l'opérationnel est à votre charge.

Les jobs seront, de la même manière que les services, packagés dans des images Docker dont la création pourra opportunément passer par l’outil BuildPack et vous soulager de l’écriture d’un Dockerfile valide.

Cloud Run Jobs, pour quels besoins ?

Les besoins auxquels répond Cloud Run Jobs sont nombreux mais ce dernier ne les invente pas. Il les facilite en donnant la possibilité de les migrer dans un paradigme serverless voire Cloud Native.

Nous pouvons penser aux points suivants :

  • Lancement de script
    Envisagé on-prem ou sur une VM dans le Cloud, le scripting de tâche de maintenance ou du traitement batch est rarement naturellement associé au paradigme serverless.
    Bien entendu il est possible de les penser ainsi mais au dépend d’une refactorisation pour s’adapter aux contraintes de runtime.

  • Batch de traitement de donnée
    Même argumentation que le point précédent. Notons tout de même qu’à partir d’une certaine volumétrie et complexité de transformation, on préférera l’usage de  Dataflow ou Dataproc serverless pour continuer de bénéficier d’une expérience totalement managée.

  • Paralléliser des tâches
    Au moment d’écrire ces lignes Cloud Run Jobs peut paralléliser jusqu’à 10K tâches.  
    Avec Cloud Run Service, la parallélisation s'envisage par le lancement de plusieurs requêtes sur un même service. La détection de la terminaison de l’ensemble des tâches est à notre charge et est non triviale.  
    Avec Cloud Run Jobs, non seulement la parallélisation est intégrée en tant que paramètre de configuration, mais on aura aussi un retour du job sur la terminaison de l'ensemble des sous tâches.

Points d’attention…

Cloud Run Jobs est un service en bêta et ne bénéficie à ce titre ni de SLA ni de SLO. On en interdira donc l’usage en environnement de production.
Pour l’instant les possibilités en termes d’appel restent limitées avec une intégration minimaliste au CLI gcloud.
Le minimum est tout de même bien là avec une intégration à Cloud Operations et une capacité acceptable à configurer ses jobs (politique de retry, parallélisme, politique de timeout, …).

Côté facturation, le modèle diffère de Cloud Run Service et vous facture la mémoire et le CPU sur le temps d’existence de l’instance portant un job plutôt que le temps d'exécution effectif de ce dernier. La facturation sera au minimum d’une minute.

…et ouvertures

Pour voir en œuvre quelques exemples concrets, Google met à disposition un dépôt Github non mentionné dans la documentation officielle de Cloud Run (jusqu’à preuve du contraire).

Cela reste basique pour le moment. Il va être intéressant de regarder du côté des patterns et bonnes pratiques qui émergeront à l’usage de Cloud Run Jobs.
Parmi les sujets d’intérêt se trouvent les points non exhaustifs suivants :

  • Concept de dead letter queue
    Lors d’un job tournant en parallèle, une seule tâche en échec fait échouer tout le job.
    Ce n’est probablement pas souhaitable dans de nombreux cas.
    On pourra penser à un système s’apparentant à une dead letter queue pour pouvoir investiguer et compléter le job plus tard.

  • Idempotence des jobs
    Dans le même ordre d’idée, un job parallélisé ne se termine que sur le succès de la totalité des sous tâches. Que penser alors d’un job en échec mais dont la majorité des tâches se sont effectuées ? L’idempotence d’un job sera comme souvent quelque chose de hautement recommandable voire obligatoire pour s’éviter de traiter des états incohérents.

  • Découpage des tâches
    Le sujet de la limitation de temps d'exécution à maximum 60 min devrait aussi inciter à diviser le plus possible ces tâches pour favoriser d’une part le rejeu et le debug mais aussi se prémunir d’exception dûe au temps d'exécution.

  • Job versioning
    Contrairement aux services Cloud Run, il n’y a pas encore de notion de version d’un Job (hormis celle que vous avez sur votre repository Git contenant le code du job).
    C’est problématique dans un contexte de transformation de la donnée car les capacités de rejeu d’une transformation doit aussi se penser temporellement pour appliquer les bonnes transformations disponibles à T-1.

  • Ajout d’une notion de callback
    Il serait intéressant d’intégrer la notion de callback pour notifier des services de la terminaison d’un job parallélelisé.
    En particulier pour l’intégration avec des orchestrateurs de Workflow pour leur signifier de passer à l’étape suivante.

Conclusion

Cloud Run Jobs apporte une brique très appréciable au paradigme serverless existant. Cantonné aux workloads de serveurs web, il fallait détourner l’usage premier de Cloud Run pour sortir de ce paradigme et lancer des processus qui relèvent plus du traitement de données ou du scripting. Quel que soit le traitement envisagé, il fallait passer par une requête POST et se plier aux contraintes de Runtime imposées par Cloud Run Services.
Cloud Run Jobs modifie ces contraintes pour permettre d’exposer des jobs dont l’usage premier n’est pas de répondre à une requête mais de lancer des workloads arbitraires.
Cloud Run devient donc envisageable pour des opérations essentiellement pensées pour des VMs et qui, cette fois, deviennent possibles dans un paradigme serverless. Au-delà du classique développeur full-stack, c’est désormais des data engineer, ops et autres profils qui peuvent tirer profit de Cloud Run.

Bien que ce service ne soit qu’en bêta, c’est une perspective intéressante et une facilitation supplémentaire dans le cadre d’une migration vers le cloud, et plus précisément vers le paradigme cloud natif.

Aller plus loin: