This is the sixth in a collection of articles as I explore serverless software development atop Kubernetes with Google/Pivotal Knative. The full set of articles are:
- Deploying 12-factor apps to Knative
- Building and deploying applications to Knative
- Adding public traffic to Knative on Google Kubernetes Engine
- Adding a custom hostname domain for Knative services
- Build Docker images inside your Kubernetes with Knative Build
- Binding secrets to Knative services
In the previous articles we’ve deployed a sample application with explicit environment variables as configuration.
knctl deploy \ --service simple-app \
--image index.docker.io/drnic/knative-simple-app \
--env SIMPLE_MSG="App container configured with this env var"
Yet Kubernetes has two first class resources for configuration: Secrets, and ConfigMaps. In this article we will look at how we can bind Secrets and ConfigMaps into our Knative services with --env-secret
and --env-config-map
flags.
This article uses improvements introduced in knctl v0.0.10 by Dmitriy & Dr Max.
Explicit Environment Variables
In the very first Knative blog post Deploying 12-factor apps to Knative we deployed a pre-existing Docker image, with an explicit environment variable to configure the application. For example:
knctl deploy \
--service simple-app \
--image index.docker.io/drnic/knative-simple-app \
--env SIMPLE_MSG="App container configured with this env var"
The knctl deploy
command also allows us to construct environment variables for our service using Kubernetes Secrets and ConfigMaps.
Secrets
To experiment, let’s create a Kubernetes secret simple-app-message
with a key message
.
kubectl create secret generic simple-app-message \
--from-literal=message="This message came from a Kube Secret"
In our previous articles we explicitly provided --env SIMPLE_MSG="some string"
which set the $SIMPLE_MSG
environment variable to an explicit value.
This time we want the environment variable to take on the value from the secret simple-app-message/message
– the simple-app-message
secret’s message
key.
We replace --env
flag with --env-secret
and knctl
will construct the appropriate Knative Serving manifest and deploy our service.
knctl deploy \
--service simple-app \
--image index.docker.io/drnic/knative-simple-app \
--env-secret SIMPLE_MSG=simple-app-message/message
Our deployed revision includes the secret baked into it as an environment variable.
$ knctl curl --service simple-app
Running: curl '-sS' '-H' 'Host: simple-app.default.knative.starkandwayne.com' 'http://35.197.73.136:80'
<h1>This message came from a Kube Secret</h1>
Succeeded
ConfigMap
Similarly you can pull in ConfigMap values with --env-config-map
instead of --env-secret
above.
To create an example configmap:
kubectl create configmap simple-app-configmap \
--from-literal=message="This message came from a Kube ConfigMap"
Now deploy again with --env-config-map
:
knctl deploy \
--service simple-app \
--image index.docker.io/drnic/knative-simple-app \
--env-config-map SIMPLE_MSG=simple-app-configmap/message
Our newly deployed revision includes the configmap baked into it as an environment variable.
$ knctl curl --service simple-app
Running: curl '-sS' '-H' 'Host: simple-app.default.knative.starkandwayne.com' 'http://35.197.73.136:80'
<h1>This message came from a Kube ConfigMap</h1>
Succeeded
Summary
Knative Serving subsystem, and the knctl deploy
CLI experience, support the ability for you to bind Kubernetes first-class Secrets and ConfigMap resources into your services.
Meanwhile…
I’ve recently been researching Service Catalog. This allows a Kubernetes user to provision external services — say a database managed by the cloud provider — and bind to them — say to generate a new user and store their credentials in Kubernetes Secrets. With knctl deploy --env-secret
we will now be able to combine Knative with Service Catalog. And thus, combine Knative with any externally managed service that offers an Open Service Broker API.
Stay tuned for an explanation of the following commands – provision a free external MySQL database, generate a user and credentials and store it in a secret called db
, and deploy your application with $DATABASE_URL
pointing to the remote database:
svcat provision db --class cleardb --plan spark
svcat bind db
knctl deploy --env-secret DATABASE_URL=db/uri ...