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.
Video
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
|
|
Enable proxy access to deployed applications | |
Create a YAML template file. Call it "nginx-2-node-deployment.yaml
apiVersion: v1 kind: Namespace metadata: name: nginx-dev "labels": { "name": "development" } --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: nginx-deployment namespace: nginx-dev spec: selector: matchLabels: app: nginx replicas: 2 # tells deployment to run 2 pods matching the template template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19.1 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service namespace: nginx-dev spec: selector: app: nginx-deployment ports: - protocol: TCP port: 80 targetPort: 80 | |
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 NAME READY UP-TO-DATE AVAILABLE AGE 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> Annotations: deployment.kubernetes.io/revision: 1 kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"apps/v1","kind":"Deployment","metadata":... 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 Containers: nginx: Image: nginx:1.19.1 Port: 80/TCP Host Port: 0/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: nginx-deployment-9bcf74994 (2/2 replicas created) Events: 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 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service ClusterIP 10.96.22.26 <none> 80/TCP 14m | |
Get service details $ kubectl describe service nginx-service --namespace nginx-dev Name: nginx-service Namespace: nginx-dev Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name"... Selector: app=nginx-deployment Type: ClusterIP IP: 10.96.22.26 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.
$ 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 127.0.0.1:8001 |
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
- https://www.ovh.com/blog/getting-external-traffic-into-kubernetes-clusterip-nodeport-loadbalancer-and-ingress/
- https://kubernetes.io/docs/concepts/services-networking/ingress/
- https://kubernetes.io/docs/concepts/services-networking/service/
- https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/
- https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
- https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/
- https://kind.sigs.k8s.io/docs/design/initial/
Great tutorial, thanks Joe for your effort
ReplyDelete