Kubernetes Handnotes
Tags: kubernetes, docker, reference, cicd
Published: 2021-03-11 04:50:21

---
title: Kubernetes Handnotes
published: true
description: Kubernetes notes that I have managed to prepare over the course of a few years working with kubernetes
tags: kubernetes,docker,reference,cicd
//cover_image: https://direct_url_to_image.jpg
---

These are some of the handnotes that I've prepared over the course of a few years working with kubernetes. Many of these are generally not known well, unless a person has dug deep into the official kubernetes docs.

These are in no specific order, and are meant to be used as notes for quick, and comparatively detailed reference to kubernetes.

The target audience for these handnotes are beginners who have familiaried themselves with the core concepts of kubernetes, and now wish to dig deeper for better understanding, and professionals, who want a quick and thorough reference to the most important aspects of kubernetes without referring to official docs again and again. 

These are in no way a replacement for kubernetes official docs. They are, for all purposes, the best available resources for learning kubernetes. These handnote just try to provide a better ratio of _knowledge gained vs the time taken_, compared to the official kubernetes docs.

---

#### Resources covered:
1. Pods
2. ReplicaSets
3. Controller
4. Master Components
5. Node components
6. Objects
7. UID’s
8. Namespaces
9. Services
10. Labels
11. Label Selectors
12. Field Selectors
13. Annotations
14. Object Management
15. Init Containers
16. Secret generator
17. Persistent volumes(pv) and Persistent volumes claims(pvc)
18. Ingress
19. Ingress Controller
20. Service discovery
21. Endpoint
22. Kube proxy
23. Kube dns
24. Etcd

---

#### Pods
1. Each Pod in a Kubernetes cluster has a unique IP address, even Pods on the same Node.
2. Every container in a Pod shares the network namespace, including the IP address and network ports.
3. By default, docker uses host-private networking, so containers can talk to other containers only if they are on the same machine.
4. Containers inside a Pod can communicate with one another using localhost, and all pods in a cluster can see each other without NAT.
5. All containers in the Pod can access the shared volumes, allowing those containers to share data.
6. Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service. _Services allow your applications to receive traffic_.

#### ReplicaSets
1. Scaling is accomplished by changing the number of replicas in a Deployment
2. A __ReplicaSet__ might dynamically drive the cluster back to desired state via creation of new Pods to keep your application running
3. Kubernetes also supports autoscaling of Pods, but it is outside of the scope of this article. Scaling to zero is also possible, and it will terminate all Pods of the specified Deployment.
4. States in a kubernetes replicaset
    - 1. _DESIRED_ : Configured number of replicas
    - 2. _CURRENT_ : Show how many replicas are running now
    - 3. _UP-TO-DATE_ : Number of replicas that were updated to match the desired (configured) state
    - 4. _AVAILABLE_ : Shows how many replicas are actually AVAILABLE to the users
5. Updates in kubernetes are versioned, and any _deployment update_ can be reverted to a previous (stable) version.

#### Controller
1. A __controller__ handles all aspects of pod management including, but not limited to, creation, scheduling, replication, and healing of pods.

#### Kubernetes Master Components
1. __kube-apiserver__ : Exposes the Kubernetes API. It is designed to scale horizontally
2. __etcd__ : Consistent and highly-available key value store used as Kubernetes’ backing store for all cluster data. Always have a backup plan for etcd’s data for your Kubernetes cluster.
3. __kube-scheduler__ : Schedules newly created pods to run on nodes based on individual and collective resource requirements, hardware/software/policy constraints, affinity and anti-affinity specifications, data locality, inter-workload interference and deadlines.
4. __kube-controller-manager__ : Runs controllers. Each controller includes:
    - 1. __Node controller__: Responsible for noticing and responding when nodes go down.
    - 2. __Replication Controller__: Responsible for maintaining the correct number of pods for every replication controller object in the system.
    - 3. __Endpoints Controller__: Populates the Endpoints object (that is, joins Services & Pods).
    - 4. __Service Account & Token Controllers__: Create default accounts and API access tokens for new namespaces.
