Creare un controller di ingresso HTTPS nel servizio Azure Kubernetes

Un controller di ingresso è un componente software che fornisce proxy inverso, routing del traffico configurabile e terminazione TLS per i servizi Kubernetes. Le risorse di ingresso Kubernetes vengono usate per configurare le regole di ingresso e le route per i singoli servizi Kubernetes. Usando un controller di ingresso e regole di ingresso è possibile servirsi di un singolo indirizzo IP per instradare il traffico a più servizi in un cluster Kubernetes.

Questo articolo illustra come distribuire il controller di ingresso NGINX in un cluster del servizio Azure Kubernetes. Il progetto cert-manager viene usato per generare e configurare automaticamente certificati Let's Encrypt. Infine, due applicazioni vengono eseguite nel cluster servizio Azure Kubernetes, ognuna delle quali è accessibile tramite un singolo indirizzo IP.

È anche possibile:

Prima di iniziare

Questo articolo presuppone che si disponga di un cluster del servizio Azure Kubernetes esistente. Se è necessario un cluster del servizio Azure Portale di Azure, vedere la guida introduttiva al servizio Azure Azure PowerShell usando l'interfaccia della riga di comando di Azureportale di Azure .

Questo articolo presuppone anche che l'utente abbia un dominio personalizzato con una zona DNS nello stesso gruppo di risorse del cluster del servizio Web AKS.

Questo articolo usa Helm 3 per installare il controller di ingresso NGINX in una versione supportata di Kubernetes. Assicurarsi di usare la versione più recente di Helm e di avere accesso ai ingress-nginx jetstack repository Helm e . I passaggi descritti in questo articolo potrebbero non essere compatibili con le versioni precedenti del grafico Helm, del controller di ingresso NGINX o di Kubernetes.

Per altre informazioni sulla configurazione e l'uso di Helm, vedere Installare le applicazioni con Helm nel servizio Azure Kubernetes. Per istruzioni sull'aggiornamento, consultare Installare i documenti Helm.

In questo articolo si presuppone inoltre che sia presente un cluster del servizio Web Disassociato di Microsoft Con un record di controllo di accesso integrato. Per altre informazioni sulla creazione di un cluster del servizio Web Diaks con un registro di controllo di accesso integrato, vedere Eseguire l'autenticazione con Registro Azure Container da servizio Azure Kubernetes.

Questo articolo richiede anche l'esecuzione dell'interfaccia della riga di comando di Azure versione 2.0.64 o successiva. Eseguire az --version per trovare la versione. Se è necessario eseguire l'installazione o l'aggiornamento, vedere Installare l'interfaccia della riga di comando di Azure.

Importare le immagini usate dal grafico Helm nel record di controllo di acr

Questo articolo usa il grafico Helm del controller di ingresso NGINX,che si basa su tre immagini del contenitore.

Usare az acr import per importare tali immagini nel record di controllo di accesso.

REGISTRY_NAME=<REGISTRY_NAME>
SOURCE_REGISTRY=k8s.gcr.io
CONTROLLER_IMAGE=ingress-nginx/controller
CONTROLLER_TAG=v1.0.4
PATCH_IMAGE=ingress-nginx/kube-webhook-certgen
PATCH_TAG=v1.1.1
DEFAULTBACKEND_IMAGE=defaultbackend-amd64
DEFAULTBACKEND_TAG=1.5
CERT_MANAGER_REGISTRY=quay.io
CERT_MANAGER_TAG=v1.5.4
CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector

az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$CONTROLLER_IMAGE:$CONTROLLER_TAG --image $CONTROLLER_IMAGE:$CONTROLLER_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$PATCH_IMAGE:$PATCH_TAG --image $PATCH_IMAGE:$PATCH_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG --image $DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG

Nota

Oltre a importare immagini del contenitore nel record di controllo di accesso, è anche possibile importare grafici Helm nel record di controllo di accesso. Per altre informazioni, vedere Eseguire il push e il pull di grafici Helm in un Registro Azure Container.

Creare un controller di ingresso

Per creare il controller di ingresso, usare il helm comando per installare nginx-ingress. Per maggiore ridondanza, vengono distribuite due repliche dei controller di ingresso NGINX con il parametro --set controller.replicaCount. Per sfruttare appieno le repliche del controller di ingresso in esecuzione, assicurarsi che nel cluster servizio Azure Kubernetes siano presenti più nodi.

Il controller di ingresso deve anche essere pianificato in un nodo Linux. I nodi di Windows Server non devono eseguire il controller di ingresso. Un selettore di nodo viene specificato con il parametro --set nodeSelector per indicare all'utilità di pianificazione Kubernetes di eseguire il controller di ingresso NGINX in un nodo basato su Linux.

