This tutorial shows how to build a custom Knative serving service that transforms a graph description input parameter into a diagram in the PNG image format. It uses Graphviz that is installed as a system package in the service's container environment. Graphviz is used via command-line utilities to serve requests.
Objectives
- Write and build a custom container with a Dockerfile
- Write, build, and deploy a Knative serving service
- Use Graphviz dot utility to generate diagrams
- Test the service by posting a DOT syntax diagram from the collection or your own creation
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
- This tutorial assumes that you have Knative serving installed and configured on your cluster.
- Ensure that your command-line environment is set up and the tools are up-to-date:
Retrieving the code sample
To retrieve the 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/system-package/ - Python- cd python-docs-samples/run/system-package/ - Go- cd golang-samples/run/system_package/ - Java- cd java-docs-samples/run/system-package/ 
Visualizing the architecture
The basic architecture looks like this:
 
 The user makes an HTTP request to the Knative serving service which executes a Graphviz utility to transform the request into an image. That image is delivered to the user as the HTTP response.
Understanding the code
Defining your environment configuration with the Dockerfile
  Your Dockerfile is specific to the language and base operating environment, such as Ubuntu, that your service will use.
This service requires one or more additional system packages not available by default.
- Open the - Dockerfilein an editor.
- Look for a - Dockerfile- RUNstatement. This statement allows running arbitrary shell commands to modify the environment. If the- Dockerfilehas multiple stages, identified by finding multiple- FROMstatements, it will be found in the last stage.- The specific packages required and the mechanism to install them varies by the operating system declared inside the container. - To get instructions for your operating system or base image, click the appropriate tab. - Debian/Ubuntu - Alpine Alpine requires a second package for font support.- To determine the operating system of your container image, check the name in the - FROMstatement or a README associated with your base image. For example, if you extend from- node, you can find documentation and the parent- Dockerfileon Docker Hub.
- Test your customization by building the image, using - docker buildlocally or Cloud Build.
Handling incoming requests
The sample service uses parameters from the incoming HTTP request to invoke a system call that executes the appropriate dot utility command.
In the HTTP handler below, a graph description input parameter is extracted from the dot querystring variable.
Graph descriptions can include characters which must be URL encoded for use in a querystring.
Node.js
Python
Go
Java
You'll need to differentiate between internal server errors and invalid user input. This sample service returns an Internal Server Error for all dot command-line errors unless the error message contains the string syntax, which indicates a user input problem.
Generating a diagram
The core logic of diagram generation uses the dot command-line tool to process the graph description input parameter into a diagram in the PNG image format.
Node.js
Python
Go
Java
Designing a secure service
Any vulnerabilities in the dot tool are potential vulnerabilities of the web service. You can mitigate this by using up-to-date versions of the graphviz package through re-building the container image on a regular basis.
If you extend the current sample to accept user input as command-line parameters, you should protect against command-injection attacks. Some of the ways to prevent injection attacks include:
- Mapping inputs to a dictionary of supported parameters
- Validating inputs match a range of known-safe values, perhaps using regular expressions
- Escaping inputs to ensure shell syntax is not evaluated
Shipping the code
To ship your code, you build with Cloud Build, and upload to Container Registry, and deploy to Knative serving:
- Run the following command to build your container and publish on Container Registry. - Node.js- gcloud builds submit --tag gcr.io/PROJECT_ID/graphviz - Where PROJECT_ID is your Google Cloud project ID, and - graphvizis 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/graphviz - Where PROJECT_ID is your Google Cloud project ID, and - graphvizis 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/graphviz - Where PROJECT_ID is your Google Cloud project ID, and - graphvizis 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. - JavaThis 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/graphviz-base - Where PROJECT_ID is your Google Cloud project ID. 
- Build your final container with Jib and publish on Container Registry: - mvn compile jib:build \ -Dimage=gcr.io/PROJECT_ID/graphviz \ -Djib.from.image=gcr.io/PROJECT_ID/graphviz-base - Where PROJECT_ID is your Google Cloud project ID. 
 
- Deploy using the following command: - gcloud run deploy graphviz-web --create-if-missing --image gcr.io/PROJECT_ID/graphviz - Where PROJECT_ID is your Google Cloud project ID, and - graphvizis the name of the container from above and- graphviz-webis the name of the service.- Wait until the deployment is complete: this can take about half a minute. 
- If you want to deploy a code update to the service, repeat the previous steps. Each deployment to a service creates a new revision and automatically starts serving traffic when ready. 
Try it out
Try out your service by sending HTTP POST requests with DOT syntax descriptions in the request payload.
- Send an HTTP request to your service. - You can embed the diagram in a web page: -  To obtain the external IP for the Load Balancer, run the following command: kubectl get svc istio-ingressgateway -n ASM-INGRESS-NAMESPACE Replace ASM-INGRESS-NAMESPACE with the namespace where your Cloud Service Mesh ingress is located. Specify istio-systemif you installed Cloud Service Mesh using its default configuration.The resulting output looks similar to the following: NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) istio-ingressgateway LoadBalancer XX.XX.XXX.XX pending 80:32380/TCP,443:32390/TCP,32400:32400/TCP where the EXTERNAL-IP value is your external IP address of the Load Balancer. 
- Run a curl command using this - EXTERNAL-IPaddress in the URL. Do not include the protocol (e.g.:- http://) in- SERVICE_DOMAIN.- curl -G -H "Host: SERVICE_DOMAIN" http://EXTERNAL-IP/diagram.png \ --data-urlencode "dot=digraph Run { rankdir=LR Code -> Build -> Deploy -> Run }" \ > diagram.png 
 
-  
- Open the resulting - diagram.pngfile in any application that supports- PNGfiles, such as Chrome.- It should look like this:   - Source: DOT Description 
You can explore a small collection of ready-made diagram descriptions.
- Copy the contents of the selected .dotfile
- Paste it into a - curlcommand:- curl -G -H "Host: SERVICE_DOMAIN" http://EXTERNAL-IP/diagram.png \ --data-urlencode "dot=digraph Run { rankdir=LR Code -> Build -> Deploy -> Run }" \ > diagram.png 
Clean up
You can delete the resources created for this tutorial to avoid incurring costs.
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 container image named gcr.io/<var>PROJECT_ID</var>/graphvizfrom Container Registry.
- If you created a cluster for this tutorial, delete the cluster.
 
- Delete the container image named 
What's next
- Experiment with your graphviz app: - Add support for other graphviz utilities which apply different algorithms to diagram generation.
- Save diagrams to Cloud Storage. Do you want to save the image or the DOT syntax?
- Implement content abuse protection with Cloud Natural Language API.
 
- Explore reference architectures, diagrams, and best practices about Google Cloud. Take a look at our Cloud Architecture Center.