persona-read fixes: Service selectors + ClusterIP as a DNAT rule + CoreDNS + kube-proxy (the networking Linux bridge), cgroup limits and the describe/logs commands, 1/1 explained, second de-slop pass
This commit is contained in:
+34
-16
@@ -15,7 +15,7 @@
|
|||||||
<li><a href="#c2"><b>Course II</b><span>Kubernetes - a cluster is a promise, not a place</span></a></li>
|
<li><a href="#c2"><b>Course II</b><span>Kubernetes - a cluster is a promise, not a place</span></a></li>
|
||||||
<li><a href="#c3a"><b>Course IIIa</b><span>The node - where intent becomes a process</span></a></li>
|
<li><a href="#c3a"><b>Course IIIa</b><span>The node - where intent becomes a process</span></a></li>
|
||||||
<li><a href="#c3b"><b>Course IIIb</b><span>The pod - one IP, shared fate</span></a></li>
|
<li><a href="#c3b"><b>Course IIIb</b><span>The pod - one IP, shared fate</span></a></li>
|
||||||
<li><a href="#c4"><b>Course IV</b><span>The traffic - pods are cattle, Services are the brand</span></a></li>
|
<li><a href="#c4"><b>Course IV</b><span>The traffic - pods die constantly, the address does not</span></a></li>
|
||||||
<li><a href="#c5"><b>Course V</b><span>OpenShift - Kubernetes with opinions, and a security guard</span></a></li>
|
<li><a href="#c5"><b>Course V</b><span>OpenShift - Kubernetes with opinions, and a security guard</span></a></li>
|
||||||
<li><a href="#c6"><b>Course VI</b><span>GitOps - nobody deploys anything; the cluster syncs itself</span></a></li>
|
<li><a href="#c6"><b>Course VI</b><span>GitOps - nobody deploys anything; the cluster syncs itself</span></a></li>
|
||||||
<li><a href="#c7"><b>Course VII</b><span>The image supply chain - a tag is a promise, a digest is a fact</span></a></li>
|
<li><a href="#c7"><b>Course VII</b><span>The image supply chain - a tag is a promise, a digest is a fact</span></a></li>
|
||||||
@@ -72,6 +72,8 @@
|
|||||||
OpenShift's CLI. Everything shown works identically with <span class="mono">kubectl</span> -
|
OpenShift's CLI. Everything shown works identically with <span class="mono">kubectl</span> -
|
||||||
<span class="mono">oc</span> is a superset that adds OpenShift's own verbs. Read
|
<span class="mono">oc</span> is a superset that adds OpenShift's own verbs. Read
|
||||||
<span class="mono">kubectl</span> in the docs, type whichever your cluster gives you.</p>
|
<span class="mono">kubectl</span> in the docs, type whichever your cluster gives you.</p>
|
||||||
|
<p>That <span class="mono">1/1</span> reads as containers-ready over containers-wanted: a pod
|
||||||
|
can hold more than one, which is Course IIIb.</p>
|
||||||
<p>An image got <b>built</b> - of what, exactly? <b>Pushed</b> - to where, and what travelled?
|
<p>An image got <b>built</b> - of what, exactly? <b>Pushed</b> - to where, and what travelled?
|
||||||
<b>Applied</b> - which is not the same as launched. <b>Running</b> - according to whom?
|
<b>Applied</b> - which is not the same as launched. <b>Running</b> - according to whom?
|
||||||
Every course below takes one of those words apart. The armour is already loose.</p>
|
Every course below takes one of those words apart. The armour is already loose.</p>
|
||||||
@@ -165,7 +167,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="prose">
|
<div class="prose">
|
||||||
<h3>Desired against actual, forever</h3>
|
<h3>Desired against actual, on a loop</h3>
|
||||||
<p>The habit underneath everything: the <b>reconciliation loop</b> - compare desired state
|
<p>The habit underneath everything: the <b>reconciliation loop</b> - compare desired state
|
||||||
against actual state, fix the difference, repeat. That <span class="mono">oc apply</span>
|
against actual state, fix the difference, repeat. That <span class="mono">oc apply</span>
|
||||||
didn't launch anything; it filed paperwork. The machine took it from there, and it never
|
didn't launch anything; it filed paperwork. The machine took it from there, and it never
|
||||||
@@ -230,8 +232,8 @@
|
|||||||
runtime pulls the image (through the mirror of Course VII) and actually creates and starts
|
runtime pulls the image (through the mirror of Course VII) and actually creates and starts
|
||||||
the container, handing the low-level work to runc or crun. A <b>CNI plugin</b> hands the pod
|
the container, handing the low-level work to runc or crun. A <b>CNI plugin</b> hands the pod
|
||||||
a real IP, and <b>kube-proxy</b> - or an eBPF datapath replacing it - makes Service
|
a real IP, and <b>kube-proxy</b> - or an eBPF datapath replacing it - makes Service
|
||||||
addresses route to real pods. The kubelet drives and the runtime executes - and it is the
|
addresses route to real pods - and it is the runtime, not the kubelet, that calls the CNI
|
||||||
runtime, not the kubelet, that calls the CNI plugin to wire the pod up.</p>
|
plugin to wire the pod up.</p>
|
||||||
<p class="sayit">The kubelet decides what should run. The runtime is what starts it.</p>
|
<p class="sayit">The kubelet decides what should run. The runtime is what starts it.</p>
|
||||||
<p class="fieldnote"><b>Field note.</b> Node NotReady? Check kubelet-to-API-server
|
<p class="fieldnote"><b>Field note.</b> Node NotReady? Check kubelet-to-API-server
|
||||||
connectivity before anything else - a node that cannot phone home is presumed lost.</p>
|
connectivity before anything else - a node that cannot phone home is presumed lost.</p>
|
||||||
@@ -280,7 +282,11 @@
|
|||||||
It does not say by whom. The kernel's OOM killer surfaces as reason OOMKilled; a failed
|
It does not say by whom. The kernel's OOM killer surfaces as reason OOMKilled; a failed
|
||||||
liveness probe shows up in the pod's events; eviction and node pressure look different again.
|
liveness probe shows up in the pod's events; eviction and node pressure look different again.
|
||||||
One exit code, several possible crimes - read the termination reason and the events, never
|
One exit code, several possible crimes - read the termination reason and the events, never
|
||||||
the number alone.</p>
|
the number alone: <span class="mono">oc describe pod <name></span> shows both together,
|
||||||
|
and <span class="mono">oc logs --previous</span> shows what the dead container said on its
|
||||||
|
way out. Worth connecting to what you already know: a memory limit becomes a
|
||||||
|
<b>cgroup ceiling</b>, and the kernel's OOM killer enforces it exactly as it would for any
|
||||||
|
other process on the box.</p>
|
||||||
<p class="closeline">The pod is the smallest schedulable unit - the jacket, never the
|
<p class="closeline">The pod is the smallest schedulable unit - the jacket, never the
|
||||||
container. Once that distinction lands, half of Kubernetes networking stops being
|
container. Once that distinction lands, half of Kubernetes networking stops being
|
||||||
mysterious.</p>
|
mysterious.</p>
|
||||||
@@ -294,7 +300,7 @@
|
|||||||
<section class="course" id="c4" data-scene="traffic" aria-labelledby="c4h">
|
<section class="course" id="c4" data-scene="traffic" aria-labelledby="c4h">
|
||||||
<header class="chead">
|
<header class="chead">
|
||||||
<p class="eyebrow">Course IV · The traffic</p>
|
<p class="eyebrow">Course IV · The traffic</p>
|
||||||
<h2 id="c4h" class="thesis">Pods are cattle.<br><em>Services are the brand.</em></h2>
|
<h2 id="c4h" class="thesis">Pods die constantly.<br><em>The address does not.</em></h2>
|
||||||
<p class="lede">Pods die, respawn and change addresses - and traffic still arrives. Scroll,
|
<p class="lede">Pods die, respawn and change addresses - and traffic still arrives. Scroll,
|
||||||
and the delivery route assembles checkpoint by checkpoint; watch what happens to the pod
|
and the delivery route assembles checkpoint by checkpoint; watch what happens to the pod
|
||||||
that stops answering.</p>
|
that stops answering.</p>
|
||||||
@@ -315,6 +321,20 @@
|
|||||||
<p>A <b>Service</b> is the fixed point: a ClusterIP inside, a LoadBalancer at the edge,
|
<p>A <b>Service</b> is the fixed point: a ClusterIP inside, a LoadBalancer at the edge,
|
||||||
Ingress or the Gateway API doing host- and path-routing above. Clients hold the name; the
|
Ingress or the Gateway API doing host- and path-routing above. Clients hold the name; the
|
||||||
pods behind it come and go without anyone being told.</p>
|
pods behind it come and go without anyone being told.</p>
|
||||||
|
<h3>How a Service actually finds its pods</h3>
|
||||||
|
<p>A Service holds no list of pods. It holds a <b>label selector</b> - match
|
||||||
|
<span class="mono">app: api</span> - and a controller continuously matches that against every
|
||||||
|
pod in the namespace, keeping the passing set in an <b>EndpointSlice</b>. Labels are how
|
||||||
|
everything here finds everything else, from a Service picking pods to a fleet hub picking
|
||||||
|
whole clusters (Course VI). Wear the label and you are eligible; readiness decides whether
|
||||||
|
you stay.</p>
|
||||||
|
<p>And the ClusterIP is worth a Linux translation: <b>no interface owns that address</b>.
|
||||||
|
Nothing answers ARP for it. It exists as a rule - <b>kube-proxy</b> programs iptables (or
|
||||||
|
IPVS) on every node so packets aimed at the virtual IP are DNATed to one of the ready pod
|
||||||
|
IPs, and an eBPF dataplane does the same job further down without the rule tables. Cluster
|
||||||
|
DNS - <b>CoreDNS</b> - resolves <span class="mono">api.myns.svc.cluster.local</span> to that
|
||||||
|
VIP. If you have ever written a DNAT rule by hand, you have already built a small Service.</p>
|
||||||
|
|
||||||
<h3>Readiness decides membership</h3>
|
<h3>Readiness decides membership</h3>
|
||||||
<p>A pod failing its readiness probe <b>silently leaves the pool</b>. No error, no event at
|
<p>A pod failing its readiness probe <b>silently leaves the pool</b>. No error, no event at
|
||||||
the client - traffic simply stops arriving. That is the feature: broken instances remove
|
the client - traffic simply stops arriving. That is the feature: broken instances remove
|
||||||
@@ -327,7 +347,7 @@
|
|||||||
<p class="fieldnote"><b>Field note.</b> "The network is broken" after a deploy is usually
|
<p class="fieldnote"><b>Field note.</b> "The network is broken" after a deploy is usually
|
||||||
readiness telling the truth about your app - not the network lying about your packets.</p>
|
readiness telling the truth about your app - not the network lying about your packets.</p>
|
||||||
<p class="closeline">The dark pod in the scene is not an error state - it is the system
|
<p class="closeline">The dark pod in the scene is not an error state - it is the system
|
||||||
working. Membership is earned per probe, continuously, forever.</p>
|
working. Membership is re-earned every few seconds, by every pod, for as long as it serves.</p>
|
||||||
<p class="reads"><b>Pre-reads:</b> C-III's pod scene (readiness lives there)
|
<p class="reads"><b>Pre-reads:</b> C-III's pod scene (readiness lives there)
|
||||||
 <b>Further:</b> <a href="https://kubernetes.io/docs/concepts/services-networking/">Services and networking</a></p>