5. __Cloud controller manager__ : runs controllers that interact with the underlying cloud providers. The cloud-controller-manager binary is an alpha feature introduced in Kubernetes release 1.6. The following controllers have cloud provider dependencies:
    - 1. __Node Controller__: For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding
    - 2. __Route Controller__: For setting up routes in the underlying cloud infrastructure
    - 3. __Service Controller__: For creating, updating and deleting cloud provider load balancers
    - 4. __Volume Controller__: For creating, attaching, and mounting volumes, and interacting with the cloud provider to orchestrate volumes

#### Kubernetes Node components
1. __kubelet__ : An agent that runs on each node in the cluster. It makes sure that containers are running in a pod. It doesn’t manage containers which were not created by Kubernetes.
2. __Container runtime__
3. __Addons__ : Provides cluster features
4. __DNS__ : DNS server. Serves DNS records for Kubernetes services. Containers started by Kubernetes automatically include this DNS server in their DNS searches.
5. __Web UI__
6. __Container Resource Monitoring__
7. __Cluster-level logging__

#### Kubernetes Objects
1. They are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. 
2. By creating an object, you’re effectively telling the Kubernetes system what you want your cluster’s workload to look like; this is your cluster’s desired state.
3. Every Kubernetes object includes two nested object fields that govern the object’s configuration: the object spec and the object status. 
    - 1. __Spec__ : It describes your desired state for the object
    - 2. __Status__ : It describes the actual state of the object, and is supplied and updated by the Kubernetes system.
4. Required fields in an _object spec_ file:
    - 1. __apiVersion__
    - 2. __kind__
    - 3. __metadata__
        - 1. _name_: mandatory
        - 2. _uid_: mandatory: system provided
        - 3. _namespace_: optional
    - 4. __spec__
5. All objects in the Kubernetes REST API are unambiguously identified by a __Name__ and a __UID__.
6. _Name_ is a client-provided string that refers to an object in a resource URL, such as _/api/v1/pods/some-name_. This becomes DNS_NAME?.
7. Only one object of a given kind can have a given name at a time. However, if you delete the object, you can make a new object with the same name.

#### Kubernetes UID's
1. They are a kubernetes _systems-generated strings to uniquely identify objects_.
2. Every object created over the whole lifetime of a Kubernetes cluster has a __distinct UID__. It is intended to distinguish between historical occurrences of similar entities.

#### Namespaces
1. Kubernetes supports multiple virtual clusters backed by the same physical cluster. These virtual clusters are called __namespaces__.
2. Namespaces are intended for use in environments with many users spread across multiple teams, or projects.
3. Namespaces provide a scope for names. _Names of resources need to be unique within a namespace, but not across namespaces_.
4. Namespaces can not be nested inside one another.
5. Default namesspaces:
    - 1. __default__
    - 2. __kube-system__: For objects created by the Kubernetes system
    - 3. __kube-public__: Readable by all users (including those not authenticated).
35. If you want to reach a service across namespaces, you need to use the fully qualified domain name (FQDN).
36. Default behavior of kubernetes is to lookup a service in local namespace. Service DNS entry is of the form: __<service-name>.<namespace-name>.svc.cluster.local__.
37. _Namespace resources_ are not themselves in a namespace. 
38. _Low-level resources_, such as _nodes_ and _persistentVolumes_, are __not__ in any namespace.

#### Services
1. A __Service__ in Kubernetes is an abstraction which defines a logical set of Pods, and a policy by which to access them. Services enable a _loose coupling between dependent Pods_.
2. Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service. _Services allow your applications to receive traffic_.
3. A service is assigned a unique IP address (also called clusterIP). 
4. This address is tied to the lifespan of the Service, and will not change while the Service is alive
5. A Service is backed by a group of Pods, and these pods are exposed through endpoints.
6. The Service’s selector will be evaluated continuously and the results will be POSTed to an Endpoints object
7. When a Pod dies, it is automatically removed from the endpoints, and new Pods matching the Service’s selector will automatically get added to the endpoints.
8. A service IP is _completely virtual_, it never hits the wire.
9. Kubernetes services provides a stable, __virtual IP (VIP)__ address.
10. Virtual IP(VIP) address means it is not attached to any network interface
11. VIP's purpose is to forward traffic to pods
12. Keeping the mapping between the VIP and the pods up-to-date is the job of _kube-proxy_, a process that runs on every node, which queries the API server to learn about new services in the cluster.
13. The _target for service may not necessarily be a pod_. It can be external cluster component, component in some other namespace, non-kubernetes component. Just define your service without the selector attribute.
14. With no selector attribute, no endpoints object is created.
15. For multi-port services (services that expose more than one port), you must give all of your ports names, so that endpoints can be disambiguated
16. Services can be exposed in different ways by specifying a type in the _ServiceSpec_:
    - 1. __ClusterIP (default)__ - Exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster.
    - 2. __NodePort__ - Exposes the Service on the same port of each selected Node in the cluster using NAT. Makes a Service accessible from outside the cluster using `<NodeIP>:<NodePort>`. This acts as superset of ClusterIP.
    - 3. __LoadBalancer__ - Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP to the Service. This acts as  superset of NodePort.
    - 4. __ExternalName__ - Exposes the Service using an arbitrary name (specified by externalName in the spec) by returning a CNAME record with the name. No proxy is used. This type requires v1.7 or higher of kube-dns.
    - 5. To summarize, __ExternalName__ => is superset of __LoadBalancer__ => is superset of __NodePort__ => is superset of __ClusterIP__
