Kubernetes and Azure Pipeline in action. Detailed guide.
Tags: azure, devops, cicd, csharp
Published: 2023-06-21 13:27:49

## Entry
In the previous article, I showed how to create a pipeline on GitHub. Today, I would like to show you how to create the pipeline in Azure DevOps. In the previous article, I haven't built containers and checked them. It might be helpful if you want to deploy your application to Azure. I'll not show how to deploy your application, but I show how to prepare the application, create Kubernetes configuration, and configure Azure Pipeline. Sit back, and let's start.

##Preconditions
Before we start, I want to enumerate preconditions for a better understanding of this material. For this practice work, you should have:
- Should be installed IDE or text editor and Docker Desktop. 
- Also you should have experience with Docker.

##Project
I'll not create a new template project since it'll be too simple and uninteresting. Instead, let's clone to any convenient folder the finished project from GitHub:
```bash
git clone https://github.com/SergKorol/ManagementSystem.git
``` 
And now, let's ensure that your Docker Desktop is already run and Kubernetes is also enabled and run. Both services should be green.

![Docker left panel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4q2iebbgmbe7azkbkiat.png)

If everything is OK, build the project and ensure that it's not having errors, and also build up the Docker image. You should ensure that the project is opening through Docker.

##Kubernetes
Now, let's start creating the configuration for Kubernetes. I'll create it in ShopManagementSystem.Dashboard project, however, you can create into any different folder at your discretion.
```bash
cd src/ShopManagementSystem/ShopManagementSystem.Dashboard
```
And create a YAML file in this folder:
```bash
touch k8s.deploy.yaml
```

Open it in any editor and paste this code:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop-system
  labels:
    app: shop-system-app
spec:
  replicas: 1
  selector:
    matchLabels:
      service: shop-system
  template:
    metadata:
      labels:
        app: shop-system-app
        service: shop-system
    spec:
      containers:
        - name: shop-system
          image: managementsystem-webmvc
          imagePullPolicy: Never
          ports:
            - containerPort: 80
              protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: shop-system
  labels:
    app: shop-system-app
    service: shop-system
spec:
  type: LoadBalancer
  ports:
    - port: 11000
      targetPort: 80
      protocol: TCP
  selector:
    service: shop-system
```

The configuration file is divided into two parts. In the first part, the configuration of Kubernetes and mounting existing built Docker image. It's a simplified configuration with one replica, but injected service that is described below. The service type of LoadBalancer.
Save this file and let's apply it. **Important, your Kubernetes should work!**. Paste this command to the terminal:
```bash
kubectl apply -f k8s.deploy.yaml
```
If everything is OK, you'll see the message like this:
```bash
deployment.apps/shop-system configured
service/shop-system created
```
Let's check out and see our pods, put this command:
```bash
kubectl get pod
```
You should see this table:
```bash
NAME                           READY   STATUS              RESTARTS   AGE
shop-system-7f5dc5f85f-czp7q   1/1     Running             0          3h17m
```
With the pod is OK. Next, let's check the service. Put this command:
```bash
 kubectl get service
```
You should see cluster and service, like this:
```bash
NAME          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE
kubernetes    ClusterIP      10.96.0.1       <none>        443/TCP           15h
shop-system   LoadBalancer   10.98.254.189   localhost     11000:31224/TCP   3h6m
```
Pay attention, your service should have external IP. If it has a "pending" status, you should wait or delete it and create it again. And let's check out the work and type `localhost:11000` in the browser. It should work fine.

##Pipeline
The Azure Pipeline is similar to GitHub Actions, however, I'm gonna make it more difficult and add create a cluster. Go to the root folder of this project and paste the command and open it:
```bash
touch azure-pipelines.yml
```
Next step, paste this code:
```yaml
trigger:
  branches:
    include:
      - main

pool:
  vmImage: 'ubuntu-latest'

variables:
  buildConfiguration: 'Release'

