Services

Cette page décrit les services Kubernetes et leur utilisation dans Google Kubernetes Engine (GKE). Pour apprendre à créer un service, consultez la page Exposer des applications à l'aide de services.

Qu'est-ce qu'un service ?

Dans l'idée, un service consiste à regrouper un ensemble de points de terminaison de pods 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 ?

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

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 HTTP(S) externe utilise un service du type NodePort. Pour en savoir plus, consultez la page Configurer l'équilibrage de charge HTTP(S) avec l'objet Entrée.

Veuillez noter qu'un équilibreur de charge HTTP(S) est un serveur proxy qui, en tant que tel, diffère fondamentalement de l'équilibreur de charge réseau décrit sur cette page dans la section Service du type LoadBalancer.

Services de type LoadBalancer

Lorsque vous créez un service de type LoadBalancer, Google Cloud configure un équilibreur de charge réseau dans votre projet. L'équilibreur de charge a une adresse IP stable accessible depuis l'extérieur du projet.

Un équilibreur de charge réseau n'est pas un serveur proxy. Il achemine les paquets sans modification vers les adresses IP source et de destination.

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

apiVersion: v1
kind: Service
metadata:
  name: my-nlb-service
spec:
  selector:
    app: metrics
    department: engineering
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080

Après avoir créé le service, vous pouvez consulter sa spécification et voir l'adresse IP externe stable à l'aide de la commande kubectl get service -o yaml :

spec:
  clusterIP: 10.11.242.115
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32676
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: metrics
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
  status:
    loadBalancer:
      ingress:
      - ip: 203.0.113.100

Dans le résultat, l'adresse IP de l'équilibreur de charge réseau figure sous loadBalancer:ingress:. Les clients externes appellent le service en utilisant l'adresse IP externe de l'équilibreur de charge ainsi que le port TCP spécifié par port. La requête est transmise à l'un des pods membres du port TCP spécifié par targetPort. Dans l'exemple précédent, le client appelle le service à l'adresse 203.0.113.100 sur le port TCP 80. 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 LoadBalancer est une extension du type NodePort, qui est une extension du type ClusterIP.

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.

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 du service, d'autres parties de l'abstraction sont appliquées par l'équilibrage de charge réseau ou l'équilibrage de charge HTTP(S).

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.

Étapes suivantes