> ## Documentation Index
> Fetch the complete documentation index at: https://www.latitude.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# LKS

> Managed Kubernetes on Latitude.sh bare metal

export const ReactFlowDiagram = ({nodes = [], edges = [], height = 'md', className, interactive = false, showControls = interactive, showMiniMap = false, showBackground = true, fitView = true, fitViewPadding = 0.25, orientation = 'horizontal'}) => {
  const reactFlowVersion = '12.10.2';
  const reactVersion = '18.3.1';
  const reactUrl = `https://unpkg.com/react@${reactVersion}/umd/react.production.min.js`;
  const reactDomUrl = `https://unpkg.com/react-dom@${reactVersion}/umd/react-dom.production.min.js`;
  const reactFlowUrl = `https://unpkg.com/@xyflow/react@${reactFlowVersion}/dist/umd/index.js`;
  const reactFlowCssUrl = `https://unpkg.com/@xyflow/react@${reactFlowVersion}/dist/style.css`;
  const heightClassNames = {
    sm: 'h-64',
    md: 'h-96'
  };
  const heightStyles = {
    lg: {
      height: '560px'
    },
    xl: {
      height: '820px'
    }
  };
  const nodeToneClassNames = {
    default: 'border-zinc-950/20 bg-white text-zinc-950 dark:border-white/20 dark:bg-zinc-950 dark:text-white',
    accent: 'border-violet-500/30 bg-violet-50 text-zinc-950 dark:border-violet-400/30 dark:bg-violet-950/40 dark:text-white',
    success: 'border-emerald-500/30 bg-emerald-50 text-zinc-950 dark:border-emerald-400/30 dark:bg-emerald-950/40 dark:text-white',
    warning: 'border-amber-500/30 bg-amber-50 text-zinc-950 dark:border-amber-400/30 dark:bg-amber-950/40 dark:text-white'
  };
  const classNames = (...values) => values.filter(Boolean).join(' ');
  const containerRef = useRef(null);
  const rootRef = useRef(null);
  const [errorMessage, setErrorMessage] = useState(null);
  const heightStyle = heightStyles[height];
  const heightClassName = heightClassNames[height] || (heightStyle ? null : height);
  const isVertical = orientation === 'vertical';
  const loadScript = src => {
    if (document.querySelector(`script[src="${src}"]`)) return Promise.resolve();
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = src;
      script.async = true;
      script.onload = resolve;
      script.onerror = () => reject(new Error(`Failed to load ${src}`));
      document.head.appendChild(script);
    });
  };
  const loadStylesheet = href => {
    if (document.querySelector(`link[href="${href}"]`)) return;
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = href;
    document.head.appendChild(link);
  };
  const ensureJsxRuntime = () => {
    if (window.jsxRuntime || !window.React) return;
    const createElement = (type, props = {}, key) => {
      const elementProps = key === undefined ? props : {
        ...props,
        key
      };
      return window.React.createElement(type, elementProps);
    };
    window.jsxRuntime = {
      Fragment: window.React.Fragment,
      jsx: createElement,
      jsxs: createElement
    };
  };
  const loadReactFlow = async () => {
    if (window.ReactFlow) return window.ReactFlow;
    if (!window.__latitudeReactFlowLoader) {
      window.__latitudeReactFlowLoader = Promise.resolve().then(() => loadStylesheet(reactFlowCssUrl)).then(() => window.React ? undefined : loadScript(reactUrl)).then(() => ensureJsxRuntime()).then(() => window.ReactDOM ? undefined : loadScript(reactDomUrl)).then(() => loadScript(reactFlowUrl)).then(() => window.ReactFlow).catch(err => {
        window.__latitudeReactFlowLoader = null;
        return Promise.reject(err);
      });
    }
    return window.__latitudeReactFlowLoader;
  };
  const createDiagramNode = (React, Handle, Position) => {
    const DiagramNode = ({data}) => {
      const positions = {
        top: Position.Top,
        right: Position.Right,
        bottom: Position.Bottom,
        left: Position.Left
      };
      const targetPosition = positions[data?.targetPosition] || (isVertical ? Position.Top : Position.Left);
      const sourcePosition = positions[data?.sourcePosition] || (isVertical ? Position.Bottom : Position.Right);
      if (data?.kind === 'label') {
        const isBadge = data?.tone === 'badge';
        return React.createElement('div', {
          className: isBadge ? 'rounded border px-1.5 py-0.5 text-xs font-semibold leading-none' : 'text-sm font-semibold leading-5 text-zinc-900 dark:text-zinc-100',
          style: {
            backgroundColor: isBadge ? 'var(--latitude-diagram-label-bg)' : undefined,
            borderColor: isBadge ? 'hsl(var(--latitude-diagram-border-strong))' : undefined,
            color: 'hsl(var(--latitude-diagram-node-text))',
            textAlign: data?.align || 'left',
            width: data?.width || 320
          }
        }, data?.title);
      }
      if (data?.kind === 'boundary') {
        return React.createElement('div', {
          className: 'rounded-xl border border-dashed border-zinc-950/70 bg-transparent dark:border-white/70',
          style: {
            width: data?.width || 640,
            height: data?.height || 520
          }
        }, React.createElement(Handle, {
          type: 'target',
          position: targetPosition,
          isConnectable: false,
          className: 'opacity-0'
        }), React.createElement('div', {
          className: 'px-4 py-3 text-sm font-semibold leading-5 text-zinc-800 dark:text-zinc-100'
        }, data?.title), React.createElement(Handle, {
          type: 'source',
          position: sourcePosition,
          isConnectable: false,
          className: 'opacity-0'
        }));
      }
      if (data?.kind === 'zone') {
        return React.createElement('div', {
          className: 'rounded-xl border border-violet-300/70 bg-violet-100/50 dark:border-violet-400/30 dark:bg-violet-950/30',
          style: {
            width: data?.width || 520,
            height: data?.height || 300
          }
        }, React.createElement(Handle, {
          type: 'target',
          position: targetPosition,
          isConnectable: false,
          className: 'opacity-0'
        }), React.createElement('div', {
          className: 'px-4 py-3 text-sm font-medium leading-5 text-zinc-700 dark:text-zinc-200'
        }, data?.title), React.createElement(Handle, {
          type: 'source',
          position: sourcePosition,
          isConnectable: false,
          className: 'opacity-0'
        }));
      }
      if (data?.kind === 'container') {
        const containerHandles = [{
          type: 'target',
          position: Position.Top,
          id: 'target-top'
        }, {
          type: 'source',
          position: Position.Top,
          id: 'source-top'
        }, {
          type: 'target',
          position: Position.Right,
          id: 'target-right'
        }, {
          type: 'source',
          position: Position.Right,
          id: 'source-right'
        }, {
          type: 'target',
          position: Position.Bottom,
          id: 'target-bottom'
        }, {
          type: 'source',
          position: Position.Bottom,
          id: 'source-bottom'
        }, {
          type: 'target',
          position: Position.Left,
          id: 'target-left'
        }, {
          type: 'source',
          position: Position.Left,
          id: 'source-left'
        }];
        return React.createElement('div', {
          style: {
            width: data?.width || 480,
            height: data?.height || 200,
            border: data?.border || '1px solid hsl(var(--latitude-diagram-brand-uv) / 0.35)',
            backgroundColor: data?.backgroundColor || 'transparent',
            borderRadius: data?.borderRadius ?? 12,
            boxSizing: 'border-box'
          }
        }, ...containerHandles.map(handle => React.createElement(Handle, {
          key: `${handle.type}-${handle.id}`,
          type: handle.type,
          position: handle.position,
          id: handle.id,
          isConnectable: false,
          className: 'opacity-0'
        })));
      }
      if (data?.kind === 'resource') {
        const icon = data?.icon || data?.badge || '';
        const hexColor = data?.hexColor || '#2563eb';
        return React.createElement('div', {
          className: 'flex w-32 flex-col items-center text-center text-zinc-800 dark:text-zinc-100'
        }, React.createElement(Handle, {
          type: 'target',
          position: targetPosition,
          isConnectable: false,
          className: 'opacity-0'
        }), React.createElement('div', {
          className: 'flex h-20 w-20 items-center justify-center text-lg font-bold tracking-wide text-white shadow-sm',
          style: {
            backgroundColor: hexColor,
            clipPath: 'polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%)'
          }
        }, icon), React.createElement('div', {
          className: 'mt-2 text-sm font-semibold leading-5'
        }, data?.title), data?.subtitle ? React.createElement('div', {
          className: 'mt-0.5 text-xs leading-4 text-zinc-600 dark:text-zinc-300'
        }, data.subtitle) : null, React.createElement(Handle, {
          type: 'source',
          position: sourcePosition,
          isConnectable: false,
          className: 'opacity-0'
        }));
      }
      const tone = nodeToneClassNames[data?.tone] || nodeToneClassNames.default;
      const width = data?.width || (data?.size === 'wide' ? 320 : 256);
      const blockColumns = data?.blockColumns || 3;
      return React.createElement('div', {
        className: classNames('rounded-lg border px-4 py-3 shadow-sm', tone),
        style: {
          width
        }
      }, React.createElement(Handle, {
        type: 'target',
        position: targetPosition,
        isConnectable: false,
        className: 'opacity-0'
      }), React.createElement('div', {
        className: 'flex items-start justify-between gap-3'
      }, React.createElement('div', {
        className: 'min-w-0'
      }, React.createElement('div', {
        className: 'truncate text-base font-semibold leading-6'
      }, data?.title), data?.subtitle ? React.createElement('div', {
        className: 'mt-1 text-sm leading-5 text-zinc-600 dark:text-zinc-300'
      }, data.subtitle) : null), data?.badge ? React.createElement('span', {
        className: 'shrink-0 rounded-full border border-zinc-950/10 px-1.5 py-0.5 text-xs font-medium leading-none text-zinc-600 dark:border-white/20 dark:text-zinc-300'
      }, data.badge) : null), data?.blocks?.length ? React.createElement('div', {
        className: 'mt-3',
        style: {
          display: 'grid',
          gap: '0.5rem',
          gridTemplateColumns: `repeat(${blockColumns}, minmax(0, 1fr))`
        }
      }, ...data.blocks.map((block, index) => {
        const blockData = typeof block === 'string' ? {
          label: block
        } : block;
        return React.createElement('div', {
          key: `${blockData.label}-${index}`,
          className: 'flex min-h-14 items-center justify-center rounded-md border border-zinc-950/10 bg-zinc-950/[0.03] px-2 text-center text-xs font-medium leading-4 text-zinc-700 dark:border-white/15 dark:bg-white/10 dark:text-zinc-200'
        }, blockData.label);
      })) : null, React.createElement(Handle, {
        type: 'source',
        position: sourcePosition,
        isConnectable: false,
        className: 'opacity-0'
      }));
    };
    return React.memo(DiagramNode);
  };
  const normalizeNodes = (inputNodes, Position) => inputNodes.map(node => {
    const positions = {
      top: Position.Top,
      right: Position.Right,
      bottom: Position.Bottom,
      left: Position.Left
    };
    return {
      draggable: false,
      selectable: false,
      ...node,
      type: node.type || 'diagramNode',
      sourcePosition: positions[node.sourcePosition] || positions[node.data?.sourcePosition] || (isVertical ? Position.Bottom : Position.Right),
      targetPosition: positions[node.targetPosition] || positions[node.data?.targetPosition] || (isVertical ? Position.Top : Position.Left),
      data: {
        title: node.label || node.id,
        ...node.data || ({})
      }
    };
  });
  const normalizeEdges = inputEdges => inputEdges.map(edge => ({
    type: 'smoothstep',
    animated: true,
    ...edge,
    style: {
      stroke: 'hsl(var(--latitude-diagram-border-strong))',
      strokeWidth: 1.5,
      strokeDasharray: '5 7',
      ...edge.style || ({})
    },
    ...edge.markerEnd ? {
      markerEnd: edge.markerEnd
    } : {}
  }));
  const renderDiagram = ({container}) => {
    const React = window.React;
    const ReactDOM = window.ReactDOM;
    const {Background, Controls, Handle, MiniMap, Position, ReactFlow} = window.ReactFlow;
    const nodeTypes = {
      diagramNode: createDiagramNode(React, Handle, Position)
    };
    const children = [showBackground ? React.createElement(Background, {
      key: 'background'
    }) : null, showMiniMap ? React.createElement(MiniMap, {
      key: 'minimap',
      pannable: interactive,
      zoomable: interactive
    }) : null, showControls ? React.createElement(Controls, {
      key: 'controls',
      showInteractive: false
    }) : null].filter(Boolean);
    const flowElement = React.createElement(ReactFlow, {
      nodes: normalizeNodes(nodes, Position),
      edges: normalizeEdges(edges),
      nodeTypes,
      fitView,
      fitViewOptions: {
        padding: fitViewPadding
      },
      nodesDraggable: interactive,
      nodesConnectable: false,
      elementsSelectable: interactive,
      panOnDrag: interactive,
      panOnScroll: false,
      zoomOnScroll: false,
      zoomOnPinch: interactive,
      zoomOnDoubleClick: interactive,
      preventScrolling: false
    }, ...children);
    const root = ReactDOM.createRoot ? ReactDOM.createRoot(container) : {
      render: element => ReactDOM.render(element, container),
      unmount: () => ReactDOM.unmountComponentAtNode(container)
    };
    root.render(flowElement);
    return root;
  };
  useEffect(() => {
    let isMounted = true;
    loadReactFlow().then(() => {
      if (!isMounted || !containerRef.current) return;
      rootRef.current?.unmount();
      rootRef.current = renderDiagram({
        container: containerRef.current
      });
    }).catch(error => {
      if (!isMounted) return;
      setErrorMessage(error.message);
    });
    return () => {
      isMounted = false;
      rootRef.current?.unmount();
      rootRef.current = null;
    };
  }, [nodes, edges, interactive, showControls, showMiniMap, showBackground, fitView, fitViewPadding, orientation]);
  return <div className={classNames('latitude-react-flow-diagram not-prose my-6 overflow-hidden rounded-xl border border-zinc-950/10 bg-zinc-50 dark:border-white/10 dark:bg-zinc-950/50', heightClassName, className)} data-interactive={interactive ? 'true' : 'false'} style={heightStyle}>
      <style>
        {`
          .latitude-react-flow-diagram {
            --latitude-diagram-brand-uv: var(--brand-uv, 241 87% 61%);
            --latitude-diagram-border: var(--hsl-border, 0 0% 92%);
            --latitude-diagram-border-strong: 210 4% 53%;
            --latitude-diagram-node-bg: 0 0% 100%;
            --latitude-diagram-node-text: 210 4% 20%;
            --latitude-diagram-node-border: 210 4% 28%;
            --latitude-diagram-label-bg: #ffffff;
            --latitude-diagram-surface: 0 0% 100%;
          }

          .dark .latitude-react-flow-diagram {
            --latitude-diagram-brand-uv: var(--brand-uv, 71 99% 67%);
            --latitude-diagram-border: var(--hsl-border, 71 2% 18%);
            --latitude-diagram-border-strong: 71 1.5% 50%;
            --latitude-diagram-node-bg: 71 1.5% 10%;
            --latitude-diagram-node-text: 71 1.5% 90%;
            --latitude-diagram-node-border: 71 1.5% 38%;
            --latitude-diagram-label-bg: hsl(71 1.5% 7%);
            --latitude-diagram-surface: 71 1.5% 7%;
          }

          .latitude-react-flow-diagram[data-interactive="false"] .react-flow__handle {
            opacity: 0;
          }

          .latitude-react-flow-diagram .react-flow__node-default {
            background: hsl(var(--latitude-diagram-node-bg));
            border: 1px solid hsl(var(--latitude-diagram-node-border));
            border-radius: 6px;
            box-shadow: 0 1px 2px hsl(0 0% 0% / 0.06);
            color: hsl(var(--latitude-diagram-node-text));
            font-size: 13px;
            line-height: 1.2;
            padding: 10px 14px;
            white-space: nowrap;
          }

          .latitude-react-flow-diagram .react-flow__edge.animated path {
            animation-duration: 1.7s;
          }

          .dark .latitude-react-flow-diagram .react-flow__node-default {
            background: hsl(var(--latitude-diagram-node-bg));
            border-color: hsl(var(--latitude-diagram-brand-uv) / 0.35);
            box-shadow: 0 0 0 1px hsl(0 0% 0% / 0.2);
            color: hsl(var(--latitude-diagram-node-text));
          }
        `}
      </style>
      {errorMessage ? <div className="flex h-full items-center justify-center px-4 text-sm text-red-600 dark:text-red-400">
          React Flow failed to load: {errorMessage}
        </div> : <div ref={containerRef} className="h-full w-full" />}
    </div>;
};

