Hi, all!
We have developed a RESTful API in the previous ASP.NET Core blog post series, and then we deployed that to the Azure App Services. In this blog post series, I’ll try to mention how we can containerize a RESTful API, and then how we can deploy it to Kubernetes using Azure Container Service, based my experience in the .NET Core transformation process at the company I’m currently working at.
Topics are:
- Building a Docker Image and Push to Docker Hub
- Creating a Kubernetes Cluster using Azure Container Service
- Creating an SSH RSA Public Key
- Creating a Service Principal Client ID and Secret
- Creating a Kubernetes Cluster
- Connecting to Kubernetes Cluster
- Running ASP.NET Core RESTful API inside to Kubernetes Cluster’s Pod
- Exposing Kubernetes Pod to Outside with Kubernetes Service
- Creating and Exposing Kubernetes Deployment Controller
NOTE: In this article, I won’t describe some topics, such as what the Docker is and why we need that etc. For this article, you need to know some Docker information.
As we know, a container image is a lightweight, stand-alone, executable package of a piece of software. Containers isolate applications in the same infrastructure. Thus, development and staging environment differences are separated from each other, thereby helping to reduce any conflicts that may occur.
We will use the example project that we developed in my previous post titled “ASP.NET Core Series 01: Building RESTful API with Dapper and Deploy to Azure App Services” for containerizing. Let’s download the example project from GitHub, and then unzip to the desktop.
1. Building a Docker Image and Push to Docker Hub
NOTE: Btw, I’m using DockerToolbox on the Windows.
First, we need to create a Dockerfile to building an image. Let’s create a Dockerfile in the root directory of the project as shown below.
FROM microsoft/aspnetcore:1.1 ENTRYPOINT ["dotnet", "aspnetcore-rest-api-with-dapper.dll"] ARG source=. WORKDIR /app EXPOSE 5000 COPY $source .
In the Dockerfile, we defined that we want to use the official compiled ASP.NET Core image and expose on port “5000“. Also as an entrypoint, we specified the “aspnetcore-rest-api-with-dapper.dll” file that we’ll get after publishing the project. Now, let’s build the project using a command-line tool as shown below.
dotnet build
NOTE: Don’t forget to restore packages using the “dotnet restore” command.
After building the project, we need to publish the project using as following command:
dotnet publish -c release
Now, we can build an image using the Dockerfile.
docker build bin\Release\netcoreapp1.1\publish -t aspnetcorerestapionlinux
We built an image called “aspnetcorerestapionlinux” using the “bin\Release\netcoreapp1.1\publish” path. Let’s see the image using the following command:
docker images
There are the “aspnetcorerestapionlinux” image as we can see on the above picture.
Now, let’s run the container to make sure everything is okay.
docker run -d -p 5000:5000 aspnetcorerestapionlinux
We ran the “aspnetcorerestapionlinux” image in a container and exposed it to outside on the port “5000“. Let’s open the “http://192.168.99.100:5000/swagger” URL on the browser.
Yeap, the image is running successfully in the container. Now, we have the containerized ASP.NET Core RESTful API.
We need to push the “aspnetcorerestapionlinux” image to the Docker Hub. Thus, we can pull this image, and then run in a Kubernetes cluster with Azure Container Service. First, we need to have a Docker Hub account. If you don’t have an account, you can create one here.
Let’s add a tag on the image as shown below.
docker tag aspnetcorerestapionlinux gokgokalp/aspnetcorerestapionlinux
NOT: Don’t forget to change “gokgokalp” field with your Docker Hub username.
Now, we need to login.
docker login
After the login process, we can push the image to the Docker Hub.
docker push gokgokalp/aspnetcorerestapionlinux
2. Creating a Kubernetes Cluster using Azure Container Service
Azure Container Service provides solutions to simplify the creation of virtual machines for containerized applications, and to make it easier to configure and manage clusters. Microsoft made the Kubernetes container orchestration service completely available a few months ago. In this way, deploying containerized applications efficiently and scaling them is made easy.
Now, we will create a basic Kubernetes cluster using Azure Container Service. We need the following items to create a cluster:
- Azure subscription – I mentioned in “ASP.NET Core Series 01” blog post, how we can get a subscription.
- SSH RSA public key – We need to create this for authenticating to virtual machines.
- Service Principal client ID and secret – Also, we need to “Azure Active Directory service principal client ID” and a “secret”, for using Kubernetes orchestrator.
2.1 Creating an SSH RSA Public Key
Git for Windows should be installed on your computer. If you need: https://git-for-windows.github.io/
Let’s create a “myPrivateKey” and “myCert” certificate using the “openssl.exe” with Git Bash.
openssl.exe req -x509 -nodes -days 365 -newkey rsa:2048 \-keyout myPrivateKey.key -out myCert.pem
While in this process, we need to fill some information such as “Country Name, State, E-mail, Organization Name“. After this process, the “myPrivateKey” and “myCert” certificate will be created under the related file path.
Now, we will create a public key with the private key that we have created.
openssl.exe rsa -pubout -in myPrivateKey.key -out myPublicKey.key
We have to create an additional key to use PuTTY SSH client as shown below:
openssl rsa -in ./myPrivateKey.key -out myPrivateKey_rsa
After execution the above command, so we got the private key called “myPrivateKey_rsa“.
Now, we will create a public key so that we can create a Linux VM on the Azure portal. First, we need to have PuTTY. If you need, you can download it from here. Let’s run the “PuTTYgen“, and click “Load“. Now we have to choose the “myPrivateKey_rsa” key file that we have created.
Now, we have a public key starting with “ssh-rsa” prefix as you can see on the above picture. We need to keep this public key to use later.
2.2 Creating a Service Principal Client ID and Secret
At this point, we can create an Azure AD (Active Directory) service principal using the portal’s terminal. After the login process to Azure portal, let’s click “Cloud Shell” button at the top right of the portal.
Now let’s create a resource group called “aspnetcore-test-restapi” using the following command.
az group create -n "aspnetcore-test-restapi" -l "westeurope"
After creating the resource group, we need to replace “mySubscriptionID” field of the following command with our subscription ID. After this, let’s run the command.
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/mySubscriptionID/resourceGroups/aspnetcore-test-restapi"
Now, we will see the following output.
We will use “appId” and “password” fields as principal client ID and secret.
2.3 Creating a Kubernetes Cluster
- Log in to the Azure Portal.
- Click “New” button at the top left of the Portal.
- Select “Containers > Azure Container Service” section as shown below.
- In the “Basics” section, click “Use existing” button from resource group and select the “aspnetcore-test-restapi” value that we have created, and then fill other fields as shown below.
- Now we’ll specify some important information such as orchestrator from the “Master configuration” section. Select “Kubernetes” as an “Orchestrator“, and then fill the “DNS name prefix” and others fields as shown below.
Then complete the other fields such as “SSH public key” and “Service principal” with the information that we have created earlier. - In the “Agent configuration” section, let’s select “1” as the “Agent count“, and “Standard DS2” as the “Agent virtual machine size“.
Now, we have a Kubernetes cluster.
2.4 Connecting to Kubernetes Cluster
We need to have “kubectl” to be able to connect to the Kubernetes cluster. First, let’s download and install Azure CLI from here. After installation step, open a command tool and install “kubectl” using the following command.
az acs kubernetes install-cli
Now we have to download Kubernetes cluster configuration info. Therefore, login to Azure portal.
az login
Let’s run the following command (don’t forget to change related fields):
az acs kubernetes get-credentials --resource-group=aspnetcore-test-restapi --name=aspnetcore-container-service --ssh-key-file=C:\Users\GOKGOKALP\myPrivateKey_rsa
After the downloading process, let’s see the node list to make sure the cluster configuration info has been successfully downloaded.
kubectl get nodes
2.5 Running ASP.NET Core RESTful API inside to Kubernetes Cluster’s Pod
If I should say something about Pod, as in its documentation:
Pods are the smallest deployable units of computing in Kubernetes.
A Pod can contain one or more application containers. First, we need to create a new YAML file called “aspnetcore-rest-api-pod.yaml” under the root directory of the project to be able to create a pod in the Kubernetes cluster.
apiVersion: v1 kind: Pod metadata: name: aspnetcore-restapi labels: app: aspnetcore-restapi spec: containers: - name: aspnetcore-container image: "gokgokalp/aspnetcorerestapionlinux" ports: - containerPort: 5000
In the “image” section of YAML file, we specified our Docker image that we have pushed to Docker repo. If you remembered, we have exposed the API in a container on the port “5000“.
Now let’s run the following command using a command tool, under the root directory of the project.
kubectl create -f aspnetcore-rest-api-pod.yaml
We created the pod successfully. Let’s see the pod list.
kubectl get pods
As we can see the “aspnetcore-restapi” pod’s status is “running“. In this pod is running ASP.NET Core RESTful API that we have developed. At this point, we just need to expose this pod using Kubernetes Service.
2.6 Exposing Kubernetes Pod to Outside with Kubernetes Service
Basically, Kubernetes Service is an abstraction to creating policies and sets of a logical pod. If you want to reach more information, just look at here.
We need to create a new YAML file called “aspnetcore-rest-api-ks.yaml” for Kubernetes Service.
apiVersion: v1 kind: Service metadata: name: aspnetcore-restapi-service labels: app: aspnetcore-restapi-service spec: selector: app: aspnetcore-restapi ports: - port: 80 targetPort: 5000 protocol: TCP type: LoadBalancer
With the above YAML file, we’ll create a Kubernetes Service called “aspnetcore-restapi-service” and target TCP port “5000“. We should also make sure that the “app: aspnetcore-restapi” value is the same with pod label that we have created. Let’s run the following command:
kubectl create -f aspnetcore-rest-api-ks.yaml
Now we can see the service in the service list.
kubectl get services
If we look at the above picture, we can see the “aspnetcore-restapi-service” service has a “52.232.119.105” external IP and exposed to outside.
NOTE: IP assigning operation could take a few minutes.
When we reach to the external IP through the browser, we should see the Swagger UI as shown below.
Finally, we just need to create the Deployment Controller.
2.7 Creating and Exposing Kubernetes Deployment Controller
At this point, we have created a Kubernetes cluster using the Azure Container Service, and we defined a pod as the container of our RESTful API. Then, we defined a Kubernetes Service and exposed it to outside on the port “80” with a Load Balancer.
Well, if you read the topic “Durability of pods (or lack thereof)” here, you can see that pods are not durable entities and you can’t reuse them in some situations, such as scheduling failures and node failures. This means when the pod dies, the related service will be unavailable. At this point, we need to use Kubernetes Controller to be production ready. There are a few Controllers such as Deployments and Replication in the Kubernetes. In here, we’ll use the Deployments, which is the new generation of the Replication Controller. Deployments generally provide important operations such as self-healing, rollout management and scaling.
Let’s create a new YAML file called “aspnetcore-rest-api-deployment.yaml“.
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: aspnetcore-restapi-deployment spec: replicas: 3 selector: matchLabels: app: aspnetcore-restapi template: metadata: labels: app: aspnetcore-restapi spec: containers: - name: aspnetcore-container image: "gokgokalp/aspnetcorerestapionlinux" ports: - containerPort: 5000
We defined the “replicas” section of the YAML file as “3“, and then under the “containers” section, we specified image and port info as they were in the pod creation YAML file. Thus, if any situation occurs such as scheduling failures and node failures, the Deployment will make sure that the number of replicas is 3.
Before creating of the deployment, we need to delete the “aspnetcore-rest-api-pod.yaml” pod and the “aspnetcore-rest-api-ks.yaml” service that we have created.
kubectl delete -f aspnetcore-rest-api-pod.yaml
kubectl delete -f aspnetcore-rest-api-ks.yaml
Now, we can create a deployment using the following command:
kubectl create -f aspnetcore-rest-api-deployment.yaml
Let’s have a look at the pods.
kubectl get pods
We can see on the above picture, the deployment created the 3 pods and they are in “running” statuses. It also possible to automatically scale more loads with a deployment. For more information, click here.
The last thing we only have to do is to create a service and expose again this 3 pods to outside. For this operation, we’ll use again the “aspnetcore-rest-api-ks.yaml” file. Because a few steps before we have deleted the service to be able to create pods with the deployment controller.
apiVersion: v1 kind: Service metadata: name: aspnetcore-restapi-service labels: app: aspnetcore-restapi-service spec: selector: app: aspnetcore-restapi ports: - port: 80 targetPort: 5000 protocol: TCP type: LoadBalancer
This service will expose the 3 pods with the label “app: aspnetcore-restapi” to outside from the port “80“.
kubectl create -f aspnetcore-rest-api-ks.yaml
That’s all. We exposed these 3 pods to outside with the Load Balancer. If we want to see the endpoints, just run the following command:
kubectl describe services aspnetcore-restapi-service
After running the command, we can see that the Load Balancer service exposed the “10.244.1.7:5000“, “10.244.1.8:5000” and “10.244.1.9:5000” pods to outside on the “http://52.232.119.105” URL.
I know, this is a long article, but it’s a really enjoyable and important topic. Currently, I’m working on Containerizing and Kuberneting topics at my company’s .NET Core transformation process for some projects. I hope, this article would help who needs any information about Containerizing and Kuberneting to .NET Core applications.
In the next .NET Core article series, I’ll try to describe how we can include these operations in the CI pipeline process using Jenkins.
https://github.com/GokGokalp/containerizing-and-kubernetes-sample-files
Some References and Resources
https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/container-service/container-service-tutorial-kubernetes-prepare-app.md
https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/container-service/container-service-tutorial-kubernetes-prepare-acr.md
https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/container-service/container-service-tutorial-kubernetes-deploy-cluster.md
https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/container-service/container-service-tutorial-kubernetes-deploy-application.md
https://www.docker.com/what-container
https://docs.microsoft.com/tr-tr/azure/container-service/container-service-intro
https://kubernetes.io/docs/concepts/overview/what-is-kubernetes
https://docs.microsoft.com/en-us/azure/container-service/container-service-deployment
https://docs.microsoft.com/en-us/azure/virtual-machines/linux/ssh-from-windows
https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough
http://www.c-sharpcorner.com/blogs/containerizing-a-net-core-application-using-docker-acs-and-kubernetespart-4
https://kubernetes.io/docs/concepts/services-networking/service/
süper bir konu kalemine sağlık
Çok teşekkür ederim.