Suggerimento

L'esempio seguente crea uno spazio dei nomi Kubernetes per le risorse in ingresso denominate ingress-basic e deve funzionare all'interno di tale spazio dei nomi. Specificare uno spazio dei nomi per il proprio ambiente in base alle esigenze.

Suggerimento

Se si vuole abilitare la conservazione dell'IP di origine client per le richieste ai contenitori nel cluster, aggiungere --set controller.service.externalTrafficPolicy=Local al comando di installazione Helm. L'indirizzo IP di origine del client viene archiviato nell'intestazione della richiesta in X-Forwarded-For. Quando si usa un controller di ingresso con la conservazione dell'IP di origine client abilitata, il pass-through TLS non funzionerà.

# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>

# Use Helm to deploy an NGINX ingress controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
    --namespace ingress-basic --create-namespace \
    --set controller.replicaCount=2 \
    --set controller.nodeSelector."kubernetes\.io/os"=linux \
    --set controller.image.registry=$ACR_URL \
    --set controller.image.image=$CONTROLLER_IMAGE \
    --set controller.image.tag=$CONTROLLER_TAG \
    --set controller.image.digest="" \
    --set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux \
    --set controller.admissionWebhooks.patch.image.registry=$ACR_URL \
    --set controller.admissionWebhooks.patch.image.image=$PATCH_IMAGE \
    --set controller.admissionWebhooks.patch.image.tag=$PATCH_TAG \
    --set controller.admissionWebhooks.patch.image.digest="" \
    --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
    --set defaultBackend.image.registry=$ACR_URL \
    --set defaultBackend.image.image=$DEFAULTBACKEND_IMAGE \
    --set defaultBackend.image.tag=$DEFAULTBACKEND_TAG \
    --set defaultBackend.image.digest=""

Durante l'installazione viene creato un indirizzo IP pubblico di Azure per il controller di ingresso. Questo indirizzo IP pubblico è statico per la durata di vita del controller di ingresso. Se si elimina il controller di ingresso, l'assegnazione dell'indirizzo IP pubblico viene persa. Se si crea quindi un controller di ingresso aggiuntivo, viene assegnato un nuovo indirizzo IP pubblico. Se si vuole mantenere l'uso dell'indirizzo IP pubblico, è possibile creare un controller di ingresso con un indirizzo IP pubblico statico.

Per ottenere l'indirizzo IP pubblico, usare il comando kubectl get service. Per l'assegnazione dell'indirizzo IP al servizio, sono necessari pochi minuti.

$ kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller

NAME                                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.74.133   EXTERNAL_IP     80:32486/TCP,443:30953/TCP   44s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx

Non è ancora stata creata alcuna regola di ingresso. Se si passa all'indirizzo IP pubblico, viene visualizzata la pagina predefinita 404 del controller di ingresso NGINX.

Aggiungere un record A alla zona DNS

Aggiungere un record A alla zona DNS con l'indirizzo IP esterno del servizio NGINX usando az network dns record-set a add-record.

az network dns record-set a add-record \
    --resource-group myResourceGroup \
    --zone-name MY_CUSTOM_DOMAIN \
    --record-set-name "*" \
    --ipv4-address MY_EXTERNAL_IP

Configurare un nome di dominio completo per il controller di ingresso

Facoltativamente, è possibile configurare un nome di dominio completo per l'indirizzo IP del controller di ingresso anziché un dominio personalizzato. Il nome di dominio completo sarà nel formato <CUSTOM LABEL>.<AZURE REGION NAME>.cloudapp.azure.com .

Per questa configurazione sono disponibili due metodi, descritti di seguito.

Metodo 1: Impostare l'etichetta DNS usando l'interfaccia della riga di comando di Azure

Si noti che questo esempio è per una shell Bash.

# Public IP address of your ingress controller
IP="MY_EXTERNAL_IP"

# Name to associate with public IP address
DNSNAME="demo-aks-ingress"

# Get the resource-id of the public ip
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public ip address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME

# Display the FQDN
az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv

Metodo 2: Impostare l'etichetta DNS usando le impostazioni del grafico Helm

È possibile passare un'impostazione di annotazione alla configurazione del grafico Helm usando il --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name" parametro . Può essere impostato quando il controller di ingresso viene distribuito per la prima volta oppure può essere configurato in un secondo momento. L'esempio seguente illustra come aggiornare questa impostazione dopo la distribuzione del controller.

DNS_LABEL="demo-aks-ingress"
NAMESPACE="nginx-basic"

helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL

Installare cert-manager

