Créer un service et un objet Ingress

Ce document explique comment créer un objet Ingress Kubernetes dans un cluster utilisateur, hybride ou autonome pour GKE sur Bare Metal. Une entrée est associée à un ou plusieurs services, chacun étant associé à un ensemble de pods.

Avant de commencer

Obtenez une connexion SSH entre votre cluster et votre poste de travail d'administrateur.

Créer un déploiement

Voici un fichier manifeste de déploiement.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
spec:
  selector:
    matchLabels:
      greeting: hello
  replicas: 3
  template:
    metadata:
      labels:
        greeting: hello
    spec:
      containers:
      - name: hello-world
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50000"
      - name: hello-kubernetes
        image: "gcr.io/google-samples/node-hello:1.0"
        env:
        - name: "PORT"
          value: "8080"

Pour les besoins de cet exercice, voici les points importants à comprendre concernant le fichier manifeste de déploiement :

  • Chaque pod appartenant au déploiement possède le libellé greeting: hello.

  • Chaque pod possède deux conteneurs.

  • Les champs env spécifient que les conteneurs hello-app écoutent sur le port TCP 50000 et que les conteneurs node-hello écoutent sur le port TCP 8080. Pour hello-app, vous pouvez examiner l'effet de la variable d'environnement PORT en consultant le code source.

Copiez le fichier manifeste dans un fichier nommé hello-deployment.yaml, puis créez le déploiement :

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-deployment.yaml

Remplacez CLUSTER_KUBECONFIG par le nom du fichier kubeconfig de votre cluster.

Exposer votre déploiement avec un service

Pour fournir aux clients un moyen stable d'envoyer des requêtes aux pods de votre déploiement, créez un service.

Voici un fichier manifeste pour un objet Service qui expose votre objet déploiement aux clients de votre cluster :

apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  type: ClusterIP
  selector:
    greeting: hello
  ports:
  - name: world-port
    protocol: TCP
    port: 60000
    targetPort: 50000
  - name: kubernetes-port
    protocol: TCP
    port: 60001
    targetPort: 8080

Copiez le fichier manifeste dans un fichier nommé hello-service.yaml, puis créez le service :

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-service.yaml

Remplacez CLUSTER_KUBECONFIG par le nom du fichier kubeconfig de votre cluster.

Consultez le Service :

kubectl --kubeconfig CLUSTER_KUBECONFIG get service hello-service --output yaml

La sortie affiche la valeur clusterIP qui a été attribuée au service. Exemple :

apiVersion: v1
kind: Service
metadata:
  annotations:
    ...
spec:
  clusterIP: 10.96.14.249
  clusterIPs:
  - 10.96.14.249
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    greeting: hello
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

Dans le résultat précédent, le champ ports est un tableau d'objets ServicePort : l'un nommé world-port et l'autre nommé kubernetes-port. Pour en savoir plus sur les champs de service, consultez la page ServiceSpec dans la documentation de Kubernetes.

Voici comment un client peut appeler le service :

  • À l'aide de world-port : un client s'exécutant sur l'un des nœuds de cluster envoie une requête au clusterIP sur le port. Dans cet exemple, 10.96.14.249:60000. La requête est transférée à un pod membre sur le targetPort. Dans cet exemple, POD_IP_ADDRESS:50000.

  • À l'aide de kubernetes-port : un client s'exécutant sur l'un des nœuds de cluster envoie une requête au clusterIP sur le port. Dans cet exemple, 10.96.14.249:60001. La requête est transférée à un pod membre sur le targetPort. Dans cet exemple, POD_IP_ADDRESS:8080.

Composants d'Ingress

Voici quelques-uns des composants de cluster liés à l'entrée :

  • Le déploiement istio-ingress. Il s'agit du proxy d'entrée. Le proxy d'entrée transfère le trafic vers les services internes conformément aux règles spécifiées dans un objet Ingress.

  • Le service istio-ingress. Ce service expose le déploiement istio-ingress.

  • Le déploiement istiod. Il s'agit du contrôleur d'entrée. Le contrôleur d'entrée surveille la création des objets Ingress et configure le proxy d'entrée en conséquence.

Tous ces composants Istio internes au cluster sont installés dans l'espace de noms gke-system. Cet espace de noms n'entre pas en conflit avec une installation Istio/Anthos Service Mesh complète.

Créer un objet Ingress

Voici un fichier manifeste d'Entrée :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
      paths:
      - path: /greet-the-world
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60000
      - path: /greet-kubernetes
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60001

Copiez le manifeste dans un fichier nommé my-ingress.yaml et créez l'Ingress :

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress.yaml