17. Difference b/w port, targetPort and nodePort:
    - 1. __Port__: Port number which makes a service visible to other services running within the same cluster
    - 2. __TargetPort__: Port on which service is running
    - 3. __NodePort__: Port on which the service can be accessed from _external users_ using __Kube-Proxy__
18. A Service routes traffic across a set of Pods.
19. A few notes about __NodePort__ type service:
    - 1. It is _not_ designed for production environments. Use _LoadBalancer_ or _Ingress Controller/Resource_ for same
    - 2. Need to specify extra nodePort attribute to service definition
    - 3. Opens specified (or automatically chosen if not specified) port on every node
    - 4. You can only have once service per port
    - 5. You can only use ports 30000–32767
    - 6. If your Node/VM IP address change, you need to deal with that
20. A few notes about __LoadBalancer__ type service:
    - 1. Best method to expose a service to outside world, if your cloud provider supports it
    - 2. There is no filtering, no routing, etc. This means you can send almost any kind of traffic to it, like HTTP, TCP, UDP, Websockets, gRPC, or whatever.
    - 3. Each service exposed with _LoadBalancer_ will get its own IP address, and you have to pay for a LoadBalancer per exposed service, which can get expensive.
21. Use _externalIPs_ in service spec to set an ip address as target of service. This can be outside cluster
22. Services have an integrated load-balancer that will distribute network traffic to all Pods of an exposed Deployment. Services will monitor continuously the running Pods using endpoints, to ensure the traffic is sent only to available Pods.
23. If you want to reach a service across namespaces, you need to use the fully qualified domain name (FQDN).
24. Default behavior of kubernetes is to lookup a service in local namespace. Service DNS entry is of the form: _\<service-name>.\<namespace-name>.svc.cluster.local_.
25. Kubernetes offers a DNS __cluster addon service__ that automatically assigns dns names to other services.
26. A few notes about __Headless services__: 
    - 1. When you don’t need or want load-balancing and a single service IP.
    - 2. Specify _None_ as the _clusterIP_ value.
    - 3. Allows developers to reduce coupling to the Kubernetes system by allowing them freedom to do discovery their own way.
    - 4. Cluster IP is not allocated.
    - 5. kube-proxy does not handle these services.
    - 6. There is no load balancing or proxying done by the platform for them.
    - 7. If selectors are defined, the endpoints controller creates Endpoints records in the API, and modifies the DNS configuration to return A records (addresses) that point directly to the Pods backing the Service.
    - 8. If selectors are not defined, no _endpoints_ objects are created. But, _CNAME_ records for _ExternalName_ type services are created and A records for any _Endpoints_ that share a name with the service, for all other types.

#### Labels
1. Labels can be attached to objects at creation time or later on. also, they can be modified at any time.
2. Labels are used to specify identifying attributes of objects.
3. _The name segment_ is __required__ and must be _63 characters or less_.
4. The __prefix__ must be a DNS subdomain: a series of DNS labels separated by dots (.), not longer than 253 characters in total, followed by a slash (/).
5. Labels are used to specify __identifying attributes of objects__. _Non-identifying information_ should be recorded using __annotations__.
6. If the prefix is omitted, the label Key is presumed to be private to the user.
7. The __kubernetes.io/__ and __k8s.io/__ prefixes are reserved for Kubernetes core components.
8. Valid label values must be 63 characters or less. They could be empty too.