Il controller di ingresso NGINX supporta la terminazione TLS. Il recupero e la configurazione di certificati per HTTPS possono essere eseguiti in modi diversi. Questo articolo descrive l'uso di cert-manager, che consente di generare automaticamente il certificato Let's Encrypt e che dispone di funzionalità di gestione.

Per installare il controller cert-manager:

# Label the ingress-basic namespace to disable resource validation
kubectl label namespace ingress-basic cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
  --namespace ingress-basic \
  --version $CERT_MANAGER_TAG \
  --set installCRDs=true \
  --set nodeSelector."kubernetes\.io/os"=linux \
  --set image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CONTROLLER \
  --set image.tag=$CERT_MANAGER_TAG \
  --set webhook.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_WEBHOOK \
  --set webhook.image.tag=$CERT_MANAGER_TAG \
  --set cainjector.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CAINJECTOR \
  --set cainjector.image.tag=$CERT_MANAGER_TAG

Per altre informazioni sulla configurazione di cert-manager, vedere progetto cert-manager.

Creare un'autorità di certificazione (CA) cluster

Per poter emettere i certificati, cert-manager richiede un autorità di certificazione o una risorsa ClusterIssuer. Queste risorse Kubernetes hanno funzionalità identiche, ma Issuer funziona in uno spazio dei nomi singolo, mentre ClusterIssuer funziona in tutti gli spazi dei nomi. Per altre informazioni, vedere la documentazione relativa all'autorità di certificazione cert-manager.

Creare un'autorità di certificazione del cluster, ad esempio cluster-issuer.yaml, tramite il manifesto di esempio seguente. Aggiornare l'indirizzo di posta elettronica con un indirizzo valido della propria organizzazione:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: MY_EMAIL_ADDRESS
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
        ingress:
          class: nginx
          podTemplate:
            spec:
              nodeSelector:
                "kubernetes.io/os": linux

Per creare l'autorità di certificazione, usare il comando kubectl apply.

kubectl apply -f cluster-issuer.yaml

Eseguire applicazioni demo

Sono stati configurati un controller di ingresso e una soluzione di gestione dei certificati. A questo punto è possibile eseguire due applicazioni demo nel cluster servizio Azure Kubernetes. In questo esempio Helm viene usato per distribuire due istanze di una semplice applicazione Hello world.

Per visualizzare il controller in ingresso in azione, eseguire due applicazioni demo nel cluster del servizio Web Diaks. In questo esempio si usa kubectl apply per distribuire due istanze di una semplice applicazione Hello world.

Creare un file aks-helloworld-one.yaml e copiarlo nell'esempio YAML seguente:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aks-helloworld-one
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aks-helloworld-one
  template:
    metadata:
      labels:
        app: aks-helloworld-one
    spec:
      containers:
      - name: aks-helloworld-one
        image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
        ports:
        - containerPort: 80
        env:
        - name: TITLE
          value: "Welcome to Azure Kubernetes Service (AKS)"
---
apiVersion: v1
kind: Service
metadata:
  name: aks-helloworld-one
spec:
  type: ClusterIP
  ports:
  - port: 80
  selector:
    app: aks-helloworld-one

Creare un file aks-helloworld-two.yaml e copiarlo nell'esempio YAML seguente:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aks-helloworld-two
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aks-helloworld-two
  template:
    metadata:
      labels:
        app: aks-helloworld-two
    spec:
      containers:
      - name: aks-helloworld-two
        image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
        ports:
        - containerPort: 80
        env:
        - name: TITLE
          value: "AKS Ingress Demo"
---
apiVersion: v1
kind: Service
metadata:
  name: aks-helloworld-two
spec:
  type: ClusterIP
  ports:
  - port: 80
  selector:
    app: aks-helloworld-two

Eseguire le due applicazioni demo usando kubectl apply :

kubectl apply -f aks-helloworld-one.yaml --namespace ingress-basic
kubectl apply -f aks-helloworld-two.yaml --namespace ingress-basic

Creare una route in ingresso

Entrambe le applicazioni sono in esecuzione nel cluster Kubernetes. Sono tuttavia configurati con un servizio di tipo ClusterIP e non sono accessibili da Internet. Per renderle disponibili pubblicamente, creare una risorsa di ingresso Kubernetes. La risorsa di ingresso configura le regole che instradano il traffico a una delle due applicazioni.

Nell'esempio seguente il traffico verso l'indirizzo hello-world-ingress. MY_CUSTOM_DOMAIN viene instradato al servizio aks-helloworld-one. Traffico verso l'indirizzo hello-world-ingress. MY_CUSTOM_DOMAIN/hello-world-two viene instradato al servizio aks-helloworld-two. Traffico verso hello-world-ingress. MY_CUSTOM_DOMAIN/static viene indirizzato al servizio denominato aks-helloworld-one per gli asset statici.

