Services


Cette page décrit les services Kubernetes et leur utilisation dans Google Kubernetes Engine (GKE). Il existe différents types de services, que vous pouvez utiliser pour regrouper un ensemble de points de terminaison de pod en une seule ressource. Pour apprendre à créer un service, consultez la page Exposer des applications à l'aide de services.

Qu'est-ce qu'un service Kubernetes ?

Dans l'idée, un service consiste à regrouper un ensemble de points de terminaison de pod dans une seule ressource. Vous pouvez configurer différents types d'accès à ce regroupement. Par défaut, vous obtenez une adresse IP de cluster stable que les clients du cluster peuvent utiliser afin de contacter les pods du service. Un client envoie une requête à l'adresse IP stable, et la requête est acheminée vers l'un des pods du service.

Un service identifie ses pods membres à l'aide d'un sélecteur. Pour qu'un pod soit membre du service, il doit comporter tous les libellés spécifiés dans le sélecteur. Un libellé est une paire clé/valeur arbitraire associée à un objet.

Le fichier manifeste du service ci-dessous a un sélecteur qui spécifie deux libellés. Le champ selector indique que tous les pods comportant les libellés app: metrics et department:engineering sont membres de ce service.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Pourquoi utiliser un service Kubernetes ?

Dans un cluster Kubernetes, chaque pod dispose d'une adresse IP interne. Cependant, les pods d'un déploiement vont et viennent et leurs adresses IP changent. Il n'est donc pas logique d'utiliser directement les adresses IP des pods. Avec un service, vous obtenez une adresse IP stable qui dure toute la vie du service, même lorsque les adresses IP des pods membres changent.

Un service fournit également un équilibrage de charge. Les clients appellent une seule adresse IP stable, et leurs requêtes sont équilibrées entre les pods membres du service.

Types de services Kubernetes

Il existe cinq types de services :

  • ClusterIP (valeur par défaut) : les clients internes envoient des requêtes à une adresse IP interne stable.

  • NodePort : les clients envoient des requêtes à l'adresse IP d'un nœud sur une ou plusieurs valeurs nodePort spécifiées par le service.

  • LoadBalancer : les clients envoient des requêtes à l'adresse IP d'un équilibreur de charge réseau.

  • ExternalName : les clients internes utilisent le nom DNS d'un service comme alias pour un nom DNS externe.

  • Sans adresse IP de cluster : un service sans adresse IP de cluster vous permet de regrouper des pods sans disposer d'une adresse IP stable.

Le type NodePort est une extension du type ClusterIP. Ainsi, un service de type NodePort a une adresse IP de cluster.

Le type LoadBalancer est une extension du type NodePort. Ainsi, un service de type LoadBalancer a une adresse IP de cluster ainsi qu'une ou plusieurs valeurs nodePort.

Services de type ClusterIP

Lorsque vous créez un service de type ClusterIP, Kubernetes crée une adresse IP stable accessible à partir des nœuds du cluster.

Voici le fichier manifeste d'un service de type ClusterIP :

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Vous pouvez créer le service à l'aide de la commande kubectl apply -f [MANIFEST_FILE]. Après avoir créé le service, vous pouvez utiliser kubectl get service pour afficher l'adresse IP stable :

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
my-cip-service   ClusterIP   10.11.247.213   none          80/TCP

Les clients du cluster appellent le service à l'aide de l'adresse IP du cluster et du port TCP spécifié dans le champ port du fichier manifeste du service. La requête est transmise à l'un des pods membres du port TCP spécifié dans le champ targetPort. Dans l'exemple précédent, un client appelle le service à l'adresse 10.11.247.213 sur le port TCP 80. La requête est transmise à l'un des pods membres sur le port TCP 8080. Le pod membre doit disposer d'un conteneur qui écoute sur le port TCP 8080. Si aucun conteneur n'écoute sur le port 8080, les clients verront un message du type "Échec de la connexion" ou "Ce site est inaccessible".

Services de type NodePort

Lorsque vous créez un service de type NodePort, Kubernetes vous attribue une valeur nodePort. Le service est ensuite accessible en utilisant l'adresse IP de n'importe quel nœud ainsi que la valeur nodePort.

