Aan de slag met Google Cloud Run

Eenvoudig serverless webapplicaties draaien

Wil je een applicatie in de cloud te draaien, maar weet je niet goed waar je moet beginnen? Met Cloud Run heb je je applicatie in een handomdraai op de Google Cloud draaiend.

Door: Benjamin Komen 

Tegenwoordig zijn er tal van mogelijkheden om je webapplicatie in de cloud te draaien. Dit vereist echter vaak kennis van infrastructuur om clusters met virtuele machines te configureren, wat ook nog eens flink geld kan kosten om draaiend te houden. Bij oplossingen met een hogere abstractie qua infrastructuur, kun je enigszins beperkt worden in welke programmeertaal en versie je kunt gebruiken, zoals bij Google App Engine of Amazon Elastic Beanstalk het geval is. Andere beperkingen kunnen zijn dat je applicatie in slaapstand wordt gezet na 30 minuten van inactiviteit, wat bijvoorbeeld bij Heroku het geval is [1]. Daarnaast is het lastig om een applicatie lokaal te testen, omdat het niet mogelijk is alle cloud diensten lokaal te emuleren.

Cloud Run is een relatief nieuwe dienst binnen het Google Cloud Platform, die veel van deze problemen oplost.

Hoe werkt Cloud Run precies?

Bij Cloud Run verpak je je service in een Docker container, waarin je je webapplicatie laat opstarten en laat luisteren naar netwerkverkeer op een bepaalde poort. Google regelt alle onderliggende infrastructuur voor je, wat deze dienst serverless maakt. Daarnaast worden een aantal zaken goed geregeld, zoals autoscaling. Als er geen verkeer binnenkomt wordt je service teruggeschaald naar nul instanties, alsmede de kosten. Mocht er plotseling veel netwerkverkeer naar je service zijn, dan wordt er automatisch opgeschaald tot maximaal 1000 servers.

Wanneer te gebruiken?

Belangrijk is wel te vermelden dat je service stateless moet zijn, omdat achtereenvolgende netwerkverzoeken door verschillende instanties afgehandeld moeten kunnen worden. Zo zul je sessies van gebruikers en andere state dus buiten de containers op moeten slaan. Verder kan je service alleen CPU gebruiken terwijl er een netwerkverzoek wordt afgehandeld. Om toch achtergrondprocessen te draaien kun je vanuit andere Google diensten zoals Cloud Pub/Sub of Cloud Tasks een verzoek naar je service laten doen.

Google Cloud voorbereiden

Om Cloud Run te proberen is het nodig een Google Cloud account te hebben. Als je deze nog niet hebt, kun je deze gratis aanmaken. Je krijgt dan 300 dollar tegoed, wat ruim voldoende is om te experimenteren. Maak een nieuw project aan, zodat je dit complete project met alle aangemaakte resources kunt verwijderen als je klaar bent met experimenteren. Dan weet je zeker dat er achteraf geen kosten in rekening worden gebracht.

Om de CLI te gebruiken moet je de Google Cloud SDK installeren op je computer. Als alternatief kun je de Cloud Shell [2] gebruiken, waarmee je alles vanuit de Google Cloud Console in je browser kunt doen en niks lokaal hoeft te installeren. Zorg dat je nieuw aangemaakte project geselecteerd is, en de benodigde APIs, Cloud Build, Container Registry en Cloud Run, aan staan.

gcloud config set project [PROJECT-ID]
gcloud services enable cloudbuild.googleapis.com 
containerregistry.googleapis.com run.googleapis.com

Listing 1.

Docker image bouwen

Op Cloud Run kan een willekeurige Docker container met webserver draaien. Je kunt dus bijvoorbeeld een Java project met Spring Boot, Micronaut of Thorntail maken. Maar je kunt ook een andere programmeertaal gebruiken. Ter illustratie gaan we een simpel Spring Boot project gebruiken. Clone of download deze hier via Github en navigeer naar de map in je terminal of de Cloud Shell.

Dit project bevat een Spring Boot applicatie met slechts een hello world endpoint. Bouw deze met Docker.

docker build -t cloudrun ./cloudrun

Listing 2.

Dit bouwt een Docker image vanuit de map “cloudrun” en geeft hem een tag met de naam “cloudrun” mee. De Dockerfile (listing 3), maakt gebruik van de zogenaamde multi-stage build. In de eerste fase wordt vanuit je bronbestanden met behulp van Maven een JAR gemaakt. In de tweede fase wordt deze JAR uitgevoerd.

