mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-07-28 09:11:18 +00:00
556 lines
11 KiB
Markdown
556 lines
11 KiB
Markdown
# 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.yaml` or `kubectl 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 `kubectl` to 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:
|
|
```bash
|
|
kubectl run --dry-run=client -o yaml purple --image=jpetazzo/color
|
|
```
|
|
|
|
- Save it to a file:
|
|
```bash
|
|
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:
|
|
```bash
|
|
kubectl create -f pod-purple.yaml
|
|
```
|
|
|
|
- Confirm that the Pod is running
|
|
```bash
|
|
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`:
|
|
```bash
|
|
kubectl run yellow --image=jpetazzo/color
|
|
```
|
|
|
|
- Compare both Pod manifests and status:
|
|
```bash
|
|
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:
|
|
```bash
|
|
kubectl create deployment purple --image=jpetazzo/color -o yaml --dry-run=client
|
|
```
|
|
|
|
- Save it to a file:
|
|
```bash
|
|
kubectl create deployment purple --image=jpetazzo/color -o yaml --dry-run=client \
|
|
> deployment-purple.yaml
|
|
```
|
|
|
|
- And create the Deployment:
|
|
```bash
|
|
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:
|
|
```bash
|
|
vim deployment-purple.yaml
|
|
```
|
|
|
|
- Find the line with `replicas: 1` and update the number of replicas
|
|
|
|
]
|
|
|
|
---
|
|
|
|
## Applying our changes
|
|
|
|
- Problem: `kubectl create` won't update ("overwrite") resources
|
|
|
|
.lab[
|
|
|
|
- Try it out:
|
|
```bash
|
|
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 scale` or `kubectl edit` the 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
|
|
<br/>(and display error message)
|
|
|
|
- `kubectl apply -f whatever.yaml`
|
|
|
|
- creates resources if they don't exist
|
|
|
|
- if resources already exist, update them
|
|
<br/>(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:
|
|
```bash
|
|
kubectl delete deployment purple
|
|
```
|
|
|
|
- Re-create it using `kubectl apply`:
|
|
```bash
|
|
kubectl apply -f deployment-purple.yaml
|
|
```
|
|
|
|
- Edit the YAML manifest, change the number of replicas again:
|
|
```bash
|
|
vim deployment-purple.yaml
|
|
```
|
|
|
|
- Apply the new manifest:
|
|
```bash
|
|
kubectl apply -f deployment-purple.yaml
|
|
```
|
|
|
|
]
|
|
|
|
---
|
|
|
|
## `create` → `apply`
|
|
|
|
- What are the differences between `kubectl create -f` an `kubectl apply -f`?
|
|
|
|
- `kubectl apply` adds an annotation
|
|
<br/>
|
|
(`kubectl.kubernetes.io/last-applied-configuration`)
|
|
|
|
- `kubectl apply` makes an extra `GET` request
|
|
<br/>
|
|
(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 -f` instead of `kubectl 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`:
|
|
```bash
|
|
kubectl expose deployment purple --port 80 -o yaml --dry-run=client
|
|
```
|
|
|
|
- Save it to a file:
|
|
```bash
|
|
kubectl expose deployment purple --port 80 -o yaml --dry-run=client \
|
|
> service-purple.yaml
|
|
```
|
|
|
|
]
|
|
|
|
- Note: if the Deployment doesn't exist, `kubectl expose` won't work!
|
|
|
|
---
|
|
|
|
## What if the Deployment doesn't exist?
|
|
|
|
- We can also use `kubectl create service`
|
|
|
|
- The syntax is slightly different
|
|
|
|
(`--port` becomes `--tcp` for some reason)
|
|
|
|
.lab[
|
|
|
|
- Generate the YAML with `kubectl create service`:
|
|
```bash
|
|
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:
|
|
```bash
|
|
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
|
|
<br/>
|
|
(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
|
|
<br/>
|
|
(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:
|
|
```bash
|
|
kubectl apply -f app-purple.yaml
|
|
```
|
|
|
|
- Add a label to both the Deployment and the Service:
|
|
```bash
|
|
kubectl label -f app-purple.yaml release=production
|
|
```
|
|
|
|
- Delete them:
|
|
```bash
|
|
kubectl delete -f app-purple.yaml
|
|
```
|
|
|
|
]
|
|
|
|
---
|
|
|
|
class: extra-details
|
|
|
|
## Pruning¹ resources
|
|
|
|
- We can also tell `kubectl` to 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 apply` in 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 deployment` and `kubectl 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](https://github.com/zegl/kube-score) (installable with krew)
|
|
|
|
[kube-linter](https://github.com/stackrox/kube-linter)
|
|
|
|
- Check live resources with tools like [popeye](https://popeyecli.io/)
|
|
|
|
- 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
|