Create your first Knative app

Knative is a great way to get started quickly on serverless development with Kubernetes.
Register or Login to like
Working from home at a laptop

Knative is an open source community project that adds components to Kubernetes for deploying, running, and managing serverless, cloud-native applications. It enables more productive development with less interaction with Kubernetes' infrastructure.

There is a large amount of information out there about Knative, networking, and serverless deployments, and this introductory tutorial covers just a bite-size amount of it. In this walkthrough, I'll use Knative with Minikube to create a Knative app—a simple container that prints messages in response to a curl command or in a web browser at a link provided by the deployment.

First, some background

Knative uses custom resource definitions (CRDs), a network layer, and a service core. For this walkthrough, I used Ubuntu 18.04, Kubernetes 1.19.0, Knative 0.17.2, and Kourier 0.17.0 as the Knative networking layer, as well as the Knative command-line interface (CLI).

A CRD is a custom resource definition within Kubernetes. A resource is an endpoint in the Kubernetes API that stores a collection of API objects of a certain kind; for example, the built-in pod's resource contains a collection of pod objects. This allows an expansion of the Kubernetes API with new definitions. One example is the Knative serving core, which is defined to have internal autoscaling and rapid deployment of pods with the correct roles and access predefined.

Kourier is an Ingress (a service to let in external network traffic) for Knative serving and a lightweight alternative for the Istio ingress. Its deployment consists only of an Envoy proxy and a control plane for it.

To understand the concepts in this tutorial, I recommend you are somewhat familiar with:

  • Serverless, cloud-native applications
  • Ingress with Envoy proxies, i.e., Istio
  • DNS in Kubernetes
  • Kubernetes patching configurations
  • Custom resource definitions in Kubernetes
  • Configuring YAML files for Kubernetes

Set up and installation

There are some prerequisites you must do before you can use Knative.

Configure Minikube

Before doing anything else, you must configure Minikube to run Knative locally in your homelab. Below are the configurations I suggest and the commands to set them:

$ minikube config set kubernetes-version v1.19.0
$ minikube config set memory 4000
$ minikube config set cpus 4

To make sure those configurations are set up correctly in your environment, run the Minikube commands to delete and start your cluster:

$ minikube delete
$ minikube start

Install the Knative CLI

You need the Knative CLI to make a deployment, and you need Go v1.14 or later to work with the CLI. I created a separate directory to make it easier to find and install these tools. Use the following commands to set up the command line:

$ mkdir knative
$ cd knative/
$ git clone
$ cd client/
$ hack/ -f
$ sudo cp kn /usr/local/bin
$ kn version
Version:        v20201018-local-40a84036
Build Date:   2020-10-18 20:00:37
Git Revision: 40a84036
Supported APIs:
* Serving
  - (knative-serving v0.18.0)
* Eventing
  - (knative-eventing v0.18.0)
  - (knative-eventing v0.18.0)

Once the CLI is installed, you can configure Knative in the Minikube cluster.

Install Knative

Since Knative is composed of CRDs, much of its installation uses YAML files with kubectl commands. To make this easier, set up some environment variables in the terminal so that you can get the needed YAML files a little faster and in the same version:

$ export KNATIVE="0.17.2"

First, apply the service resource definitions:

$ kubectl apply -f$KNATIVE/serving-crds.yaml

Then apply the core components to Knative:

$ kubectl apply -f$KNATIVE/serving-core.yaml

This deploys the services and deployments to the namespace knative-serving. You may have to wait a couple of moments for the deployment to finish.

To confirm the deployment finished, run the kubectl command to get the deployments from the namespace:

$ kubectl get deployments -n knative-serving
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
3scale-kourier-control   1/1    1               1               107m
activator               1/1     1               1               108m
autoscaler              1/1     1               1               108m
controller              1/1     1               1               108m
webhook                 1/1     1               1               108m

Install Kourier

Because you want to use a specific version and collect the correct YAML file, use another environment variable:

$ export KOURIER="0.17.0"

Then apply your networking layer YAML file:

$ kubectl apply -f$KOURIER/kourier.yaml

You will find the deployment in the kourier-system namespace. To confirm the deployment is correctly up and functioning, use the kubectl command to get the deployments:

$ kubectl get deployments -n kourier-system
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
3scale-kourier-gateway   1/1    1               1               110m

Next, configure the Knative serving to use Kourier as default. If you don't set this, the external networking traffic will not function. Set it with this kubectl patch command:

$ kubectl patch configmap/config-network \
  --namespace knative-serving \
  --type merge \
  --patch '{"data":{"ingress.class":""}}'

Configure the DNS

Before you can access the load balancer, you need to run the minikube tunnel command in a separate terminal window. This command creates a route to services deployed with type LoadBalancer and sets their Ingress to their ClusterIP. Without this command, you will never get an External-IP from the load balancer. Your output will look like this:

    machine: minikube
    pid: 57123
    route: ->
    minikube: Running
    services: [kourier]
         minikube: no errors
         router: no errors
         loadbalancer emulator: no errors
    machine: minikube
    pid: 57123
    route: ->
    minikube: Running
    services: [kourier]
         minikube: no errors
         router: no errors
         loadbalancer emulator: no errors

Now that the services and deployments are complete, configure the DNS for the cluster. This enables your future deployable application to support DNS web addresses. To configure this, you need to get some information from your Kourier service by using the kubectl get command:

$ kubectl get service kourier -n kourier-system
NAME    TYPE            CLUSTER-IP      EXTERNAL-IP     PORT(S)                        
kourier   LoadBalancer   80:32676/TCP,443:30558/TCP

