Skip to main content

Free O’Reilly Book | Linkerd: Up & Running

Download
close

Hands-on, engineer-focused training from the creators of the service mesh

Buoyant's Service Mesh Academy offers hands-on workshops and self-paced courses to help DevOps engineers, SREs, and architects master Linkerd, the CNCF-graduated service mesh for Kubernetes.

Sign up for our next live workshop

August 13, 2026

Windows Mesh Expansion (WME) with Linkerd

Self-paced courses

Get service mesh certified with
Buoyant’s Service Mesh Academy

Upcoming
Workshops

August 13, 2026

Windows Mesh Expansion (WME) with Linkerd

Windows mesh expansion pulls Windows VMs and bare-metal hosts into your Linkerd mesh so you get all of the Linkerd goodness wherever those machines run,

Register to attend

On-demand Workshops

Jul 17, 2026

|

Joe Fuller

Let Your Trust Anchor Rotate Itself

Watch now
Unlock the recording

Jun 18, 2026

|

Ivan Porta

Community Ingress-Nginx is Retired. What are Your Ingress Controller Options Now?

Watch now
Unlock the recording

May 18, 2026

|

Ivan Porta

Help! Something’s Wrong With My Mesh: A Linkerd Troubleshooting Checklist

Watch now
Unlock the recording

Apr 17, 2026

|

Joe Fuller

Buoyant Cloud: See What Your Mesh Is Telling You

Watch now
Unlock the recording

Feb 13, 2026

|

Ivan Porta

Running Linkerd on Amazon EKS

Watch now
Unlock the recording

Jan 15, 2026

|

Phil Henderson

A Guide to Linkerd Production Readiness

Watch now
Unlock the recording

Dec 11, 2025

|

Zahari Dichev

Yes! Linkerd Does Windows

Watch now
Unlock the recording

Oct 16, 2025

|

Flynn

Managing Linkerd Certificates without Losing Your Mind

Watch now
Unlock the recording

Sep 19, 2025

|

Cortney Nickerson & Flynn

Kyverno 101 with Linkerd

Watch now
Unlock the recording

Aug 14, 2025

|

Flynn

Reducing Cloud Spend with High Availability Zonal Load Balancing

Watch now
Unlock the recording

Jul 18, 2025

|

Flynn

Anti-Complex Multicluster: Federated Services

Watch now
Unlock the recording

Jun 19, 2025

|

Bailey Hayes, Cosmonic

Wasm 101 with Linkerd

Watch now
Unlock the recording

May 15, 2025

|

Flynn

Linkerd 2.18: Protocol Declarations, Windows, and Gateway API Improvements

Watch now
Unlock the recording

Mar 13, 2025

|

Shane Utt & Mattia Lavacca

Gateway API 101 with Linkerd

Watch now
Unlock the recording

Feb 13, 2025

|

Michele Mancioppi, Dash0

OpenTelemetry and Linkerd

Watch now
Unlock the recording

Jan 16, 2025

|

Flynn

Service Mesh 2025 Kickoff: Back to Basics

Watch now
Unlock the recording

Dec 12, 2024

|

Flynn

Linkerd 2.17 Feature Tour: Egress and Federated Services

Watch now
Unlock the recording

Oct 17, 2024

|

Ben Lambert

Building a Secure, Reliable, Observable IDP with Backstage and Linkerd

Watch now
Unlock the recording

Sep 12, 2024

|

Flynn

Top Five Things You Need to Know about Linkerd 2.16

Watch now
Unlock the recording

Aug 15, 2024

|

Flynn

Metrics, Dashboards, and Charts, oh my!

Watch now
Unlock the recording

Jul 18, 2024

|

Flynn

Practical Multi-Cluster: Disaster Recovery, Cloud Migration, Progressive Delivery, and More

Watch now
Unlock the recording

Jun 14, 2024

|

Flynn

IPv6 with Linkerd: Future-Proofing your Network

Watch now
Unlock the recording

May 17, 2024

|

Fynn & Andrew Gracey

Linkerd Outside of Kubernetes: The Easy Way

Watch now
Unlock the recording

Apr 18, 2024

|

Flynn

Linkerd major feature deep dive: Mesh expansion, HAZL, and native sidecar support

Watch now
Unlock the recording

Feb 15, 2024

|

Flynn

Beyond Kubernetes with Linkerd 2.15 and SPIFFE