# Fase 1: compileer een JAR bestand.
FROM maven:3.6.3-jdk-13 as builder

# Kopieer lokale code naar de container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src

# Bouw een te publiceren artifact.
RUN mvn package -DskipTests

# Fase 2: voer de eerder gebouwde JAR uit.
FROM adoptopenjdk/openjdk13:alpine-slim

COPY --from=builder /app/target/cloudrun-*.jar /cloudrun.jar

# Draai de web service bij het opstarten van de container.
CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/cloudrun.jar"]

Listing 3.

Als Cloud Run deze Docker image draait, wordt er een PORT variabele geïnjecteerd. Als je deze Docker image zelf lokaal wilt draaien, zul je deze variabele mee moeten geven.

docker run -it -e PORT=8080 -p 8080:8080 cloudrun

Listing 4.

Je ziet in je console hoe Spring Boot opstart. Je applicatie is nu benaderbaar in je browser via deze link, of als je niet lokaal maar in de Cloud Shell [2] draait, kun je klikken op het ‘Web Preview’ icoontje naast het potloodje rechtsboven en vervolgens ‘Preview on port 8080’. Om de Docker container te stoppen, type je Ctrl + C in je terminal of shell.

Cloud Build

Bij het lokaal bouwen van een Docker image, is deze alleen lokaal beschikbaar. Om de Docker image beschikbaar te maken voor Cloud Run, is het handig als deze in de Container Registry van je Google Cloud project staat. Om dit eenvoudig te doen kun je gebruik maken van Cloud Build, waarmee een Docker image gebouwd en gepubliceerd wordt in de Container Registry (listing 5). Docker images die je hier publiceert, zijn standaard niet publiek toegankelijk, maar alleen binnen je project te gebruiken.

gcloud builds submit --tag gcr.io/[PROJECT_ID]/[IMAGE_NAME] ./cloudrun

Listing 5.

Hierbij is PROJECT_ID het id van je project en IMAGE_NAME kun je zelf kiezen, bijvoorbeeld “cloudrun”. Je kunt de gebouwde image vervolgens vinden in de Container Registry.

Draaien op Cloud Run

Nu we een Docker image in de Container Registry gepubliceerd hebben, kunnen we een container gaan draaien op de Cloud Run (listing 6).

gcloud run deploy [SERVICE] \
 --image gcr.io/[PROJECT_ID]/[IMAGE_NAME] \
 --platform managed \
 --region europe-west1 \
 --allow-unauthenticated \
 --memory 1Gi

Listing 6.

Hierbij is SERVICE een naam die je zelf kunt verzinnen, bijvoorbeeld “cloudrun”. De PROJECT_ID en IMAGE_NAME zijn hetzelfde als wat we bij het Cloud Build commando hebben gebruikt. De platform managed vlag geeft aan dat we Cloud Run fully managed willen gebruiken. Dit betekent dat Google de onderliggende infrastructuur volledig regelt. Als alternatief kun je Cloud Run gebruiken in combinatie met een eigen Google Kubernetes cluster. De vlag region, waar “europe-west1” staat, geeft aan in welke regio hij wordt gedraaid, wat je uiteraard zo dicht mogelijk bij je eindgebruikers wilt hebben. Binnen deze regio wordt je applicatie gedupliceerd over meerdere zones [3]. De vlag allow-unauthenticated geeft aan dat de service publiekelijk toegankelijk via het internet beschikbaar is. De memory vlag is in het geval van Java en Spring Boot aan te bevelen. Deze instelling kan op maximaal 2 gibibyte geheugen gezet worden.

Je kunt de applicatie dan vervolgens bezoeken via de URL in de output van het commando.

Automatisch nieuwe versies bouwen

Een nieuwe revisie van het project publiceren hoeft niet steeds met handmatige commando’s. Dit kan namelijk ook met behulp van een GitHub trigger [4]. Dit zorgt er voor dat als je een nieuwe commit naar GitHub pusht, de trigger afvuurt en er een nieuwe versie van je Cloud Run service gebouwd wordt. Hiervoor moet er een bestand genaamd cloudbuild.yaml aan het project worden toegevoegd, waar de volledige build pipeline in geconfigureerd staat: het bouwen met Cloud Build, releasen van Docker image naar de Container Registry en het publiceren van een nieuwe versie op Cloud Run (zie afbeelding 1). Deze YAML configuratie kan ook gebruikt worden als instructie om handmatig te deployen.