|
 <b>Further:</b> <a href="https://kubernetes.io/docs/concepts/services-networking/">Services and networking</a></p>
|
||||||
</div>
|
</div>
|
||||||
@@ -369,8 +389,8 @@
|
|||||||
<p class="fieldnote"><b>Field note.</b> Deployment stuck at 0/1 with no pod at all? The
|
<p class="fieldnote"><b>Field note.</b> Deployment stuck at 0/1 with no pod at all? The
|
||||||
refusal happened above scheduling - read the ReplicaSet events. The error lives a level
|
refusal happened above scheduling - read the ReplicaSet events. The error lives a level
|
||||||
up.</p>
|
up.</p>
|
||||||
<p class="closeline">Everything in the ring is opinion wrapped around the same core you
|
<p class="closeline">Everything in the ring wraps the same core you already know. What
|
||||||
already know. Learn the core once; the opinions are just house rules.</p>
|
OpenShift adds is a house style with teeth - and admission is where it bites first.</p>
|
||||||
<p class="reads"><b>Pre-reads:</b> C-II
|
<p class="reads"><b>Pre-reads:</b> C-II
|
||||||
 <b>Further:</b> <a href="https://docs.redhat.com/en/documentation/openshift_container_platform">OpenShift documentation</a> ·
|
 <b>Further:</b> <a href="https://docs.redhat.com/en/documentation/openshift_container_platform">OpenShift documentation</a> ·