Get the CLUSTER-IP address and save it for the next step. Next, configure the domain to determine your internal website on local DNS. (I ended mine in, and you can also use This requires another kubectl patch command:

$ kubectl patch configmap -n knative-serving config-domain -p "{\"data\": {\"\": \"\"}}"

Once it's patched, you will see this output:

configmap/config-domain patched

Use the Knative CLI

Now that your configurations are done, you can create an example application to see what happens.

Deploy a service

Earlier in this walkthrough, you installed the Knative CLI, which is used for Serving and Eventing resources in a Kubernetes cluster. This means you can deploy a sample application and manage services and routes. To bring up the command-line menu, type kn. Here is a snippet of the output:

$ kn
kn is the command line interface for managing Knative Serving and Eventing resources

 Find more information about Knative at:

Serving Commands:
  service       Manage Knative services
  revision      Manage service revisions
  route         List and describe service routes

Next, use the Knative CLI to deploy a basic "hello world" application with a web frontend. Knative provides some examples you can use; this one does a basic deployment:

kn service create hello --image

Your output should look something like this:

$ kn service create hello --image
Creating service 'hello' in namespace 'default':

  0.032s The Configuration is still working to reflect the latest desired specification.
  0.071s The Route is still working to reflect the latest desired specification.
  0.116s Configuration "hello" is waiting for a Revision to become ready.
 34.908s ...
 34.961s Ingress has not yet been reconciled.
 35.020s unsuccessfully observed a new generation
 35.208s Ready to serve.

Service 'hello' created to latest revision 'hello-dydlw-1' is available at URL:

This shows that the service was deployed with a URL into the namespace default. You can deploy to another namespace by running something like the following, then look at the output:

$ kn service create hello --image --namespace hello
Creating service 'hello' in namespace 'hello':

  0.015s The Configuration is still working to reflect the latest desired specification.
  0.041s The Route is still working to reflect the latest desired specification.
  0.070s Configuration "hello" is waiting for a Revision to become ready.
  5.911s ...
  5.958s Ingress has not yet been reconciled.
  6.043s unsuccessfully observed a new generation
  6.213s Ready to serve.

Service 'hello' created to latest revision 'hello-wpbwj-1' is available at URL:

Test your new deployment

Check to see if the new service you deployed is up and running. There are two ways to check:

  1. Check your web address in a browser
  2. Run a curl command to see what returns

If you check the address in a web browser, you should see something like this:

Good! It looks like your application's frontend is up!

Next, test the curl command to confirm everything works from the command line. Here is an example of a curl to my application and the output:

$ curl
Hello World!

Interact with the Knative app

From here, you can use the Knative CLI to make some basic changes and test the functionality. Describe the service and check the output:

$ kn service describe hello
Name:           hello
Namespace:  default
Age:            12h

  100%  @latest (hello-dydlw-1) [1] (12h)
        Image: (pinned to 5ea96b)

  OK TYPE                       AGE REASON
  ++ Ready                      12h
  ++ ConfigurationsReady        12h
  ++ RoutesReady                12h

It looks like everything is up and ready as you configured it. Some other things you can do with the Knative CLI (which won't show up now due to the minimal configuration in this example) are to describe and list the routes with the app:

$ kn route describe hello
Name:           hello
Namespace:  default
Age:            12h
Service:        hello

Traffic Targets:  
  100%  @latest (hello-dydlw-1)

  OK TYPE                       AGE REASON
  ++ Ready                      12h
  ++ AllTrafficAssigned         12h
  ++ CertificateProvisioned     12h TLSNotEnabled
  ++ IngressReady               12h
jess@Athena:~/knative/client$ kn route list hello
NAME    URL                                     READY
hello   True

This can come in handy later when you need to troubleshoot issues with your deployments.

Clean up

Just as easily as you deployed your application, you can clean it up:

$ kn service delete hello
Service 'hello' successfully deleted in namespace 'default'.

jess@Athena:~/knative/client$ kn service delete hello --namespace hello
Service 'hello' successfully deleted in namespace 'hello'.

Make your own app

This walkthrough used an existing Knative example, but you are probably wondering about making something that you want. You are right, so I'll provide this example YAML then explain how you can apply it with kubectl and manage it with the Knative CLI.

Example YAML

: Service
: helloworld
: default
     - image
             - containerPort
: 8080
        - name
: "This is my app"

Save this to apps.yaml, and then you can make changes to some things. For example, you can change your metadata, name, and namespace. You can also change the value of the target (which I set to This is my app) so that, rather than Hello World, you'll see a new message that says Hello ${TARGET} ! when you deploy the file.

To deploy a file like this, you will have to use kubectl apply -f apps.yaml.

First, deploy your new service using the apply command:

$ kubectl apply -f apps.yaml created

Next, you can describe your new deployment, which is the name provided in the YAML file:

$ kn service describe helloworld
Name:           helloworld
Namespace:  default
Age:            50s

  100%  @latest (helloworld-qfr9s) [1] (50s)
        Image: (at 5ea96b)

  OK TYPE                       AGE REASON
  ++ Ready                      43s
  ++ ConfigurationsReady        43s
  ++ RoutesReady                43s

Run a curl command to confirm it produces the new output you defined in your YAML file:

$ curl
Hello This is my app!

Double-check by going to the simple web frontend.

This proves your application is running! Congratulations!

Final thoughts

Knative is a great way for developers to move quickly on serverless development with networking services that allow users to see changes in apps immediately. It is fun to play with and lets you take a deeper dive into serverless and other exploratory uses of Kubernetes!

What to read next
User profile image.
Tech nomad, working in about anything I can find. Evangelist of silo prevention in the IT space, the importance of information sharing with all teams. Believer in educating all and open source development. Lover of all things tech. All about K8s, chaos and anything new and shiny I can find!

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.