Deploying and exposing a stateless app with Kubernetes and Docker Desktop

Kubernetes and Containers are becoming the defacto standard for cloud deployments. It seems like every PaaS platform is now running docker with K8s under the hood. I thought I understood it until I actually used it.

Here is a quick run through deploying a stateless app in Kubernetes on a Windows 10 using a single node Docker Desktop cluster. We will run two copies of NGINX in the cluster so they will both be on the single K8s worker node.  Kubernetes apps aren't visible to the host machine by default so we will use the kubctl proxy to provide access.

I actually ran this on a Kind provisioned K8s cluster with 3 worker nodes and two control plain nodes.  This let me run multiple worker nodes that I could spread the deployed containers across.


Deploy App - Make endpoint visible to host browser

We need to deploy the application and then make it visible to browsers on the host. We will deploy two replicas of the application on your 3 nod network. They should end up getting spread across the nodes.
Set up environment

Pre game preparation
  • Install Docker Desktop
  • Enable Kubernetes or install Kind
Enable proxy access to deployed applications

Create a YAML template file.  Call it "nginx-2-node-deployment.yaml   
  • This file creates a two server nginx server and creates a service for it.
  • This deployment is of type ClusterIP which means the endpoints are only visible inside the Kube cluster.
  "labels": {
apiVersionapps/v1 # for versions before 1.9.0 use apps/v1beta2
  replicas2 # tells deployment to run 2 pods matching the template
      - namenginx
        - containerPort80
    - protocolTCP

Apply the yaml file.  This will create a nginx-dev namespace
        $ kubectl apply -f <filename>.yaml
$ kubectl apply -f nginx-2-node-deployment.yaml
namespace/nginx-dev created
deployment.apps/nginx-deployment created
service/nginx-service created

Verify our namespace was created.

$ kubectl get namespaces
NAME                   STATUS   AGE
default                Active   45h
kube-node-lease        Active   45h
kube-public            Active   45h
kube-system            Active   45h
kubernetes-dashboard   Active   44h
local-path-storage     Active   45h
nginx-dev              Active   43m

Verify the deployment. Notice the replica count

$ kubectl get deployments --namespace nginx-dev
nginx-deployment   2/2     2            2           42m

Get deployment details. Notice the replica count

$ kubectl describe deployment nginx-deployment --namespace nginx-dev
Name:                   nginx-deployment
Namespace:              nginx-dev
CreationTimestamp:      Sun, 19 Jul 2020 15:12:14 -0400
Labels:                 <none>
Selector:               app=nginx
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
    Image:        nginx:1.19.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-9bcf74994 (2/2 replicas created)
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  42m   deployment-controller  Scaled up replica set nginx-deployment-9bcf74994 to 2
Verify 2 pods were provisioned

$ kubectl get pods --namespace nginx-dev
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-9bcf74994-ksl7z   1/1     Running   0          12m
nginx-deployment-9bcf74994-mczrb   1/1     Running   0          12m            

Verify the pods are bound to a service. Note that this is ClusterIP which means the service is only visible internally.

$ kubectl get service --namespace nginx-dev
nginx-service   ClusterIP   <none>        80/TCP    14m

Get service details   

$ kubectl describe service nginx-service --namespace nginx-dev
Name:              nginx-service
Namespace:         nginx-dev
Labels:            <none>
Selector:          app=nginx-deployment
Type:              ClusterIP
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>
Expose and connect to the deployment

Expose the deployment via the proxy server.  
  • Note: I could not connect if I exposed the service with kubectl expose service ... 
  • Note: I could not figure out how to add "expose deployment" to a yaml file.
$ kubectl expose deployment nginx-deployment --name nginx-dev-http --namespace nginx-dev --port=80 --target-port=80
service/nginx-dev-http exposed
Start the proxy server to expose the API and exposed deployments.

$ kubectl proxy
Starting to server on

Find nginx-dev namespace in the api server
Find nginx-dev in the list of exposed services
Exposed deployments show up with this syntax
Delete everything

Delete the namespace and everything in it. This may take a minute.

$ kubectl delete namespace nginx-dev
namespace "nginx-dev" deleted

Verify everything is gone

$ kubectl get deployments --all-namespaces
NAMESPACE              NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
kube-system            coredns                     2/2     2            2           45h
kubernetes-dashboard   dashboard-metrics-scraper   1/1     1            1           45h
kubernetes-dashboard   kubernetes-dashboard        1/1     1            1           45h
local-path-storage     local-path-provisioner      1/1     1            1           45h

Related Links


Post a Comment

Popular posts from this blog

Understanding your WSL2 RAM and swap - Changing the default 50%-25%

Installing the RNDIS driver on Windows 11 to use USB Raspberry Pi as network attached

DNS for Azure Point to Site (P2S) VPN - getting the internal IPs