Service est un objet kubernetes. Son « shorname » est svc. Le détail de l’objet est disponible ici.
Publier un pod à travers un Deployment au sein d’un namespace est une chose, le rendre accessible à l’intérieur et à l’extérieur du cluster en est une autre.
C’est pour couvrir ce besoin qu’il existe l’objet Service.
Un Service va permettre d’exposer vos pods pour qu’ils puissent se solliciter les uns les autres et également les rendre accessibles à l’extérieur de votre cluster si nécessaire.
Un pod s’exécute sur un node (un serveur physique ou virtuel). Ce node est sur un réseau “externe” qui n’est pas celui de votre pod.
Votre pod dispose d’une IP dans un subnet spécifique, interne au cluster et établie à l’installation de ce dernier. Par défaut seul les conteneurs qui sont présents au sein de votre pod peuvent discuter les uns avec les autres puisqu’ils se partagent cette même IP.
Si vous souhaitez à minima exposer les applications de ce pod à vos autres pods, il vous faudra passer par un Service.
Les Services disposent également de leur propre subnet interne, lui aussi déclaré à l'installation du cluster. Comme pour le subnet des pods, ce réseau n’est pas routé en dehors du cluster.
Un Service peut être déployé principalement selon trois types:
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
Personnellement, en interne j’ai plutôt tendance à associer un load balancer autonome hors kubernetes qui renvoie vers des ports type 443/80 pour lesquelles j’ai configuré un Ingress Controler, qui lui-même pilote des Ingress rattaché à des Services type ClusterIP pour router mes demandes fonction de mes urls. Mais ce n’est pas l’objectif de l’article.
Déclarer un service se fait comme d’habitude avec un fichier yaml.
Exemple pour un ClusterIP:
---
apiVersion: v1
kind: Service
metadata:
name: mon-service-cluster-ip
spec:
selector:
app: ma-super-app
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
Exemple pour un NodePort:
---
apiVersion: v1
kind: Service
metadata:
name: mon-service-node-port
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
nodePort: 32765
selector:
app: ma-super-app
type: NodePort
Exemple pour LoadBalancer:
---
apiVersion: v1
kind: Service
metadata:
name: mon-service-node-loadbalancer
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
nodePort: 30216
selector:
run: ma-super-app
type: LoadBalancer
La section spec de l’objet permet d’indiquer le type de Service. Fonction du type de Service, certaines options peuvent différées les unes des autres avec néanmoins toujours une base commune.
Comme expliqué pour l’objet Deployment, kubernetes se base sur des labels pour associer les objets entre eux. Il en va de même pour les Services pour lesquels il faudra renseigner dans la section selection les labels des pods pour lesquels ils vont devoir fournir l’accessibilité.
C'est de cette manière qu'un service se raccroche à un pod.
Si vous voulez exposer un pod « ma-super-apps » via un service type NodePort , il faudra que votre pod « ma-super-apps » dispose des labels correspondant aux règles de sélection de votre service.
Le déploiement d'un service à partir de son fichier yaml est à l'identique de tous objets kubernetes:
kubectl apply -f monservice.yaml
Cliquez sur l'image pour l'agrandir.
une fois vos Services en place, il suffit d'utiliser la commande suivante pour les lister:
kubectl get svc
Cliquez sur l'image pour l'agrandir.
(pour l'illustration j'utilise un namespace spécifique d'ou l'ajout du suffixe -n)
Davantage de détails vous sont accessibles, si vous utilisez la commande:
kubectl describe mon_service
Cliquez sur l'image pour l'agrandir.
Vous y retrouverez l'IP de votre service et les labels qu'il utilise pour identifier les pods auquels il doit se rattacher.
Très pratique également la commande:
kubectl get endpoints
Elle vous permet de savoir si votre service est "orphelin" n'ayant trouvé aucun pod correspondant à ce qu'il a dans sa propriété selector
Cliquez sur l'image pour l'agrandir.
ou si au contraire il est bien rattaché à un ou des pods avec dans ce cas la liste des IPs de ces pods dans la colonne "ENDPOINT"
Cliquez sur l'image pour l'agrandir.
Les Service ont un rôle capital au sein de l’infrastructure kubernetes. Peu importe le type choisi, il est important de bien comprendre la logique de routage interne à K8S.
En dehors même de la problématique de choisir un provider réseaux au sein de votre cluster, gardez en tête quelques principes de bases, à commencer par l’existence d’un podSubnet et d’un serviceSubnet au sein de votre cluster.
Dans les deux cas, il s’agit de réseau interne à votre cluster qu’il vous est possible de choisir au déploiement de ce dernier (ne choisissez donc jamais des réseaux routés existants dans votre infra pour cela).
Chaque pod se voit assigner une IP issue du podSubnet et chaque service se voit associer une IP issue du serviceSubnet.
La communication d’un service et d’un pod se fait donc via un routage entre ces deux subnets avec l’usage d’un port de sortie propre au service et un port d’entrée propre au pod.
C’est la machinerie interne à K8S, le choix d’un service type ClusterIP, NodePort, LoadBalancer est surtout lié à la manière dont vous allez exposer votre service et à son périmètre d'exposition.
Globalement on retrouve dans les Services, des notions propres au load balancing. Pour ceux qui manipuleraient des outils de ce type (HAproxy, Netscaler, F5…), vous devriez retrouver des logiques communes.