tunnel grid

Service Mesh : découverte et mise en oeuvre

Cet article est une introduction au Service Mesh ou « maillage de services », avec un focus sur Istio, dans un contexte Kubernetes.

Par Yann Provost, Consultant Cloud @ObjectifLibre.

Public visé : Administrateurs Kubernetes


What the Mesh ?

Trouver une explication simple du Service Mesh équivaut à passer par la Bretagne sans goûter au Kouign-amann : impossible.
Nous allons donc nous prêter au jeu et proposer une définition simple, en une phrase :

« Un Service Mesh s’apparente à une plateforme de contrôle et de gestion, sécurisée et performante de l’interconnexion entre tous les (micro) services d’une application »

Le plus souvent, il s’organise autour de deux composants d’architecture :

  • Un Control Plane, regroupant toutes les briques core : configuration, policies, authentification, expositions des métriques, etc.
  • Un Data Plane, maillage de proxys, qui pourront être présents :
    • au niveau d’un nœud ; on parle alors de Shared host proxy, déployé par un DaemonSet.
    • au niveau de chaque pod ; on parle alors de sidecar proxy, déployé par injection auprès d’un conteneur existant.

 

Ensemble, ces deux éléments vont permettre une administration des services réseau plus efficace, proposer de nouvelles fonctionnalités et notamment améliorer :

  • L’équilibrage de charge du trafic réseau de haut niveau (L7) HTTP, mais aussi TCP ou encore WebSocket
  • Les ACLs : white/blacklisting, accès à l’API, quotas
  • La collecte de traces réseau, métriques et logs
  • Le service-discovery
  • La sécurité inter-services (support TLS)

Voilà pour la vision générique du Service Mesh.

 

Who you gonna call ?

Plusieurs solutions existent actuellement pour mettre en œuvre votre Service Mesh. Il s’agira de choisir en fonction de vos besoins, de votre appétence ou de votre écosystème.
On ne fera pas une liste exhaustive, mais voici les principaux intervenants.

Les leaders

  • Istio
    Issu de la collaboration entre Google, IBM et Lyft. Il s’appuie sur le proxy Envoy. La plupart des acteurs évoluant autour de Kubernetes travaillent au développement de solutions basées sur Istio. C’est cette solution que nous allons détailler.
  • Linkerd (à prononcer Linker-dee)
    Premier Service Mesh à avoir vu le jour en 2016, mis au point par des ingénieurs de Twitter. Ils l’ont développé pour faciliter la résolution des problématiques d’échelle sur les infrastructures de très grandes tailles.
  • SuperGloo
    Très orienté haut niveau, c’est LA solution montante d’orchestration de services réseau de Solo.io. Il est devenu très populaire ces derniers mois. SuperGloo offre un Service Mesh beaucoup plus simple et automatisé que ses homologues. Il prend en charge le trafic ingress (nord-sud) et mesh (est-ouest). Les utilisateurs peuvent choisir n’importe quelle association ingress/mesh, SuperGloo s’occupe de tout et gère le fonctionnement de toutes les paires automatiquement.

Les outsiders

  • Consul
    HashiCorp pense que le principe du load-balancing n’est pas optimum : augmentation des coûts, SPOF, latence. L’idée est donc de miser sur une registry qui va rassembler toutes les informations sur les différents nœuds, services et composants de la plateforme. On parle alors de Service Discovery. Depuis sa version 1.2, Consul propose Connect, son propre Data Plane et sidecar proxy. Cependant, certaines fonctions (route L7, gateway) sont encore en version Beta. Pour cela, Connect propose une intégration avec Envoy (et d’autres proxys) afin de palier aux manques (et en attendant le plein développement de cette solution).
  • NGINX
    On ne présente plus l’entreprise ni le serveur web du même nom. Mais le développement de son propre Service Mesh est en cours, basé sur… Istio.
  • Envoy
    Le « sidecar proxy », utilisé notamment par la solution Istio, vise à développer son propre Service Mesh. À suivre de très près.

Istio sort du lot ?

Cet article visant aussi à vous présenter plus en détails le fonctionnement et les principes du Service Mesh, nous allons nous concentrer sur un produit, le mettre en œuvre et l’expliciter.
Le choix s’est porté sur Istio pour différentes raisons :

  • Très présent dans la communauté, notamment Kubernetes.
  • Reçoit le soutien de grands acteurs du domaine, comme RedHat (pour sa solution OpenShift).
  • S’appuie sur une référence en terme de sidecar proxy, à savoir Envoy.
  • Produit déjà orienté et pensé pour la production et l’exploitation, sûrement le plus abouti actuellement.

 