export const lksArchitectureNodes = [{
  id: 'lks-label',
  position: {
    x: 90,
    y: 0
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    title: 'Latitude Kubernetes Service (LKS)',
    width: 540,
    align: 'center'
  }
}, {
  id: 'lks-sublabel',
  position: {
    x: 90,
    y: 22
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    tone: 'badge',
    title: 'Managed Control Plane, your Node Pools',
    width: 540,
    align: 'center'
  }
}, {
  id: 'customer',
  position: {
    x: 10,
    y: 70
  },
  type: 'default',
  data: {
    label: 'You (kubectl)'
  },
  style: {
    width: 170
  },
  sourcePosition: 'bottom'
}, {
  id: 'end-users',
  position: {
    x: 520,
    y: 70
  },
  type: 'default',
  data: {
    label: 'End users / Internet'
  },
  style: {
    width: 210
  },
  sourcePosition: 'bottom'
}, {
  id: 'control-plane-label',
  position: {
    x: 10,
    y: 150
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    title: 'Managed Control Plane',
    width: 460,
    align: 'center'
  }
}, {
  id: 'control-plane-zone',
  position: {
    x: 0,
    y: 175
  },
  type: 'diagramNode',
  data: {
    kind: 'container',
    width: 480,
    height: 140,
    backgroundColor: 'hsl(var(--latitude-diagram-brand-uv) / 0.08)'
  }
}, {
  id: 'cp-api',
  position: {
    x: 40,
    y: 45
  },
  type: 'default',
  parentId: 'control-plane-zone',
  extent: 'parent',
  data: {
    label: 'API server'
  },
  style: {
    width: 180
  },
  targetPosition: 'top',
  sourcePosition: 'bottom'
}, {
  id: 'cp-etcd',
  position: {
    x: 260,
    y: 45
  },
  type: 'default',
  parentId: 'control-plane-zone',
  extent: 'parent',
  data: {
    label: 'etcd'
  },
  style: {
    width: 180
  },
  targetPosition: 'top',
  sourcePosition: 'bottom'
}, {
  id: 'control-plane-subtitle',
  position: {
    x: 10,
    y: 322
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    tone: 'badge',
    title: 'Managed by Latitude.sh, highly available',
    width: 460,
    align: 'center'
  }
}, {
  id: 'worker-plane-label',
  position: {
    x: 10,
    y: 370
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    title: 'Your Node Pools',
    width: 460,
    align: 'center'
  }
}, {
  id: 'worker-zone',
  position: {
    x: 0,
    y: 395
  },
  type: 'diagramNode',
  data: {
    kind: 'container',
    width: 480,
    height: 140,
    backgroundColor: 'hsl(var(--latitude-diagram-brand-uv) / 0.05)'
  }
}, {
  id: 'worker-1',
  position: {
    x: 20,
    y: 45
  },
  type: 'default',
  parentId: 'worker-zone',
  extent: 'parent',
  data: {
    label: 'Node'
  },
  style: {
    width: 130
  },
  targetPosition: 'top'
}, {
  id: 'worker-2',
  position: {
    x: 175,
    y: 45
  },
  type: 'default',
  parentId: 'worker-zone',
  extent: 'parent',
  data: {
    label: 'Node'
  },
  style: {
    width: 130
  },
  targetPosition: 'top'
}, {
  id: 'worker-3',
  position: {
    x: 330,
    y: 45
  },
  type: 'default',
  parentId: 'worker-zone',
  extent: 'parent',
  data: {
    label: 'Node'
  },
  style: {
    width: 130
  },
  targetPosition: 'right'
}, {
  id: 'worker-plane-subtitle',
  position: {
    x: 10,
    y: 542
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    tone: 'badge',
    title: 'Your Workloads, Cilium CNI, bring-your-own ingress',
    width: 460,
    align: 'center'
  }
}, {
  id: 'network-label',
  position: {
    x: 520,
    y: 150
  },
  type: 'diagramNode',
  data: {
    kind: 'label',
    title: 'Networking',
    width: 200,
    align: 'center'
  }
}, {
  id: 'network-zone',
  position: {
    x: 510,
    y: 175
  },
  type: 'diagramNode',
  data: {
    kind: 'container',
    width: 220,
    height: 400,
    backgroundColor: 'hsl(var(--latitude-diagram-brand-uv) / 0.05)'
  }
}, {
  id: 'lb-ips',
  position: {
    x: 30,
    y: 40
  },
  type: 'default',
  parentId: 'network-zone',
  extent: 'parent',
  data: {
    label: 'LoadBalancer IPs'
  },
  style: {
    width: 160
  },
  targetPosition: 'top',
  sourcePosition: 'left'
}, {
  id: 'eip-bgp',
  position: {
    x: 30,
    y: 170
  },
  type: 'default',
  parentId: 'network-zone',
  extent: 'parent',
  data: {
    label: 'Elastic IP + BGP'
  },
  style: {
    width: 160
  }
}, {
  id: 'metallb',
  position: {
    x: 30,
    y: 300
  },
  type: 'default',
  parentId: 'network-zone',
  extent: 'parent',
  data: {
    label: 'MetalLB'
  },
  style: {
    width: 160
  }
}];

