knative

À la fin de chaque formation k8s utilisation, nous notons que les stagiaires voient bien l’intérêt de k8s en terme de possibilités de déploiements. Toutefois, ces possibilités se noient dans une certaine complexité de mise en œuvre. Et c’est encore plus vrai pour un public de développeurs. Knative serait-il la réponse à cette frustration ?

Public visé : utilisateurs k8s et développeurs

Par Jacques Roussel, Cloud Consultant @Objectif Libre

Définition

Knative est un framework serverless. Cela signifie que c’est un outil qui permet l’exécution de code (peu importe le langage) sans se soucier ni du ou des serveurs sous-jacents pour l’exécution, ni du « routing » réseau pour y accéder. En résumé, on dit à la plateforme « exécute tel code », et c’est tout. En outre, la plateforme gère aussi le scaling automatique de votre application.

Mise en place de l’environnement

Pré-requis

Pour cet environnement de démonstration, vous aurez besoin d’une vm de 8vcpu et 16Go de ram sous ubuntu 18.04. Attention au CPU et à la ram car l’ensemble est assez gourmand. Sur cette vm, nous déploierons k8s, calico, helm, istio et enfin knative.

Installation de k8s

Pour l’installation de k8s, vous pouvez utiliser le script suivant :

#!/bin/bash
#
# install.sh
#

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" |sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo swapoff -a
sudo kubeadm init --pod-network-cidr=192.168.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
USER_UID=$(id -u)
USER_GID=$(id -g)
sudo chown ${USER_UID}:${USER_GID} $HOME/.kube/config
MASTER_NAME=$(kubectl get no -o=jsonpath='{.items[0].metadata.name}')
kubectl taint node ${MASTER_NAME} node-role.kubernetes.io/master:NoSchedule-
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

Puis vous l’exécutez :

bash install.sh

À ce stade, vous devriez avoir un k8s fonctionnel avec un seul nœud. Avant de continuer, vérifiez bien que le cluster est Ready :

kubectl get no
NAME         STATUS   ROLES    AGE   VERSION
k8s-master   Ready    master   15m   v1.14.1

Installation de helm

curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
tar -xvzf helm-v2.13.1-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/

Préparons ensuite le fichier pour le service account tiller :

# tiller.yml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

Il faut ensuite créer le serviceaccount et déployer tiller :

kubectl apply -f tiller.yml
helm init --service-account tiller

Attendons un peu et vérifions que tiller est bien déployé :