#### Label Selectors
1. The client, or a user can identify a set of objects. The __label selector__ is the core grouping primitive in Kubernetes.
2. Following _types of label selectors_ are supported: __equality-based__ and __set-based__.
    - 1. Equality based label selectors:
    - 2. Set based label selectors:
3. Equality based label selectors:
    - 1. Operators allowed: `=,==,!=`
    - 2. These can be specified as:
        - 1. New line terminated:
        ```
        environment = production
        tier != frontend
        ```
        - 2. Comma separated:
        ```
        environment=production,tier!=frontend
        ```
4. Set based label selectors:
    - 1. Operators allowed: `in, notin and exists` (only the key identifier)
    - 2. Examples:
      ```
      environment in (production, qa)
      tier notin (frontend, backend)
      partition
      !partition
      partition,environment notin (qa)
      >>> Above one selects resources with a partition key(no matter the value) and with environment different than  qa
      ```
5. _Set-based_ label selectors can be mixed with _equality-based_ selectors. Example: `partition in (customerA, customerB),environment!=qa`
6. Label selectors can be clubbed with API calls as query params and kubectl commands to _filter the returned results_. Examples:
`partition in (customerA, customerB),environment!=qa`
7. _Service_ and _ReplicationController_ does NOT support _set based label selectors_.
8. Newer resources, such as _Job_, _Deployment_, _Replica Set_, and _Daemon Set_, support set-based label selectors.

#### Field Selectors
1. They let you select Kubernetes resources based on the value of one or more resource fields. Examples:```
status.phase=Pending
kubectl get pods --field-selector status.phase=Running
```
2. Supported field selectors vary by Kubernetes resource type. 
3. All resource types support the _metadata.name_ and _metadata.namespace_ fields. 
4. Using unsupported field selectors produces an error.
5. Multiple resources can be filtered in one go. Also, multiple field selectors can be given using comma as separator. Example:
```
kubectl get statefulsets,services --field-selector=status.phase!=Running,spec.restartPolicy=Always
```

#### Annotations
1. They store _non-identifying object data_. They _cannot_ be used to target/select objects based on their value(s).
2. The _metadata_ in an annotation can be small or large, structured or unstructured, and can include characters not permitted by labels.
3. Annotations have the _same syntax as labels_.

#### Kubernetes Object Management
Following are the 3 ways to interact with kubernetes objects:
1. Using __Imperative commands__: They operate on _Live objects_
2. Using __Imperative object configuration__: They operate on _Individual files_
3. Using __Declarative object configuration__: They operate on _Directories of files_

#### Imperative commands
1. Used with kubectl with resource name in the command

#### Imperative object configuration
1. Used with kubectl with operation(create, replace, etc.) and single object config file.
2. The object config file specified must contain a full definition of the object in YAML or JSON format. 
3. Multiple files can also be specified. Example:
```
kubectl delete -f nginx.yaml -f redis.yaml
```

#### Declarative object configuration
1. Operates on object configuration files stored locally. 
2. The user does not define the operations to be taken on the files.
3. Create, update, and delete operations are automatically detected per-object by kubectl.
4. Uses __patch__ operation to preserve changes made by other writers, while applying new changes (_diffs only_).
5. To see what changes are going to be made, use:```
kubectl diff -f configs/
```
6. To apply the changes:```
kubectl apply -f configs/
```
7. Use command line flag __-R__ to process directories recursively.
8. These files are known as resource configs.

#### Init Containers
1. They are _specialized containers that run before app containers_.
2. Thwy can contain utilities or setup scripts, not present in the app image.
3. They always run to completion.
4. Each one must complete successfully before the next one is started.
5. _Custom containers_ can be specified as __initContainers__ using _initContainers field of PodSpec_.
6. Almost exactly same as regular containers in all aspects of the _specs_ object.
7. Does not support readiness probes as they must run to completion before the pod can be ready.
8. They are started __after__ network and volumes are initialized.
9. Changes to the _init container spec_ are limited to the container image field.
10. The __activeDeadlineSeconds__ is applicable on both types of containers.
11. App container image changes only restarts the app container, not the init containers. For that, init container image needs to changed.