Stappenplan van Cloud Run deployment.

Eigen domeinnaam kiezen

De URL die je standaard krijgt voor je applicatie is niet makkelijk te onthouden. Echter, het is eenvoudig een eigen domeinnaam te gebruiken. Als je naar het dashboard in de Google Cloud gaat en boven op ‘Manage custom domains’ klikt, kun je binnen een aantal kliks bij Google een domeinnaam registreren en wordt deze toegevoegd. Dit kan al vanaf ongeveer 12 euro per jaar. Daarnaast kun je een elders geregistreerde domeinnaam toevoegen met behulp van DNS records.

Bekijken en beheren via dashboard

Nu je applicatie op Cloud Run draait, kun je enkele zaken op het dashboard bekijken. Je ziet hier een tabel met je services. Binnen een Google Cloud project kun je dus meerdere Cloud Run services hebben, bijvoorbeeld een backend en een frontend service die met elkaar communiceren.

Elke service heeft een lijst van revisies. Bij elke publicatie van een nieuwe versie, wordt er automatisch een nieuwe revisie aangemaakt. Dit kun je gebruiken om terug te gaan naar een eerdere revisie, of om een gedeelte van het verkeer naar de ene revisie te leiden, en een gedeelte naar een andere revisie. Daarnaast kun je performance metrics zien, zoals hoeveelheid requests, CPU en geheugengebruik. In het logging tabblad kun je de logs zien. Deze worden automatisch verstuurd naar Stackdriver, de logging dienst van de Google Cloud.

Kosten

Bij Cloud Run betaal je niet voor de onderliggende infrastructuur, maar per 100 milliseconden dat er requests worden afgehandeld door je service. Tenzij je service continue aangeroepen wordt, zal dit dus beduidend minder zijn dan betalen voor een virtuele machine die continu aan staat.

Een voorbeeld van een rekening zie je in afbeelding 2. Je ziet dat er voor CPU-gebruik, geheugengebruik, opslag (van de Docker images) en netwerkverkeer een bedrag in rekening wordt gebracht.

Voorbeeld van een maandelijkse rekening van Google Cloud Platform.

Vergelijking met concurrentie

In onderzoek van Gartner [5] wordt Google samen met Amazon en Microsoft als leider op het gebied van Cloud technologie genoemd. Het is dus interessant om af te vragen hoe Cloud Run zicht verhoudt ten opzichte van de concurrentie.

Amazon AWS

Een vergelijkbare dienst van Amazon is AWS Fargate. Hiermee kun je een Docker container draaien op infrastructuur die Amazon voor jou beheert. Hoewel AWS Fargate vergelijkbaar is met Google Cloud Run, is er wel meer configuratie nodig. Zo moet je een Task Definition maken met CPU, geheugen en netwerk configuratie en een Service die deze draaiende taak beheert. Wil je gebruik maken van bijvoorbeeld load balancing, zul je apart een AWS load balancer moeten configureren.

Microsoft Azure

Een vergelijkbare dienst van Microsoft is Azure Container Instances. Hierbij draai je een Docker container op een Resource group waar je CPU, geheugen en netwerkinstellingen beheert. Je betaalt voor de gealloceerde CPUs en geheugen per seconde dat je container instance draait. Er vindt geen autoscaling plaats. Om dat te bereiken kun je bijvoorbeeld Azure Kubernetes Services (AKS) gebruiken. Als je alleen ACI gebruikt, zul je dus handmatig containers moeten stoppen als je ze niet wilt gebruiken en handmatig moeten opstarten als je er meer nodig hebt.

Conclusie

Met Cloud Run kun je eenvoudig een web service in de cloud draaien, zonder kennis van onderliggende infrastructuur. Je betaalt alleen voor daadwerkelijk gebruik en kunt snel op- en neerschalen bij meer of minder vraag. Cloud Run onderscheidt zich hiermee ten opzichte van concurrentie en er is nauwelijks sprake van vendor lock-in. Een Docker container die op Cloud Run draait, kan je eenvoudig ook op een ander platform laten draaien. Hierdoor is Cloud Run een goede oplossing om zo snel mogelijk containers te laten draaien, waar je later nog alle kanten mee op kunt.