helm version
Client: &version.Version{SemVer:"v2.13.1", GitCommit:"618447cbf203d147601b4b9bd7f8c37a5d39fbb4", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.13.1", GitCommit:"618447cbf203d147601b4b9bd7f8c37a5d39fbb4", GitTreeState:"clean"}

Installation d’istio

Istio est le service mesh sur lequel repose knative. Il est donc nécessaire de le déployer.

curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.1.5 sh -
cd istio-1.1.5/
helm install install/kubernetes/helm/istio-init --name istio-init --namespace istio-system

Il faut attendre que tous les CRD montent. Il doit y en avoir 53 :

kubectl get crds | grep 'istio.io\|certmanager.k8s.io' | wc -l
53

Terminons ensuite l’installation d’istio :

helm install install/kubernetes/helm/istio --name istio --namespace istio-system

Avant de passer à la suite, il faut bien attendre que tous les composants istio soient fonctionnels :

kubectl get pods -n istio-system
NAME                                      READY   STATUS      RESTARTS   AGE
istio-citadel-86b5b9fb58-425gf            1/1     Running     0          2m46s
istio-galley-5b98bd6859-qnx5z             1/1     Running     0          2m46s
istio-ingressgateway-65576f8745-hjghv     1/1     Running     0          2m46s
istio-init-crd-10-6t6zn                   0/1     Completed   0          6m31s
istio-init-crd-11-vdh4n                   0/1     Completed   0          6m31s
istio-pilot-78fff96ddf-wxsvm              2/2     Running     0          2m46s
istio-policy-5fb895b86d-b2m9p             2/2     Running     1          2m46s
istio-sidecar-injector-855966f687-pjzq6   1/1     Running     0          2m46s
istio-telemetry-75bc675d7d-4cd29          2/2     Running     2          2m46s
prometheus-d8d46c5b5-mfglm                1/1     Running     0          2m46s

Installation de knative

À présent, il nous reste à déployer knative. Cela passe par des manifests k8s :

kubectl label namespace default istio-injection=enabled
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.5.0/serving.yaml --filename https://github.com/knative/build/releases/download/v0.5.0/build.yaml --filename https://github.com/knative/eventing/releases/download/v0.5.0/release.yaml --filename https://github.com/knative/eventing-sources/releases/download/v0.5.0/eventing-sources.yaml --filename https://github.com/knative/serving/releases/download/v0.5.0/monitoring.yaml --filename https://raw.githubusercontent.com/knative/serving/v0.5.0/third_party/config/build/clusterrole.yaml
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.5.0/serving.yaml --filename https://github.com/knative/build/releases/download/v0.5.0/build.yaml --filename https://github.com/knative/eventing/releases/download/v0.5.0/release.yaml --filename https://github.com/knative/eventing-sources/releases/download/v0.5.0/eventing-sources.yaml --filename https://github.com/knative/serving/releases/download/v0.5.0/monitoring.yaml --filename https://raw.githubusercontent.com/knative/serving/v0.5.0/third_party/config/build/clusterrole.yaml

Nous lançons la commande deux fois à cause des issues suivantes : 968 et 1036.

Attendons ensuite que tout soit démarré :

kubectl get pods --namespace knative-serving
kubectl get pods --namespace knative-build
kubectl get pods --namespace knative-eventing
kubectl get pods --namespace knative-sources
kubectl get pods --namespace knative-monitoring

Nous sommes maintenant prêts à utiliser knative.

Utilisation

L’idée ici est de montrer comment, d’un dépôt de code, il est possible d’arriver au déploiement d’une application. Pour cela, vous aurez besoin d’un espace dans une registry quelconque. Dans cet article, j’utiliserai le dockerhub.

Configurer la partie build

Préparez le fichier push-account.yml :

# push-account.yml
apiVersion: v1
kind: Secret
metadata:
  name: basic-user-pass
  annotations:
    build.knative.dev/docker-0: https://index.docker.io/v1/
type: kubernetes.io/basic-auth
data:
  username: REDACTED
  password: REDACTED
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-bot
secrets:
  - name: basic-user-pass

ATTENTION le username et le password doivent être en base64.

Il faut créer le secret et ajouter le template de base pour construire notre application :

kubectl apply -f push-account.yml
kubectl apply --filename https://raw.githubusercontent.com/knative/build-templates/master/kaniko/kaniko.yaml

Ce template requiert la présence d’un Dockerfile à la racine du projet git.

Construire et déployer son application

# deploy.yml
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
  name: app-from-source
  namespace: default
spec:
  runLatest:
    configuration:
      build:
        apiVersion: build.knative.dev/v1alpha1
        kind: Build
        spec:
          serviceAccountName: build-bot
          source:
            git:
              url: https://github.com/ObjectifLibre/knative-article.git
              revision: master
          template:
            name: kaniko
            arguments:
              - name: IMAGE
                value: docker.io/jarou/knative-python-helloworld:latest
          timeout: 10m
      revisionTemplate:
        metadata:
          annotations:
            autoscaling.knative.dev/minScale: "1"
            autoscaling.knative.dev/target: "10"
        spec:
          container:
            image: docker.io/jarou/knative-python-helloworld:latest
            imagePullPolicy: Always

ATTENTION Pensez à changer l’url de push par la vôtre, sinon le push ne fonctionnera pas.

On notera ici deux valeurs ajoutées : autoscaling.knative.dev/minScale qui dit à knative de toujours garder une instance running et autoscaling.knative.dev/target: « 10 » qui baisse la valeur des connexions entrantes pour le scaling (100 par défaut).

Nous pouvons à présent déployer notre application :

kubectl apply -f deploy.yml

Notre application est en cours de build et déploiement.

kubectl get po
NAME                                                READY   STATUS      RESTARTS   AGE
app-from-source-bms72-pod-ea603c                    0/1     Completed   0          111s
app-from-source-qhpp5-deployment-6f5b85b68f-mppxt   3/3     Running     0          15s

Pour vérifier :

INGRESSGATEWAY=istio-ingressgateway
INGRESSGATEWAY_LABEL=istio
IP_ADDRESS=$(kubectl get po --selector $INGRESSGATEWAY_LABEL=ingressgateway --namespace istio-system --output 'jsonpath={.items[0].status.hostIP}'):$(kubectl get svc $INGRESSGATEWAY --namespace istio-system --output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')
curl -H "Host: app-from-source.default.example.com" http://${IP_ADDRESS}

Voyons si l’auto-scaling fonctionne :

curl -LO https://storage.googleapis.com/jblabs/dist/hey_linux_v0.1.2
chmod +x hey_linux_v0.1.2
kubectl get po
app-from-source-bms72-pod-ea603c                    0/1     Completed   0          20m
app-from-source-qhpp5-deployment-6f5b85b68f-mppxt   3/3     Running     0          19m
./hey_linux_v0.1.2 -z 30s -c 50 -host app-from-source.default.example.com http://${IP_ADDRESS}
kubectl get po
NAME                                                READY   STATUS      RESTARTS   AGE
app-from-source-bms72-pod-ea603c                    0/1     Completed   0          20m
app-from-source-qhpp5-deployment-6f5b85b68f-7mk6f   3/3     Running     0          28s
app-from-source-qhpp5-deployment-6f5b85b68f-mppxt   3/3     Running     0          19m
app-from-source-qhpp5-deployment-6f5b85b68f-qhvgx   3/3     Running     0          30s
app-from-source-qhpp5-deployment-6f5b85b68f-rw9d6   3/3     Running     0          30s
app-from-source-qhpp5-deployment-6f5b85b68f-vpxdv   3/3     Running     0          28s

Conclusion

Nous avons pu voir dans cet article la mise en place de knative ainsi qu’une utilisation simple de celui-ci. En effet, nous n’avons fait que déployer un bout de code python qui ne fait rien. Cependant, si l’on regarde le contenu du dépôt source, on s’aperçoit que seul le fichier contenant le code et un Dockerfile sont présents. Or à la fin du déploiement, j’ai une fonction qui tourne et qui scale en n’ayant rien fait de plus. Le pari semble donc gagné.
Si vous êtes développeur et que vous souhaitez vous mettre à une approche plus serverless voir eventdriven, knative est sans doute un produit à regarder !