Lorsque vous créez un cluster d'utilisateur, vous spécifiez une valeur pour loadbalancer.ingressVIP dans le fichier de configuration du cluster. Cette adresse IP est configurée sur l'équilibreur de charge du cluster. Lorsque vous créez une entrée, celle-ci reçoit la même adresse IP virtuelle que son adresse IP externe.

Lorsqu'un client envoie une requête à votre adresse IP virtuelle d'entrée de cluster d'utilisateur, la requête est acheminée vers votre équilibreur de charge. L'équilibreur de charge utilise le service istio-ingress pour transférer la requête au proxy d'entrée qui s'exécute dans votre cluster d'utilisateur. Le proxy d'entrée est configuré pour transférer la requête à différents backends en fonction du chemin d'accès dans l'URL de la requête.

Chemin d'accès /greet-the-world

Dans votre fichier manifeste d'entrée, vous pouvez trouver une règle indiquant que le chemin d'accès /greet-the-world est associé à serviceName: hello-service et servicePort: 60000. Rappelez-vous que 60000 est la valeur port dans la section world-port de votre service hello-service.

- name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000

Le service d'entrée transfère la requête à l'adresse clusterIP:50000. La requête est ensuite transmise à l'un des pods membres du service hello-service. Le conteneur qui écoute sur le port 50000 dans ce pod affiche le message Hello World!.

Chemin d'accès /greet-kubernetes

Dans votre fichier manifeste d'entrée, vous pouvez trouver une règle indiquant que le chemin d'accès /greet-kubernetes est associé à serviceName: hello-service et servicePort: 60001. Rappelez-vous que 60001 est la valeur port dans le champ kubernetes-port de votre service hello-service.

- name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080

Le service d'entrée transfère la requête à l'adresse clusterIP: 8080. La requête est ensuite transmise à l'un des pods membres du service hello-service. Le conteneur qui écoute sur le port 8080 dans ce pod affiche le message Hello Kubernetes!.

Tester l'objet Ingress

Testez l'entrée à l'aide du chemin d'accès /greet-the-world :

curl CLUSTER_INGRESS_VIP/greet-the-world

Remplacez CLUSTER_INGRESS_VIP par l'adresse IP externe de l'objet Ingress.

Le résultat affiche un message Hello, world! :

Hello, world!
Version: 2.0.0
Hostname: ...

Testez l'entrée à l'aide du chemin d'accès /greet-kubernetes :

curl CLUSTER_INGRESS_VIP/greet-kubernetes

Le résultat affiche un message Hello, Kubernetes! :

Hello Kubernetes!

Désactiver le Ingress intégré

La fonctionnalité Ingress intégrée avec GKE sur Bare Metal n'est compatible qu'avec la fonctionnalité d'entrée. Vous pouvez choisir d'intégrer Istio ou Anthos Service Mesh. Ces produits offrent des avantages supplémentaires d'un maillage de services entièrement fonctionnel, tels que le protocole TLS mutuel (mTLS), la possibilité de gérer l'authentification entre les services et l'observabilité des charges de travail. Si vous effectuez une intégration à Istio ou à Anthos Service Mesh, nous vous recommandons de désactiver la fonctionnalité d'Ingress groupée.

Vous pouvez activer ou désactiver l'Ingress groupée à l'aide du champ spec.clusterNetwork.bundledIngress dans le fichier de configuration de votre cluster. Ce champ n'est disponible que pour les clusters version 1.13.0 ou ultérieure. Le champ bundledIngress est défini par défaut sur true et n'est pas présent dans le fichier de configuration de cluster généré. Ce champ est modifiable et peut être modifié lorsque vous créez ou mettez à jour un cluster version 1.13.0 ou ultérieure. Vous pouvez également spécifier ce champ lorsque vous mettez à niveau un cluster vers la version 1.13.0 ou une version ultérieure.

L'exemple de fichier de configuration de cluster suivant montre comment configurer votre cluster pour désactiver la fonctionnalité Ingress groupée:

apiVersion: v1
kind: Namespace
metadata:
  name: cluster-hybrid-basic
---
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: hybrid-basic
  namespace: cluster-hybrid-basic
spec:
  type: hybrid
  profile: default
  anthosBareMetalVersion: 1.13.0
  gkeConnect:
    projectID: project-fleet
  controlPlane:
    nodePoolSpec:
      nodes:
      - address: 10.200.0.2
  clusterNetwork:
    bundledIngress: false
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - 10.96.0.0/20
...

Configurer HTTPS pour l'objet Ingress

