In this sample, we'll build an image processing pipeline to connect Google Cloud Storage events to various services with Knative Eventing on GKE.
- An image is saved to an input Cloud Storage bucket.
- Cloud Storage update event is read into Knative by
CloudStorageSource
. - Filter service receives the Cloud Storage event. It uses Vision API to
determine if the image is safe. If so, it creates a custom
CloudEvent
of typedev.knative.samples.fileuploaded
and passes it onwards. - Resizer service receives the
fileuploaded
event, resizes the image using ImageSharp library, saves to the resized image to the output bucket, creates a customCloudEvent
of typedev.knative.samples.fileresized
and passes the event onwards. - Watermark service receives the
fileresized
event, adds a watermark to the image using ImageSharp library and saves the image to the output bucket. - Labeler receives the
fileuploaded
event, extracts labels of the image with Vision API and saves the labels to the output bucket.
We're assuming that you already went through Cloud Storage triggered service tutorial where you setup Knative with GCP & PubSub Topic and also initialized Cloud Storage with Pub/Sub events. Here we will start with creating buckets for the pipeline.
Create 2 unique storage buckets to save pre and post processed images:
export BUCKET1="$(gcloud config get-value core/project)-images-input"
export BUCKET2="$(gcloud config get-value core/project)-images-output"
gsutil mb gs://${BUCKET1}
gsutil mb gs://${BUCKET2}
Create a CloudStorageSource
to connect storage events from the first bucket to
the Broker
in Knative Eventing.
cloudstoragesource.yaml
defines the CloudStorageSource
. Make sure you update the bucket name to the
actual bucket name in your project.
Create the CloudStorageSource:
kubectl apply -f cloudstoragesource.yaml
You should see the CloudStorageSource
running:
kubectl get cloudstoragesource
NAME READY REASON AGE
storagesource-images-input True 23s
Make sure there's a Broker in the default namespace by following instructions in Broker Creation page.
Some services use Vision API. Make sure the Vision API is enabled:
gcloud services enable vision.googleapis.com
This service receives Cloud Storage events for saved images. It uses Vision API to determine if the image is safe. If so, it passes a custom event onwards.
The code of the service is in filter folder.
Inside the top level processing-pipelines folder, build and push the container image:
export SERVICE_NAME=filter
docker build -t meteatamel/${SERVICE_NAME}:v1 -f image/${SERVICE_NAME}/csharp/Dockerfile .
docker push meteatamel/${SERVICE_NAME}:v1
Create the service defined in kservice.yaml:
kubectl apply -f kservice.yaml
The trigger of the service filters on Cloud Storage finalize events:
com.google.cloud.storage.object.finalize
.
Create the trigger for the service defined in trigger.yaml:
kubectl apply -f trigger.yaml
This service receives the custom event, resizes the image using ImageSharp library and passes the event onwards.
The code of the service is in resizer folder.
Inside the top level processing-pipelines folder, build and push the container image:
export SERVICE_NAME=resizer
docker build -t meteatamel/${SERVICE_NAME}:v1 -f image/${SERVICE_NAME}/csharp/Dockerfile .
docker push meteatamel/${SERVICE_NAME}:v1
Create the service defined in
kservice.yaml.
Make sure you update the BUCKET
env variable to the value of $BUCKET2
:
kubectl apply -f kservice.yaml
The trigger of the service filters on dev.knative.samples.fileuploaded
event
types which is the custom event type emitted by the filter service.
Create the trigger for the service defined in trigger.yaml:
kubectl apply -f trigger.yaml
This service receives the event, adds the watermark to the image using ImageSharp library and saves the image to the output bucket.
The code of the service is in watermarker folder.
Inside the top level processing-pipelines folder, build and push the container image:
export SERVICE_NAME=watermarker
docker build -t meteatamel/${SERVICE_NAME}:v1 -f image/${SERVICE_NAME}/csharp/Dockerfile .
docker push meteatamel/${SERVICE_NAME}:v1
Create the service defined in
kservice.yaml.
Make sure you update the BUCKET
env variable to the value of $BUCKET2
:
kubectl apply -f kservice.yaml
The trigger of the service filters on dev.knative.samples.fileresized
event
types which is the custom event type emitted by the resizer service.
Create the trigger for the service defined in trigger.yaml:
kubectl apply -f trigger.yaml
Labeler receives the event, extracts labels of the image with Vision API and saves the labels to the output bucket.
The code of the service is in labeler folder.
Inside the top level processing-pipelines folder, build and push the container image:
export SERVICE_NAME=labeler
docker build -t meteatamel/${SERVICE_NAME}:v1 -f image/${SERVICE_NAME}/csharp/Dockerfile .
docker push meteatamel/${SERVICE_NAME}:v1
Create the service defined in
kservice.yaml.
Make sure you update the BUCKET
env variable to the value of $BUCKET2
:
kubectl apply -f kservice.yaml
The trigger of the service filters on dev.knative.samples.fileuploaded
event
types which is the custom event type emitted by the filter service.
Create the trigger for the service defined in trigger.yaml:
kubectl apply -f trigger.yaml
Before testing the pipeline, make sure all the triggers are ready:
kubectl get trigger
NAME READY REASON BROKER SUBSCRIBER_URI AGE
trigger-filter True default http://filter.default.svc.cluster.local 3d19h
trigger-labeler True default http://labeler.default.svc.cluster.local 3d
trigger-resizer True default http://resizer.default.svc.cluster.local 3d19h
trigger-watermarker True default http://watermarker.default.svc.cluster.local 3d
You can upload an image to the input storage bucket:
gsutil cp ../../pictures/beach.jpg gs://${BUCKET1}
After a minute or so, you should see resized, watermarked and labelled image in the output bucket:
gsutil ls gs://${BUCKET2}
gs://knative-atamel-images-output/beach-400x400-watermark.jpeg
gs://knative-atamel-images-output/beach-400x400.png
gs://knative-atamel-images-output/beach-labels.txt