Comme on le voit sur ce schéma, Istio présente différentes briques qui ont des fonctions bien particulières au sein du Control Plane :

  • Mixer : gère le contrôle d’accès et la collecte de métriques depuis Envoy.
  • Pilot : gère le routage intelligent (a/b testing, canary deployment etc.) et résiliant (timeouts, tentatives d’essais etc.).
  • Citadel : gère les identités ainsi que l’authentification inter-services et utilisateur final.
  • Galley : sorte de meta composant, il va s’occuper de toute la configuration de tous les composants d’Istio et notamment la relation avec l’infrastructure sur laquelle il tourne.

.. et du Data Plane :

  • Envoy : proxy, déployé comme sidecar, va permettre de gérer tout le trafic par le service concerné. Il apporte de nombreuses fonctionnalités (load balancing, TLS, health checks etc.).

Ceci représente la BASE d’Istio. Nous allons voir que suivant le type d’installation et de briques ajoutées, d’autres composants peuvent être présents (pour rappel, nous ferons le focus sur la stack demo).

 

Mise en œuvre

Afin de plonger dans le vif du sujet, vous allez pouvoir suivre une procédure permettant d’obtenir un service Istio fonctionnel sur une plateforme Kubernetes (autour de minikube).
Suivez le guide et rendez-vous de l’autre coté !

Pré-requis (pour cette démo) :

  • Un système Ubuntu 16.04/18.xx
  • 16 Go de Ram / 4 vCPU

Optionnel :

  • Une solution de virtualisation (kvm, virtualbox etc.)

Installation de notre stack :

1\ Minikube

But : disposer de notre environnement, à savoir Kubernetes

# Installation de Docker

$ sudo apt-get install docker.io

# Récupération du binaire minikube

$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube
$ sudo install minikube /usr/local/bin

# Démarrage du cluster

$ sudo minikube start --memory=16384 --cpus=4 --kubernetes-version=v1.14.2 --vm-driver=none
$ sudo chown -R $USER $HOME/.kube $HOME/.minikube

# Récupération du binaire kubectl

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl

# Vérification du bon fonctionnement :

$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS
coredns-fb8b8dccf-mbz77 1/1 Running 0
coredns-fb8b8dccf-rt8mj 1/1 Running 0
etcd-minikube 1/1 Running 0
kube-addon-manager-minikube 1/1 Running 0
kube-apiserver-minikube 1/1 Running 0
kube-controller-manager-minikube 1/1 Running 0
kube-proxy-5v4gv 1/1 Running 0
kube-scheduler-minikube 1/1 Running 0
storage-provisioner 1/1 Running 0
tiller-deploy-7f656b499f-4ktj2 1/1 Running 0

2\ Helm

But : disposer du gestionnaire de packages Helm, pour ensuite déployer Istio

# Récupération du script d’installation

$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh

# Déploiement

$ ./get_helm.sh

# Installation, si manquant, de socat, nécessaire à Helm

$ sudo apt-get install socat

3\ Istio

# Récupération de la dernière version

$ curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.2.2 sh -

# Ajout du binaire istioctl dans le PATH

$ cd istio-1.2.2/
$ export PATH=$PWD/bin:$PATH

# Création du ServiceAccount et ClusterRoleBinding pour utiliser Helm

$ kubectl apply -f install/kubernetes/helm/helm-service-account.yaml

# Updgrade de tiller

$ helm init --upgrade --service-account tiller

# Déploiement des CRDs Istio

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

# Vérification de nombre de CRDs : il doit y en avoir 23 (et non 53 comme en version 1.1.x)

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

# Déploiement d’Istio en mode demo

/!\ Pour une utilisation hors cloud provider, il est nécessaire de modifier le type du service istio-ingressgateway de LoadBalancer à NodePort (grace à la directive --set gateways.istio-ingressgateway.type=NodePort)

$ helm install install/kubernetes/helm/istio --name istio --namespace istio-system --values install/kubernetes/helm/istio/values-istio-demo.yaml --set gateways.istio-ingressgateway.type=NodePort

# Vérification du déploiement

$ kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
grafana ClusterIP 10.111.12.28 <none> 3000/TCP
istio-citadel ClusterIP 10.105.178.155 <none> 8060/TCP,15014/TCP
istio-egressgateway ClusterIP 10.111.34.207 <none> 80/TCP,443/TCP,15443/TCP
istio-galley ClusterIP 10.109.117.14 <none> 443/TCP,15014/TCP,9901/TCP
istio-ingressgateway NodePort 10.100.108.48 <none> 15020:32378/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:30694/TCP,15030:30395/TCP,15031:31105/TCP,15032:32748/TCP,15443:31005/TCP
istio-pilot ClusterIP 10.106.251.175 <none> 15010/TCP,15011/TCP,8080/TCP,15014/TCP
istio-policy ClusterIP 10.110.158.161 <none> 9091/TCP,15004/TCP,15014/TCP
istio-sidecar-injector ClusterIP 10.104.47.230 <none> 443/TCP
istio-telemetry ClusterIP 10.111.71.245 <none> 9091/TCP,15004/TCP,15014/TCP,42422/TCP
jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP
jaeger-collector ClusterIP 10.103.76.38 <none> 14267/TCP,14268/TCP
jaeger-query ClusterIP 10.109.245.234 <none> 16686/TCP
kiali ClusterIP 10.99.45.168 <none> 20001/TCP
prometheus ClusterIP 10.108.186.42 <none> 9090/TCP
tracing ClusterIP 10.104.184.13 <none> 80/TCP
zipkin ClusterIP 10.102.89.77 <none> 9411/TCP
$ kubectl get po -n istio-system
NAME READY STATUS RESTARTS
grafana-6fb9f8c5c7-wp59t 1/1 Running 0
istio-citadel-68c85b6684-m8bhb 1/1 Running 0
istio-cleanup-secrets-1.2.2-dr7sj 0/1 Completed 0
istio-egressgateway-5f7889bf58-lnwq8 1/1 Running 0
istio-galley-77d697957f-plrdb 1/1 Running 0
istio-ingressgateway-8b858ff84-7458b 1/1 Running 0
istio-init-crd-10-r8c86 0/1 Completed 0
istio-init-crd-11-h7qmf 0/1 Completed 0
istio-init-crd-12-cfjzz 0/1 Completed 0
istio-pilot-5544b58bb6-6g2zz 2/2 Running 0
istio-policy-68946fb9b9-vcfb5 2/2 Running 2
istio-security-post-install-1.2.2-lmf6n 0/1 Completed 0
istio-sidecar-injector-66549495d8-ddtkr 1/1 Running 0
istio-telemetry-7749c6d54f-vn8h4 2/2 Running 0
istio-tracing-5d8f57c8ff-x7d87 1/1 Running 0
kiali-7d749f9dcb-rghlh 1/1 Running 0
prometheus-776fdf7479-xkmgw 1/1 Running 0

A ce stade, nous disposons de :

  • Kubernetes fonctionnel
  • Helm, qui nous a permis de déployer facilement la suite
  • Istio, déployé en mode démo : c’est-à-dire avec des outils permettant son exploitation/présentation (prometheus, grafana, Kiali etc.)

Par défaut, dans notre déploiement d’Istio, l’injection du sidecar Envoy sera presque automatique (via le contrôleur d’admission WebHook). Il suffit juste d’ajouter un label sur le ou les namespace(s) concerné(s).

# Exemple avec le namespace default:

$ kubectl label namespace default istio-injection=enabled

A partir de là, tous les pods créés dans ce namespace auront un conteneur supplémentaire : istio-proxy
Notons que la création d’un conteneur d’initialisation istio-init est également visible.

Et maintenant ?

Istio fournit un déploiement de test, qui va permettre de se rendre compte des possibilités qui nous sont offertes.
Cette application se nomme BookInfo et va prendre place dans le namespace default (sur lequel nous avons déjà activé l’injection du sidecar proxy).

$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

Vérifier ensuite que les services & pods soient up & running avec les commandes kubectl get svc et kubectl get po

  • On constate d’ailleurs que plusieurs versions de certains composants sont présentes.

Assurez-vous que l’application elle-même tourne correctement :

$ kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

 

 

Enfin, pour rendre l’application accessible depuis l’extérieur du cluster, nous allons utiliser un objet gateway :

$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

Une Gateway est une porte d’entrée depuis l’extérieur du cluster pointant directement vers Istio.

Similaire à l’ingress, elle va en revanche permettre de disposer de toutes les fonctionnalités fournies par le Service Mesh.

Ce manifest a également créé des objets VirtualService qui sont comparables aux vhosts traditionnels dans le monde Apache/NginX. Ils pourront être mis en relation ou non avec les DestinationRule mentionnés juste après.

Pour accéder à l’application, il conviendra de récupérer :

  • le port http ou https du service istio-ingressgateway dans le namespace istio-system
  • l’IP de votre host (ici dans une installation avec minikube)

