11 KiB
Deploying with YAML
-
So far, we created resources with the following commands:
-
kubectl run -
kubectl create deployment -
kubectl expose
-
-
We can also create resources directly with YAML manifests
Why use YAML? (1/3)
-
Some resources cannot be created easily with
kubectl(e.g. DaemonSets, StatefulSets, webhook configurations...)
-
Some features and fields aren't directly available
(e.g. resource limits, healthchecks, volumes...)
Why use YAML? (2/3)
-
Create a complicated resource with a single, simple command:
kubectl create -f stuff.yaml -
Create multiple resources with a single, simple command:
kubectl create -f more-stuff.yamlorkubectl create -f directory-with-yaml/ -
Create resources from a remote manifest:
kubectl create -f https://.../.../stuff.yaml -
Create and update resources:
kubectl apply -f stuff.yaml
Why use YAML? (3/3)
-
YAML lets us work declaratively
-
Describe what we want to deploy/run on Kubernetes
("desired state")
-
Use tools like
kubectl, Helm, kapp, Flux, ArgoCD... to make it happen("reconcile" actual state with desired state)
-
Very similar to e.g. Terraform
class: extra-details
Overrides and kubectl set
Just so you know...
-
kubectl create deployment ... --overrides '{...}'specify a patch that will be applied on top of the YAML generated by
kubectl -
kubectl set ...lets us change e.g. images, service accounts, resources, and much more
Various ways to write YAML
-
From examples in the docs, tutorials, blog posts, LLMs...
(easiest option when getting started)
-
Dump an existing resource with
kubectl get -o yaml ...(includes many extra fields; it is recommended to clean up the result)
-
Ask
kubectlto generate the YAML(with
kubectl --dry-run=client -o yaml create/run ...) -
Completely from scratch with our favorite editor
(black belt level😅)
Writing a Pod manifest
- Let's use
kubectl --dry-run=client -o yaml
.lab[
-
Generate the Pod manifest:
kubectl run --dry-run=client -o yaml purple --image=jpetazzo/color -
Save it to a file:
kubectl run --dry-run=client -o yaml purple --image=jpetazzo/color \ > pod-purple.yaml
]
Running the Pod
- Let's create the Pod with the manifest we just generated
.lab[
-
Create all the resources (at this point, just our Pod) described in the manifest:
kubectl create -f pod-purple.yaml -
Confirm that the Pod is running
kubectl get pods
]
class: extra-details
Comparing with direct kubectl run
- The Pod should be identical to one created directly with
kubectl run
.lab[
-
Create a Pod directly with
kubectl run:kubectl run yellow --image=jpetazzo/color -
Compare both Pod manifests and status:
kubectl get pod purple -o yaml kubectl get pod yellow -o yaml
]
Generating a Deployment manifest
- After a Pod, let's create a Deployment!
.lab[
-
Generate the YAML for a Deployment:
kubectl create deployment purple --image=jpetazzo/color -o yaml --dry-run=client -
Save it to a file:
kubectl create deployment purple --image=jpetazzo/color -o yaml --dry-run=client \ > deployment-purple.yaml -
And create the Deployment:
kubectl create -f deployment-purple.yaml
]
Updating our Deployment
-
What if we want to scale that Deployment?
-
Option 1:
kubectl scale -
Option 2: update the YAML manifest
-
Let's go with option 2!
.lab[
-
Edit the YAML manifest:
vim deployment-purple.yaml -
Find the line with
replicas: 1and update the number of replicas
]
Applying our changes
- Problem:
kubectl createwon't update ("overwrite") resources
.lab[
- Try it out:
kubectl create -f deployment-purple.yaml # This gives an error ("AlreadyExists")
]
- So, what can we do?
Updating resources
-
Option 1: delete the Deployment and re-create it
(effective, but causes downtime!)
-
Option 2:
kubectl scaleorkubectl editthe Deployment(effective, but that's cheating - we want to use YAML!)
-
Option 3:
kubectl apply
kubectl apply vs create
-
kubectl create -f whatever.yaml-
creates resources if they don't exist
-
if resources already exist, don't alter them
(and display error message)
-
-
kubectl apply -f whatever.yaml-
creates resources if they don't exist
-
if resources already exist, update them
(to match the definition provided by the YAML file) -
stores the manifest as an annotation in the resource
-
Trying kubectl apply
.lab[
-
First, delete the Deployment:
kubectl delete deployment purple -
Re-create it using
kubectl apply:kubectl apply -f deployment-purple.yaml -
Edit the YAML manifest, change the number of replicas again:
vim deployment-purple.yaml -
Apply the new manifest:
kubectl apply -f deployment-purple.yaml
]
create → apply
-
What are the differences between
kubectl create -fankubectl apply -f?-
kubectl applyadds an annotation
(kubectl.kubernetes.io/last-applied-configuration) -
kubectl applymakes an extraGETrequest
(to get the existing object, or at least check if there is one)
-
-
Otherwise, the end result is the same!
-
It's almost always better to use
kubectl apply(except when we don't want the extra annotation, e.g. for huge objects like some CRDs)
-
From now on, we'll almost always use
kubectl apply -finstead ofkubectl create -f
Adding a Service
- Let's generate the YAML for a Service exposing our Deployment
.lab[
-
Run
kubectl expose, once again with-o yaml --dry-run=client:kubectl expose deployment purple --port 80 -o yaml --dry-run=client -
Save it to a file:
kubectl expose deployment purple --port 80 -o yaml --dry-run=client \ > service-purple.yaml
]
- Note: if the Deployment doesn't exist,
kubectl exposewon't work!
What if the Deployment doesn't exist?
-
We can also use
kubectl create service -
The syntax is slightly different
(
--portbecomes--tcpfor some reason)
.lab[
- Generate the YAML with
kubectl create service:kubectl create service clusterip purple --tcp 80 -o yaml --dry-run=client
]
Combining manifests
-
We can put multiple resources in a single YAML file
-
We need to separate them with the standard YAML document separator
(i.e.
---standing by itself on a single line)
.lab[
- Generate a combined YAML file:
for YAMLFILE in deployment-purple.yaml service-purple.yaml; do echo --- cat $YAMLFILE done > app-purple.yaml
]
class: extra-details
Resource ordering
-
In general, the order of the resources doesn't matter:
-
in many cases, resources don't reference each other explicitly
(e.g. a Service can exist even if the corresponding Deployment doesn't) -
in some cases, there might be a transient error, but Kubernetes will retry
(and eventually succeed)
-
-
One exception: Namespaces should be created before resources in them!
Using -f with other commands
- We can also use
kubectl delete -f,kubectl label -f, and more!
.lab[
-
Apply the resulting YAML file:
kubectl apply -f app-purple.yaml -
Add a label to both the Deployment and the Service:
kubectl label -f app-purple.yaml release=production -
Delete them:
kubectl delete -f app-purple.yaml
]
class: extra-details
Pruning¹ resources
-
We can also tell
kubectlto remove old resources -
This is done with
kubectl apply -f ... --prune -
It will remove resources that don't exist in the YAML file(s)
-
But only if they were created with
kubectl applyin the first place(technically, if they have an annotation
kubectl.kubernetes.io/last-applied-configuration)
.footnote[¹If English is not your first language: to prune means to remove dead or overgrown branches in a tree, to help it to grow.]
Advantage of YAML
-
Using YAML (instead of
kubectl create <kind>) allows to be declarative -
The YAML describes the desired state of our cluster and applications
-
YAML can be stored, versioned, archived (e.g. in git repositories)
-
To change resources, change the YAML files
(instead of using
kubectl edit/scale/label/etc.) -
Changes can be reviewed before being applied
(with code reviews, pull requests ...)
-
Our version control system now has a full history of what we deploy
GitOps
-
This workflow is sometimes called "GitOps"
-
There are tools to facilitate it, e.g. Flux, ArgoCD...
-
Compares to "Infrastructure-as-Code", but for app deployments
class: extra-details
Actually GitOps?
There is some debate around the "true" definition of GitOps:
My applications are defined with manifests, templates, configurations... that are stored in source repositories with version control, and I only make changes to my applications by changing these files, like I would change source code.
vs
Same, but it's only "GitOps" if the deployment of the manifests is
full automated (as opposed to manually running commands like kubectl apply
or more complex scripts or tools).
Your instructor may or may not have an opinion on the matter! 😁
YAML in practice
-
Get started with
kubectl create deploymentandkubectl expose(until you have something that works)
-
Then, run these commands again, but with
-o yaml --dry-run=client(to generate and save YAML manifests)
-
Try to apply these manifests in a clean environment
(e.g. a new Namespace)
-
Check that everything works; tweak and iterate if needed
-
Commit the YAML to a repo 💯🏆️
"Day 2" YAML
-
Don't hesitate to remove unused fields
(e.g.
creationTimestamp: null, most{}values...) -
Check your YAML with:
kube-score (installable with krew)
-
Check live resources with tools like popeye
-
Remember that like all linters, they need to be configured for your needs!
class: extra-details
Specifying the namespace
-
When creating resources from YAML manifests, the namespace is optional
-
If we specify a namespace:
-
resources are created in the specified namespace
-
this is typical for things deployed only once per cluster
-
example: system components, cluster add-ons ...
-
-
If we don't specify a namespace:
-
resources are created in the current namespace
-
this is typical for things that may be deployed multiple times
-
example: applications (production, staging, feature branches ...)
-
???
:EN:- Deploying with YAML manifests :FR:- Déployer avec des manifests YAML :EN:- Techniques to write YAML manifests :FR:- Comment écrire des manifests YAML