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
CloudEventof typedev.knative.samples.fileuploadedand passes it onwards. - Resizer service receives the
fileuploadedevent, resizes the image using ImageSharp library, saves to the resized image to the output bucket, creates a customCloudEventof typedev.knative.samples.fileresizedand passes the event onwards. - Watermark service receives the
fileresizedevent, adds a watermark to the image using ImageSharp library and saves the image to the output bucket. - Labeler receives the
fileuploadedevent, 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.yamlYou should see the CloudStorageSource running:
kubectl get cloudstoragesource
NAME READY REASON AGE
storagesource-images-input True 23sMake 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.comThis 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}:v1Create the service defined in kservice.yaml:
kubectl apply -f kservice.yamlThe 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.yamlThis 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}:v1Create the service defined in
kservice.yaml.
Make sure you update the BUCKET env variable to the value of $BUCKET2:
kubectl apply -f kservice.yamlThe 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.yamlThis 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}:v1Create the service defined in
kservice.yaml.
Make sure you update the BUCKET env variable to the value of $BUCKET2:
kubectl apply -f kservice.yamlThe 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.yamlLabeler 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}:v1Create the service defined in
kservice.yaml.
Make sure you update the BUCKET env variable to the value of $BUCKET2:
kubectl apply -f kservice.yamlThe 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.yamlBefore 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 3dYou 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