On pourra alors tester et requêter l’application, via une commande curl ou dans un navigateur web :

$ curl -s http://IP:PORT_HTTP/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
  • BookInfo est désormais accessible depuis l’extérieur, via Istio.

Gestion du trafic et routage des versions d’application

Comme nous l’avons vu, il y a plusieurs versions cibles pour BookInfo :

kubectl get po
NAME READY STATUS RESTARTS
details-v1-5544dc4896-wtmk5 2/2 Running 0
productpage-v1-7868c48878-k2zkk 2/2 Running 0
ratings-v1-858fb7569b-jbmc7 2/2 Running 0
ratings-v2-dbd656795-xspd5 2/2 Running 0
reviews-v1-796d4c54d7-sz4v5 2/2 Running 0
reviews-v2-5d5d57db85-4r6rn 2/2 Running 0
reviews-v3-77c6b4bdff-tdwcf 2/2 Running 0

Pour bénéficier du routage en fonction des versions, il est nécessaire de créer pour chaque composants de l’application BookInfo une DestinationRule contenant les subsets de chaque version, avec leur label :

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml

Test par l’exemple

Nous pouvons alors mettre en place de l’A/B Testing sur le composant reviews:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 75
    - destination:
        host: reviews
        subset: v2
      weight: 25

 

Ici, nous orientons 75% du trafic vers la version v1 de reviews et 25% vers la version v2

Visualisation et métriques

Le déploiement d’Istio que nous avons mis en œuvre contient également des composants de collecte de métriques (prometheus) et des dashboards correspondants (grafana).

Pour y accéder, il est possible d’ouvrir un accès temporaire via un port-forward sur le composant adéquat :

$ kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 3000:3000

NB : l’ajout de --address 0.0.0.0 peut être utile dans le cas d’une machine distante.

 

 

De nombreuses informations sont disponibles concernant le trafic réseau, la consommation CPU, les vhosts etc.

Vous pouvez accéder également aux autres services de télémétries comme Kiali, Jaeger ou zipkin.

Administration d’Istio/Envoy

Le binaire istioctl permet de consulter l’état fonctionnel des proxys, leurs configurations ou encore d’injecter un sidecar

$ istioctl proxy-status
NAME CDS LDS EDS RDS PILOT VERSION
details-v1-5544dc4896-wtmk5.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
istio-egressgateway-5f7889bf58-lnwq8.istio-system SYNCED SYNCED SYNCED (100%) NOT SENT istio-pilot-5544b58bb6-6g2zz 1.2.2
istio-ingressgateway-8b858ff84-7458b.istio-system SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
mongodb-v1-679d664df4-4pcl9.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
productpage-v1-7868c48878-k2zkk.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
ratings-v1-858fb7569b-jbmc7.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
ratings-v2-dbd656795-xspd5.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
reviews-v1-796d4c54d7-sz4v5.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
reviews-v2-5d5d57db85-4r6rn.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
reviews-v3-77c6b4bdff-tdwcf.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-5544b58bb6-6g2zz 1.2.2
$ istioctl proxy-config cluster reviews-v1-796d4c54d7-sz4v5.default
SERVICE FQDN PORT SUBSET DIRECTION TYPE
BlackHoleCluster - - - STATIC
PassthroughCluster - - - ORIGINAL_DST
details.default.svc.cluster.local 9080 - outbound EDS
details.default.svc.cluster.local 9080 v1 outbound EDS
details.default.svc.cluster.local 9080 v2 outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-citadel.istio-system.svc.cluster.local 8060 - outbound EDS
istio-citadel.istio-system.svc.cluster.local 15014 - outbound EDS
istio-egressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-egressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-egressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-galley.istio-system.svc.cluster.local 443 - outbound EDS
istio-galley.istio-system.svc.cluster.local 9901 - outbound EDS
istio-galley.istio-system.svc.cluster.local 15014 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15020 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15029 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15030 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15031 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15032 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
[...]

En conclusion

Les possibilités offertes par le Service Mesh et Istio sont très nombreuses et ne pourraient être décrites en un seul article.
Il s’agissait donc, après sa mise en œuvre, de toucher du doigt les concepts et options offerts.

D’autres articles suivront, ils détailleront davantage l’éventail des bénéfices à tirer de l’ajout du Service Mesh à votre infrastructure, de l’adjonction d’un service d’API Gateway ou encore d’un Control Plane multi-cluster.

Stay tuned !

Pour aller plus loin