diff --git a/slides/k8s/authoring-yaml.md b/slides/k8s/authoring-yaml.md deleted file mode 100644 index cf97357b..00000000 --- a/slides/k8s/authoring-yaml.md +++ /dev/null @@ -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 - ``` - - - -] - -Note: we don't need to specify `--validate=false` here. - ---- - -## Advantage of YAML - -- Using YAML (instead of `kubectl create `) 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 diff --git a/slides/k8s/namespaces.md b/slides/k8s/namespaces.md index 1dca77c9..b0be0e7d 100644 --- a/slides/k8s/namespaces.md +++ b/slides/k8s/namespaces.md @@ -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- < + (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` diff --git a/slides/k8s/yamldeploy.md b/slides/k8s/yamldeploy.md index 894b6cb7..f85959fa 100644 --- a/slides/k8s/yamldeploy.md +++ b/slides/k8s/yamldeploy.md @@ -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 +
+ (`kubectl.kubernetes.io/last-applied-configuration`) + + - `kubectl apply` makes an extra `GET` request +
+ (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 +
+ (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: + ```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 `) 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 diff --git a/slides/kube-fullday.yml b/slides/kube-fullday.yml index 5ac7e868..7e4540c2 100644 --- a/slides/kube-fullday.yml +++ b/slides/kube-fullday.yml @@ -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 diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml index 750b3801..aaa97481 100644 --- a/slides/kube-selfpaced.yml +++ b/slides/kube-selfpaced.yml @@ -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 diff --git a/slides/kube-twodays.yml b/slides/kube-twodays.yml index 0afad680..bb2c4293 100644 --- a/slides/kube-twodays.yml +++ b/slides/kube-twodays.yml @@ -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