This tutorial demonstrates using Knative serving, Cloud Vision API, and ImageMagick to detect and blur offensive images uploaded to a Cloud Storage bucket. This tutorial builds on the tutorial Using Pub/Sub with Knative serving.
This tutorial walks through modifying an existing sample app. You can also download the completed sample if you want.
Objectives
- Write, build, and deploy an asynchronous data processing service to Knative serving
- Invoke the service by uploading a file to Cloud Storage, creating a Pub/Sub message.
- Use the Cloud Vision API to detect violent or adult content.
- Use ImageMagick to blur offensive images.
- Test the service by uploading an image of a flesh-eating zombie.
Costs
In this document, you use the following billable components of Google Cloud:
To generate a cost estimate based on your projected usage,
use the pricing calculator.
Before you begin
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Knative serving and Cloud Vision APIs.
- Install and initialize the gcloud CLI.
- Install the
kubectl
component:gcloud components install kubectl
- Update components:
gcloud components update
- Using Knative serving, create a new cluster using the instructions in Setting up Knative serving.
- Set up a Pub/Sub topic, a secure push subscription, and an initial Knative serving service to handle messages by following the Using Pub/Sub with Knative serving tutorial.
Setting up gcloud defaults
To configure gcloud with defaults for your Knative serving service:
Set your default project:
gcloud config set project PROJECT_ID
Replace PROJECT_ID with the name of the project you use for this tutorial.
Configure gcloud for your cluster:
gcloud config set run/platform gke gcloud config set run/cluster CLUSTER-NAME gcloud config set run/cluster_location REGION
Replace:
- CLUSTER-NAME with the name you used for your cluster,
- REGION with the supported cluster location of your choice.
Understanding the sequence of operations
The flow of data in this tutorial follows these steps:
- A user uploads an image to a Cloud Storage bucket.
- Cloud Storage publishes a message about the new file to Pub/Sub.
- Pub/Sub pushes the message to the Knative serving service.
- The Knative serving service retrieves the image file referenced in the Pub/Sub message.
- The Knative serving service uses the Cloud Vision API to analyze the image.
- If violent or adult content is detected, the Knative serving service uses ImageMagick to blur the image.
- The Knative serving service uploads the blurred image to another Cloud Storage bucket for use.
Subsequent use of the blurred image is left as an exercise for the reader.
Setting up Cloud Storage buckets
Create a Cloud Storage bucket for uploading images, where INPUT_BUCKET_NAME is a globally unique bucket name:
gcloud storage buckets create gs://INPUT_BUCKET_NAME
The Knative serving service only reads from this bucket.
Create a second Cloud Storage bucket to receive blurred images, where BLURRED_BUCKET_NAME is a globally unique bucket name:
gcloud storage buckets create gs://BLURRED_BUCKET_NAME
The Knative serving service uploads blurred images to this bucket. Using a separate bucket prevents processed images from re-triggering the service.
In the following steps, you create and deploy a service that processes notification of file uploads to the INPUT_BUCKET_NAME. You turn on notification delivery after you deploy and test the service, to avoid premature invocation of the new service.
Modifying the Pub/Sub tutorial sample code
This tutorial builds on the code assembled in the Using Pub/Sub tutorial. If you have not yet completed that tutorial, do so now, skipping the cleanup steps, then return here to add image processing behavior.
Adding image processing code
The image processing code is separated from request handling for readability and ease of testing. To add image processing code:
Change to the directory of the Pub/Sub tutorial sample code.
Add code to import the image processing dependencies, including libraries to integrate with Google Cloud services, ImageMagick, and the file system.
Node.js
Open a newimage.js
file in your editor, and copy in the following:Python
Open a newimage.py
file in your editor, and copy in the following:Go
Open a newimagemagick/imagemagick.go
file in your editor, and copy in the following:Java
Open a newsrc/main/java/com/example/cloudrun/ImageMagick.java
file in your editor, and copy in the following:Add code to receive a Pub/Sub message as an event object and control the image processing.
The event contains data about the originally uploaded image. This code determines if the image needs to be blurred by checking the results of a Cloud Vision analysis for violent or adult content.
Node.js
Python
Go
Java
Retrieve the referenced image from the Cloud Storage input bucket created above, use ImageMagick to transform the image with a blur effect, and upload the result to the output bucket.
Node.js
Python
Go
Java
Integrating image processing into the Pub/Sub sample code
To modify the existing service to incorporate the image processing code:
Add new dependencies for your service, including the Cloud Vision and Cloud Storage client libraries:
Node.js
npm install --save gm @google-cloud/storage @google-cloud/vision
Python
Add the necessary client libraries so that yourrequirements.txt
will look something like this:Go
The go sample application uses go modules, the new dependencies added above in theimagemagick/imagemagick.go
import statement will automatically download by the next command that needs them.Java
Add the following dependency under<dependencyManagement>
in thepom.xml
: Add the following dependencies under<dependencies>
in thepom.xml
:Add the ImageMagick system package to your container by modifying the
Dockerfile
below theFROM
statement. If using a "multi-stage" Dockerfile, place this in the final stage.Debian/Ubuntu Alpine Read more about working with system packages in your Knative serving service in the Using system packages tutorial.
Replace the existing Pub/Sub message handling code with a function call to our new blurring logic.
Node.js
Theapp.js
file defines the Express.js app and prepares received Pub/Sub messages for use. Make the following changes:- Add code to import the new
image.js
file - Remove the existing "Hello World" code from the route
- Add code to further validate the Pub/Sub message
Add code to call the new image processing function
When you are finished, the code will look like this:
Python
Themain.py
file defines the Flask app and prepares received Pub/Sub messages for use. Make the following changes:- Add code to import the new
image.py
file - Remove the existing "Hello World" code from the route
- Add code to further validate the Pub/Sub message
Add code to call the new image processing function
When you are finished, the code will look like this:
Go
Themain.go
file defines the HTTP service and prepares received Pub/Sub messages for use. Make the following changes:- Add code to import the new
imagemagick.go
file - Remove the existing "Hello World" code from the handler
- Add code to further validate the Pub/Sub message
- Add code to call the new image processing function
Java
ThePubSubController.java
file defines the controller that handles HTTP requests and prepares received Pub/Sub messages for use. Make the following changes:- Add the new imports
- Remove the existing "Hello World" code from the controller
- Add code to further validate the Pub/Sub message
- Add code to call the new image processing function
- Add code to import the new
Downloading the complete sample
To retrieve the complete Image Processing code sample for use:
Clone the sample app repository to your local machine:
Node.js
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Python
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Go
git clone https://github.com/GoogleCloudPlatform/golang-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Java
git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Change to the directory that contains the Knative serving sample code:
Node.js
cd nodejs-docs-samples/run/image-processing/
Python
cd python-docs-samples/run/image-processing/
Go
cd golang-samples/run/image-processing/
Java
cd java-docs-samples/run/image-processing/
Shipping the code
Shipping code consists of three steps: building a container image with Cloud Build, uploading the container image to Container Registry, and deploying the container image to Knative serving.
To ship your code:
Build your container and publish on Container Registry:
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub
Where PROJECT_ID is your GCP project ID, and
pubsub
is the name you want to give your service.Upon success, you will see a SUCCESS message containing the ID, creation time, and image name. The image is stored in Container Registry and can be re-used if desired.
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub
Where PROJECT_ID is your GCP project ID, and
pubsub
is the name you want to give your service.Upon success, you will see a SUCCESS message containing the ID, creation time, and image name. The image is stored in Container Registry and can be re-used if desired.
Go
gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub
Where PROJECT_ID is your GCP project ID, and
pubsub
is the name you want to give your service.Upon success, you will see a SUCCESS message containing the ID, creation time, and image name. The image is stored in Container Registry and can be re-used if desired.
Java
This sample uses Jib to build Docker images using common Java tools. Jib optimizes container builds without the need for a Dockerfile or having Docker installed. Learn more about building Java containers with Jib.Using the Dockerfile, configure and build a base image with the system packages installed to override Jib's default base image:
gcloud builds submit --tag gcr.io/PROJECT_ID/imagemagick
Where PROJECT_ID is your GCP project ID.
Build your final container with Jib and publish on Container Registry:
mvn compile jib:build \ -Dimage=gcr.io/PROJECT_ID/pubsub \ -Djib.from.image=gcr.io/PROJECT_ID/imagemagick
Where PROJECT_ID is your GCP project ID.
Run the following command to deploy your service, using the same service name you used in the Pub/Sub tutorial:
Node.js
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME
Python
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME
Go
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME
Java
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME --memory 512M
Replace PROJECT_ID with your GCP project ID.
pubsub
is the container name andpubsub-tutorial
is the name of the service. Notice that the container image is deployed to the service and cluster that you configured previously under Setting up gcloud defaults.Replace BLURRED_BUCKET_NAME with your Cloud Storage bucket you created earlier to receive blurred images to set the environment variable.
Wait until the deployment is complete: this can take about half a minute. On success, the command line displays the service URL.
Turning on notifications from Cloud Storage
Configure Cloud Storage to publish a message to a Pub/Sub topic whenever a file (known as an object), is uploaded or changed. Send the notification to the previously created topic so any new file upload will invoke the service.
gcloud storage buckets notifications create gs://INPUT_BUCKET_NAME --topic=myRunTopic --payload-format=json
This command is installed as part of the Google Cloud CLI. myRunTopic
is the
topic you created in the previous tutorial.
Replace INPUT_BUCKET_NAME with the name you used when you created the buckets.
For more details about storage bucket notifications, read object change notifications.
Trying it out
Upload an offensive image, such as this image of a flesh-eating zombie:
gcloud storage cp zombie.jpg gs://INPUT_BUCKET_NAME
where INPUT_BUCKET_NAME is the Cloud Storage bucket you created earlier for uploading images.
Navigate to the service logs:
Navigate to the Knative serving page in the Google Cloud console:
Click the
pubsub-tutorial
service.Select the Logs tab. Logs might take a few moments to appear. If you don't see them immediately, check again after a few moments.
Look for the
Blurred image: zombie.png
message.You can view the blurred images in the BLURRED_BUCKET_NAME Cloud Storage bucket you created earlier: locate the bucket in the Cloud Storage page in the Google Cloud console
Clean up
If you created a new project for this tutorial, delete the project. If you used an existing project and wish to keep it without the changes added in this tutorial, delete resources created for the tutorial.
Deleting the project
The easiest way to eliminate billing is to delete the project that you created for the tutorial.
To delete the project:
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
Deleting tutorial resources
Delete the Knative serving service you deployed in this tutorial:
gcloud run services delete SERVICE-NAME
Where SERVICE-NAME is your chosen service name.
You can also delete Knative serving services from the Google Cloud console:
Remove the gcloud default configurations you added during the tutorial setup:
gcloud config unset run/platform gcloud config unset run/cluster gcloud config unset run/cluster_location
Remove the project configuration:
gcloud config unset project
Delete other Google Cloud resources created in this tutorial:
- Delete the Pub/Sub topic
myRunTopic
- Delete the Pub/Sub subscription
myRunSubscription
- Delete the container image named
gcr.io/
PROJECT_ID/pubsub
from Container Registry - Delete the invoker service account
cloud-run-pubsub-invoker@PROJECT_ID.iam.gserviceaccount.com
- Delete the Cloud Storage buckets created for the placeholders
INPUT_BUCKET_NAME
andBLURRED_BUCKET_NAME
- If you created a cluster for this tutorial, delete the cluster
- Delete the Pub/Sub topic
What's next
- Learn more about persisting data with Knative serving via Cloud Storage
- Learn how to use Cloud Vision API to detect things besides explicit content.
- Explore reference architectures, diagrams, and best practices about Google Cloud. Take a look at our Cloud Architecture Center.