Imperative vs Declarative
There’s a lot of styles for how you can work in a Kubernetes cluster, you can choose to use just one approach or mix both of them to best suit your needs. Each style has its pros and cons; let’s break that down.
Imperative - Focus on how a program operates.
- Using imperative approach you need to tell exactly how you need that resource to be created, including all the details.
- Uses mostly
kubectl run
,kubectl create
,kubectl update
, andkubectl replace
commands.
Pros
- Easier when you know the state of your resource or object.
- Easier to get started.
Cons
- Not easy to automate.
- Needs to use different commands to change resources or objects.
- Mostly used for small environments or local development.
Declarative - Focus on what a program should accomplish.
- On declarative approach, you just need to tell Kubernetes what you need and it will be provisioned for you.
- Uses mostly
kubectl apply -f <config_file>
command.
Pros
- Uses the same command each time (tiny exceptions for delete).
- Resources can be inside one file, or many files because you can apply a whole directory (
kubectl apply -f myyaml/
) if needed. - Easy to automate your orchestration.
- Used in almost all production environments.
Cons
- Requires understanding of YAML keys and values.
- Takes more work to start running applications.
YAML Syntax
YAML file is a simplified version of JSON that is made of maps of key-values, in which a map is just an object, containing values and keys.
A key can contain a map of subkeys and values:
keyA:
subkeyA: subvalueA
subkeyB: subvalueB
subkeyC: subvalueC
The equivalent JSON will be:
{
"keyA": {
"subkeyA": "subvalueA",
"subkeyB": "subvalueB",
"subkeyC": "subvalueC"
}
}
A map of 3 values should look like this:
keyA: valueA
keyB: valueB
keyC: valueC
In JSON syntax should be like:
{
"keyA": "valueA",
"keyB": "valueB",
"keyC": "valueC",
}
YAML list items are represented with a “-“ in front of it:
listKey:
- listItemA
- listItemB
- listItemC
JSON equivalent will be:
{
"listKey": [
"listItemA",
"listItemB",
"listItemC"
]
}
In YAML you can have maps inside list items:
listKey:
- listItemA
mapItemA: mapValueA
mapItemB: mapValueB
- listItemB
- listItemC
In JSON, a list item containing a map it’s just an object in an array:
{
"listKey": [
"listItemA",
{
"mapItemA": "mapValueA",
"mapItemB": "mapValueB"
},
"listItemB",
"listItemC"
]
}
YAML Spec
The spec format is different for each Kubernetes object. The spec is where you will be describing your object in more detail. You can have more details looking at Kubernetes API Reference.
Examples of different specs:
Specifying CPU Requests and Limits
apiVersion: v1
kind: Pod
metadata:
name: range-pod
namespace: cpu-limited # Namespace is used to create virtual clusters when you have multiple teams or you need to segregate resources.
spec:
containers:
- name: range-container
image: nginx
resources:
limits: # Limits the usage of CPU to 1
cpu: 1
requests: # Limits the CPU requests to 0.5
cpu: 0.5
args: # When pod starts will be allowed to use 2 CPUs
- cpus
2
Configuring a Volume
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis # Volume will be mounted at this path
volumes:
- name: redis-storage
emptyDir: {} # Creates a initially empty volume, but if a pod is removed from the node the data is lost.
Creating a Load Balancer Service
apiVersion: v1
kind: Service
metadata:
name: range-service
spec:
type: LoadBalancer # Type of service
selector:
app: rangeforce
ports:
- port: 8700 # Port exposed inside the cluster
targetPort: 8080 # Port your application is listening on
Creating a Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx # Label is used to identify an object
spec:
replicas: 3
selector:
matchLabels:
app: nginx # Identify what pods the deployment will apply to.
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19.0
ports:
- containerPort: 80 # Specify the port to access on the containers belonging to pods targeted by your service.
Apply command
Apply creates and updates resources through files in a cluster, by running kubectl apply
. This is the recommended way of managing Kubernetes applications on production.
Kubernetes manifests can be defined in YAML or JSON. The file extensions accepted are .yaml, .yml, and .json.
kubectl apply usage:
kubectl apply (-f FILENAME | -k DIRECTORY)
Create resource(s)
kubectl apply -f ./my-manifest.yaml
Create resource(s) from multiple files
kubectl apply -f ./my1.yaml -f ./my2.yaml
Create resource(s) in all manifest files in /root/home
kubectl apply -f /root/home
Create resource(s) from url
kubectl apply -f <url>
Conclusion
A good understanding of YAML syntax, keys, and values is capital when you are using a declarative approach. This can help you create more consistent and assertive manifests for your applications.