
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]/