Kubernetes Creates Pods: Imperative vs Declarative
Introduction
Design and implementation microservices may have different approaches. During the design phase, we may need a quick proof of concept, or even multiple PoCs to compare. However, after we have a solid design, we may need to carefully plan how those microservices are working together in the cloud production. It demands us to specifically write Deployment, Service, ServiceAccount, ConfigMap etc. then, compile them to be a helm chart.
This article introduces comparison of some of kubernetes concepts, Pod vs Deployment, Declarative vs Imperative. Hope it can facilitate our daily work.
Pod vs. Deployment
Both Pod and Deployment are full-fledged objects in the Kubernetes API. After Kubernetes has a version 1.18 release at the end of March 2020, kubectl run
only creates Pod, no more Deployment. If we need to create other resources in an imperative way, we can use the kubectl create
command.
Available Commands:
clusterrole Create a ClusterRole.
clusterrolebinding Create a ClusterRoleBinding for a particular ClusterRole
configmap Create a configmap from a local file, directory or literal value
cronjob Create a cronjob with the specified name.
deployment Create a deployment with the specified name.
job Create a job with the specified name.
namespace Create a namespace with the specified name
poddisruptionbudget Create a pod disruption budget with the specified name.
priorityclass Create a priorityclass with the specified name.
quota Create a quota with the specified name.
role Create a role with single rule.
rolebinding Create a RoleBinding for a particular Role or ClusterRole
secret Create a secret using specified subcommand
service Create a service using specified subcommand.
serviceaccount Create a service account with the specified name
Pod is the smallest unit that kubernetes cluster is able to manage. Pod is the abstraction of the container. One pod can hold multiple containers, as Sidecar, Adapter or Ambassador pattern.
Deployment is the abstraction of the pod. For example, a deployment declares how many replicas of a pod should be running. It also declares how many CPUs and how much memories that limits to each pod.
In order to create a pod, we could write a Pod object YAML to apply to the K8S cluster. Or, We could use kubectl run --generator=run-pod/v1 ...
to create a pod. However, we cannot expect kubernetes is able to clone more pods by means of ReplicaSets. It is unlikely that we will put Pod objects into helm charts and deploy it into production.
Deployment object will use template to create one or more application container(s) with many specifications. Service object is the abstraction of network utilities. The one reason we need a standalone Service object is because the Deployment may be killed or scale up. The network such as load balancer, node port or cluster IP should be kept persistently.
Imperative vs. Declarative
There are two approaches to manage Kubernetes objects: imperative and declarative. Imperative approach is to use kubectl run
or other command to manage resources without manifest files (YAML definition). Declarative approach is to use kubectl apply
command for predefined manifest files. The latter approach is using in production deployment.
Create a nginx imperatively
The following command creates a pod as well as a service, but no deployment object.
kubectl run --generator=run-pod/v1 web --image=nginx --labels app=web --expose --port 80
Both pod and service are created. However, there is no deployment.
> kubectl get pods
NAMESPACE NAME READY STATUS RESTARTS AGE
default web 1/1 Running 0 27h
> kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
web ClusterIP 10.103.242.17 <none> 80/TCP 27h
If there is an accident that the pod is deleted, Kubenetes will not bring it up because there is no target state defined in manifest file.
kubectl delete pod nginx
The pod will not be up again.
Create a nginx declaratively
The following Deployment and Service definition will declare the target state of ngnix service running in Kubernetes.
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Service
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
department: dev
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 8080
There are three replicas of nginx pods. If one pod is deleted accidentally, Kubernetes will bring it up to meet target state defined in the Deployment manifest file.
Conclusion
Both kubectl run --generator
and kubectl apply
give us ways to create microservices. The imperative way will speed up the proof of concept work flow. In addition, the --dry-run
and -o yaml
options will save our time to write declarative YAML from scratch. Eventually, we need manifest files for all resources to be a helm chart to deploy to the production.