Nota

Se è stato configurato un FQDN per l'indirizzo IP del controller di ingresso anziché un dominio personalizzato, usare il nome di dominio completo anziché hello-world-ingress. MY_CUSTOM_DOMAIN. Ad esempio, se l'FQDN demo-aks-ingress.eastus.cloudapp.azure.com, sostituire hello-world-ingress. MY_CUSTOM_DOMAIN con demo-aks-ingress.eastus.cloudapp.azure.com in hello-world-ingress.yaml .

Creare un file denominato hello-world-ingress.yaml usando l'esempio YAML seguente. Aggiornare gli elementi hosts e host in base al nome DNS creato in un passaggio precedente.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/use-regex: "true"
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path: /hello-world-one(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
      - path: /hello-world-two(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-two
            port:
              number: 80
      - path: /(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress-static
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /static/$2
    nginx.ingress.kubernetes.io/use-regex: "true"
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path:
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port: 
              number: 80
        path: /static(/|$)(.*)

Creare la risorsa di ingresso con il comando kubectl apply.

kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic

Verificare che sia stato creato un oggetto certificato

Successivamente, è necessario creare una risorsa certificato. La risorsa certificato definisce il certificato X.509 desiderato. Per altre informazioni, vedere Certificati di cert-manager. Cert-manager ha creato automaticamente un oggetto certificato usando ingress-shim, che viene distribuito automaticamente con cert-manager a partire dalla versione 0.2.2. Per altre informazioni, consultare la documentazione su ingress-shim.

Per verificare che il certificato sia stato creato correttamente, usare il comando e verificare che READY sia True , che kubectl get certificate --namespace ingress-basic potrebbe richiedere alcuni minuti.

$ kubectl get certificate --namespace ingress-basic

NAME         READY   SECRET       AGE
tls-secret   True    tls-secret   11m

Testare la configurazione di ingresso

Aprire un Web browser per hello-world-ingress. MY_CUSTOM_DOMAIN del controller di ingresso Kubernetes. Si noti che si viene reindirizzati all'uso di HTTPS e il certificato è attendibile e l'applicazione demo viene visualizzata nel Web browser. Aggiungere il percorso /hello-world-two e notare che viene visualizzata la seconda applicazione demo con il titolo personalizzato.

Pulire le risorse

Questo articolo ha usato Helm per installare i componenti di ingresso, i certificati e le app di esempio. Quando si distribuisce un grafico Helm, viene creato un certo numero di risorse di Kubernetes. Queste risorse includono pod, distribuzioni e servizi. Per pulire queste risorse, è possibile eliminare l'intero spazio dei nomi di esempio o le singole risorse.

Eliminare lo spazio dei nomi di esempio e tutte le risorse

Per eliminare l'intero spazio dei nomi di esempio, usare kubectl delete il comando e specificare il nome dello spazio dei nomi. Tutte le risorse nello spazio dei nomi vengono eliminate.

kubectl delete namespace ingress-basic

Eliminare le risorse singolarmente

In alternativa, un approccio più granulare consiste nell'eliminare le singole risorse create. Rimuovere prima di tutto le risorse dell'autorità emittente del cluster:

kubectl delete -f cluster-issuer.yaml --namespace ingress-basic

Elencare le versioni helm con il helm list comando . Cercare i grafici denominati nginx e cert-manager, come illustrato nell'output di esempio seguente:

$ helm list --namespace ingress-basic

NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
cert-manager            ingress-basic   1               2020-01-15 10:23:36.515514 -0600 CST    deployed        cert-manager-v0.13.0    v0.13.0    
nginx                   ingress-basic   1               2020-01-15 10:09:45.982693 -0600 CST    deployed        nginx-ingress-1.29.1    0.27.0  

Disinstallare le versioni con il helm uninstall comando . L'esempio seguente disinstalla le distribuzioni NGINX in ingresso e cert-manager.

$ helm uninstall cert-manager nginx --namespace ingress-basic

release "cert-manager" uninstalled
release "nginx" uninstalled

Rimuovere quindi le due applicazioni di esempio:

kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic

Rimuovere la route in ingresso che ha indirizzato il traffico verso le app di esempio:

kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic

Infine, è possibile eliminare lo spazio dei nomi stesso. Usare il comando kubectl delete e specificare il nome dello spazio dei nomi:

kubectl delete namespace ingress-basic

Passaggi successivi

In questo articolo sono stati inclusi alcuni componenti esterni ad servizio Azure Kubernetes. Per altre informazioni su questi componenti, vedere le pagine di progetto seguenti:

È anche possibile: