<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Day 2 on Eriks training corner</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/index.html</link><description>Recent content in Day 2 on Eriks training corner</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="https://training.caha.cloud/en/kubernetesintro/day-02/index.xml" rel="self" type="application/rss+xml"/><item><title>Troubleshooting routine</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/01-troubleshooting/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/01-troubleshooting/index.html</guid><description>&lt;h1 id="troubleshooting-routine"&gt;Troubleshooting routine&lt;/h1&gt;
&lt;p&gt;One order of operations, every time. It is short because it works.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph TB
A[&amp;#34;kubectl get pod -o wide&amp;lt;br/&amp;gt;what state? which node?&amp;#34;] --&amp;gt; B[&amp;#34;kubectl describe pod&amp;lt;br/&amp;gt;read the Events at the bottom&amp;#34;]
B --&amp;gt; C{&amp;#34;did the container start?&amp;#34;}
C --&amp;gt;|no| D[&amp;#34;fix from the event:&amp;lt;br/&amp;gt;image, scheduling, volume, probe&amp;#34;]
C --&amp;gt;|yes| E[&amp;#34;kubectl logs [--previous]&amp;lt;br/&amp;gt;what did the app say?&amp;#34;]
E --&amp;gt; F[&amp;#34;kubectl exec -it -- sh&amp;lt;br/&amp;gt;only if it is running&amp;#34;]&lt;/div&gt;&lt;h2 id="the-states-and-what-they-mean"&gt;The states and what they mean&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Where the answer is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Pending&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;describe&lt;/code&gt; -&amp;gt; FailedScheduling: no capacity, a taint, an unbound PVC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ContainerCreating&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;describe&lt;/code&gt; -&amp;gt; image pull or volume mount in progress, or stuck&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ImagePullBackOff&lt;/code&gt; / &lt;code&gt;ErrImagePull&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;wrong image name or tag, or registry credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CrashLoopBackOff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;logs --previous&lt;/code&gt; - the app started and exited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Running&lt;/code&gt; but not &lt;code&gt;Ready&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the readiness probe is failing; the Service will not send traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OOMKilled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;describe&lt;/code&gt; -&amp;gt; Last State; memory limit too low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Terminating&lt;/code&gt; forever&lt;/td&gt;
&lt;td&gt;a finalizer, or a container ignoring SIGTERM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="wider-than-one-pod"&gt;Wider than one Pod&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get events --sort-by&lt;span class="o"&gt;=&lt;/span&gt;.lastTimestamp &lt;span class="p"&gt;|&lt;/span&gt; tail -20
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get events -A --field-selector &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Warning
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -A -o wide &lt;span class="p"&gt;|&lt;/span&gt; grep -v Running
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl top nodes &lt;span class="p"&gt;;&lt;/span&gt; kubectl top pods
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="when-the-application-answers-nothing"&gt;When the application answers nothing&lt;/h2&gt;
&lt;p&gt;Work outwards from the Pod: is the Pod ready, does the Service have endpoints,
does DNS resolve, does the Gateway route.&lt;/p&gt;</description></item><item><title>Namespaces</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/02-namespaces/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/02-namespaces/index.html</guid><description>&lt;h1 id="namespaces"&gt;Namespaces&lt;/h1&gt;
&lt;p&gt;A virtual cluster inside the cluster: a name scope for objects, and a place to
attach quotas and policies.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph TB
subgraph cluster
subgraph ns1 [namespace: dev]
P1[pod web] --- P2[pod db]
end
subgraph ns2 [namespace: prod]
P3[pod web] --- P4[pod db]
end
N[nodes, PVs - not namespaced]
end&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get ns
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl create ns dev
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -n dev
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -A
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl config set-context --current --namespace&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl api-resources --namespaced&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;# what lives outside namespaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Namespaced: Pods, Deployments, Services, ConfigMaps, Secrets, PVCs, HTTPRoutes.
Not namespaced: Nodes, PersistentVolumes, StorageClasses, ClusterRoles, CRDs.&lt;/p&gt;</description></item><item><title>ReplicaSets</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/03-replicasets/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/03-replicasets/index.html</guid><description>&lt;h1 id="replicasets"&gt;ReplicaSets&lt;/h1&gt;
&lt;p&gt;A ReplicaSet keeps &lt;em&gt;N&lt;/em&gt; copies of a Pod running. That is the whole job.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph LR
RS[ReplicaSet replicas=3] --&amp;gt; P1[Pod]
RS --&amp;gt; P2[Pod]
RS --&amp;gt; P3[Pod]
P2 -.node dies.-&amp;gt; X((gone))
RS --&amp;gt;|reconcile| P4[new Pod]&lt;/div&gt;&lt;p&gt;The loop never stops: count Pods matching the selector, compare with
&lt;code&gt;spec.replicas&lt;/code&gt;, create or delete the difference. Self-healing and scaling are
the same mechanism.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;web&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;web &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# must match the selector&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pods are bound by the &lt;strong&gt;selector&lt;/strong&gt;, not by name: a loose Pod carrying a matching
label gets adopted and counted.&lt;/p&gt;</description></item><item><title>Deployments</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/04-deployments/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/04-deployments/index.html</guid><description>&lt;h1 id="deployments"&gt;Deployments&lt;/h1&gt;
&lt;p&gt;A Deployment owns ReplicaSets and each ReplicaSet owns Pods. That extra level is
what makes zero-downtime updates and rollbacks possible.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph TB
D[Deployment nginx] --&amp;gt; RS1[ReplicaSet v1 - replicas 0]
D --&amp;gt; RS2[ReplicaSet v2 - replicas 3]
RS2 --&amp;gt; P1[Pod]
RS2 --&amp;gt; P2[Pod]
RS2 --&amp;gt; P3[Pod]&lt;/div&gt;&lt;p&gt;Changing the Pod template creates a &lt;strong&gt;new&lt;/strong&gt; ReplicaSet and scales the old one
down in steps. The old ReplicaSet stays at 0 replicas - that is your rollback.&lt;/p&gt;</description></item><item><title>DaemonSets</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/05-daemonsets/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/05-daemonsets/index.html</guid><description>&lt;h1 id="daemonsets"&gt;DaemonSets&lt;/h1&gt;
&lt;p&gt;One Pod per node - automatically, including nodes that join later.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph TB
DS[DaemonSet log-agent] --&amp;gt; P1[Pod on control01]
DS --&amp;gt; P2[Pod on worker01]
DS --&amp;gt; P3[Pod on worker02]
DS --&amp;gt; P4[Pod on worker03]
N[new node joins] -.-&amp;gt; P5[Pod created automatically]&lt;/div&gt;&lt;p&gt;There is no &lt;code&gt;replicas&lt;/code&gt; field. The node list &lt;em&gt;is&lt;/em&gt; the replica count.&lt;/p&gt;
&lt;p&gt;Typical users: CNI agents, kube-proxy, log shippers, node exporters, storage
drivers. Your cluster is already running several - &lt;code&gt;kubectl get ds -A&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Scheduling: taints, tolerations, affinity</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/06-scheduling/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/06-scheduling/index.html</guid><description>&lt;h1 id="scheduling-taints-tolerations-affinity"&gt;Scheduling: taints, tolerations, affinity&lt;/h1&gt;
&lt;p&gt;By default the scheduler puts a Pod wherever it fits. Three mechanisms let you
change that, and they work in opposite directions.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph LR
N[Node] --&amp;gt;|taint: repels| P1[Pod without toleration - rejected]
N --&amp;gt;|taint tolerated| P2[Pod with toleration - allowed]
P3[Pod] --&amp;gt;|nodeSelector / affinity: attracts| N&lt;/div&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Lives on&lt;/th&gt;
&lt;th&gt;Says&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Taint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the node&lt;/td&gt;
&lt;td&gt;&amp;ldquo;keep Pods away unless they tolerate this&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Toleration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the Pod&lt;/td&gt;
&lt;td&gt;&amp;ldquo;I can put up with that taint&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;nodeSelector / node affinity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the Pod&lt;/td&gt;
&lt;td&gt;&amp;ldquo;I want to run on a node like this&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The pair is asymmetric on purpose. A toleration &lt;strong&gt;permits&lt;/strong&gt; but does not attract:
a Pod that tolerates a taint may still land anywhere else. If you want it &lt;em&gt;on&lt;/em&gt;
those nodes, you need affinity as well.&lt;/p&gt;</description></item><item><title>Services</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/07-services/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/07-services/index.html</guid><description>&lt;h1 id="services"&gt;Services&lt;/h1&gt;
&lt;p&gt;Pods come and go and their IPs change. A Service is the stable address in front
of them, with load balancing built in.&lt;/p&gt;
&lt;div class="mermaid align-center"&gt;graph LR
C[Client] --&amp;gt; S[Service nginx-svc&amp;lt;br/&amp;gt;ClusterIP 10.96.x.x]
S --&amp;gt; P1[Pod 10.244.1.5]
S --&amp;gt; P2[Pod 10.244.2.7]
S --&amp;gt; P3[Pod 10.244.3.9]&lt;/div&gt;&lt;p&gt;The Service selects Pods by &lt;strong&gt;label&lt;/strong&gt;. Matching, &lt;em&gt;ready&lt;/em&gt; Pod IPs land in an
EndpointSlice, and kube-proxy programs each node accordingly.&lt;/p&gt;
&lt;h2 id="types"&gt;Types&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Reachable from&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ClusterIP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inside the cluster only&lt;/td&gt;
&lt;td&gt;the default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NodePort&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;any-node-ip&amp;gt;:30000-32767&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;opens the port on every node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LoadBalancer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;outside&lt;/td&gt;
&lt;td&gt;needs a cloud provider or MetalLB - not in this cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ExternalName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;just a DNS CNAME&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;NodePort&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;nginx &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# must match the Pod labels&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# the Service port&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;targetPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# the container port&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;nodePort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;30080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# the port on every node&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="dns"&gt;DNS&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;nginx-svc # same namespace
nginx-svc.dev # other namespace
nginx-svc.dev.svc.cluster.local # fully qualified
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="headless-services"&gt;Headless Services&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;clusterIP: None&lt;/code&gt; gives no virtual IP; DNS returns the Pod IPs directly. This is
how StatefulSets give each replica a stable name - see
&lt;a href="https://training.caha.cloud/en/kubernetesintro/day-03/03-statefulsets/"&gt;StatefulSets&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Gateway API</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/08-gateway-api/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/08-gateway-api/index.html</guid><description>&lt;h1 id="gateway-api"&gt;Gateway API&lt;/h1&gt;
&lt;p&gt;A NodePort per application does not scale: you end up remembering that the shop
is on 30080 and the wiki on 30081. You want one HTTP entry point that routes by
host name and path.&lt;/p&gt;
&lt;p&gt;Kubernetes has had two answers to that. &lt;strong&gt;Ingress&lt;/strong&gt; is the old one - stable, but
frozen: every controller extended it with its own annotations, so a rewrite rule
for nginx means nothing to Traefik. &lt;strong&gt;Gateway API&lt;/strong&gt; is the replacement: the same
job expressed as real, typed resources, and it is where all the development now
happens.&lt;/p&gt;</description></item><item><title>Nodes</title><link>https://training.caha.cloud/en/kubernetesintro/day-02/09-nodes/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://training.caha.cloud/en/kubernetesintro/day-02/09-nodes/index.html</guid><description>&lt;h1 id="nodes"&gt;Nodes&lt;/h1&gt;
&lt;p&gt;A node is a machine that runs Pods. Cluster-scoped - not in a namespace.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl get nodes -o wide&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detail, conditions, taints, capacity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl describe node worker01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop scheduling new Pods&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl cordon worker01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cordon &lt;strong&gt;and&lt;/strong&gt; evict&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl drain worker01 --ignore-daemonsets --delete-emptydir-data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allow scheduling again&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl uncordon worker01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove from the cluster&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl delete node worker01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="mermaid align-center"&gt;stateDiagram-v2
[*] --&amp;gt; Ready
Ready --&amp;gt; SchedulingDisabled: cordon
SchedulingDisabled --&amp;gt; Ready: uncordon
SchedulingDisabled --&amp;gt; Drained: drain
Drained --&amp;gt; Ready: uncordon&lt;/div&gt;&lt;p&gt;Drain is the maintenance command. What it will not move:&lt;/p&gt;</description></item></channel></rss>