
In this blog, I will cover up, how to create OCI docker image from Windows ASP .Net application to .Net Core container using open source “Pack” API and deploy on Kubernetes cluster using open source Contour ingress controller. Also, will set up MetaLB load balancer of Kubernetes cluster.
Objective:
- Build .Net Core OCI docker image of ASP .Net application using Pack buildpack API
- Run this docker image on docker for quick docker verification
- Push docker image to image registry Harbor
- Install and configure Contour ingress controller
- MetalLB load balancer for Kubernetes LoadBalancer service to expose as an external IP to public
- Create a deployment and Service script to deploy docker image
- Create an ingress resource and expose this .Dot app to external IP using Contour ingress controller
Prerequisite:
- Kubernetes cluster setup. Note: I have used VMware’s Tanzu Kubernetes Grid (TKG)
- Kubectl CLI
- Pack buildpack API
- Image registry Harbor setup
- git CLI to download Github source code
- MacOS/Ubuntu Linux or any shell
1. Build OCI docker image of ASP .Net application using Pack buildpack API:
Install and configure “Pack” API. I have installed on Ubuntu Linux:
wget https://github.com/buildpacks/pack/releases/download/v0.11.2/pack-v0.11.2-linux.tgz tar xvf pack-v0.11.2-linux.tgz mv pack /usr/local/bin
# Browse all suggested builders $ pack suggest-builders Suggested builders: Google: gcr.io/buildpacks/builder Ubuntu 18 base image with buildpacks for .NET, Go, Java, Node.js, and Python Heroku: heroku/buildpacks:18 heroku-18 base image with buildpacks for Ruby, Java, Node.js, Python, Golang, & PHP Paketo Buildpacks: gcr.io/paketo-buildpacks/builder:base Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang Paketo Buildpacks: gcr.io/paketo-buildpacks/builder:full-cf cflinuxfs3 base image with buildpacks for Java, .NET, NodeJS, Golang, PHP, HTTPD and NGINX Paketo Buildpacks: gcr.io/paketo-buildpacks/builder:tiny Tiny base image (bionic build image, distroless run image) with buildpacks for Golang Tip: Learn more about a specific builder with: pack inspect-builder <builder-image> # Set this full-cf .Net builder which has support for most of the languages (Java, .NET, NodeJS, Golang, PHP, HTTPD and NGINX).Syntax: pack set-default-builder <builder-image> $ pack set-default-builder gcr.io/paketo-buildpacks/builder:full-cf # Clone the GitHub project $ git clone https://github.com/rajivmca2004/paketo-samples-demo.git and && cd paketo-samples-demo/dotnet-core/aspnet # Building docker image and convert into .Net core container $ pack build dotnet-aspnet-sample
2. Run this docker image on docker for quick docker verification
# Running docker image for quick verification before deploying to K8s cluster $ docker run --interactive --tty --env PORT=8080 --publish 8080:8080 dotnet-aspnet-sample # Viewing $ curl http://localhost:8080
3. Push docker image to image registry Harbor
$ docker login -u admin -p Harbor123 harbor.vmwaredc.com/library #Push to Harbor image registry $ docker push harbor.vmwaredc.com/library/dotnet-aspnet-sample
We need an ingress controller to expose Kubernetes services as external IP. It will work as an internal load balancer to expose to K8s services on http/https and REST APIs of microservices.
4. Install and configure Contour ingress controller
Refer this installation doc of Contour open source for more information
# Run this command to download and install Contour open source project $ kubectl apply -f https://projectcontour.io/quickstart/contour.yaml
5. MetalLB load balancer for Kubernetes LoadBalancer service to expose as an external IP to public
Kubernetes does not offer an implementation of network load-balancers (Services of type LoadBalancer) for bare metal clusters. The implementations of Network LB that Kubernetes does ship with are all glue code that calls out to various IaaS platforms (vSphere, TKG, GCP, AWS, Azure, OpenStack etc). If you’re not running on a supported IaaS platform, LoadBalancers will remain in the “pending” state indefinitely when created.
Bare metal cluster operators are left with two lesser tools to bring user traffic into their clusters, “NodePort” and “externalIPs” services. Both of these options have significant downsides for production use, which makes bare metal clusters second class citizens in the Kubernetes ecosystem.
Please follow this MetalLB installation doc for the latest version. Check that MetalLB is running.
$ kubectl get pods -n metallb-system
Create layer 2 configuration:
Create a metallb-configmap.yaml file and modify your IP range accordingly.
$vim metallb-configmap.yaml apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: - 10.10.40.200-10.10.40.250 # Configure MetalLB $ kubectl apply -f metallb-configmap.yaml
6. Create a deployment and Service script to deploy docker image
You can download and refer complete code from GitHub repo.
$ vim dotnetcore-asp-deployment.yml apiVersion: v1 kind: Service metadata: name: dotnetcore-demo-service namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: dotnetcore-demo-app sessionAffinity: None type: ClusterIP status: loadBalancer: {} --- apiVersion: apps/v1 kind: Deployment metadata: name: dotnetcore-app-deployment namespace: default spec: securityContext: runAsUser: 0 selector: matchLabels: app: dotnetcore-demo-app replicas: 3 template: # create pods using pod definition in this template metadata: labels: app: dotnetcore-demo-app spec: containers: - name: dotnetcore-demo-app image: harbor.vmwaredc.com/library/dotnet-aspnet-sample ports: - containerPort: 9080 name: server
Deploy the .Net Core pods:
$ kubectl apply -f nginx-deployment.yml
7. Create an ingress resource and expose this .Dot app to external IP using Contour ingress controller
Create an ingress resource:
$ vim dotnetcore-ingress-cluster.yml apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: dotnetcore-demo-cluster1-gateway labels: app: dotnetcore-demo-app spec: rules: - http: paths: - path: / backend: serviceName: dotnetcore-demo-service servicePort: 80 # Create ingress resource $ kubectl apply -f dotnetcore-ingress-cluster1.yaml
Get the IP of the .Net Core K8s service to access the application:
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE dotnetcore-demo-service LoadBalancer 10.109.51.83 10.10.40.201 80:30452/TCP 5m
To test open this URL in your browser with external IP=> http://[EXTERNAL-IP]/