Kubernetes
What is it? > Architecture > Pod > ReplicaSet > Special Attributes > Deployment > Deployment Strategy > Service > Ingress > Network Policy > Network > Volume > Namespace > Secrets > Service Account > Affinity, Taints and Tolerations > Security > CronJob > Hands-On
Introduction
What is it?
The tradicional deployment didn't scale the resource and it impact in the cost. Another alternative of deployment is the virtualiation, that isolate the apps. It is a better utilization of resources and scalability but each VM represents a enteire machine. Using containers as the third alternative is possible to have the isolation of the application and share the other resources secondary to the application. Also, the cycle of deployment is easear to handle. This last solution is considered lightweight.
The kubernetes or K8s comes as solution for container orchestration that provides a framework to run distributed systems resiliently, takes care of scaling and failover for your application and provides deployment patterns. It is a container orchestration technology. It orchestrates the deplyment and management of containers. The containers can be managed by Docker. Some of features available are: Service discovery and load balancing, Storage orchestration, Automated rollouts and rollbacks, Secret and configuration management, Horizontal scaling, IPv4/IPv6 dual-stack, etc.
Architecture
Node is a machine where K8s is intalled. It includes kubelet, container runtime and kube-proxy. They are managed by the control plane.
Cluster is a group of Nodes managed to keep the application available even if one node fails. That management is done by a node called Master. This node is configured to have the information about the other nodes and manage them. It is responsible for the orchestration of the containers.
Components in Node Master, the orchestrator [Control Plane Componenets]:
- kube-apiserver: it is between K8s and external Node communication. It communicates with Worker Node by kubelet.
- etcd: is respnsible to store all data used to manage the cluster to be used by K8s. For instance, it implements locks to avoid conflicts between masters.
- Scheduler: responsible for distributing work or containers across multiple nodes.
- Controller [kube-controller-manager][cloud-controller-manager]: the brain behind the orchastration - noticing and responding when nodes, containers or endpoints goes down. It makes decisions to bring up new containers
Components in worker nodes [Node Components]<:/p>
- Container Runtime: software used to run container (e.g Docker).
- kublet: agent that runs on each node in the cluster. It is responsible that the containers are running on the nodes as expected
- kube-proxy: is a network proxy that runs on each node of the cluster, and maintains network rules on nodes. It allows the network communication to the Pods in the cluster
Basic Concepts
A note before we start this journey: be aware kubernetes allow two ways to manage the objects. The first one is declarative that use file definitions; and imperative, that use command line directy.
Pod
Pod is a kubernate object that represents a deployable unit of a set of containers. The containers are encapsulated into the Pod that run an instance of the application. If you need to increase the application with more Pods then you need increase the replication number (scale up). To have an application in a Pod is assumed that the application is already developed and built into an images and it is available in some repository. Also assume that the Kubernetes cluster has set up and working. The Pod can have more than one container (only one instance), but the best practices is to have only one container by Pod.
A special feature to Pods is the Pod Initialization. It uses an Init Container to initialize a Pod before an application Container runs.
Any trouble with your pod you can Debug Pod and Debug Running Pod.
ReplicaSet
ReplicaSet maintain a stable set of replicas running at any given time. it is used to guarantee the availability of a specified number of identical Pods. Then, it ensures high availability and handle loads across the pods (load balancing). Even the Pods already created, it's possible to scale that number.
Special Attributes
- Labels and selectors: the objects in kubernates have labels to be used to monitor that objects. For selector, the 'matchLabels' are used to filter the objects. The idea of selectors is to have flexibility when it comes to expressing which other resource be connected to or controlled by other resource.
- Environment Variables: It's possible to use env attributes to add the variables to be used. It can be a direct key-value pair or doing a reference to a external file.
- ConfigMap: it is a key-value pair configuration used as more organized way to create the configuration using separated files.
Deployment
Deployment build the desired state. A Deployment provides declarative updates for Pods and ReplicaSets. It allow edit any field/property of the POD template. After the change, the deployment will automatically delete and create a new pod with the new changes. The deployment can be rollback when the deployment is not stable. Also, you can scale the deployment if you need increase or decrease the replicas. If you delete the deployment object, the others object created by it will be deleted (e.g., pods and replicase).
Deployment Strategy
The kubernetes allows to use different Strategy that define how the application should be updated. When you create a deployment, it triggers the deployment process. Also, it creates a new Deployment revision. A fancy diagrame comparing the strategies you can see here.
- Rolling deployment: replace the pods one by one
- Recreate: terminate all the pods and replace all the pods
- Canary: progressivelly delivery - change the traffic step by step
- Blue/Green: replicate the environment
Network
When the K8s is configured it creates an internal private network and attache all PODs. The Pods will have an IP when they are deployed.
Service
Service: Expose an application running in your cluster behind a single outward-facing endpoint. Pods have an internal IP but it cannot be used to access the Pod outside of the cluster. Beside, the IP changes always when a Pod is replaced. The service groups Pods with a shared IP which will not change, and that address can be exposed internally and externally of the custer, what allow the Pods be accessible outside of the cluster.
Types of services [1][2][3][4]
- ClusterIP: expose only inside the cluster (defaut). There are virtual IP to allow communication between them, e.g, frontend and backend inside the cluster.
- NodePort: Exposes the Service on each Node's IP at a static port (the NodePort). It makes the pod available outside of the node mapping the port on Node (NodePort - 30000 to 32767) to the port on the Pod (TargetPort).
- LoadBalancer: Exposes the Service externally using an external load balancer
Any trouble with your service you can Debug Service.
Ingress
The Ingress is an API object that manages external access to the services in a cluster. Traffic routing is controlled by rules defined on the Ingress resource. The difference between service and ingressis that service create a single point of access to a group of pods, and ingress expose multiple services using one IP through rules that define the graphic. A good example you can see here.
Network Policy
The Network Policy can be used to control the traffic.
Storage
The volume is a directory which is accessible to the containers in a pod. The volume persists even if container restart. However, the volumes are removed when the Pods are destroyed. Considering One-Node environment, the hostPath property helps to keep the data visible for that Node.
Persistent Volume is a volume in the cluster with the lifecycle independent of the Pod. Persistent Volume Claim is a request for storage by user.
Namespace
Namespace: mechanism for isolating groups of resources (pods, rs, jobs, deployments, svc, secrets, roles, rolebinding, configmaps, PVC) within a single cluster. However, some resources (e.g Node, PV clusterroles, namespaces, clusterbindings) are cluster scope and cannot be grouped.
Secret
The Secrets objects are used to store sensitive data which is done in an encoded format. It is created independent of the Pod. You can see different ways of manage the secrets here.
Service Account
Service Account is an account to allow the communication machine-to-machine. When it is created, a token is generated inside a secret object. When you create a cluster, Kubernetes automatically creates a ServiceAccount object named default for every namespace in your cluster.
Affinity, Taints and Tolerations
Node affinity is applied to Node and allow to constrain which nodes a Pod can be scheduled on based on node labels.
Taints are applied to node and allow a node to repel a set of pods.
Tolerations are applied to pods. Tolerations allow the scheduler to schedule pods with matching taints.
Security
The Security is an important topic in K8s. The kube-apiserver is the first point of defense because it is the point of communication in the cluster. By default, all ports can access all other ports, allowing the communication between Pods inside the custer. It can be restricted by Network Policies.
- Authentication (Who can access): static pwd and token file (deprecated 1.19), certification, LDAP, service account
- Authorization (what they can do): Node, RBAC, ABAC, Node authorization, Webhook mode
The service account is managed by K8s but the other users are managed by a third system like LDAP or Okta. The K8s uses the details or certificate to validate them.
This file has the credentials and there are three section: cluster (it has the server specification), users (it has keys and certification) and context (which user has access to which cluster). Pay attention that is using users that already exist.
The K8s API has different groups to manipulate the resources. For instace in '/api' endpoint there is the core group where you will find the core funcionalities (pods, namespace, rs, pv, etc). The '/apis' you will find the named group where you will find extension, apps, networking.k8s.io, storage.k8s.io, etc.
It will happen after the authentication. Then, API server validates if the request is allowed or not based on requests attributes and policies, and eventually some external services. The authorization modes are:
- Node Authorized: Kublet access kube API to read services, endpoints, Nodes,Pods; and Write Node status, Pod status and events
- ABAC: external access for the API; create API with policies; any changes in those files is necessary to restart the kube-apiserver
- RBAC: Define Roles instead of associate a user or group to a set of permissions.
- Webhook: external policies
- AlwasyAllow is the default.
- AlwasyDeny blocks all requests.
It is used to give permissions in cluster scopes like view, create or delete Nodes. (e.g cluster admin).
It links the user to the clusterrole.
It intercept the request after the authorization and authentication but before persist the objects. It can modify the object (Mutating). Admission controllers limit requests to create, delete, modify objects; it can also block custom verbs, however, it cannot block requests to read (get, watch or list) objects.
A security context defines privilege and access control settings for a Pod or Container.
Job
A Job creates one or more Pods and will continue to retry execution of the Pods until a specified number of them successfully terminate.
CronJob
ConJob is a resource in K8s that schedule jobs to execute repeatable actions.
Hands On
Step 0 - Prepare local environment
The first steps are to install the tools necessary to make it works. It means install docker, kubectl and colima. After that you can start colima with kubernetes.
Step 1 - prepare the image
Considering you will create your image, we have to create the image from a project and send it to the Docker Hub. More details about Docker and commands you can see here. For our example we are using this github code.
Now you have everything to test. So, do the tests using a browser and a tool for requests (Postman, Insomnia, IntelliJ).
After you've checked everything is ok, you can send your image to your Docker Hub. For our local tests purpose, also is possible to used the local image.
Step 2 - Check the goals and plane your actions
For this scenario let's create the objects in kubernetes locally and allow to do the same tests we did before. Beside the access, let's create roles to a user 'developer' can create all the objects.
Step 3 - Action
Considering the idea to practices the user restriction, let's start for this. Check your '~/.kube/config' file. Then, we will create a role and link it with the colima user.
Now, let's create the volume that will be used by the Pod. For that, we will create an environment variable to be used to identify the folder name for store data. Then, we will create a deployment with the pod with the reference to the environment and our image. If you want to use your local image you have to add the attribute 'imagePullPolicy=Never'. The last step is to create the service to expose the application. All these files are in the Github project.
Now you have everything to test again.
Step 3 - Rollout
Now, let's change something in the project and create the image again. Pay attention to the fact that the image has to have a new tag to be recognized as a different image.
As a last step for practice purposes, let's use an image that does not exist.
Step 4 - Minikube
Optionally, you can intall minikube to try an interface to manage the K8s objects. It is a good option because it will help you become familiar with those kinds of tools.
You can repeat all the steps to create the objects in a cluster without the namespace and see the results in minikube.
Also, you can try with this application: kubernetes-security-nodejs-mysql. It has example of insecure and secure application with the best practices.
Step 5 - Extra practice
First of all, let's create a new node to add k8s objects. In localhost is allow only one node. For exercice purpuse, let's pretend it works :D.
Now we are available to create deployment and service to that node by affinity and add rules of telerations. Also, you can assign a pod to a node by attribute.
For practices purpose, lets add readiness and liveness attributes to the pods. The liveness probes is used to decide when restart a container, and the readiness is used to identify when a container is ready to start accepting traffic.
Now let's create an Ingress that will redirect and call to that service.