Skip to content

Commit 601f6d3

Browse files
committed
Add rest of article pages refactored to List components
1 parent f38c56d commit 601f6d3

72 files changed

Lines changed: 7210 additions & 1280 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
"mlflow",
204204
"Moodle",
205205
"moyai",
206+
"MPLS",
206207
"MTTA",
207208
"MTTD",
208209
"MTTR",
@@ -289,6 +290,7 @@
289290
"Qube",
290291
"QUIC",
291292
"raci",
293+
"readyz",
292294
"redigo",
293295
"redocly",
294296
"referer",

_TODO.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,48 @@ if (window.matchMedia) {
8686

8787
- Add a QR code at the bottom of printed pages so it's easier for someone to navigate to from a printed page.
8888

89-
- Need a layout alternative to Markup that formats for print. It needs to handle TOC differently as a full-width page.
89+
- Need a layout alternative to Markup that formats for print. It needs to handle TOC differently as a full-width page. Need a fixed header format that adds article title, subtitle, and date.
9090

9191
- Need to make sure that on print, when we have a tabbed code block with multiple languages, only the first language is printed and the other language tabs are hidden. The styling should be different for print for the code block. Maybe move other language code tabs to an appendix and add a link to them.
9292

9393
[This article](https://excessivelyadequate.com/posts/print.html) shows how to control the following properties in Chrome's Print Properties dialog box from CSS: Layout, Paper size, Margins, Headers and footers, and Background graphics. Headers and footers is the checkbox that by default is enabled and adds information on printed pages. It also shows how to use Chrome from the terminal in headless mode to output a PDF file from an HTML page.
9494

95+
For printed pages, your header should shift from a navigation tool to a document identifier. Since users cannot click links or icons on paper, these elements are "cruft" that waste space and ink.
96+
97+
1. Recommended Print Header Format
98+
99+
A professional print header typically includes only these three elements:
100+
101+
- Brand Identity: A high-contrast version of your logo or the site name in plain text for brand recognition.
102+
- Document Title: The main title of the page (usually the <h1>), ensuring the reader knows exactly what the document is.
103+
- Source URL: A small, plain-text URL so the reader can find the live version later.
104+
105+
2. Elements to Remove
106+
107+
Hide any interactive or screen-specific components using display: none; in your @media print block:
108+
109+
- Navigation Menus: All top-level and dropdown links.
110+
- Search Icons/Bars: These are non-functional on paper.
111+
- Breadcrumbs: While useful on-screen for site hierarchy, they often look like cluttered, disconnected text on paper. Most designers remove them to keep the focus on the primary content.
112+
- Social Media & CTA Buttons: "Sign In" or "Follow Us" buttons are irrelevant in print.
113+
114+
3. Expand External Links For Print:
115+
116+
We can't (yet) directly interface with a printed page to explore links, so link URLs should be visible on the printed version of the Web page. To keep the page relatively clean, I prefer to expand only outbound links in articles, and suppress internal ones. If you've used relative URLs on your website for local links, you can easily do this through an attribute selector and :after pseudo=classes, thus preventing internal links and links around images from being printed:
117+
118+
```css
119+
@media print {
120+
article a {
121+
font-weight: bolder;
122+
text-decoration: none;
123+
}
124+
125+
article a[href^=http]:after {
126+
content:" <" attr(href) "> ";
127+
}
128+
}
129+
```
130+
95131
## PDF File Generation
96132

97133
- Need a workflow to generate PDF files from Markdown for downloads.
@@ -108,6 +144,20 @@ Paged.js Polyfill: Use the Paged.js library to handle sophisticated print layout
108144

109145
This article has different approaches to [print pagination](https://www.customjs.space/blog/html-print-pagination-footer/). One approach overlaps with PagedJS's approach.
110146

147+
- Headers and Footers (Native Support)
148+
149+
Puppeteer can inject dynamic data into your headers and footers using specific CSS classes. To use this, you must set `displayHeaderFooter: true` in the `page.pdf()` options.
150+
151+
Dynamic Classes: Puppeteer automatically replaces these classes with actual values:
152+
`.pageNumber`: Current page number.
153+
`.totalPages`: Total number of pages.
154+
`.title`: The document's `<title>` tag.
155+
`.date`: The date the PDF was generated.
156+
157+
Requirements: You must provide sufficient margins (e.g.,` margin: { top: '50px', bottom: '50px' }`), or the headers/footers will be hidden behind the content.
158+
159+
Styling: You must use inline CSS within your `headerTemplate` or `footerTemplate` strings, as they cannot access your external stylesheet.
160+
111161
## ToolTips
112162

113163
Need a tooltip component for consistency. List to add tooltips to:

src/content/articles/helm-release-management-drift-detection-debugging/pdf.mdx

Lines changed: 123 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,33 @@ The critical thing to understand: Helm's stored manifest represents what Helm _t
9191
9292
Drift shows up in predictable patterns, and recognizing which pattern you're dealing with speeds up recovery.
9393
94-
- _Manual kubectl edits_ are the most common source. Someone runs `kubectl edit deployment` to bump resource limits during an incident, or `kubectl patch` to add an annotation. The cluster state changes, but Helm doesn't know. The next `helm upgrade` may revert those changes unexpectedly, or the three-way merge may produce surprising results.
95-
- _Partial upgrade failures_ leave you in limbo. If Helm times out or hits an error mid-upgrade, some resources may be updated while others aren't. You'll see pods running different versions, ConfigMaps updated but Deployments not, and a release status of "failed" that blocks further operations.
96-
- _Secret storage corruption_ is less common but more painful. If cleanup scripts, namespace recreation, or manual deletion removes Helm's release secrets, the cluster still has the resources but Helm has no record of them. `helm list` shows nothing, but `helm install` fails with "already exists."
97-
- _Hook failures_ create orphaned state. Pre-upgrade or post-upgrade hooks that fail can leave partial resources. The release is marked failed, but the hook's job or pod may still exist, and main resources may or may not have been deployed depending on when the hook failed.
98-
- _Three-way merge conflicts_ are the trickiest. When Helm computes an upgrade, it compares the old manifest, new manifest, and live cluster state. If someone modified a field in the cluster that you're also changing in the new manifest, the merge can produce unexpected results—fields deleted, values unexpectedly retained, or strategic merge patches behaving counter-intuitively.
94+
<List
95+
variant="check-icons-list"
96+
content={{
97+
items: [
98+
{
99+
lead: "Manual kubectl edits",
100+
text: "are the most common source. Someone runs `kubectl edit deployment` to bump resource limits during an incident, or `kubectl patch` to add an annotation. The cluster state changes, but Helm doesn't know. The next `helm upgrade` may revert those changes unexpectedly, or the three-way merge may produce surprising results.",
101+
},
102+
{
103+
lead: "Partial upgrade failures",
104+
text: "leave you in limbo. If Helm times out or hits an error mid-upgrade, some resources may be updated while others aren't. You'll see pods running different versions, ConfigMaps updated but Deployments not, and a release status of \"failed\" that blocks further operations.",
105+
},
106+
{
107+
lead: "Secret storage corruption",
108+
text: "is less common but more painful. If cleanup scripts, namespace recreation, or manual deletion removes Helm's release secrets, the cluster still has the resources but Helm has no record of them. `helm list` shows nothing, but `helm install` fails with \"already exists.\"",
109+
},
110+
{
111+
lead: "Hook failures",
112+
text: "create orphaned state. Pre-upgrade or post-upgrade hooks that fail can leave partial resources. The release is marked failed, but the hook's job or pod may still exist, and main resources may or may not have been deployed depending on when the hook failed.",
113+
},
114+
{
115+
lead: "Three-way merge conflicts",
116+
text: "are the trickiest. When Helm computes an upgrade, it compares the old manifest, new manifest, and live cluster state. If someone modified a field in the cluster that you're also changing in the new manifest, the merge can produce unexpected results—fields deleted, values unexpectedly retained, or strategic merge patches behaving counter-intuitively.",
117+
},
118+
],
119+
}}
120+
/>
99121

100122
<Table
101123
variant="vertical-column-delineation-table"
@@ -259,9 +281,22 @@ helm list --all-namespaces --output json
259281

260282
The output includes release name, namespace, chart name and version, app version, status, and last deployment timestamp. Aggregate this across clusters and you can answer questions like:
261283

262-
- Which releases are using chart version X vs Y?
263-
- Are there any failed releases that need attention?
264-
- Which services haven't been deployed in over 30 days?
284+
<List
285+
variant="check-icons-list"
286+
content={{
287+
items: [
288+
{
289+
text: "Which releases are using chart version X vs Y?",
290+
},
291+
{
292+
text: "Are there any failed releases that need attention?",
293+
},
294+
{
295+
text: "Which services haven't been deployed in over 30 days?",
296+
},
297+
],
298+
}}
299+
/>
265300

266301
For multi-cluster environments, tools like [helm-exporter](https://github.com/sstarcher/helm-exporter) expose this data as Prometheus metrics automatically. This lets you build dashboards and alerts without custom collection scripts.
267302

@@ -366,11 +401,28 @@ For higher-risk changes, upgrade in stages rather than all at once.
366401

367402
_Canary upgrades_ deploy to a subset first—typically staging, then one production namespace or cluster—and verify before continuing. This gives you a chance to catch problems before they affect all users. The process looks like:
368403

369-
1. Upgrade in staging, run smoke tests, verify metrics
370-
2. Upgrade a single canary production instance
371-
3. Monitor for error rate increases or latency regression
372-
4. If healthy after your bake time (15-30 minutes), proceed with remaining instances
373-
5. If problems appear, rollback the canary and investigate
404+
<List
405+
variant="numbered-with-background-list"
406+
content={{
407+
items: [
408+
{
409+
text: "Upgrade in staging, run smoke tests, verify metrics",
410+
},
411+
{
412+
text: "Upgrade a single canary production instance",
413+
},
414+
{
415+
text: "Monitor for error rate increases or latency regression",
416+
},
417+
{
418+
text: "If healthy after your bake time (15-30 minutes), proceed with remaining instances",
419+
},
420+
{
421+
text: "If problems appear, rollback the canary and investigate",
422+
},
423+
],
424+
}}
425+
/>
374426

375427
_Rolling namespace upgrades_ work well for multi-tenant deployments where each namespace is isolated. Upgrade one namespace, verify, then move to the next. If something breaks, only one tenant is affected while you fix it.
376428

@@ -463,11 +515,33 @@ helm template my-release ./my-chart -f values.yaml | kubectl apply --dry-run=ser
463515

464516
### Common Failure Patterns
465517

466-
- _Hook timeouts_ show up as releases stuck in "pending-upgrade" or "pending-install." The release lock prevents further operations until you resolve it. Check for stuck hook jobs with `kubectl get jobs -l helm.sh/hook` and review their logs. If the hook is stuck, delete the job and either fix the underlying issue or temporarily skip hooks with `--no-hooks`.
467-
- _"Resource already exists" errors_ happen when a previous failed install left orphaned resources that Helm doesn't know about. You have two options: use `helm upgrade --force` to adopt the existing resources, or delete them manually and reinstall clean.
468-
- _ImagePullBackOff_ means Helm is waiting for pods that can't pull their images. Check the image name and tag in your values, verify your registry credentials (imagePullSecrets), and confirm network connectivity to the registry. Once fixed, run `helm upgrade --reuse-values --force`.
469-
- _Admission webhook rejections_ produce errors like "admission webhook denied the request." Your manifests are violating cluster policies. Use `helm template | kubectl apply --dry-run=server -f -` to see the exact rejection message, then update your values or templates to comply.
470-
- _Resource quota exceeded_ shows up as pods stuck in Pending with quota rejection events. Either reduce resource requests in your values, request a quota increase, or free up quota by removing unused releases.
518+
<List
519+
variant="check-icons-list"
520+
content={{
521+
items: [
522+
{
523+
lead: "Hook timeouts",
524+
text: "show up as releases stuck in \"pending-upgrade\" or \"pending-install.\" The release lock prevents further operations until you resolve it. Check for stuck hook jobs with `kubectl get jobs -l helm.sh/hook` and review their logs. If the hook is stuck, delete the job and either fix the underlying issue or temporarily skip hooks with `--no-hooks`.",
525+
},
526+
{
527+
lead: "\"Resource already exists\" errors",
528+
text: "happen when a previous failed install left orphaned resources that Helm doesn't know about. You have two options: use `helm upgrade --force` to adopt the existing resources, or delete them manually and reinstall clean.",
529+
},
530+
{
531+
lead: "ImagePullBackOff",
532+
text: "means Helm is waiting for pods that can't pull their images. Check the image name and tag in your values, verify your registry credentials (imagePullSecrets), and confirm network connectivity to the registry. Once fixed, run `helm upgrade --reuse-values --force`.",
533+
},
534+
{
535+
lead: "Admission webhook rejections",
536+
text: "produce errors like \"admission webhook denied the request.\" Your manifests are violating cluster policies. Use `helm template | kubectl apply --dry-run=server -f -` to see the exact rejection message, then update your values or templates to comply.",
537+
},
538+
{
539+
lead: "Resource quota exceeded",
540+
text: "shows up as pods stuck in Pending with quota rejection events. Either reduce resource requests in your values, request a quota increase, or free up quota by removing unused releases.",
541+
},
542+
],
543+
}}
544+
/>
471545

472546
<Callout type="success">
473547
When a release is stuck in "pending-upgrade," the release lock prevents further operations. Check for stuck hooks first (`kubectl get jobs -l helm.sh/hook`). If needed, manually delete the hook job and the release secret for the pending revision, then retry.
@@ -578,12 +652,37 @@ Helm's simplicity at small scale becomes operational complexity at large scale.
578652

579653
The key practices that keep Helm manageable:
580654

581-
- _Understand Helm state_: Know where release secrets live, how three-way merge works, and what causes drift. This knowledge pays off during debugging.
582-
- _Detect drift continuously_: Run scheduled drift checks with alerting. Don't discover drift during an incident.
583-
- _Maintain release inventory_: Export release metadata as metrics. Track version consistency across clusters.
584-
- _Use safe upgrade patterns_: Default to `--atomic` for production. Use canary or blue-green for high-risk changes.
585-
- _Debug systematically_: Follow the diagnosis workflow. Check status, history, events, and logs in a consistent order.
586-
- _Consider GitOps_: Flux and ArgoCD eliminate drift as a category by continuously reconciling cluster state to Git.
655+
<List
656+
variant="check-icons-list"
657+
content={{
658+
items: [
659+
{
660+
lead: "Understand Helm state",
661+
text: "Know where release secrets live, how three-way merge works, and what causes drift. This knowledge pays off during debugging.",
662+
},
663+
{
664+
lead: "Detect drift continuously",
665+
text: "Run scheduled drift checks with alerting. Don't discover drift during an incident.",
666+
},
667+
{
668+
lead: "Maintain release inventory",
669+
text: "Export release metadata as metrics. Track version consistency across clusters.",
670+
},
671+
{
672+
lead: "Use safe upgrade patterns",
673+
text: "Default to `--atomic` for production. Use canary or blue-green for high-risk changes.",
674+
},
675+
{
676+
lead: "Debug systematically",
677+
text: "Follow the diagnosis workflow. Check status, history, events, and logs in a consistent order.",
678+
},
679+
{
680+
lead: "Consider GitOps",
681+
text: "Flux and ArgoCD eliminate drift as a category by continuously reconciling cluster state to Git.",
682+
},
683+
],
684+
}}
685+
/>
587686

588687
The tools exist. The challenge is using them consistently. Build automation that enforces good practices—drift detection CronJobs, pre-deployment checks in CI, alerting on failed releases—rather than relying on manual discipline.
589688

src/content/articles/idempotent-message-handlers-deduplication-retries/index.mdx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,29 @@ The idempotency key is the identifier your handler uses to recognize duplicate m
2929

3030
There are four common strategies, each with distinct tradeoffs:
3131

32-
- **Producer-supplied message ID** is the cleanest approach. The producer generates a UUID or ULID when creating the message and includes it in the payload. This key survives redeliveries because it's part of the message content, not queue metadata. The downside is that it requires producer discipline - every producer must generate and include a unique ID.
33-
- **Content hash** works when you can't control producers. Hash the message payload with SHA-256 and use that as the key. Identical content produces identical keys automatically. The risk is that sometimes identical content _should_ be processed multiple times (two separate orders for the same product), and a content hash would incorrectly dedupe them.
34-
- **Business key composite** combines entity identifiers with operation context: `order:12345:payment:v3`. This approach has semantic meaning, making debugging easier, but requires careful thought about what constitutes a unique operation.
35-
- **Queue message ID** - avoid this approach. SQS assigns a new MessageId on each redelivery. RabbitMQ's delivery tag changes. This approach only deduplicates within a single delivery attempt, which defeats the purpose entirely.
32+
<List
33+
variant="check-icons-list"
34+
content={{
35+
items: [
36+
{
37+
lead: "Producer-supplied message ID",
38+
text: "is the cleanest approach. The producer generates a UUID or ULID when creating the message and includes it in the payload. This key survives redeliveries because it's part of the message content, not queue metadata. The downside is that it requires producer discipline - every producer must generate and include a unique ID.",
39+
},
40+
{
41+
lead: "Content hash",
42+
text: "works when you can't control producers. Hash the message payload with SHA-256 and use that as the key. Identical content produces identical keys automatically. The risk is that sometimes identical content _should_ be processed multiple times (two separate orders for the same product), and a content hash would incorrectly dedupe them.",
43+
},
44+
{
45+
lead: "Business key composite",
46+
text: "combines entity identifiers with operation context: `order:12345:payment:v3`. This approach has semantic meaning, making debugging easier, but requires careful thought about what constitutes a unique operation.",
47+
},
48+
{
49+
lead: "Queue message ID",
50+
text: "- avoid this approach. SQS assigns a new MessageId on each redelivery. RabbitMQ's delivery tag changes. This approach only deduplicates within a single delivery attempt, which defeats the purpose entirely.",
51+
},
52+
],
53+
}}
54+
/>
3655

3756
The recommended pattern combines producer-supplied IDs with business context:
3857

0 commit comments

Comments
 (0)