#### Secret generator: kustomization.yaml
1. A Secret is an object that stores a piece of sensitive data like a password or key. 
2. Since 1.14, kubectl supports the management of kubernetes objects using a kustomization file. 
3. You can create a secret by generators in __kustomization.yaml__.

#### Persistent volumes(pv) and Persistent volumes claims(pvc)
1. Use __ReadWriteMany__ and not __ReadWriteOnce__ when using shared volume.
2. _Access control_: __gid(group id)__ can be assigned to the created volume to _restrict access_ to specific pods with the same gid.
3. A __PersistentVolume (PV)__ is a piece of storage in the cluster that has been manually provisioned by an administrator, or dynamically provisioned by kubernetes using a __StorageClass__.
4. A __PersistentVolumeClaim (PVC)__ is a request for storage by a user that can be fulfilled by a _Persistent Volume_. 
5. PersistentVolumes and PersistentVolumeClaims are independent from Pod lifecycles and preserve data through restarting, rescheduling, and even deleting Pods.
6. Many cluster environments have a default StorageClass installed. When a StorageClass is not specified in the PersistentVolumeClaim, the cluster’s default StorageClass is used instead.
7. In local clusters with default storage class (hostPath), data is saved in node's __/tmp__ directory. Hence, could be lost on reboot.

#### Kubernetes *Secret* object type
1. Stores a piece of sensitive data like a password or key.

#### DNS
1. Kubernetes offers a DNS __cluster addon service__ that automatically assigns dns names to other services.
2. To check whether the same is running on your cluster or not, use following:
```
kubectl get services kube-dns --namespace=kube-system
```

#### Ingress
1. An API object that manages external access to the services in a cluster, typically HTTP.
2. Ingress can provide load balancing, SSL termination and name-based virtual hosting.
3. Kind of like a reverse proxy
4. An Ingress can be configured to give services externally-reachable URLs, load balance traffic, terminate SSL, and offer name based virtual hosting.
5. An Ingress does not expose arbitrary ports or protocols. Exposing services other than HTTP and HTTPS to the internet typically uses a service of type `Service.Type=NodePort` or `Service.Type=LoadBalancer`.
6. You must have an __Ingress controller__ to satisfy an Ingress. _Only creating an Ingress resource has no effect_.
7. Note that NOT all ingress controllers support the full spec. Be careful while choosing.
8. It supports TLS.
9. Supports load balancing. A few of the common algorithms are supported. For others, service loadbalancer can be used.
10. Health checks not exposed by default. But, readiness probes can be used.
11. Cross availability zones deployments can be done, but depends on cloud provider support. Refer __federation documentation__ for details on deploying _Ingress in a federated cluster_.
12. Types of Ingress:
    - 1. _Single Service Ingress_: Expose a single service. No host and path mapping
    - 2. _Sample Fanout_: Exposes multiple services using path-only mapping
    - 3. _Name based virtual hosting_: Uses domain and path mappings
13. At least on GKE, spins up a L7 layer HTTP load balancer, hence, is non-protocol agnostic.
14. Lot of available ingress controllers: Google Cloud Load Balancer, Nginx, Contour, Istio, and more.

#### Ingress Controller
1. An Ingress Controller listens to the Kubernetes API for _Ingress resources_ and then handle requests that match them.
2. Can technically be any system capable of reverse proxying, but the most common is Nginx.
3. Nginx controller needs a backend. Other controllers _might_ not need one.
4. An Ingress with no rules sends all traffic to a single default backend.
5. The default backend is typically a configuration option of the Ingress controller and is not specified in your Ingress resources

#### Service discovery
Following are the 2 ways in which service discovery can be provisioned:
1. Using environment variables
2. DNS (recommended)

#### Environment variables - for service discovery
1. kubelet exposes environment variables of the form {SVCNAME}_{SOME_NAME}. Example, for a redis service with cluser ip of _10.0.0.11_:
```
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
```

#### DNS - for service discovery
1. It's a cluster add-on.
2. The DNS server _watches the Kubernetes API_ for new _services_, and creates a set of DNS records for each.
3. For service _my-service_ in namespace _my-ns_, a DNS record for _my-service.my-ns_ is created.
4. No need to specify namespace, if pods belong to the same.
5. The Kubernetes DNS server is the only way to access services of type ExternalName.