jobs:
- job: Build
  displayName: 'Build Solution'
  steps:
  - task: UseDotNet@2
    displayName: 'Install .NET SDK'
    inputs:
      packageType: 'sdk'
      version: '7.x'
      installationPath: '$(Agent.ToolsDirectory)/dotnet'

  - script: dotnet restore
    displayName: 'Restore NuGet packages'
    workingDirectory: '$(Build.SourcesDirectory)/src/ShopManagementSystem'

  - script: dotnet build --configuration $(buildConfiguration) --no-restore
    displayName: 'Build Solution'
    workingDirectory: '$(Build.SourcesDirectory)/src/ShopManagementSystem'

- job: Test
  displayName: 'Run Tests'
  dependsOn: Build
  steps:
  - script: dotnet restore
    displayName: 'Restore NuGet packages'
    workingDirectory: '$(Build.SourcesDirectory)/src/ShopManagementSystem'
  - script: dotnet build --configuration $(buildConfiguration) --no-restore --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)
    displayName: 'Build Output'
    workingDirectory: '$(Build.SourcesDirectory)/src/ShopManagementSystem'
  - script: dotnet test $(Build.ArtifactStagingDirectory)/$(buildConfiguration)/ShopManagementSystem.UnitTests.dll --configuration $(buildConfiguration) --no-build --collect "Code Coverage"
    displayName: 'Run Unit Tests'
    workingDirectory: '$(Build.SourcesDirectory)/src/ShopManagementSystem'

- job: Publish
  displayName: 'Publish Artifacts'
  dependsOn: Test
  steps:
  - script: dotnet publish --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)
    displayName: 'Publish Solution'
    workingDirectory: '$(Build.SourcesDirectory)/src/ShopManagementSystem'

  - task: CmdLine@2
    displayName: 'Build Docker Image'
    inputs:
      script: 'docker-compose -f docker-compose.yml build'
      workingDirectory: '$(Build.SourcesDirectory)'

  - task: CopyFiles@2
    displayName: 'Copy Kubernetes Deployment Files'
    inputs:
      SourceFolder: '$(Build.SourcesDirectory)/src/ShopManagementSystem/ShopManagementSystem.Dashboard'
      Contents: '**/k8s.deploy.yaml'
      TargetFolder: '$(Build.ArtifactStagingDirectory)'
      CleanTargetFolder: true
      OverWrite: true
      flattenFolders: true

  - task: PublishBuildArtifacts@1
    displayName: 'Publish Artifacts'
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)'
      ArtifactName: 'drop'
      publishLocation: 'AzureBlob'
```

As I already mentioned, It's similar to GitHub Actions and also has a trigger for the branch. Sure, it also has the same jobs. The first job run building the project, install of SDK, making of restore. If this job was passed, the next job will run a unit test. This job requires restoring and building, otherwise, you'll get fail. The next job is composite with several tasks, that build images, create clusters and services and publish artifacts.

##Azure
For adding a pipeline to Azure DevOps, you should log in to https://dev.azure.com/ and make several actions:

![start page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su930d0w2873qudgj2if.png)



- Create a project

![create project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izf1v292btg8af6jbdta.png)


- In the left panel add a repo. If you use the Azure repo then push your changes, otherwise inject your existing updated repo to Azure from GitHub.

![repo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9ahsr0v215nfksevb5d.png)


- Go to pipelines in the left panel and create a new pipeline. Select your Azure repo or external repo, and add a configuration file.


![add pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vex6hwliwc1cmfok07sy.png)

- Your pipeline should finish successfully.

You'll see a pipeline report like this:

![Pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3m2gdesjxkwn0qayh8ws.png)

##Conclusion
Azure Pipeline isn't more complicated than GitHub Actions. However more flexible. This approach consists of deploying the whole project to Azure. You'll have the base cluster and services if you decide to deploy to the Azure instance.

Happy coding!

<a href="https://www.buymeacoffee.com/b9z99kntvtQ" target="_blank"><img src="http://dartfordwaffler.co.uk/wp-content/uploads/2021/03/buy-me-a-beer.jpg" alt="Buy Me A Beer" style="height: 60px !important;width: 317px !important;" ></a>