mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-07-19 04:49:19 +00:00
🏭️ Refactor YAML and Namespace chapters
This commit is contained in:
@@ -1,279 +0,0 @@
|
||||
# Authoring YAML
|
||||
|
||||
- We have already generated YAML implicitly, with e.g.:
|
||||
|
||||
- `kubectl run`
|
||||
|
||||
- `kubectl create deployment` (and a few other `kubectl create` variants)
|
||||
|
||||
- `kubectl expose`
|
||||
|
||||
- When and why do we need to write our own YAML?
|
||||
|
||||
- How do we write YAML from scratch?
|
||||
|
||||
---
|
||||
|
||||
## The limits of generated YAML
|
||||
|
||||
- Many advanced (and even not-so-advanced) features require to write YAML:
|
||||
|
||||
- pods with multiple containers
|
||||
|
||||
- resource limits
|
||||
|
||||
- healthchecks
|
||||
|
||||
- DaemonSets, StatefulSets
|
||||
|
||||
- and more!
|
||||
|
||||
- How do we access these features?
|
||||
|
||||
---
|
||||
|
||||
## Various ways to write YAML
|
||||
|
||||
- Completely from scratch with our favorite editor
|
||||
|
||||
(yeah, right)
|
||||
|
||||
- Dump an existing resource with `kubectl get -o yaml ...`
|
||||
|
||||
(it is recommended to clean up the result)
|
||||
|
||||
- Ask `kubectl` to generate the YAML
|
||||
|
||||
(with a `kubectl create --dry-run=client -o yaml`)
|
||||
|
||||
- Use The Docs, Luke
|
||||
|
||||
(the documentation almost always has YAML examples)
|
||||
|
||||
---
|
||||
|
||||
## Generating YAML from scratch
|
||||
|
||||
- Start with a namespace:
|
||||
```yaml
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: hello
|
||||
```
|
||||
|
||||
- We can use `kubectl explain` to see resource definitions:
|
||||
```bash
|
||||
kubectl explain -r pod.spec
|
||||
```
|
||||
|
||||
- Not the easiest option!
|
||||
|
||||
---
|
||||
|
||||
## Dump the YAML for an existing resource
|
||||
|
||||
- `kubectl get -o yaml` works!
|
||||
|
||||
- A lot of fields in `metadata` are not necessary
|
||||
|
||||
(`managedFields`, `resourceVersion`, `uid`, `creationTimestamp` ...)
|
||||
|
||||
- Most objects will have a `status` field that is not necessary
|
||||
|
||||
- Default or empty values can also be removed for clarity
|
||||
|
||||
- This can be done manually or with the `kubectl-neat` plugin
|
||||
|
||||
`kubectl get -o yaml ... | kubectl neat`
|
||||
|
||||
---
|
||||
|
||||
## Generating YAML without creating resources
|
||||
|
||||
- We can use the `--dry-run=client` option
|
||||
|
||||
.lab[
|
||||
|
||||
- Generate the YAML for a Deployment without creating it:
|
||||
```bash
|
||||
kubectl create deployment web --image nginx --dry-run=client
|
||||
```
|
||||
|
||||
- Optionally clean it up with `kubectl neat`, too
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Using `--dry-run` with `kubectl apply`
|
||||
|
||||
- The `--dry-run` option can also be used with `kubectl apply`
|
||||
|
||||
- However, it can be misleading (it doesn't do a "real" dry run)
|
||||
|
||||
- Let's see what happens in the following scenario:
|
||||
|
||||
- generate the YAML for a Deployment
|
||||
|
||||
- tweak the YAML to transform it into a DaemonSet
|
||||
|
||||
- apply that YAML to see what would actually be created
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## The limits of `kubectl apply --dry-run=client`
|
||||
|
||||
.lab[
|
||||
|
||||
- Generate the YAML for a deployment:
|
||||
```bash
|
||||
kubectl create deployment web --image=nginx -o yaml > web.yaml
|
||||
```
|
||||
|
||||
- Change the `kind` in the YAML to make it a `DaemonSet`:
|
||||
```bash
|
||||
sed -i s/Deployment/DaemonSet/ web.yaml
|
||||
```
|
||||
|
||||
- Ask `kubectl` what would be applied:
|
||||
```bash
|
||||
kubectl apply -f web.yaml --dry-run=client --validate=false -o yaml
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
The resulting YAML doesn't represent a valid DaemonSet.
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Server-side dry run
|
||||
|
||||
- Since Kubernetes 1.13, we can use [server-side dry run and diffs](https://kubernetes.io/blog/2019/01/14/apiserver-dry-run-and-kubectl-diff/)
|
||||
|
||||
- Server-side dry run will do all the work, but *not* persist to etcd
|
||||
|
||||
(all validation and mutation hooks will be executed)
|
||||
|
||||
.lab[
|
||||
|
||||
- Try the same YAML file as earlier, with server-side dry run:
|
||||
```bash
|
||||
kubectl apply -f web.yaml --dry-run=server --validate=false -o yaml
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
The resulting YAML doesn't have the `replicas` field anymore.
|
||||
|
||||
Instead, it has the fields expected in a DaemonSet.
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Advantages of server-side dry run
|
||||
|
||||
- The YAML is verified much more extensively
|
||||
|
||||
- The only step that is skipped is "write to etcd"
|
||||
|
||||
- YAML that passes server-side dry run *should* apply successfully
|
||||
|
||||
(unless the cluster state changes by the time the YAML is actually applied)
|
||||
|
||||
- Validating or mutating hooks that have side effects can also be an issue
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## `kubectl diff`
|
||||
|
||||
- Kubernetes 1.13 also introduced `kubectl diff`
|
||||
|
||||
- `kubectl diff` does a server-side dry run, *and* shows differences
|
||||
|
||||
.lab[
|
||||
|
||||
- Try `kubectl diff` on the YAML that we tweaked earlier:
|
||||
```bash
|
||||
kubectl diff -f web.yaml
|
||||
```
|
||||
|
||||
<!-- ```wait status:``` -->
|
||||
|
||||
]
|
||||
|
||||
Note: we don't need to specify `--validate=false` here.
|
||||
|
||||
---
|
||||
|
||||
## 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 ...)
|
||||
|
||||
- This workflow is sometimes called "GitOps"
|
||||
|
||||
(there are tools like Weave Flux or GitKube to facilitate it)
|
||||
|
||||
---
|
||||
|
||||
## 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!
|
||||
|
||||
???
|
||||
|
||||
:EN:- Techniques to write YAML manifests
|
||||
:FR:- Comment écrire des *manifests* YAML
|
||||
@@ -1,73 +1,38 @@
|
||||
# Namespaces
|
||||
|
||||
- We would like to deploy another copy of DockerCoins on our cluster
|
||||
- Resources like Pods, Deployments, Services... exist in *Namespaces*
|
||||
|
||||
- We could rename all our deployments and services:
|
||||
- So far, we (probably) have been using the `default` Namespace
|
||||
|
||||
hasher → hasher2, redis → redis2, rng → rng2, etc.
|
||||
|
||||
- That would require updating the code
|
||||
|
||||
- There has to be a better way!
|
||||
|
||||
--
|
||||
|
||||
- As hinted by the title of this section, we will use *namespaces*
|
||||
- We can create other Namespaces to organize our resources
|
||||
|
||||
---
|
||||
|
||||
## Identifying a resource
|
||||
## Use-cases
|
||||
|
||||
- We cannot have two resources with the same name
|
||||
- Example: a "dev" cluster where each developer has their own Namespace
|
||||
|
||||
(or can we...?)
|
||||
(and they only have access to their own Namespace, not to other folks' Namespaces)
|
||||
|
||||
--
|
||||
- Example: a cluster with one `production` and one `staging` Namespace
|
||||
|
||||
- We cannot have two resources *of the same kind* with the same name
|
||||
(with similar applications running in each of them, but with different sizes)
|
||||
|
||||
(but it's OK to have an `rng` service, an `rng` deployment, and an `rng` daemon set)
|
||||
- Example: a "production" cluster with one Namespace per application
|
||||
|
||||
--
|
||||
(or one Namespace per component of a bigger application)
|
||||
|
||||
- We cannot have two resources of the same kind with the same name *in the same namespace*
|
||||
- Example: a "production" cluster with many instances of the same application
|
||||
|
||||
(but it's OK to have e.g. two `rng` services in different namespaces)
|
||||
|
||||
--
|
||||
|
||||
- Except for resources that exist at the *cluster scope*
|
||||
|
||||
(these do not belong to a namespace)
|
||||
(e.g. SAAS application with one instance per customer)
|
||||
|
||||
---
|
||||
|
||||
## Uniquely identifying a resource
|
||||
## Pre-existing Namespaces
|
||||
|
||||
- For *namespaced* resources:
|
||||
- On a freshly deployed cluster, we typically have the following four Namespaces:
|
||||
|
||||
the tuple *(kind, name, namespace)* needs to be unique
|
||||
|
||||
- For resources at the *cluster scope*:
|
||||
|
||||
the tuple *(kind, name)* needs to be unique
|
||||
|
||||
.lab[
|
||||
|
||||
- List resource types again, and check the NAMESPACED column:
|
||||
```bash
|
||||
kubectl api-resources
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Pre-existing namespaces
|
||||
|
||||
- If we deploy a cluster with `kubeadm`, we have three or four namespaces:
|
||||
|
||||
- `default` (for our applications)
|
||||
- `default` (initial Namespace for our applications; also holds the `kubernetes` Service)
|
||||
|
||||
- `kube-system` (for the control plane)
|
||||
|
||||
@@ -75,29 +40,29 @@
|
||||
|
||||
- `kube-node-lease` (in Kubernetes 1.14 and later; contains Lease objects)
|
||||
|
||||
- If we deploy differently, we may have different namespaces
|
||||
- Over time, we will almost certainly create more Namespaces!
|
||||
|
||||
---
|
||||
|
||||
## Creating namespaces
|
||||
## Creating a Namespace
|
||||
|
||||
- Let's see two identical methods to create a namespace
|
||||
- Let's see two ways to create a Namespace!
|
||||
|
||||
.lab[
|
||||
|
||||
- We can use `kubectl create namespace`:
|
||||
- First, with `kubectl create namespace`:
|
||||
```bash
|
||||
kubectl create namespace blue
|
||||
```
|
||||
|
||||
- Or we can construct a very minimal YAML snippet:
|
||||
- Then, with a YAML snippet:
|
||||
```bash
|
||||
kubectl apply -f- <<EOF
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: blue
|
||||
EOF
|
||||
kubectl apply -f- <<EOF
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: green
|
||||
EOF
|
||||
```
|
||||
|
||||
]
|
||||
@@ -106,38 +71,121 @@
|
||||
|
||||
## Using namespaces
|
||||
|
||||
- We can pass a `-n` or `--namespace` flag to most `kubectl` commands:
|
||||
```bash
|
||||
kubectl -n blue get svc
|
||||
```
|
||||
|
||||
- We can also change our current *context*
|
||||
|
||||
- A context is a *(user, cluster, namespace)* tuple
|
||||
|
||||
- We can manipulate contexts with the `kubectl config` command
|
||||
|
||||
---
|
||||
|
||||
## Viewing existing contexts
|
||||
|
||||
- On our training environments, at this point, there should be only one context
|
||||
- We can pass a `-n` or `--namespace` flag to most `kubectl` commands
|
||||
|
||||
.lab[
|
||||
|
||||
- View existing contexts to see the cluster name and the current user:
|
||||
- Create a Deployment in the `blue` Namespace:
|
||||
```bash
|
||||
kubectl config get-contexts
|
||||
kubectl create deployment purple --image jpetazzo/color --namespace blue
|
||||
```
|
||||
|
||||
- Check the Pods that were just created:
|
||||
```bash
|
||||
kubectl get pods --all-namespaces
|
||||
kubectl get pods --all-namespaces --selector app=purple
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
- The current context (the only one!) is tagged with a `*`
|
||||
---
|
||||
|
||||
- What are NAME, CLUSTER, AUTHINFO, and NAMESPACE?
|
||||
## Switching the active Namespace
|
||||
|
||||
- We can change the "active" Namespace
|
||||
|
||||
- This is useful if we're going to work in a given Namespace for a while
|
||||
|
||||
- it is easier than passing `--namespace ...` all the time
|
||||
|
||||
- it helps to avoid mistakes
|
||||
<br/>
|
||||
(e.g.: `kubectl delete -f foo.yaml` whoops wrong Namespace!)
|
||||
|
||||
- We're going to see ~~one~~ ~~two~~ three different methods to switch namespaces!
|
||||
|
||||
---
|
||||
|
||||
## Method 1 (kubens/kns)
|
||||
|
||||
- To switch to the `blue` Namespace, run:
|
||||
```bash
|
||||
kubens blue
|
||||
```
|
||||
|
||||
- `kubens` is sometimes renamed or aliased to `kns`
|
||||
|
||||
(even less keystrokes!)
|
||||
|
||||
- `kubens -` switches back to the previous Namespace
|
||||
|
||||
- Pros: probably the easiest method out there
|
||||
|
||||
- Cons: `kubens` is an extra tool that you need to install
|
||||
|
||||
---
|
||||
|
||||
## Method 2 (edit kubeconfig)
|
||||
|
||||
- Edit `~/.kube/config`
|
||||
|
||||
- There should be a `namespace:` field somewhere
|
||||
|
||||
- except if we haven't changed Namespace yet!
|
||||
|
||||
- in that case, change Namespace at least once using another method
|
||||
|
||||
- We can just edit that file, and `kubectl` will use the new Namespace from now on
|
||||
|
||||
- Pros: kind of easy; doesn't require extra tools
|
||||
|
||||
- Cons: there can be multiple `namespace:` fields in that file; difficult to automate
|
||||
|
||||
---
|
||||
|
||||
## Method 3 (kubectl config)
|
||||
|
||||
- To switch to the `blue` Namespace, run:
|
||||
```bash
|
||||
kubectl config set-context --current --namespace blue
|
||||
```
|
||||
|
||||
- This automatically edits the kubeconfig file
|
||||
|
||||
- This is exactly what `kubens` does behind the scenes!
|
||||
|
||||
- Pros: always works (as long as we have `kubectl`)
|
||||
|
||||
- Cons: long and complicated to type
|
||||
|
||||
(but it's a good exercise for our fingers, maybe?)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## What are contexts?
|
||||
|
||||
- Context = cluster + user + namespace
|
||||
|
||||
- Useful to quickly switch between multiple clusters
|
||||
|
||||
(e.g. dev, prod, or different applications, different customers...)
|
||||
|
||||
- Also useful to quickly switch between identities
|
||||
|
||||
(e.g. developer with "regular" access vs. cluster-admin)
|
||||
|
||||
- Switch context with `kubectl config set-context` or `kubectx` / `kctx`
|
||||
|
||||
- It is also possible to switch the kubeconfig file altogether
|
||||
|
||||
(by specifying `--kubeconfig` or setting the `KUBECONFIG` environment variable)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## What's in a context
|
||||
|
||||
- NAME is an arbitrary string to identify the context
|
||||
@@ -156,100 +204,55 @@
|
||||
|
||||
---
|
||||
|
||||
## Switching contexts
|
||||
## Namespaces, Services, and DNS
|
||||
|
||||
- We want to use a different namespace
|
||||
- When a Service is created, a record is added to the Kubernetes DNS
|
||||
|
||||
- Solution 1: update the current context
|
||||
- For instance, for service `auth` in domain `staging`, this is typically:
|
||||
|
||||
*This is appropriate if we need to change just one thing (e.g. namespace or authentication).*
|
||||
`auth.staging.svc.cluster.local`
|
||||
|
||||
- Solution 2: create a new context and switch to it
|
||||
- By default, Pods are configured to resolve names in their Namespace's domain
|
||||
|
||||
*This is appropriate if we need to change multiple things and switch back and forth.*
|
||||
- For instance, a Pod in Namespace `staging` will have the following "search list":
|
||||
|
||||
- Let's go with solution 1!
|
||||
`search staging.svc.cluster.local svc.cluster.local cluster.local`
|
||||
|
||||
---
|
||||
|
||||
## Updating a context
|
||||
## Pods connecting to Services
|
||||
|
||||
- This is done through `kubectl config set-context`
|
||||
- Let's assume that we are in Namespace `staging`
|
||||
|
||||
- We can update a context by passing its name, or the current context with `--current`
|
||||
- ... and there is a Service named `auth`
|
||||
|
||||
.lab[
|
||||
- ... and we have code running in a Pod in that same Namespace
|
||||
|
||||
- Update the current context to use the `blue` namespace:
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=blue
|
||||
```
|
||||
- Our code can:
|
||||
|
||||
- Check the result:
|
||||
```bash
|
||||
kubectl config get-contexts
|
||||
```
|
||||
- connect to Service `auth` in the same Namespace with `http://auth/`
|
||||
|
||||
]
|
||||
- connect to Service `auth` in another Namespace (e.g. `prod`) with `http://auth.prod`
|
||||
|
||||
- ... or `http://auth.prod.svc` or `http://auth.prod.svc.cluster.local`
|
||||
|
||||
---
|
||||
|
||||
## Using our new namespace
|
||||
## Deploying multiple instances of a stack
|
||||
|
||||
- Let's check that we are in our new namespace, then deploy a new copy of Dockercoins
|
||||
If all the containers in a given stack use DNS for service discovery,
|
||||
that stack can be deployed identically in multiple Namespaces.
|
||||
|
||||
.lab[
|
||||
Each copy of the stack will communicate with the services belonging
|
||||
to the stack's Namespace.
|
||||
|
||||
- Verify that the new context is empty:
|
||||
```bash
|
||||
kubectl get all
|
||||
```
|
||||
Example: we can deploy multiple copies of DockerCoins, one per
|
||||
Namespace, without changing a single line of code in DockerCoins,
|
||||
and even without changing a single line of code in our YAML manifests!
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Deploying DockerCoins with YAML files
|
||||
|
||||
- The GitHub repository `jpetazzo/kubercoins` contains everything we need!
|
||||
|
||||
.lab[
|
||||
|
||||
- Clone the kubercoins repository:
|
||||
```bash
|
||||
cd ~
|
||||
git clone https://github.com/jpetazzo/kubercoins
|
||||
```
|
||||
|
||||
- Create all the DockerCoins resources:
|
||||
```bash
|
||||
kubectl create -f kubercoins
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
If the argument behind `-f` is a directory, all the files in that directory are processed.
|
||||
|
||||
The subdirectories are *not* processed, unless we also add the `-R` flag.
|
||||
|
||||
---
|
||||
|
||||
## Viewing the deployed app
|
||||
|
||||
- Let's see if this worked correctly!
|
||||
|
||||
.lab[
|
||||
|
||||
- Retrieve the port number allocated to the `webui` service:
|
||||
```bash
|
||||
kubectl get svc webui
|
||||
```
|
||||
|
||||
- Point our browser to http://X.X.X.X:3xxxx
|
||||
|
||||
]
|
||||
|
||||
If the graph shows up but stays at zero, give it a minute or two!
|
||||
This is similar to what can be achieved e.g. with Docker Compose
|
||||
(but with Docker Compose, each stack is deployed in a Docker "network"
|
||||
instead of a Kubernetes Namespace).
|
||||
|
||||
---
|
||||
|
||||
@@ -257,19 +260,7 @@ If the graph shows up but stays at zero, give it a minute or two!
|
||||
|
||||
- Namespaces *do not* provide isolation
|
||||
|
||||
- A pod in the `green` namespace can communicate with a pod in the `blue` namespace
|
||||
|
||||
- A pod in the `default` namespace can communicate with a pod in the `kube-system` namespace
|
||||
|
||||
- CoreDNS uses a different subdomain for each namespace
|
||||
|
||||
- Example: from any pod in the cluster, you can connect to the Kubernetes API with:
|
||||
|
||||
`https://kubernetes.default.svc.cluster.local:443/`
|
||||
|
||||
---
|
||||
|
||||
## Isolating pods
|
||||
- By default, Pods in e.g. `prod` and `staging` Namespaces can communicate
|
||||
|
||||
- Actual isolation is implemented with *network policies*
|
||||
|
||||
@@ -285,47 +276,11 @@ If the graph shows up but stays at zero, give it a minute or two!
|
||||
|
||||
---
|
||||
|
||||
## Switch back to the default namespace
|
||||
|
||||
- Let's make sure that we don't run future exercises and labs in the `blue` namespace
|
||||
|
||||
.lab[
|
||||
|
||||
- Switch back to the original context:
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
Note: we could have used `--namespace=default` for the same result.
|
||||
|
||||
---
|
||||
|
||||
## Switching namespaces more easily
|
||||
|
||||
- We can also use a little helper tool called `kubens`:
|
||||
|
||||
```bash
|
||||
# Switch to namespace foo
|
||||
kubens foo
|
||||
# Switch back to the previous namespace
|
||||
kubens -
|
||||
```
|
||||
|
||||
- On our clusters, `kubens` is called `kns` instead
|
||||
|
||||
(so that it's even fewer keystrokes to switch namespaces)
|
||||
|
||||
---
|
||||
|
||||
## `kubens` and `kubectx`
|
||||
|
||||
- With `kubens`, we can switch quickly between namespaces
|
||||
- These tools are available from https://github.com/ahmetb/kubectx
|
||||
|
||||
- With `kubectx`, we can switch quickly between contexts
|
||||
|
||||
- Both tools are simple shell scripts available from https://github.com/ahmetb/kubectx
|
||||
- They were initially simple shell scripts, and are now full-fledged Go programs
|
||||
|
||||
- On our clusters, they are installed as `kns` and `kctx`
|
||||
|
||||
|
||||
@@ -12,6 +12,235 @@
|
||||
|
||||
---
|
||||
|
||||
## 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`
|
||||
@@ -32,81 +261,165 @@
|
||||
|
||||
---
|
||||
|
||||
## Creating multiple resources
|
||||
|
||||
- The manifest can contain multiple resources separated by `---`
|
||||
|
||||
```yaml
|
||||
kind: ...
|
||||
apiVersion: ...
|
||||
metadata: ...
|
||||
name: ...
|
||||
...
|
||||
---
|
||||
kind: ...
|
||||
apiVersion: ...
|
||||
metadata: ...
|
||||
name: ...
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Creating multiple resources
|
||||
|
||||
- The manifest can also contain a list of resources
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- kind: ...
|
||||
apiVersion: ...
|
||||
...
|
||||
- kind: ...
|
||||
apiVersion: ...
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deploying dockercoins with YAML
|
||||
|
||||
- We provide a YAML manifest with all the resources for Dockercoins
|
||||
|
||||
(Deployments and Services)
|
||||
|
||||
- We can use it if we need to deploy or redeploy Dockercoins
|
||||
## Trying `kubectl apply`
|
||||
|
||||
.lab[
|
||||
|
||||
- Deploy or redeploy Dockercoins:
|
||||
- First, delete the Deployment:
|
||||
```bash
|
||||
kubectl apply -f ~/container.training/k8s/dockercoins.yaml
|
||||
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
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
(If we deployed Dockercoins earlier, we will see warning messages,
|
||||
because the resources that we created lack the necessary annotation.
|
||||
We can safely ignore them.)
|
||||
---
|
||||
|
||||
## `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`
|
||||
|
||||
---
|
||||
|
||||
## Deleting resources
|
||||
## Adding a Service
|
||||
|
||||
- We can also use a YAML file to *delete* resources
|
||||
- Let's generate the YAML for a Service exposing our Deployment
|
||||
|
||||
- `kubectl delete -f ...` will delete all the resources mentioned in a YAML file
|
||||
.lab[
|
||||
|
||||
(useful to clean up everything that was created by `kubectl apply -f ...`)
|
||||
- Run `kubectl expose`, once again with `-o yaml --dry-run=client`:
|
||||
```bash
|
||||
kubectl expose deployment purple --port 80 -o yaml --dry-run=client
|
||||
```
|
||||
|
||||
- The definitions of the resources don't matter
|
||||
- Save it to a file:
|
||||
```bash
|
||||
kubectl expose deployment purple --port 80 -o yaml --dry-run=client \
|
||||
> service-purple.yaml
|
||||
```
|
||||
|
||||
(just their `kind`, `apiVersion`, and `name`)
|
||||
]
|
||||
|
||||
- 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
|
||||
@@ -123,28 +436,97 @@ We can safely ignore them.)
|
||||
|
||||
---
|
||||
|
||||
## YAML as source of truth
|
||||
## Advantage of YAML
|
||||
|
||||
- Imagine the following workflow:
|
||||
- Using YAML (instead of `kubectl create <kind>`) allows to be *declarative*
|
||||
|
||||
- do not use `kubectl run`, `kubectl create deployment`, `kubectl expose` ...
|
||||
- The YAML describes the desired state of our cluster and applications
|
||||
|
||||
- define everything with YAML
|
||||
- YAML can be stored, versioned, archived (e.g. in git repositories)
|
||||
|
||||
- `kubectl apply -f ... --prune --all` that YAML
|
||||
- To change resources, change the YAML files
|
||||
|
||||
- keep that YAML under version control
|
||||
(instead of using `kubectl edit`/`scale`/`label`/etc.)
|
||||
|
||||
- enforce all changes to go through that YAML (e.g. with pull requests)
|
||||
- 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
|
||||
@@ -169,3 +551,5 @@ class: extra-details
|
||||
|
||||
:EN:- Deploying with YAML manifests
|
||||
:FR:- Déployer avec des *manifests* YAML
|
||||
:EN:- Techniques to write YAML manifests
|
||||
:FR:- Comment écrire des *manifests* YAML
|
||||
|
||||
@@ -54,8 +54,8 @@ content:
|
||||
- k8s/labels-annotations.md
|
||||
- k8s/kubectl-logs.md
|
||||
- k8s/logs-cli.md
|
||||
- k8s/namespaces.md
|
||||
- k8s/yamldeploy.md
|
||||
- k8s/namespaces.md
|
||||
- k8s/setup-overview.md
|
||||
- k8s/setup-devel.md
|
||||
#- k8s/setup-managed.md
|
||||
@@ -76,7 +76,6 @@ content:
|
||||
#- shared/hastyconclusions.md
|
||||
#- k8s/daemonset.md
|
||||
#- shared/yaml.md
|
||||
#- k8s/authoring-yaml.md
|
||||
#- k8s/exercise-yaml.md
|
||||
#- k8s/localkubeconfig.md
|
||||
#- k8s/access-eks-cluster.md
|
||||
|
||||
@@ -54,7 +54,9 @@ content:
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
#- k8s/exercise-wordsmith.md
|
||||
- shared/yaml.md
|
||||
- k8s/yamldeploy.md
|
||||
- k8s/namespaces.md
|
||||
-
|
||||
- k8s/setup-overview.md
|
||||
- k8s/setup-devel.md
|
||||
@@ -67,8 +69,6 @@ content:
|
||||
- k8s/scalingdockercoins.md
|
||||
- shared/hastyconclusions.md
|
||||
- k8s/daemonset.md
|
||||
- shared/yaml.md
|
||||
- k8s/authoring-yaml.md
|
||||
#- k8s/exercise-yaml.md
|
||||
-
|
||||
- k8s/rollout.md
|
||||
@@ -76,7 +76,6 @@ content:
|
||||
- k8s/healthchecks-more.md
|
||||
- k8s/record.md
|
||||
-
|
||||
- k8s/namespaces.md
|
||||
- k8s/localkubeconfig.md
|
||||
#- k8s/access-eks-cluster.md
|
||||
- k8s/accessinternal.md
|
||||
|
||||
@@ -67,7 +67,6 @@ content:
|
||||
- shared/hastyconclusions.md
|
||||
- k8s/daemonset.md
|
||||
- shared/yaml.md
|
||||
- k8s/authoring-yaml.md
|
||||
#- k8s/exercise-yaml.md
|
||||
-
|
||||
- k8s/localkubeconfig.md
|
||||
|
||||
Reference in New Issue
Block a user