#### Endpoint
1. An __Endpoint__ is an _object-oriented representation of a REST API endpoint_ that is populated on the Kubernates API server. Thus, the _endpoint_ in terms of Kubernetes is the way to access its resource (e.g. a Pod) - the resource behind the 'endpoint'.
2. Contains __EndpointSubset__ array.
3. _EndpointSubset_ is a group of addresses with a common set of ports. The expanded set of endpoints is the _cartesian product of Addresses x Ports_.
4. __EndpointAddress__ of _EndpointSubset_ may __NOT__ be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). 
5. __IPv6__ is also accepted, but not fully supported on all platforms.
6. The Service’s selector is continuously evaluated, and the results are _POSTed_ to an endpoints object
7. When a Pod dies, it is automatically removed from the endpoints, and new pods matching the service’s selector are automatically added to the endpoints.
8. _Endpoints_ track the IP addresses of the objects the service send traffic to.
9. And endpoint be loosely coupled with a service by keeping service's and endpoint's name same. See https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors for more.
10. With no selector attribute mentioned (is a service), no endpoints object is created.

#### Kube proxy
1. It's a special daemon (application) running on every worker node.
2. Can run in two modes, configurable with `--proxy-mode` command line switch:
    - 1. _userspace_
    - 2. _iptables_
3. For higher throughput and better latency, use _iptables_ proxy mode.
4. _Not_ IPv6 ready.
5. Maintains network rules and performs connection forwarding.
6. This is useful for:
    - 1. Debugging your services, or connecting to them directly from your laptop for some reason
    - 2. Allowing internal traffic, displaying internal dashboards, etc.

#### Kube dns
1. This allows accessing K8s services using their names directly, rather than _VIP:PORT_ combination.
2. When you use kube-dns, K8s _injects_ certain nameservice lookup configuration into new pods that allows you to query the DNS records in the cluster.
3. kube-dns creates an _internal cluster DNS zone_ which is used for DNS and service discovery. This means that we can access the services from inside the pods via the service names directly. Example:```
curl -I nginx-svc:8080
``` 
4. You can use following to see node dns config as setup by kube-dns:```
cat /etc/resolv.conf
> search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.kube-blog.internal
  nameserver 10.32.0.10
  options ndots:5
```
5. If the service is created in default namespace, it can be accessed using the _cluster internal DNS name_, too:```
curl -I nginx-svc.default.svc.cluster.local:8080
```

#### Etcd
1. This is a consistent and highly-available key value store, used as kubernetes’ backing store for all cluster data.
2. Make sure to always have a backup plan for etcd’s data for your kubernetes cluster.
3. All data is saved in etc as registries. Example:```
/registry/services
/registry/events
/registry/secrets
/registry/minions
```
4. Following command can be used to query data in etcd:```
etcdctl --ca-file=/etc/etcd/ca.pem get /registry/services/endpoints/default/kubernetes
```

That's all, folks ¯\\_(ツ)_/¯

---

Drop me a mail at [contact@nitinbansal.dev](mailto:contact@nitinbansal.dev) or DM me on [twitter](https://twitter.com/9wxg1) if you have any suggestions or need any help with software development.

Also, do visit my blog https://nitinbansal.dev if you like this. I have much more useful content planned to be added.


### References
1. https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/
2. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands
3. https://kubernetes.io/docs/tasks/access-application-cluster/communicate-containers-same-pod-shared-volume/
4. https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
5. Examples: 
  * https://github.com/kubernetes/website/blob/master/content/en/examples/service/nginx-service.yaml
  * https://github.com/kubernetes/website/blob/master/content/en/examples/service/networking/run-my-nginx.yaml
  * https://github.com/kubernetes/examples/blob/master/mysql-wordpress-pd/wordpress-deployment.yaml
6. https://stackoverflow.com/questions/54923806/why-do-i-get-unbound-immediate-persistentvolumeclaims-on-minikube
7. https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
8. https://github.com/containous/traefik
9. https://blog.openshift.com/kubernetes-services-by-example/
10. http://containerops.org/2017/01/30/kubernetes-services-and-ingress-under-x-ray/
11. https://matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-ingress-guide-nginx-example.html
12. https://medium.com/@cashisclay/kubernetes-ingress-82aa960f658e
13. https://github.com/kubernetes/kops/tree/master/addons