Deploying a Simple .NET API to AKS Using ArgoCD and GitHub Actions

Deploying a Simple .NET API to AKS Using ArgoCD and GitHub Actions

In this guide, we'll walk through a simple example of deploying a .NET API to an Azure Kubernetes Service (AKS) using ArgoCD for GitOps automation and GitHub Actions for CI/CD. We'll containerize the .NET API using Docker, set up the necessary Azure resources, configure GitHub workflows, and use ArgoCD to manage the deployment to AKS.

GitOps - Demystified

Overview

We'll start by containerizing a simple .NET API, setting up Azure resources such as a container registry and AKS cluster, configuring GitHub workflows to build and push Docker images, and finally using ArgoCD to manage the deployment to AKS.

Step 1: Clone the Repository

Clone the repository containing the sample .NET API code from GitHub:

git clone https://github.com/Selmouni-Abdelilah/api_gitops.git

Step 2: Dockerize the .NET API

Navigate to the root directory of the cloned repository and create a Dockerfile to containerize the .NET API.

# Multi-stage Dockerfile for building and running a .NET application
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY . .
RUN dotnet restore "./api_gitops/api_gitops.csproj"
RUN dotnet publish "./api_gitops/api_gitops.csproj" -c $BUILD_CONFIGURATION -o /app --no-restore

FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app
COPY --from=build /app ./
EXPOSE 8080
ENTRYPOINT ["dotnet", "api_gitops.dll"]

Step 3: Create Azure Resources

Azure Azure everywhere! - Buzz and Woody (Toy Story) Meme Meme Generator

Set up Azure resources such as a resource group, container registry, and AKS cluster using the Azure CLI.

3.1. Create a Resource Group

az group create --name gitopsapi-rg --location eastus

3.2. Create a Container Registry

az acr create --resource-group gitopsapi-rg --name gitopscontainerregistry --sku Basic

3.3. Create an AKS Cluster

az aks create --resource-group gitopsapi-rg --name gitops-cluster --node-count 1 --generate-ssh-keys

3.4. Grant AKS Access to ACR

az aks update -n gitops-cluster -g gitopsapi-rg --attach-acr gitopscontainer

Step 4: Configure GitHub Workflow

Create GitHub Actions workflow to automate the build and push process of Docker images to the Azure Container Registry.

4.1. Create Azure Credentials

In the GitHub workflow, create Azure credentials to authenticate to the Azure CLI. Follow the instructions to create a service principal with the Contributor role scoped to the resource group for your container registry.

First, get the resource ID of your resource group. Substitute the name of your group in the following az group show command:

groupId=$(az group show --name <resource-group-name> --query id --output tsv)

Use az ad sp create-for-rbac to create the service principal:

az ad sp create-for-rbac --scope $groupId --role Contributor --json-auth

Output is similar to:

Save the JSON output because it is used in a later step. Also, take note of the clientId, which you need to update the service principal in the next section.

4.2. Update Registry Authentication

Update the Azure service principal credentials to allow push and pull access to your container registry. This step enables GitHub Actions to use the service principal to authenticate with the container registry and push and pull a Docker image.

Get the resource ID of your container registry. Substitute the name of your registry in the following az acr show command:

registryId=$(az acr show --name <registry-name> --resource-group <resource-group-name> --query id --output tsv)

Use az role assignment create to assign the AcrPush role, which gives push and pull access to the registry. Substitute the client ID of your service principal:

az role assignment create --assignee <ClientId> --scope $registryId --role AcrPush

4.3. Save Credentials to GitHub Repo

In your GitHub repository settings, navigate to Settings > Secrets > Actions

Add the following secrets:

  • AZURE_CREDENTIALS: The entire JSON output from the service principal creation step.

  • REGISTRY_LOGIN_SERVER: The login server name of your registry (all lowercase).

  • REGISTRY_USERNAME: The clientId from the JSON output of the service principal creation.

  • REGISTRY_PASSWORD: The clientSecret from the JSON output of the service principal creation.

4.4. Create Workflow File

Create a GitHub Actions workflow file named main.yml with the following content:

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

jobs:
    build-and-push:
        runs-on: ubuntu-latest
        steps:
        - name: 'Checkout GitHub Action'
          uses: actions/checkout@main

        - name: 'Login via Azure CLI'
          uses: azure/login@v1
          with:
            creds: ${{ secrets.AZURE_CREDENTIALS }}

        - name: 'Build and push image'
          uses: azure/docker-login@v1
          with:
            login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            username: ${{ secrets.REGISTRY_USERNAME }}
            password: ${{ secrets.REGISTRY_PASSWORD }}
        - run: |
            docker build . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/apigitops:latest
            docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/apigitops:latest