|
||||||
<a href="https://www.redhat.com/en/technologies/cloud-computing/openshift">Red Hat OpenShift</a></p>
|
<a href="https://www.redhat.com/en/technologies/cloud-computing/openshift">Red Hat OpenShift</a></p>
|
||||||
@@ -385,8 +405,7 @@
|
|||||||
<p class="lede">The mental model everyone arrives with: someone with credentials pushes manifests
|
<p class="lede">The mental model everyone arrives with: someone with credentials pushes manifests
|
||||||
at the cluster. In the architecture this course teaches, nothing is pushed: a repository holds
|
at the cluster. In the architecture this course teaches, nothing is pushed: a repository holds
|
||||||
the desired state, an agent inside the cluster watches it, and the cluster pulls its own future
|
the desired state, an agent inside the cluster watches it, and the cluster pulls its own future
|
||||||
from git. oc is for
|
from git.</p>
|
||||||
looking; git is for changing.</p>
|
|
||||||
</header>
|
</header>
|
||||||
<div class="pin">
|
<div class="pin">
|
||||||
<div class="viewport">
|
<div class="viewport">
|
||||||
@@ -517,8 +536,8 @@
|
|||||||
the through-line.</p>
|
the through-line.</p>
|
||||||
<p class="sayit">If the digest changed, it is not a promotion - it is a new candidate.</p>
|
<p class="sayit">If the digest changed, it is not a promotion - it is a new candidate.</p>
|
||||||
<p class="closeline">Names that can move are convenient exactly until they move. Address content
|
<p class="closeline">Names that can move are convenient exactly until they move. Address content
|
||||||
by what it is, and the supply chain stops being a chain of trust and becomes a chain of
|
by what it is, and the supply chain stops resting on trust: it rests on a hash anyone can
|
||||||
arithmetic.</p>
|
check.</p>
|
||||||
<p class="reads"><b>Pre-reads:</b> C-I ·
|
<p class="reads"><b>Pre-reads:</b> C-I ·
|
||||||
<a href="https://kubernetes.io/docs/concepts/containers/images/">Kubernetes images</a>
|
<a href="https://kubernetes.io/docs/concepts/containers/images/">Kubernetes images</a>
|
||||||
 <b>Further:</b> <a href="https://zotregistry.dev/">zot</a> ·