Watch now
Unlock the recording
'; window.hbspt.forms.create({ portalId: HS_CONFIG.portalId, formId: HS_CONFIG.formId, region: HS_CONFIG.region, target: '#wsa-hs-form-target', onFormSubmitted: function () { // Mark unlocked, then redirect to the originally clicked workshop setUnlocked(); var url = pendingRedirectUrl; // Brief delay so HubSpot can finish its own submit lifecycle setTimeout(function () { if (url) { window.location.href = url; } else { // No URL captured (shouldn't happen) — just refresh state applyGatingState(); closeModal(); } }, 250); } }); } // ===== Modal + focus trap ===== var overlay = document.getElementById('wsa-modal-overlay'); var modal = overlay ? overlay.querySelector('.wsa-modal') : null; var closeBtn = document.getElementById('wsa-modal-close'); // Focus trap strategy: // The HubSpot form renders inside a cross-origin iframe, so we cannot // observe or control focus movement between fields inside it. Instead, we // place "sentinel" focusable elements just before and after the iframe. // When the browser tabs out of the iframe, focus lands on a sentinel, and // we redirect to the close button (which is the only other focusable in // the modal). From the close button, Tab continues forward into the // iframe, completing the cycle: close -> [iframe fields] -> close -> ... function handleSentinelFocus(e) { // Both sentinels redirect to the close button. The close button is the // only non-iframe focusable inside the modal, so the cycle is: // close -> Tab -> (sentinel-before, instantly redirected) -> iframe // iframe end -> Tab -> sentinel-after -> close // close -> Shift+Tab -> sentinel-before -> ??? (handled below) if (closeBtn) closeBtn.focus(); } function handleKeydown(e) { if (e.key === 'Escape') { closeModal(); return; } // Special case: when focus is on the close button and user Shift+Tabs, // we need to send focus to the end of the iframe. We can't focus inside // a cross-origin iframe directly, but we can focus the iframe element // itself — most browsers then place focus on the last focusable inside // it when Shift+Tab is the trigger. As a fallback, the user can Tab // forward from close to re-enter the iframe naturally. if (e.key === 'Tab' && e.shiftKey && document.activeElement === closeBtn) { var iframe = document .getElementById('wsa-modal-form-container') .querySelector('iframe'); if (iframe) { e.preventDefault(); iframe.focus(); } } } function openModal(triggerEl, redirectUrl) { if (!overlay || !modal) return; lastFocusedTrigger = triggerEl || null; pendingRedirectUrl = redirectUrl || null; overlay.classList.add('is-open'); overlay.setAttribute('aria-hidden', 'false'); document.body.classList.add('wsa-modal-locked'); document.addEventListener('keydown', handleKeydown); // Wire sentinels (idempotent — safe to call on every open) var sentinelBefore = document.getElementById('wsa-sentinel-before'); var sentinelAfter = document.getElementById('wsa-sentinel-after'); if (sentinelBefore) { sentinelBefore.removeEventListener('focus', handleSentinelFocus); sentinelBefore.addEventListener('focus', handleSentinelFocus); } if (sentinelAfter) { sentinelAfter.removeEventListener('focus', handleSentinelFocus); sentinelAfter.addEventListener('focus', handleSentinelFocus); } // Load + render the HubSpot form on first open (and re-render on // subsequent opens so the form is fresh) loadHubSpotScript() .then(function () { renderHubSpotForm(); // Move focus into the iframe once it's available. HubSpot needs a // moment to inject its iframe, so we poll briefly. focusIntoForm(); }) .catch(function () { var container = document.getElementById('wsa-modal-form-container'); if (container) { container.innerHTML = '

Sorry, the form failed to load. Please refresh the page and try again.

'; } if (closeBtn) closeBtn.focus(); }); } // Poll briefly for the HubSpot iframe and focus it once it appears. // Focusing the iframe element itself causes most browsers to place focus // on the first focusable inside it, which is the first form field. function focusIntoForm() { var attempts = 0; var maxAttempts = 30; // ~3 seconds total var poll = setInterval(function () { attempts++; var container = document.getElementById('wsa-modal-form-container'); var iframe = container ? container.querySelector('iframe') : null; if (iframe) { clearInterval(poll); // Small delay to let the iframe finish loading its content setTimeout(function () { try { iframe.focus(); } catch (err) { // Fallback: focus the close button so keyboard users have a path in if (closeBtn) closeBtn.focus(); } }, 150); } else if (attempts >= maxAttempts) { clearInterval(poll); // Form never rendered — focus close button as fallback if (closeBtn) closeBtn.focus(); } }, 100); } function closeModal() { if (!overlay) return; overlay.classList.remove('is-open'); overlay.setAttribute('aria-hidden', 'true'); document.body.classList.remove('wsa-modal-locked'); document.removeEventListener('keydown', handleKeydown); pendingRedirectUrl = null; // Restore focus to the trigger that opened the modal if (lastFocusedTrigger && typeof lastFocusedTrigger.focus === 'function') { lastFocusedTrigger.focus(); } lastFocusedTrigger = null; } // ===== Click delegation ===== function handleSectionClick(e) { var trigger = e.target.closest('[data-gated-trigger]'); if (!trigger) return; // Re-check unlock state at click time (in case it changed in another tab) if (isUnlocked()) { applyGatingState(); return; // Let the native navigation proceed } e.preventDefault(); var href = trigger.getAttribute('data-original-href') || trigger.getAttribute('href'); // Resolve to absolute URL for safety var absoluteUrl; try { absoluteUrl = new URL(href, window.location.origin).href; } catch (err) { absoluteUrl = href; } openModal(trigger, absoluteUrl); } // ===== Wire up ===== function init() { var section = document.querySelector('.section_academy_list'); if (!section) return; // Portal: move the modal overlay to be a direct child of so it // escapes any parent stacking context (transforms, filters, fixed // positioning issues, etc.) that Webflow may have on ancestor elements. if (overlay && overlay.parentNode !== document.body) { document.body.appendChild(overlay); } applyGatingState(); section.addEventListener('click', handleSectionClick); if (closeBtn) { closeBtn.addEventListener('click', closeModal); } if (overlay) { // Click on backdrop (not the modal itself) closes overlay.addEventListener('click', function (e) { if (e.target === overlay) closeModal(); }); } // Sync state across tabs window.addEventListener('storage', function (e) { if (e.key === STORAGE_KEY) { applyGatingState(); } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();