export const lksArchitectureEdges = [{
  id: 'customer-cp-zone',
  source: 'customer',
  target: 'control-plane-zone',
  targetHandle: 'target-top'
}, {
  id: 'end-users-network-zone',
  source: 'end-users',
  target: 'network-zone',
  targetHandle: 'target-top'
}, {
  id: 'cp-zone-worker-zone',
  source: 'control-plane-zone',
  target: 'worker-zone',
  sourceHandle: 'source-bottom',
  targetHandle: 'target-top'
}, {
  id: 'network-zone-worker-zone',
  source: 'network-zone',
  target: 'worker-zone',
  sourceHandle: 'source-left',
  targetHandle: 'target-right'
}];

Latitude Kubernetes Service (LKS) is managed Kubernetes on bare metal. Latitude.sh runs the Control Plane; you run your Workloads on Node Pools. You get a conformant, upstream Kubernetes Cluster and a kubeconfig, then manage your applications with standard Kubernetes tooling.

<Note>
  LKS is in preview. Features and defaults may change. During the preview, LKS is managed from the dashboard; API, CLI, and SDK support is coming.
</Note>

<ReactFlowDiagram nodes={lksArchitectureNodes} edges={lksArchitectureEdges} height="lg" fitViewPadding={0.04} />

## What Latitude.sh manages

* **Control Plane.** The API server and etcd run as a managed, highly available Control Plane. You don't size, access, or patch it.
* **Networking.** Cilium is the Cluster CNI, configured and maintained for you.
* **LoadBalancer IPs.** A `Service` of type `LoadBalancer` is assigned a Latitude Elastic IP announced over BGP. See [Exposing Workloads](/docs/lks/exposing-workloads).
* **Node images.** Node operating system images are provided by Latitude.sh and roll out through Node Pool upgrades.

## What you manage

* **Workloads.** Your applications, their manifests, and their lifecycle.
* **Node Pools.** The plan, size, Labels, and Taints of each Node Pool. See [Node Pools](/docs/lks/node-pools).
* **Ingress and gateways.** LKS load balancing is L4. Bring your own Ingress or Gateway controller for HTTP routing.
* **Observability, backups, and upgrades.** You run your monitoring stack, back up your data, and choose when to upgrade Kubernetes versions.

## Getting started

Follow [Getting started](/docs/lks/getting-started) to create a Cluster, connect with `kubectl`, and run your first Workload.

## Shared responsibility

For the full breakdown of what Latitude.sh operates and what you operate across the Cluster lifecycle, see [Shared responsibility](/docs/lks/shared-responsibility).