|
 <b>Further:</b> <a href="https://zotregistry.dev/">zot</a> ·
|
||||||
@@ -578,9 +597,8 @@
|
|||||||
later as enforcement pointed at nothing.</p>
|
later as enforcement pointed at nothing.</p>
|
||||||
<p class="fieldnote"><b>Field note.</b> The failure you want is the render that refuses. It
|
<p class="fieldnote"><b>Field note.</b> The failure you want is the render that refuses. It
|
||||||
costs a red pipeline. The alternative reports healthy the whole time.</p>
|
costs a red pipeline. The alternative reports healthy the whole time.</p>
|
||||||
<p class="closeline">Fleet consistency is not a discipline problem, it is a construction
|
<p class="closeline">Consistency stops being something you police and becomes something the
|
||||||
problem. Divergence stops being something you police and becomes something the tooling cannot
|
tooling cannot express.</p>
|
||||||
express.</p>
|
|
||||||
<p class="reads"><b>Pre-reads:</b> C-II ·
|
<p class="reads"><b>Pre-reads:</b> C-II ·
|
||||||
<a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/">Kubernetes objects</a>
|
<a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/">Kubernetes objects</a>
|
||||||
 <b>Further:</b> <a href="https://helm.sh/docs/">Helm docs</a> ·
|
 <b>Further:</b> <a href="https://helm.sh/docs/">Helm docs</a> ·
|
||||||
|
|||||||
Reference in New Issue
Block a user