Si vous souhaitez accepter les requêtes HTTPS de vos clients, le proxy d'entrée doit disposer d'un certificat pour justifier son identité auprès de vos clients. Ce proxy doit également disposer d'une clé privée pour effectuer le handshake HTTPS.

L'exemple suivant utilise ces entités :

  • Proxy d'entrée : participe au handshake HTTPS, puis transfère les paquets aux pods membres du service hello-service.

  • Domaine du service hello-service : altostrat.com dans l'exemple d'organisation

Procédez comme suit :

  1. Créez un certificat racine et une clé privée. Cet exemple utilise une autorité de certification racine root.ca.example.com dans l'exemple d'organisation de l'autorité de certification racine.

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj \
        '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key \
        -out root-ca.crt
    
  2. Créez une requête de signature de certificat :

     openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \
         "/CN=altostrat.com/O=Example Org"
    
  3. Créez un certificat de diffusion pour le proxy d'entrée.

    openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 \
        -in server.csr -out server.crt
    

    Vous avez à présent créé les certificats et les clés suivants :

    • root-ca.crt : certificat de l'autorité de certification racine
    • root-ca.key : clé privée de l'autorité de certification racine
    • server.crt : certificat de diffusion pour le proxy d'entrée
    • server.key : clé privée du proxy d'entrée
  4. Créez un secret Kubernetes contenant le certificat de diffusion et la clé.

    kubectl create secret tls example-server-creds --key=server.key --cert=server.crt \
        --namespace gke-system
    

    Le secret obtenu est nommé example-server-creds.

Créer un déploiement et un service

Si vous avez créé un déploiement et un service dans la partie HTTP de ce guide, conservez-les. Si ce n'est pas le cas, créez-les maintenant en suivant les étapes décrites pour HTTP.

Créer un objet Ingress

Si vous avez déjà créé un objet Ingress dans la partie HTTP, supprimez-le avant de continuer.

Supprimez l'objet Ingress :

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingress

Pour gérer le trafic du service que vous avez créé précédemment, créez un objet Ingres doté d'une section tls. Cette action permet de faire appliquer le protocole HTTPS entre les clients et le proxy d'entrée.

Voici un fichier manifeste d'Ingress :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress-2
spec:
  tls:
  - hosts:
    - altostrat.com
    secretName: example-server-creds
  rules:
  - host: altostrat.com
    http:
      paths:
      - path: /greet-the-world
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60000
      - path: /greet-kubernetes
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60001

Enregistrez le fichier manifeste dans un fichier nommé my-ingress-2.yaml, et créez l'objet Ingress :

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress-2.yaml

Confirmez en effectuant des tests.

  • Testez le chemin /greet-the-world :

    curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP\
        https://altostrat.com/greet-the-world \
        --cacert root-ca.crt
    

    Résultat :

    Hello, world!
    Version: 2.0.0
    Hostname: hello-deployment-5ff7f68854-wqzp7
    
  • Testez le chemin /greet-kubernetes :

    curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
        https://altostrat.com/greet-kubernetes --cacert root-ca.crt
    

    Résultat :

    Hello Kubernetes!
    

Créer un service LoadBalancer

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. Par défaut, Kubernetes alloue des ports de nœuds aux services LoadBalancer. Ces allocations peuvent rapidement épuiser les ports de nœuds disponibles parmi les 2 768 alloués à votre cluster. Pour enregistrer les ports des nœuds, désactivez l'allocation de ports des nœuds de l'équilibreur de charge en définissant le champ allocateLoadBalancerNodePorts sur false dans la spécification du service LoadBalancer. Ce paramètre empêche Kubernetes d'attribuer des ports de nœud aux services LoadBalancer. Pour en savoir plus, consultez la section Désactiver l'allocation NodePort de l'équilibreur de charge dans la documentation de Kubernetes.

Voici un fichier manifeste permettant de créer un service qui n'utilise aucun port de nœud:

apiVersion: v1
kind: Service
metadata:
  name: service-does-not-use-nodeports
spec:
  selector:
    app: my-app
  type: LoadBalancer
  ports:
  - port: 8000
  # Set allocateLoadBalancerNodePorts to false
  allocateLoadBalancerNodePorts: false

Nettoyer

Supprimez l'entrée :

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAME

Remplacez INGRESS_NAME par le nom de l'objet Ingress, par exemple my-ingress ou my-ingress-2.

Supprimez le service :

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-service

Supprimez le déploiement :

kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deployment

Supprimez le service LoadBalancer:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service service-does-not-use-nodeports