Creazione di un Servizio e un Ingress

Questo documento mostra come creare un oggetto Kubernetes Ingress in un cluster utente, ibrido o autonomo per GKE su Bare Metal. Un Ingress è associato a uno o più servizi, ognuno dei quali è associato a un insieme di pod.

Prima di iniziare

Ottieni una connessione SSH dal cluster alla workstation di amministrazione.

Creazione di un deployment

Ecco un manifest per un deployment:

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"

Ai fini di questo esercizio, ecco i punti importanti da comprendere in merito al manifest del deployment:

  • Ogni pod che appartiene al deployment ha l'etichetta greeting: hello.

  • Ogni pod ha due container.

  • I campi env specificano che i container hello-app sono in ascolto sulla porta TCP 50000, mentre i container node-hello sono in ascolto sulla porta TCP 8080. Per hello-app, puoi vedere l'effetto della variabile di ambiente PORT esaminando il codice sorgente.

Copia il manifest in un file denominato hello-deployment.yaml e crea il deployment:

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

Sostituisci CLUSTER_KUBECONFIG con il nome del file kubeconfig per il tuo cluster.

Esponi il deployment con un servizio

Crea un servizio per fornire ai client un modo stabile per inviare richieste ai pod del tuo deployment.

Ecco un manifest per un servizio che espone il tuo deployment ai client all'interno del 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

Copia il manifest in un file denominato hello-service.yaml e crea il servizio:

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

Sostituisci CLUSTER_KUBECONFIG con il nome del file kubeconfig per il tuo cluster.

Visualizza il servizio:

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

L'output mostra il valore di clusterIP che è stato assegnato al servizio. Ad esempio:

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: {}

Nell'output precedente, il campo ports è un array di oggetti ServicePort: uno denominato world-port e l'altro denominato kubernetes-port. Per ulteriori informazioni sui campi Service, vedi ServiceSpec nella documentazione di Kubernetes.

Ecco i modi in cui un cliente può chiamare il Servizio:

  • Utilizzo di world-port: un client in esecuzione su uno dei nodi del cluster invia una richiesta a clusterIP il giorno port. In questo esempio, 10.96.14.249:60000. La richiesta viene inoltrata a un pod membro il giorno targetPort. In questo esempio, POD_IP_ADDRESS:50000.

  • Con kubernetes-port: un client in esecuzione su uno dei nodi del cluster invia una richiesta a clusterIP il giorno port. In questo esempio, 10.96.14.249:60001. La richiesta viene inoltrata a un pod membro il giorno targetPort. In questo esempio, POD_IP_ADDRESS:8080.

Componenti Ingress

Questi sono alcuni dei componenti del cluster relativi al traffico in entrata:

  • Il deployment istio-ingress. Questo è il proxy in entrata. Il proxy Ingress inoltra il traffico ai servizi interni in base alle regole specificate in un oggetto Ingress.

  • Il Servizio istio-ingress. Questo servizio espone il deployment istio-ingress.

  • Il deployment istiod. Questo è il controller in entrata. Il controller in entrata controlla la creazione di oggetti Ingress e configura il proxy in entrata di conseguenza.

Tutti questi componenti Istio nel cluster sono installati nello spazio dei nomi gke-system. Questo spazio dei nomi non entra in conflitto con un'installazione completa di Istio/Anthos Service Mesh.

Crea una risorsa Ingress

Ecco un manifest per un Ingress:

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

Copia il manifest in un file denominato my-ingress.yaml e crea il file Ingress:

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

Quando crei un cluster utente, specifichi un valore per loadbalancer.ingressVIP nel file di configurazione del cluster. Questo indirizzo IP è configurato sul bilanciatore del carico del cluster. Quando crei una risorsa Ingress, alla risorsa viene assegnato lo stesso VIP del suo indirizzo IP esterno.

Quando un client invia una richiesta al VIP in entrata del cluster utente, la richiesta viene instradata al bilanciatore del carico. Il bilanciatore del carico utilizza il servizio istio-ingress per inoltrare la richiesta al proxy in entrata, che viene eseguito nel cluster utente. Il proxy in entrata è configurato per inoltrare la richiesta a backend diversi a seconda del percorso nell'URL della richiesta.

Il percorso /greet-the-world

Nel file manifest Ingress puoi vedere una regola che indica che il percorso /greet-the-world è associato a serviceName: hello-service e servicePort: 60000. Ricorda che 60.000 è il valore port nella sezione world-port del servizio hello-service.

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

Il servizio Ingress inoltra la richiesta a clusterIP:50000. La richiesta viene quindi inviata a uno dei pod membro del servizio hello-service. Il container nel pod in ascolto sulla porta 50000 mostra un messaggio Hello World!.

Il percorso /greet-kubernetes

Nel file manifest Ingress puoi vedere una regola che indica che il percorso /greet-kubernetes è associato a serviceName: hello-service e servicePort: 60001. Ricorda che 60001 è il valore port nella sezione kubernetes-port del servizio hello-service.

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

Il servizio Ingress inoltra la richiesta a clusterIP: 8080. La richiesta viene quindi inviata a uno dei pod membro del servizio hello-service. Il container nel pod in ascolto sulla porta 8080 mostra un messaggio Hello Kubernetes!.

Testa Ingress

Testa Ingress utilizzando il percorso /greet-the-world:

curl CLUSTER_INGRESS_VIP/greet-the-world