Voici le fichier manifeste d'un service de type NodePort :

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Après avoir créé le service, vous pouvez consulter sa spécification et voir la valeur nodePort à l'aide de la commande kubectl get service -o yaml.

spec:
  clusterIP: 10.11.254.114
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32675
    port: 80
    protocol: TCP
    targetPort: 8080

Les clients externes appellent le service en utilisant l'adresse IP externe d'un nœud ainsi que le port TCP spécifié par nodePort. La demande est transmise à l'un des pods membres du port TCP spécifié dans le champ targetPort.

Par exemple, supposons que l'adresse IP externe de l'un des nœuds du cluster soit 203.0.113.2. Ensuite, pour l'exemple précédent, le client externe appelle le service à l'adresse 203.0.113.2 sur le port TCP 32675. La requête est transmise à l'un des pods membres sur le port TCP 8080. Le pod membre doit avoir un conteneur à l'écoute sur le port TCP 8080.

Le type de service NodePort est une extension du type de service ClusterIP. Les clients internes ont donc deux moyens d'appeler le service :

  • Utiliser clusterIP et port
  • Utiliser l'adresse IP d'un nœud et nodePort

Pour certaines configurations de cluster, l'équilibreur de charge d'application externe utilise un service de type NodePort.

Pour en savoir plus, consultez la page Configurer un équilibreur de charge d'application externe avec Ingress.

Un équilibreur de charge d'application externe est un serveur proxy qui, en tant que tel, diffère fondamentalement de l'équilibreur de charge réseau externe à stratégie directe décrit dans cette rubrique sous Services de type LoadBalancer.

Services de type LoadBalancer

Pour en savoir plus sur les services de type LoadBalancer, consultez la page Concepts de services LoadBalancer.

Services de type ExternalName

Un service de type ExternalName fournit un alias interne à un nom DNS externe. Les clients internes effectuent des requêtes à l'aide du nom DNS interne, qui sont redirigées vers le nom externe.

Voici le fichier manifeste d'un service de type ExternalName :

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

Lorsque vous créez un service, Kubernetes crée un nom DNS qui peut permettre aux clients internes d'appeler le service. Pour l'exemple précédent, le nom DNS est my-xn-service.default.svc.cluster.local. Lorsqu'un client interne envoie une requête à my-xn-service.default.svc.cluster.local, celle-ci est redirigée vers example.com.

Le type de service ExternalName est fondamentalement différent des autres types de service. En fait, un service de type ExternalName ne correspond pas à la définition du service donnée au début de cette page. Un service de type ExternalName n'est pas associé à un ensemble de pods et n'a pas d'adresse IP stable. À la place, un service de type ExternalName est le mappage entre un nom DNS interne et un nom DNS externe.

Service sans adresse IP de cluster

Un service sans adresse IP de cluster est un type de service Kubernetes qui n'alloue pas d'adresse IP de cluster. À la place, un service sans adresse IP de cluster utilise le DNS pour exposer les adresses IP des pods associés au service. Cela vous permet de vous connecter directement aux pods au lieu de passer par un proxy.

Les services sans adresse IP de cluster sont utiles dans de nombreux cas de figure. En voici quelques exemples :

  • Équilibrage de charge entre les pods : vous pouvez utiliser des services sans adresse IP de cluster pour équilibrer la charge sur les pods. Pour ce faire, créez un service avec un sélecteur correspondant aux pods pour lesquels vous souhaitez équilibrer la charge. Le service répartit alors le trafic de manière uniforme entre tous les pods correspondant au sélecteur.

  • Détection de services : vous pouvez utiliser un service sans adresse IP de cluster pour mettre en œuvre la détection de services. Pour ce faire, créez un service avec un nom et un sélecteur. L'enregistrement DNS du service sans adresse IP de cluster contient toutes les adresses IP des pods derrière le service qui correspondent au sélecteur. Les clients peuvent utiliser ces enregistrements DNS pour trouver les adresses IP des pods associés au service.

  • Accès direct aux pods : les clients peuvent se connecter directement aux pods associés à un service sans adresse IP de cluster, ce qui peut être utile pour les services nécessitant un accès direct aux pods sous-jacents, tels que les équilibreurs de charge et les serveurs DNS.

  • Flexibilité : les services sans adresse IP de cluster peuvent servir à créer diverses topologies, telles que des équilibreurs de charge, des serveurs DNS et des bases de données distribuées.

