Knative, smoothly, on K3S
I am starting today a new series of articles parallel to the Kubernetes one, dedicated to Knative which I discovered a short time ago thanks to SΓ©bastien Blanc (opens new window) (RedHat) which made last month several exciting presentations (opens new window)
# π¬π§ Knative, the tool that makes Kubernetes lovable
Knative in one sentence: it is an abstraction thought to make Kubernetes more "developer-friendly".
In other words, this tool will allow you to simplify your development workflow ("I don't care how it works, I just want to deploy my applications").
Knative is composed of two main elements:
- Knative Serving for deploying applications (what interests us today)
- Knative Eventing for event management (we will come back to this in future articles)
In the first articles in this series, I would deal with Knative Serving.
# Installation
As for the previous articles, to understand how it works, I like to install everything on my machine (π little important reminder, I wrote everything with a "developer vision"), so once again we will run all this locally and on K3S using Multipass.
The documentation (opens new window) of Knative is pretty well done, so I'm pretty much just following it and applying it in a Multipass context.
# K3S cluster creation
Knative provides its own network layer, so we need to install K3S without Traefik
- Create a
2k-cluster
directory - Create a
config
directory inside the2k-cluster
directory (we'll store in it the configuration file of our cluster:k3s.yaml
) - Next, inside
2k-cluster
, type the following commands:
vm_name="cluster-2k-vm"
vm_cpus=3
vm_mem="8G"
vm_disk="10GB"
knative_version="0.14.0"
# mount the config directory
multipass mount config ${vm_name}:config
# install k3s
multipass --verbose exec ${vm_name} -- sudo -- bash <<EOF
curl -sfL https://get.k3s.io | sh -s - --disable traefik
EOF
# get the IP address of the Multipass VM
IP=$(multipass info ${vm_name} | grep IPv4 | awk '{print $2}')
# get the cluster configuration file
multipass exec ${vm_name} sudo cat /etc/rancher/k3s/k3s.yaml > config/k3s.yaml
sed -i '' "s/127.0.0.1/$IP/" config/k3s.yaml
β I'm under OSX, if you're using Linux, replace
sed -i '' "s/127.0.0.1/$IP/" config/k3s.yaml
bysed -i "s/127.0.0.1/$IP/" config/k3s.yaml
. Or use coreutils (opens new window) for OSX
Before resume, be sure that all the system pods of K3S are "loaded" by using this command:
export KUBECONFIG=$PWD/config/k3s.yaml
kubectl get pods --namespace kube-system
You should get something like this:
NAME READY STATUS RESTARTS AGE
local-path-provisioner-58fb86bdfd-zhc2l 1/1 Running 0 10m
metrics-server-6d684c7b5-4dw68 1/1 Running 0 10m
coredns-6c6bb68b64-2d6zk 1/1 Running 0 10m
So, now, we have a running K3S cluster, and we can deploy Knative on it.
# Deploy Knative Serving component
π Knative Serving needs an Ingress Gateway to route request to the services. Usually, Istio is used, but some other are possible. We'll use Kourier (opens new window) which is a lightweight alternative, and it's a good thing when running on K3S.
multipass --verbose exec ${vm_name} -- sudo -- bash <<EOF
# Install Knative Serving
kubectl apply --filename "https://github.com/knative/serving/releases/download/v${knative_version}/serving-crds.yaml"
kubectl apply --filename "https://github.com/knative/serving/releases/download/v${knative_version}/serving-core.yaml"
# Install and configure Kourier
kubectl apply --filename https://raw.githubusercontent.com/knative/serving/v${knative_version}/third_party/kourier-latest/kourier.yaml
kubectl patch configmap/config-network --namespace knative-serving --type merge --patch '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'
EOF
Check the status of the pods (be sure that all have a Running
status):
kubectl get pods --namespace knative-serving
kubectl get pods --namespace kourier-system
Then you can veriffy that Kourier has obtained an external IP for the LoadBalancer:
kubectl --namespace kourier-system get service kourier
If all is allright, you should get this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kourier LoadBalancer 10.43.126.243 192.168.64.70 80:32717/TCP,443:32167/TCP 62m
The external IP matches your cluster IP
Now, it's time to apply a last setting. To manage the DNS part, we'll use the "easy": the xip.io (opens new window) service:
multipass --verbose exec ${vm_name} -- sudo -- bash <<EOF
# Configure xip.io DNS
kubectl apply --filename "https://github.com/knative/serving/releases/download/v${knative_version}/serving-default-domain.yaml"
EOF
Do a last test:
kubectl get pods --namespace knative-serving
The default-domain
pod should have a Completed
status:
NAME READY STATUS RESTARTS AGE
webhook-577576647-z5254 1/1 Running 0 87m
activator-65fc4d666-6c4nf 1/1 Running 0 87m
autoscaler-74b4bb97bd-x5m2d 1/1 Running 0 87m
controller-6b6978c965-jc79d 1/1 Running 0 87m
default-domain-rxfhj 0/1 Completed 0 21s
There it's done. Now we have a running K3S cluster with Knative. It's time to have fun.
ποΈ I created a project to easily reproduce the installation process:https://gitlab.com/knative-on-k3s/2k-cluster (opens new window)
# First deployment to Knative
We are going to create a NodeJS. Create a new directory named amazing-web-app
and add the following files to this directory:
index.js
package.json
Dockerfile
service.yaml
# index.js
const http = require('http')
const port = 8080
let index_page = `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: ${process.env.BACKGROUND_COLOR};
}
h1 {
font-family: "Source Sans Pro"; font-weight: 300; font-size: 100px;
display: block;
color: #${process.env.COLOR};
}
</style>
</head>
<body>
<h1>
${process.env.MESSAGE}
</h1>
</body>
</html>
`
const requestHandler = (request, response) => {
response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'})
response.end(index_page)
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
if (err) {
return console.log('π‘ something bad happened', err)
}
console.log(`π server is listening on ${port}`)
})
# package.json
{
"main": "index.js",
"scripts": {
"start": "node index.js"
}
}
# Dockerfile
FROM node:12-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --only=production
COPY . ./
CMD [ "npm", "start" ]
# service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: k-amazing-web-app
namespace: default
spec:
template:
spec:
containers:
- image: docker.io/k33g/k-amazing-web-app:latest
env:
- name: MESSAGE
value: "I π Knative"
- name: BACKGROUND_COLOR
value: "lemonchiffon"
- name: COLOR
value: "darkslateblue"
# Deployment
You have probably noticed that the yaml manifest is a lot simpler than usual. It's one of the good things you gain with Knative (and you'll see that we can do even better).
To deploy our webapp, you first need build the Docker image of it:
docker_user="your_docker_user"
docker_pwd="your_docker_password"
echo ${docker_pwd} | docker login --username ${docker_user} --password-stdin
docker build -t ${docker_user}/k-amazing-web-app .
docker push ${docker_user}/k-amazing-web-app
Once this is done, you can simply deploy:
kubectl apply --filename service.yaml
π That's all!
Type the below command:
kubectl get ksvc
You should get:
NAME URL
k-amazing-web-app http://k-amazing-web-app.default.192.168.64.70.xip.io
we've deployed on the
default
namespace
Use this URL with your browser:
# A more lovable deployment
Create a new directory sparkling-web-app
and copy the following files of the former example:
index.js
package.json
Dockerfile
ποΈ you don't need the service.yaml
file anymore π€
To do the job without the yaml file, we are going to use kn, the CLI of Knative.
You can find the Knative CLI project here: https://github.com/knative/client (opens new window) and the installation process here: https://github.com/knative/client/blob/master/docs/README.md#installing-kn (opens new window).
# Deployment (without the yaml file)
Of course, you need to build, before, the Docker image of the webapp:
echo ${docker_pwd} | docker login --username ${docker_user} --password-stdin
docker build -t ${docker_user}/sparkling-web-app .
docker push ${docker_user}/sparkling-web-app
And now, you can deploy (in a new namespace this time). We use the kn service create
command:
kubectl create namespace k-apps
kn service create sparkling-web-app \
--namespace k-apps \
--env MESSAGE="I π Knative" \
--env BACKGROUND_COLOR="mediumslateblue" \
--env COLOR="lightyellow" \
--image docker.io/k33g/sparkling-web-app
You will obtain the following output:
Creating service 'sparkling-web-app' in namespace 'k-apps':
0.294s The Route is still working to reflect the latest desired specification.
0.461s Configuration "sparkling-web-app" is waiting for a Revision to become ready.
6.200s ...
6.270s Ingress has not yet been reconciled.
6.458s Ready to serve.
Service 'sparkling-web-app' created to latest revision 'sparkling-web-app-cwxky-1' is available at URL:
http://sparkling-web-app.k-apps.192.168.64.70.xip.io
Now, use the URL in your browser:
π it' simple! π
# Deployment again (again without the yaml file)
To deploy again any updates, we'll use the kn service update
command:
kn service update sparkling-web-app \
--namespace k-apps \
--env MESSAGE="I πποΈ Knative" \
--env BACKGROUND_COLOR="crimson" \
--env COLOR="lightyellow" \
--image docker.io/k33g/sparkling-web-app
this time, we didn't change the source code but the value of the environment variables.
You will obtain the following output:
Updating Service 'sparkling-web-app' in namespace 'k-apps':
5.301s Traffic is not yet migrated to the latest revision.
5.382s Ingress has not yet been reconciled.
5.721s Ready to serve.
Service 'sparkling-web-app' updated to latest revision 'sparkling-web-app-ltxwx-2' i
s available at URL:
http://sparkling-web-app.k-apps.192.168.64.70.xip.io
Use the URL in your browser:
π As you can see, the use of Knative extremely simplify the use of Kubernetes. In the next blog posts, will see more features of this tool.
You can find the source code of the 2 examples here:
- https://gitlab.com/knative-on-k3s/amazing-web-app (opens new window)
- https://gitlab.com/knative-on-k3s/sparkling-web-app (opens new window)
Last Articles
- π«π· Type Result en Kotlin | 2020-10-31 | Kotlin
- π«π· Type Result en Kotlin | 2020-10-31 | Kotlin
- π¬π§ Every GitLab Page deserves a real CI/CD | 2020-07-23 | GitLab CI
- π«π· Lit-Element, commencer doucement | 2020-07-20 | WebComponent
- π¬π§ Build quickly and host easily your Docker images with GitLab and GitLab CI | 2020-06-02 | GitLab CI
- π¬π§ Deploy quickly on Clever Cloud with GitLab CI | 2020-05-31 | GitLab CI
- π«π· Borg Collective, mes jouets pour apprendre Knative | 2020-05-30 | Knative
- π¬π§ Borg Collective, Toys to learn Knative | 2020-05-30 | Knative
- π«π· M5Stack, une petit device IOT bien sympathique, programmable en Python | 2020-05-09 | IOT
- π«π· Knative, l'outil qui rend Kubernetes sympathique | 2020-05-02 | kubernetes