This workflow triggers on pushes to the master branch, builds the Docker image, and pushes it to the Azure Container Registry.

Navigate to your container registry and check the docker image with the latest tag

Step 5: Create Kubernetes Manifests

We need to create deployment and service manifests for our API to deploy to AKS.

5.1. Deployment Manifest (deployment.yaml)

yamlCopy codeapiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: api-app
  name: api-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api-app
  template:
    metadata:
      labels:
        app: api-app
    spec:
      containers:
        - name: api-app
          image: gitopscontainerregistry.azurecr.io/apigitops:latest
          ports:
            - containerPort: 8080
          resources:
            limits:
              memory: "512Mi"
              cpu: "256m"
            requests:
              memory: "256Mi"
              cpu: "128m"

This Kubernetes manifest defines a scalable deployment with two replicas, each running the Docker image `gitopscontainerregistry.azurecr.io/apigitop..`. It exposes port 8080 and specifies resource limits for memory and CPU.

5.2. Service Manifest (service.yaml)

yamlCopy codeapiVersion: v1
kind: Service
metadata:
  name: api-app-svc
spec:
  selector:
    app: api-app
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

This Kubernetes manifest defines a service of type LoadBalancer to expose the application externally on port 80. It routes traffic to the pods based on the specified selector.

Push everything to your GitHub repo.

Step 6: Set Up ArgoCD

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.It automates the deployment of the desired application states in the specified target environments. Application deployments can track updates to branches, tags, or pinned to a specific version of manifests at a Git commit

GitOps - Demystified

6.1. Connect to AKS Cluster

az aks get-credentials --name gitops-cluster --resource-group gitopsapi-rg

6.2. Install ArgoCD

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

6.3. Access ArgoCD Server

Use Kubernetes port-forwarding to access the ArgoCD server:

kubectl port-forward svc/argocd-server -n argocd 8080:443

Retrieve the default ArgoCD password:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

Then, open your web browser and navigate to http://localhost:8080.

You'll be prompted to sign in to ArgoCD. Use the admin username and the password retrieved from the previous command.

Note: Since there is no certificate configured, your browser may display a warning indicating that the connection is not secure. For the purpose of this demonstration, we'll ignore this warning. However, in a production environment, it's crucial to configure SSL/TLS certificates to ensure secure communication.

Step 7: Deploy Application with ArgoCD

Create an ArgoCD Application manifest named application.yaml with the following content:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argocd-app
  namespace: argocd
spec:
  project: default
  sources:
    - repoURL: https://github.com/Selmouni-Abdelilah/api_gitops.git
      targetRevision: HEAD
      path: ./
  destination:
    server: https://kubernetes.default.svc
    namespace: gitops
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
    automated:
      selfHeal: true
      prune: true

When this ArgoCD Application definition is applied to an ArgoCD instance, it orchestrates the deployment and synchronization of the specified application from the designated Git repository to the specified Kubernetes cluster and namespace.

To install the Application to Argocd, run the following command from the root folder.

kubectl apply -f application.yaml

Access your ArgoCD server at localhost:8080. After a brief period, ArgoCD will automatically synchronize with the changes and initiate the deployment process. You should observe a similar representation on your ArgoCD dashboard as depicted in the following image.

Step 8: Verify deployment

Now that we've deployed our .NET API to AKS, let's verify that it's up and running.

  1. Navigate to Azure Portal:

    Open the Azure Portal and navigate to the AKS cluster named gitops-cluster.

  2. Check Services and Ingresses:

In the AKS cluster dashboard, navigate to the Services and Ingresses section.

  1. Retrieve External IP:

    Locate the service named api-app-svc and copy its external IP address.

  2. Access API in Browser:

    Open your web browser and paste the external IP address copied in the previous step. Hit enter to access the URL.

  3. Verify API Response:

    You should see the response from your .NET API similar to the screenshot provided earlier.

    GitOps in a nutshell

Conclusion

By following these simple steps, you can deploy a .NET API to AKS using ArgoCD and GitHub Actions. This example demonstrates the basic workflow for automating the deployment process and managing Kubernetes applications with GitOps practices. Feel free to customize and expand upon this example to suit your specific requirements.

References

Some useful links:

https://learn.microsoft.com/en-us/azure/container-instances/container-instances-github-action?tabs=userlevel

https://argo-cd.readthedocs.io/en/stable/getting_started/

https://learn.microsoft.com/en-us/azure/architecture/example-scenario/gitops-aks/gitops-blueprint-aks

Thanks for reading :)