Thematischer Rahmen
Die Idee ist, Sie in diesem Artikel innerhalb weniger Absätze fit zu machen, um starten zu können. Um dies zu erreichen, sind einige wichtige Themen nicht Gegenstand dieses Artikels. Sie müssen sich jedoch um Diese kümmern, wenn Sie sowohl Docker-Images als auch Ihre Azure-Infrastruktur für die Produktionsumgebung erstellen.
Um nur einige dieser Themen zu nennen:
- Docker-Images absichern
- Minimieren der Image-Layer und Größe von Docker-Images
- Absicherung der Azure Container Registry (ACR)
- Absicherung von Azure Kubernetes Service (AKS)
- Verwenden eines dedizierten Ingress-Controllers zum Weiterleiten von eingehendem Datenverkehr in AKS
- Kontinuierliche Überwachung mit dem Azure Security Center
Zu Demonstrationszwecken nutze ich den von Microsoft erstellten „Weather Forecast“ Web-API-Blueprint durch die Verwendung von dotnet new webapi -lang c# -n HelloAKS
.
Version Information:
- .NET Core 3.1 (Vorgehensweise für .NET 5.0 ist äquivalent)
Anforderungen
Um dieser Anleitung zu folgen, sollten auf Ihrem Computer drei Dinge installiert und konfiguriert sein:
- Docker
- Azure CLI 2.0
- Ein Editor (ich verwende Visual Studio Code)
Wenn diese Tools installiert und konfiguriert sind, können wir loslegen und die .NET Core-Anwendung in einen neuen AKS-Cluster bringen.
1. Ein Docker-Image erzeugen
Mit der neu erzeugten .NET Core-Anwendung auf Ihrem lokalen Computer, müssen Sie anschließend ein Docker-Image erzeugen. Erstellen Sie dazu zwei neue Dateien im Hauptprojektordner: Dockerfile
und .dockerignore
. Bevor wir mit dem Schreiben des Dockerfile
beginnen, fügen wir einige typische Patterns für .NET-Anwendungen zur .dockerignore
hinzu, um zu verhindern, dass diese Dateien und Ordner beim Erstellen des Docker-Images an den Docker Daemon übertragen werden:
# .dockerignore
/bin/
/obj/
Das Erstellen von Docker-Images für .NET Core-Anwendungen ist unkompliziert. Microsoft stellt alle erforderlichen Base-Images bereit, damit Ihre Anwendung in einem Linux-basierten Container ausgeführt werden kann. Wir werden ein sogenanntes mehrstufiges Docker-Image erstellen.
Das bedeutet, dass wir mit einem Basis-Image beginnen, welches das .NET Core SDK enthält, um die Anwendung in diesem Image zu kompilieren und zu veröffentlichen. Sobald dies erledigt ist, nutzen wir ein weiteres Basis-Image nur mit allen erforderlichen Dingen, um .NET Core-Anwendungen auszuführen, und kopieren unsere zuvor veröffentlichte Anwendung in das neue Basis-Image. Von hier aus exponieren wir den gewünschten Port und starten die Anwendung.
Wenn wir diesem Pattern folgen, können wir die Größe des resultierenden Docker-Images deutlich reduzieren, wie Sie hier sehen können:
mcr.microsoft.com/dotnet/core/sdk 3.1-buster a0dbfc5da130 692MB
mcr.microsoft.com/dotnet/core/aspnet 3.1-buster-slim 4bee399eb313 207MB
Nun widmen wir uns dem Dockerfile
, fügen Sie den folgenden Inhalt ein:
#Dockerfile
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS builder
WORKDIR /src
COPY ./HelloAKS.csproj .
RUN dotnet restore HelloAKS.csproj
COPY . .
RUN dotnet build HelloAKS.csproj -c Debug -o /src/out
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim
WORKDIR /app
COPY --from=builder /src/out .
EXPOSE 80
ENTRYPOINT ["dotnet", "HelloAKS.dll"]
Jetzt erstellen wir das Docker-Image mithilfe der Docker CLI:
# build Docker image
docker build . -t HelloAKS:0.0.1
# Watch Docker
# pulling the images from MCR if they are not on your machine
# building .NET Application and creating the Docker Image
Nun da wir ein Docker-Image haben (Sie können jederzeit alle Docker-Images auf Ihrem System mithilfe von docker images
auflisten), können wir zum nächsten Schritt weitergehen.
2. Erstellen einer ACR Instanz
Ich verwende zur Bereitstellung des Images die ACR, da es sich gut in AKS, Azure Active Directory (Azure AD), Azure Security Center (ASC) und andere Dienste integrieren lässt. Wenn Sie sich ACR gründlicher widmen möchten, lesen Sie die Artikel meiner Azure Container Registry Unleashed Artikelserie.
Wir werden alle unseren Azure-Ressourcen in einer dedizierten Azure-Ressourcengruppe namens hello-aks
gruppieren. Wir erstellen diese mit dem Azure CLI:
# create the resource group
az group create -n hello-aks -l westeurope
Sobald die Ressourcengruppe erstellt wurde, können wir eine neue ACR-Instanz provisionieren. Für diesen Artikel genügt eine „Basic“ Edition, die ca 0,15 Euro pro Tag kostet. Der Name einer ACR-Instanz muss weltweit eindeutig sein. Sie sollten daher az acr check-name
verwenden, um zu überprüfen, ob der gewünschte Service-Name noch verfügbar ist.
# check if your desired name is available
az acr check-name -n thorstenhans
# create the ACR instance
az acr create -n thorstenhans \
-g hello-aks \
--admin-enabled false \
--sku Basic
Nach dem Erstellen der ACR sollten Sie den folgenden Befehl verwenden, um die eindeutige Cloud-Ressourcen-ID in einer Variablen zu speichern. Wir werden die ID in ein paar Minuten brauchen:
# store unique ACR id in ACR_ID
ACR_ID=$(az acr show -n thorstenhans -g hello-aks --query id -o tsv)
3. Docker-Image in die ACR schieben
Wir können das zuvor erstellte Docker-Image nicht einfach so in die Azure Container Registry pushen. Docker-Images müssen den ACR-Image-Namenskonventionen (unique-acr-name.azurecr.io/imagename:tag
) folgen, um sie in die ACR zu veröffentlichen. Wir können unser Image ganz einfach mit docker tag
neu taggen, wie hier gezeigt:
# re-tag the existing Docker Image
docker tag hello-aks:0.0.1 thorstenhans.azurecr.io/hello-aks:0.0.1
Außerdem müssen wir uns für den Zugriff auf die ACR authentifizieren:
# authenticate against ACR
az acr login -n thorstenhans
Sobald die Anmeldung erfolgreich war, verwenden wir die Standard-Docker-Befehle, um unser Docker-Image in die ACR zu pushen. Docker weiß aufgrund des ACR- Präfixes, wohin das Image während des push
-Vorgangs geleitet werden muss.
# push the docker image to ACR
docker push thorstenhans.azurecr.io/hello-aks:0.0.1
Sie können entweder die Azure CLI oder das Azure-Portal verwenden, um zu überprüfen, ob das Docker-Image in die ACR veröffentlicht wurde. (az acr repository list -n thorstenhans
)
4. Einen Kubernetes Cluster erstellen
Wir verwenden nun die Azure CLI, um einen neuen AKS-Cluster zu erstellen. Zu Demonstrationszwecken besteht unser Cluster nur aus einem einzigen Worker-Node. Das Betreiben eines Kubernetes Clusters mit einem einzelnen Worker-Node wird nicht für Produktionsszenarien empfohlen. Ich mache es hier nur, um die Gesamtkosten der Azure-Dienste so gering wie möglich zu halten. Als Teil des Erstellungsprozesses werden wir auch unsere ACR-Instanz an AKS anhängen. Dies ist auch mit vorhandenen AKS-Clustern mit dem Befehl az aks update
möglich.
# create the AKS cluster
az aks create -n aks-demo \
-g hello-aks \
--enable-managed-identity \
--attach-acr $ACR_ID \
--node-count 1
Wenn die Azure CLI die Bereitstellung des AKS-Clusters abgeschlossen hat (dies kann einige Minuten dauern), müssen wir kubectl
(die Kubernetes CLI) einrichten, welche Sie für die Kommunikation mit einem beliebigen Kubernetes Cluster verwenden. Wenn Sie kubectl
bereits installiert haben, können Sie den folgenden Befehl überspringen und mit dem Herunterladen der Cluster-Konfiguration für kubectl
fortfahren.
# Install kubectl
az aks install-cli
Sobald kubectl
auf Ihrem Rechner installiert ist, benötigen wir die Konfiguration für den aks-demo
Cluster. Auch hier bietet Azure CLI den entsprechenden Befehl:
# download cluster configuration for kubectl
az aks get-credentials \
-n aks-demo \
-g hello-aks
# verify kubectl context
kubectl config get-contexts
# prints all cluster contexts
# if kubectl does not point to aks-demo, switch context
kubectl config use-context aks-demo
5. Kubernetes Bereitstellungs-Manifeste erstellen
In Kubernetes stellen wir Docker-Images nicht direkt bereit. Die kleinste Arbeitseinheit in Kubernetes ist ein sogenannter Pod. Ein Pod bietet eine Reihe von Konfigurationsmöglichkeiten, um den gesamten Lebenszyklus einer containerisierten Anwendung zu steuern.
Wenn Sie Kubernetes gründlicher kennenlernen, lernen Sie andere Bausteine wie ReplicaSet oder Deployment kennen, die Wrapper für einen Pod sind. Diese fügen noch mehr Funktionen wie Replikationen und feingranulare Aktualisierungsstrategien hinzu. Aber jetzt beginnen wir mit Ihrem ersten Pod. Erstellen Sie im Hauptordner eine neue Datei mit dem Namen pod.yml
und fügen Sie den folgenden Inhalt hinzu. Wir werden die wichtigsten Teile in Kürze besprechen.
# pod.yml
apiVersion: v1
kind: Pod
metadata:
name: first-netcore-app
labels:
app: hello-aks
component: netcore-app
spec:
containers:
- image: thorstenhans.azurecr.io/hello-aks:0.0.1
name: webapi
ports:
- containerPort: 80
Wie Sie sehen, haben wir für unseren Pod zwei Labels angegeben. app: hello-aks
und component: netcore-app
. In Kubernetes verwenden wir Labels und Label-Selektoren, um Komponenten lose zu koppeln. Labels sind super-effizient und dennoch einfach. Betrachten Sie diese als Klebezettel, die Sie in diesem Fall an verschiedene Dinge wie den Pod anbringen.
Die spec
beschreibt die tatsächlichen Eigenschaften des Pods. Hier spezifizieren wir unser zuvor veröffentlichtes Image und konfigurieren die Port-Freigabe. Wir weisen Kubernetes an, Netzwerkverkehr für unseren Docker Container auf Port 80
zuzulassen.
Neben dem Pod möchten wir unsere API der Öffentlichkeit zugänglich machen. Um Pods zugänglich zu machen (entweder im ganzen Cluster oder extern), müssen wir einen Service in Kubernetes erstellen. Erstellen Sie erneut im Stammordner des Projekts eine neue Datei namens service.yml
und fügen Sie Folgendes hinzu:
# service.yml
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-aks
name: hello-aks
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 80
selector:
app: hello-aks
component: netcore-app
type: LoadBalancer
Bei der Überprüfung der Service-Definition sollten Sie sich auf spec
konzentrieren. Die spec definiert, dass wir einen Service vom Typ LoadBalancer
erstellen wollen. Dadurch wird Azure angewiesen, eine öffentliche IP-Adresse zuzuweisen, einen Azure Load Balancer zu erstellen und Datenverkehr aus dem öffentlichen Internet an unseren Kubernetes Cluster zu leiten.
Kubernetes unterstützt verschiedene Arten von Services. In realen Projekten verwenden Sie normalerweise keinen LoadBalancer
; Stattdessen verwenden Sie einen Ingress Controller (wie beispielsweise NGINX Ingress), der den eingehenden Datenverkehr steuert. Interne Services des Clusters wären vom Typ NodePort
oder ClusterIP
.
Der Teil spec.selector
definiert, wohin der Datenverkehr geleitet werden soll. Diese Konfiguration leitet den gesamten Verkehr auf Port 8080
an Port 80
zu allen Artefakten innerhalb des Clusters weiter, denen die Labels app: hello-aks
und component:netcore-app
zugeordnet sind.
Sie haben somit gerade beschrieben, dass der Netzwerkverkehr dynamisch in Ihren Cluster geleitet wird, ohne die Ressourcen eng miteinander zu verbinden. Wenn alles bereit ist, können wir zum letzten Schritt übergehen und alles in AKS bereitstellen.
6. Ihre Anwendung bereitstellen
Die Bereitstellung von Artefakten in Kubernetes ist unkompliziert; wir verwenden kubectl apply
, um alles in Kubernetes bereitzustellen.
# deploy artifacts to AKS
kubectl apply -f pod.yml
kubectl apply -f service.yml
Kubernetes wird nun den Service hochfahren und unser Docker-Image aus ACR abrufen, um den Pod zu instanziieren. Insbesondere die Erstellung des Services kann einige Zeit in Anspruch nehmen, da die öffentliche IP zugewiesen und der Load Balancer bereitgestellt werden müssen. Sie können mit kubectl
alle Services beobachten und warten, bis die externe IP zugeordnet ist.
# wait for service to receive its external IP
kubectl get svc -w
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-aks LoadBalancer 10.0.139.177 51.105.199.90 8080:31924/TCP 10m
kubernetes ClusterIP 10.0.0.1 443/TCP 16m
Sobald Sie die dem Service zugewiesene externe IP sehen, können Sie die Überwachung der Dienste mit [CTRL]+C
beenden und eine Anforderung zum Abrufen von Wetterdaten von unserer .NET Core-Anwendung mit curl
starten:
# get weather data from ASP.NET Core API in AKS
curl http://51.105.199.90:8080/weatherforecast | jq
[
{
"date": "2020-06-07T10:18:16.0014666+00:00",
"temperatureC": -11,
"temperatureF": 13,
"summary": "Sweltering"
},
{
"date": "2020-06-08T10:18:16.0014937+00:00",
"temperatureC": 34,
"temperatureF": 93,
"summary": "Hot"
},
{
"date": "2020-06-09T10:18:16.0015069+00:00",
"temperatureC": 28,
"temperatureF": 82,
"summary": "Chilly"
},
{
"date": "2020-06-10T10:18:16.0015195+00:00",
"temperatureC": 41,
"temperatureF": 105,
"summary": "Warm"
},
{
"date": "2020-06-11T10:18:16.0015348+00:00",
"temperatureC": -4,
"temperatureF": 25,
"summary": "Warm"
}
]
Sie sollten Ihren Pod auch mit kubectl get pods
überprüfen. Hier sollten Sie -o wide
anhängen, um die IP-Adresse des Pods zu erhalten. Um die Verbindung zwischen dem Dienst und dem Pod anzuzeigen, können Sie mit kubectl get endpoints
nach Endpunkten suchen:
# get pods and endpoints
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
first-netcore-app 1/1 Running 0 6m58s 10.244.0.10
kubectl get endpoints
NAME ENDPOINTS AGE
hello-aks 10.244.0.10:80 15m
kubernetes 20.50.227.85:443 21m
Beachten Sie, dass der Endpunkt auf die IP-Adresse und den Port des Pods verweist.
Zusammenfassung
Das wäre geschafft. Sie haben sechs Schritte zum Einrichten und Ausführen Ihrer .NET Core Web-API in Kubernetes gesehen. Dies ist ein guter Ausgangspunkt. Von hier aus können Sie weitergehen und Funktionen wie Deployments, ConfigMaps und Secrets in Kubernetes anwenden. Darüber hinaus sollten Sie sich mit Dingen wie Systemdiagnosen, Ressourcenanforderungen und -limits befassen, um die Leistungsfähigkeit von Kubernetes auszuschöpfen und Ihre containerisierte Anwendung grundsolide zu machen.
Den gesamten Code dieses Artikels finden Sie im Projektarchiv auf GitHub unter https://github.com/ThorstenHans/six-steps-to-aks