Sostituisci CLUSTER_INGRESS_VIP con l'indirizzo IP esterno della risorsa Ingress.

L'output mostra un messaggio Hello, world!:

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

Testa Ingress utilizzando il percorso /greet-kubernetes:

curl CLUSTER_INGRESS_VIP/greet-kubernetes

L'output mostra un messaggio Hello, Kubernetes!:

Hello Kubernetes!

Disattiva Ingress in bundle

La funzionalità Ingress in bundle con GKE su Bare Metal supporta solo la funzionalità in entrata. Puoi scegliere di eseguire l'integrazione con Istio o Anthos Service Mesh. Questi prodotti offrono ulteriori vantaggi di un mesh di servizi completamente funzionale, come TLS reciproca (mTLS), la capacità di gestire l'autenticazione tra i servizi e l'osservabilità dei carichi di lavoro. Se esegui l'integrazione con Istio o Anthos Service Mesh, ti consigliamo di disabilitare la funzionalità Ingress in bundle.

Puoi abilitare o disabilitare Ingress in bundle con il campo spec.clusterNetwork.bundledIngress nel file di configurazione del cluster. Questo campo è disponibile solo per i cluster dalla versione 1.13.0 e successive. Il campo bundledIngress per impostazione predefinita è true e non è presente nel file di configurazione del cluster generato. Questo campo è modificabile e può essere modificato quando crei o aggiorni un cluster alla versione 1.13.0 o successiva. Puoi specificare questo campo anche quando esegui l'upgrade di un cluster alla versione 1.13.0 o successive.

Il seguente file di configurazione del cluster di esempio mostra come configurare il cluster per disabilitare la funzionalità Ingress in bundle:

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
...

Configurazione di HTTPS per Ingress

Se vuoi accettare richieste HTTPS dai tuoi client, il proxy in entrata deve avere un certificato in modo da poter verificare la sua identità ai client. Questo proxy deve avere anche una chiave privata per completare l'handshake HTTPS.

Nell'esempio seguente vengono utilizzate queste entità:

  • Proxy in entrata: partecipa all'handshake HTTPS e poi inoltra i pacchetti ai pod membri del servizio hello-service.

  • Dominio per il servizio hello-service: altostrat.com in Organizzazione di esempio

Segui questi passaggi:

  1. Crea un certificato radice e una chiave privata. Questo esempio utilizza un'autorità di certificazione radice root.ca.example.com nell'organizzazione di esempio CA radice.

    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. Crea una richiesta di firma del certificato:

     openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \
         "/CN=altostrat.com/O=Example Org"
  3. Crea un certificato di pubblicazione per il proxy in entrata.

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

    Ora hai creato i seguenti certificati e chiavi:

    • root-ca.crt: certificato per l'autorità di certificazione principale
    • root-ca.key: chiave privata per la CA radice
    • server.crt: certificato di pubblicazione per il proxy in entrata
    • server.key: chiave privata per il proxy in entrata
  4. Crea un secret di Kubernetes che contenga il certificato e la chiave di gestione.

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

    Il secret risultante è denominato example-server-creds.

Crea un deployment e un servizio

Se hai creato un deployment e un servizio nella parte HTTP di questa guida, lasciali in posizione. In caso contrario, creali ora seguendo i passaggi descritti per HTTP.

Crea una risorsa Ingress

Se in precedenza hai creato una risorsa Ingress nella parte HTTP, eliminala prima di procedere.

Elimina la risorsa Ingress:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingress

Per gestire il traffico per il servizio creato in precedenza, crea un nuovo ingres con una sezione tls. In questo modo viene abilitato HTTPS tra i client e il proxy in entrata.

Ecco un manifest per un 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

Salva il manifest in un file denominato my-ingress-2.yaml e crea l'oggetto Ingress:

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

Conferma con il test.

  • Testa il percorso /greet-the-world:

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

    Output:

    Hello, world!
    Version: 2.0.0
    Hostname: hello-deployment-5ff7f68854-wqzp7
    
  • Testa il percorso /greet-kubernetes:

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

    Output:

    Hello Kubernetes!
    

Crea un servizio LoadBalancer

Il tipo LoadBalancer è un'estensione del tipo NodePort. Un servizio di tipo LoadBalancer ha quindi un indirizzo IP del cluster e uno o più valori nodePort. Per impostazione predefinita, Kubernetes alloca le porte dei nodi ai servizi LoadBalancer. Queste allocazioni possono esaurire rapidamente le porte dei nodi disponibili dalle 2768 assegnate al tuo cluster. Per salvare le porte dei nodi, disabilita l'allocazione delle porte dei nodi del bilanciatore del carico impostando il campo allocateLoadBalancerNodePorts su false nella specifica del servizio LoadBalancer. Questa impostazione impedisce a Kubernetes di assegnare le porte dei nodi ai servizi LoadBalancer. Per ulteriori informazioni, consulta Disabilitazione dell'allocazione di NodePort del bilanciatore del carico nella documentazione di Kubernetes.

Ecco un manifest per creare un servizio che non utilizza porte dei nodi:

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

Eseguire la pulizia

Elimina il tuo Ingress:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAME

Sostituisci INGRESS_NAME con il nome della risorsa Ingress, ad esempio my-ingress o my-ingress-2.

Elimina il servizio:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-service

Elimina il deployment:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deployment

Elimina il servizio LoadBalancer:

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