Si vous avez des exigences réseau particulières pour vos charges de travail qui ne peuvent pas être résolues en utilisant des services sans adresse IP de cluster avec des sélecteurs, il est également possible d'utiliser des services sans adresse IP de cluster sans sélecteurs. Les services sans adresse IP de cluster sont un outil utile pour accéder aux services qui ne se trouvent pas dans le cluster Kubernetes, car le plan de contrôle ne crée pas d'objets EndpointSlice. Consultez la section Service sans sélecteurs pour en savoir plus.

L'exemple suivant est un fichier manifeste pour un service sans adresse IP de cluster :

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
  - name: http
    port: 80
    targetPort: 80

Une fois que vous avez créé un service sans adresse IP de cluster, vous pouvez rechercher les adresses IP des pods associés au service en interrogeant le DNS. Par exemple, la commande suivante répertorie les adresses IP des pods associés au service nginx :

dig +short nginx.default.svc.cluster.local

Autre exemple utilisant l'extension des requêtes Kubernetes :

dig +short +search nginx

Vous pouvez créer un service sans adresse IP de cluster avec une seule commande, et les services sans adresse IP de cluster sont faciles à mettre à jour et à faire évoluer.

kubectl create service clusterip my-svc --clusterip="None" --dry-run=client -o yaml > [file.yaml]

Abstraction de service

Un service est une abstraction dans le sens où il ne s'agit pas d'un processus à l'écoute d'une interface réseau. Une partie de l'abstraction est appliquée dans les règles iptables des nœuds du cluster. Selon le type de service, d'autres parties de l'abstraction sont mises en œuvre par un équilibreur de charge réseau externe à stratégie directe ou un équilibreur de charge d'application externe.

Ports de services arbitraires

La valeur du champ port dans un fichier manifeste de service est arbitraire. La valeur de targetPort, quant à elle, ne l'est pas. Chaque pod membre doit avoir un conteneur à l'écoute sur targetPort.

Voici un service, de type LoadBalancer, dont le champ port a une valeur de 50000 :

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641
    port: 50000
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

Un client appelle le service à l'adresse 203.0.113.200 sur le port TCP 50000. La requête est transmise à l'un des pods membres sur le port TCP 8080.

Plusieurs ports

Le champ ports d'un service est un tableau d'objets ServicePort. L'objet ServicePort comporte les champs suivants :

  • name
  • protocol
  • port
  • targetPort
  • nodePort

Si vous avez plusieurs objets ServicePort, chacun d'eux doit avoir un nom unique.

Voici un service, de type LoadBalancer, qui comporte deux objets ServicePort :

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: my-second-service-port
    nodePort: 31081
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    app: tests
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.201

Dans l'exemple précédent, si un client appelle le service à l'adresse 203.0.113.201 sur le port TCP 60000, la requête est transmise à un pod membre sur le port TCP 50000. Cependant, si un client appelle le service à l'adresse 203.0.113.201 sur le port TCP 60001, la requête est transmise à un pod membre sur le port TCP 8080.

Chaque pod membre doit avoir un conteneur d'écoute sur le port TCP 50000 et un conteneur d'écoute sur le port TCP 8080. Il peut s'agir d'un conteneur unique avec deux threads ou de deux conteneurs s'exécutant dans le même pod.

Points de terminaison d'un service

Lorsque vous créez un service, Kubernetes crée un objet Endpoints avec un nom identique à celui de votre service. Kubernetes utilise l'objet Endpoints dans le but de savoir quels pods sont membres du service.

Services à pile unique et à double pile

Vous pouvez créer un service IPv6 de type ClusterIP ou NodePort. GKE est compatible avec les services à deux piles de type LoadBalancer pendant le preview, qui ne bénéficie d'aucun contrat de niveau de service ni d'aucune assistance technique.

Pour chacun de ces types de service, vous pouvez définir les champs ipFamilies et ipFamilyPolicy en tant que service IPv4, IPv6 ou à double pile.

Étapes suivantes