diff --git a/.gitignore b/.gitignore
index dc1bf5d6..7e95a9be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,3 +47,7 @@ junit.xml
# Local dev setup
.envrc
+
+# Jekyll local preview
+_site/
+.sass-cache/
diff --git a/Makefile b/Makefile
index 52ea3d43..37044bc9 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,15 @@ SUBNET_KUBECONFIG_PATH ?= $(CURDIR)/subnet-testing-kubeconfig.yaml
MGMT_KUBECONFIG_PATH ?= $(CURDIR)/mgmt-cluster-kubeconfig.yaml
IPV6_KUBECONFIG_PATH ?= $(CURDIR)/ipv6-kubeconfig.yaml
+#####################################################################
+# Local Docs Preview Setup
+#####################################################################
+
+DOCS_IMAGE := jekyll/jekyll:pages
+DOCS_CONTAINER := lccm-docs
+DOCS_PORT := 4000
+DOCS_LIVERELOAD_PORT := 35729
+
export GO111MODULE=on
.PHONY: all
@@ -260,3 +269,19 @@ helm-template:
@helm template foo deploy/chart --set apiToken="apiToken",region="us-east" > /dev/null
@helm template foo deploy/chart --set secretRef.apiTokenRef="apiToken",secretRef.name="api",secretRef.regionRef="us-east" > /dev/null
+.PHONY: serve-docs
+serve-docs:
+# Serve the documentation site locally with live reload
+ echo "Serving the docs on http://localhost:$(DOCS_PORT), press ctrl-c to stop"
+ docker run --rm --interactive --tty --name $(DOCS_CONTAINER) \
+ --publish $(DOCS_PORT):4000 \
+ --publish $(DOCS_LIVERELOAD_PORT):35729 \
+ --volume "$(shell pwd):/srv/jekyll" \
+ $(DOCS_IMAGE) \
+ jekyll serve --host 0.0.0.0 --livereload --force-polling
+
+.PHONY: build-docs
+build-docs:
+# Build the documentation site the way GitHub Pages does
+ docker run --rm --volume "$(shell pwd):/srv/jekyll" $(DOCS_IMAGE) jekyll build
+
diff --git a/_config.yaml b/_config.yaml
deleted file mode 100644
index 88b63ad6..00000000
--- a/_config.yaml
+++ /dev/null
@@ -1 +0,0 @@
-markdown: GFM
diff --git a/_config.yml b/_config.yml
new file mode 100644
index 00000000..4c0435d5
--- /dev/null
+++ b/_config.yml
@@ -0,0 +1,39 @@
+remote_theme: just-the-docs/just-the-docs
+
+# GitHub Pages turns the plugins below on by default; a local `jekyll build`
+# does not, which is why pages that rely on them (markdown without front
+# matter, titles taken from the first heading) are missing from the local nav
+# unless they are listed here. Listing them changes nothing in production.
+plugins:
+ - jekyll-remote-theme
+ - jekyll-default-layout
+ - jekyll-optional-front-matter
+ - jekyll-readme-index
+ - jekyll-relative-links
+ - jekyll-titles-from-headings
+
+title: Kubernetes Cloud Controller Manager for Linode
+search_enabled: true
+heading_anchors: true
+color_scheme: dark
+
+
+# Everything that is not documentation. Without this the site carries the whole
+# Go tree, and CHANGELOG.md is published as a stray page nothing links to.
+exclude:
+ - bin/
+ - CHANGELOG.md
+ - cloud/
+ - codecov.yml
+ - coverage.out
+ - deploy/
+ - e2e/
+ - examples/
+ - go.mod
+ - go.sum
+ - hack/
+ - main.go
+ - Makefile
+ - mise.toml
+ - renovate.json5
+ - sentry/
diff --git a/_includes/head_custom.html b/_includes/head_custom.html
new file mode 100644
index 00000000..76f1dd00
--- /dev/null
+++ b/_includes/head_custom.html
@@ -0,0 +1,100 @@
+{%- comment -%}
+ Color scheme preference: light, dark, or follow the OS ("system"). The script
+ runs in the document head so the stored choice is applied before the page
+ paints. The toggle button itself is in header_custom.html.
+
+ Two constraints on the script below:
+
+ 1. Block comments only. The theme renders pages through
+ _layouts/vendor/compress.html, which strips newlines, so a `//` comment
+ would swallow the rest of the script.
+ 2. Never write a literal `head` element tag in it. Jekyll's `--livereload`
+ server injects its reload snippet at that string, and the snippet's closing
+ script tag would end the script early, dumping the rest of the code onto
+ the page as text.
+
+ Long notes like this one belong in a Liquid comment: Jekyll strips it at build
+ time, so it never ships to the browser with every page.
+{%- endcomment -%}
+
diff --git a/_includes/header_custom.html b/_includes/header_custom.html
new file mode 100644
index 00000000..625120e2
--- /dev/null
+++ b/_includes/header_custom.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+{%- comment -%}
+ Cycles the color scheme preference (System, Light, Dark) and shows the matching
+ icon. Block comments only in the script below, and no literal element tags: see
+ the notes in head_custom.html.
+{%- endcomment -%}
+
diff --git a/_sass/custom/custom.scss b/_sass/custom/custom.scss
new file mode 100644
index 00000000..18015f3c
--- /dev/null
+++ b/_sass/custom/custom.scss
@@ -0,0 +1,62 @@
+// Overrides just-the-docs' (empty) custom stylesheet. Imported last by the
+// theme, so these rules win over the theme's own and are compiled into every
+// color scheme.
+
+// The theme pins the sidebar header to a fixed height and centers the title in
+// it, so a site title long enough to wrap (this one takes three lines) is
+// clipped and spills out of the sidebar. Let the header grow to fit instead:
+// .site-nav below it is `flex: 1 1 auto` with its own scrollbar, so it simply
+// starts lower. The theme's own min-height still applies.
+.site-header {
+ height: auto;
+ max-height: none;
+}
+
+// Color scheme toggle, rendered by _includes/header_custom.html. An icon-only
+// button styled from the theme's color variables, so it follows whichever
+// scheme is active.
+.theme-switcher {
+ display: flex;
+ align-items: center;
+ padding: $sp-2 $sp-4;
+}
+
+.theme-switcher-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ padding: 0;
+ color: $body-text-color;
+ cursor: pointer;
+ border-radius: $border-radius;
+ transition: color 150ms ease, background-color 150ms ease;
+
+ &:hover {
+ // $feedback-color is what the theme uses for its own hover surfaces.
+ color: $link-color;
+ background-color: $feedback-color;
+ }
+
+ &:focus-visible {
+ outline: 2px solid $link-color;
+ outline-offset: 1px;
+ }
+}
+
+.theme-switcher-icon {
+ width: 1.125rem;
+ height: 1.125rem;
+ fill: none;
+ stroke: currentcolor;
+ stroke-width: 2;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+
+ // SVG elements are not HTML elements, so spell out what `hidden` means here
+ // rather than relying on the browser's rule for it.
+ &[hidden] {
+ display: none;
+ }
+}
diff --git a/docs/configuration/README.md b/docs/configuration/README.md
index 3300d113..1ba869b8 100644
--- a/docs/configuration/README.md
+++ b/docs/configuration/README.md
@@ -1,3 +1,9 @@
+---
+layout: default
+title: Configuration Guide
+nav_order: 3
+---
+
# Configuration Guide
The Linode Cloud Controller Manager (CCM) offers extensive configuration options to customize its behavior. This section covers all available configuration methods and options.
diff --git a/docs/configuration/annotations.md b/docs/configuration/annotations.md
index bc07809d..14295601 100644
--- a/docs/configuration/annotations.md
+++ b/docs/configuration/annotations.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Service Annotations
+parent: Configuration Guide
+nav_order: 2
+---
+
# Service Annotations
## Overview
@@ -18,7 +25,7 @@ The keys and the values in [annotations must be strings](https://kubernetes.io/d
### Basic Configuration
| Annotation (Suffix) | Values | Default | Description |
-|--------------------|--------|---------|-------------|
+| -------------------- | -------- | --------- | ------------- |
| `throttle` | `0`-`20` (`0` to disable) | `0` | Client Connection Throttle, which limits the number of subsequent new connections per second from the same client IP |
| `default-protocol` | `tcp`, `udp`, `http`, `https` | `tcp` | This annotation is used to specify the default protocol for Linode NodeBalancer |
| `default-proxy-protocol` | `none`, `v1`, `v2` | `none` | Specifies whether to use a version of Proxy Protocol on the underlying NodeBalancer |
diff --git a/docs/configuration/environment.md b/docs/configuration/environment.md
index 91056871..625e8110 100644
--- a/docs/configuration/environment.md
+++ b/docs/configuration/environment.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Environment Variables and Flags
+parent: Configuration Guide
+nav_order: 4
+---
+
# Environment Variables and Flags
## Overview
@@ -96,7 +103,7 @@ spec:
- Adjust cache TTL based on cluster size and update frequency
- Monitor memory usage when modifying cache settings
-- Consider API rate limits when decreasing TTL (see [Linode API Rate Limits](@https://techdocs.akamai.com/linode-api/reference/rate-limits))
+- Consider API rate limits when decreasing TTL (see [Linode API Rate Limits](https://techdocs.akamai.com/linode-api/reference/rate-limits))
### API Settings
diff --git a/docs/configuration/firewall.md b/docs/configuration/firewall.md
index c5d011d4..01ca85c6 100644
--- a/docs/configuration/firewall.md
+++ b/docs/configuration/firewall.md
@@ -1,8 +1,16 @@
+---
+layout: default
+title: Firewall Setup
+parent: Configuration Guide
+nav_order: 5
+---
+
# Firewall Setup
## Overview
The CCM provides two methods for securing NodeBalancers with firewalls:
+
1. CCM-managed Cloud Firewalls (using `firewall-acl` annotation)
2. User-managed Cloud Firewalls (using `firewall-id` annotation)
@@ -13,6 +21,7 @@ The CCM provides two methods for securing NodeBalancers with firewalls:
Use the `firewall-acl` annotation to specify firewall rules. The rules should be provided as a JSON object with either an `allowList` or `denyList` (but not both).
#### Allow List Configuration
+
```yaml
apiVersion: v1
kind: Service
@@ -29,6 +38,7 @@ metadata:
```
#### Deny List Configuration
+
```yaml
metadata:
annotations:
@@ -42,6 +52,7 @@ metadata:
```
### Behavior
+
- Only one type of list (allow or deny) can be used per service
- Rules are automatically created and managed by the CCM
- Rules are updated when the annotation changes
@@ -61,6 +72,7 @@ metadata:
```
### Management
+
- User maintains full control over firewall rules
- Firewall persists after service deletion
- Manual updates required for rule changes
@@ -78,6 +90,7 @@ metadata:
- Consider future expansion
For more information:
+
- [Service Annotations](annotations.md#firewall-configuration)
- [LoadBalancer Configuration](loadbalancer.md)
- [Linode Cloud Firewall Documentation](https://www.linode.com/docs/products/networking/cloud-firewall/)
diff --git a/docs/configuration/loadbalancer.md b/docs/configuration/loadbalancer.md
index 7a166f02..6df2a1f0 100644
--- a/docs/configuration/loadbalancer.md
+++ b/docs/configuration/loadbalancer.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: LoadBalancer Services
+parent: Configuration Guide
+nav_order: 1
+---
+
# LoadBalancer Services Configuration
## Overview
diff --git a/docs/configuration/nodeipam.md b/docs/configuration/nodeipam.md
index 5b0e3920..1ae09a78 100644
--- a/docs/configuration/nodeipam.md
+++ b/docs/configuration/nodeipam.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Node IPAM using CCM
+parent: Configuration Guide
+nav_order: 8
+---
+
# Node IPAM using CCM
## Overview
@@ -21,6 +28,7 @@ Note:
Make sure node IPAM allocation is disabled in kube-controller-manager to avoid both controllers competing to assign CIDRs to nodes. To make sure its disabled, check and make sure kube-controller-manager is not started with `--allocate-node-cidrs` flag.
## Allocated subnet size
+
By default, CCM allocates /24 subnet for IPv4 addresses and /112 for IPv6 addresses to nodes. For IPv6, CCM derives /112 PodCIDRs from the node's /64 IPv6 range using the stable mnemonic subprefix `:0:c::/112`. For IPv6 CIDR allocation using CCM, Linodes should have IPv6 ranges configured on their interfaces. If one wants different subnet range, it can be configured by using `--node-cidr-mask-size-ipv4` and `--node-cidr-mask-size-ipv6` flags.
```yaml
@@ -37,4 +45,5 @@ spec:
```
## Disabling ipv6 ipam allocation
+
If one wants to just use ipv4 node ipam allocation for their nodes, they can start CCM with `--disable-ipv6-node-cidr-allocation=true` which disables ipv6 range allocation to nodes.
diff --git a/docs/configuration/nodes.md b/docs/configuration/nodes.md
index 62e308ef..1253c72c 100644
--- a/docs/configuration/nodes.md
+++ b/docs/configuration/nodes.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Node Configuration
+parent: Configuration Guide
+nav_order: 3
+---
+
# Node Configuration
## Overview
@@ -9,15 +16,19 @@ The Node Controller in CCM manages node-specific configurations and lifecycle op
The CCM automatically adds the following labels to nodes:
### Topology Labels
+
Current:
+
- `topology.kubernetes.io/region`: Linode region (e.g., "us-east")
- `topology.kubernetes.io/zone`: Linode availability zone
Legacy (deprecated):
+
- `failure-domain.beta.kubernetes.io/region`: Linode region
- `failure-domain.beta.kubernetes.io/zone`: Linode availability zone
### Provider Labels
+
- `node.kubernetes.io/instance-type`: Linode instance type (e.g., "g6-standard-4")
## Node Annotations
@@ -33,6 +44,7 @@ All node annotations must be prefixed with: `node.k8s.linode.com/`
### Use Cases
#### Private Network Configuration
+
```yaml
apiVersion: v1
kind: Node
@@ -43,7 +55,9 @@ metadata:
```
#### VPC Configuration
+
When using CCM with [Linode VPC](https://www.linode.com/docs/products/networking/vpc/), internal ip will be set to VPC ip. To use a different ip-address as internal ip, you may need to manually configure the node's InternalIP:
+
```yaml
apiVersion: v1
kind: Node
@@ -56,12 +70,15 @@ metadata:
## Node Networking
### Private Network Requirements
+
- NodeBalancers require nodes to have linode specific [private IP addresses](https://techdocs.akamai.com/cloud-computing/docs/managing-ip-addresses-on-a-compute-instance#types-of-ip-addresses)
- Private IPs must be configured in the Linode Cloud Manager or via the API
- The CCM will use private IPs for inter-node communication
### VPC Configuration
+
When using VPC:
+
1. Configure network interfaces in Linode Cloud Manager
2. Add appropriate node annotations for private IPs
3. Ensure proper routing configuration
@@ -72,23 +89,27 @@ For VPC routing setup, see [Route Configuration](routes.md).
## Node Controller Behavior
### Node Initialization
+
- Configures node with Linode-specific information
- Sets node addresses (public/private IPs)
- Applies region/zone labels
- Configures node hostnames
### Node Lifecycle Management
+
- Monitors node health
- Updates node status
- Handles node termination
- Manages node cleanup
### Node Updates
+
- Updates node labels when region/zone changes
- Updates node addresses when IP configuration changes
- Maintains node conditions based on Linode instance status
For more information:
+
- [Linode Instance Types](https://www.linode.com/docs/products/compute/compute-instances/plans/)
- [Private Networking](https://www.linode.com/docs/products/networking/private-networking/)
- [VPC Documentation](https://www.linode.com/docs/products/networking/vpc/)
diff --git a/docs/configuration/routes.md b/docs/configuration/routes.md
index 0f8b8a26..9d37b574 100644
--- a/docs/configuration/routes.md
+++ b/docs/configuration/routes.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Route Configuration
+parent: Configuration Guide
+nav_order: 6
+---
+
# Route Configuration
## Overview
@@ -15,6 +22,7 @@ The Route Controller manages network routes for pod communication in VPC environ
### Enable Route Controller
1. Via Helm chart in `values.yaml`:
+
```yaml
routeController:
vpcNames: "vpc-prod,vpc-staging" # Comma separated names of VPCs managed by CCM
@@ -23,6 +31,7 @@ routeController:
```
2. Via command line flags in CCM deployment:
+
```yaml
spec:
template:
@@ -46,6 +55,7 @@ spec:
### Automatic Operations
The Route Controller:
+
- Creates routes for pod CIDR ranges assigned to nodes
- Updates routes when nodes are added/removed
- Manages route tables in specified VPCs
@@ -67,11 +77,13 @@ The Route Controller:
## Best Practices
### CIDR Planning
+
- Ensure pod CIDR range doesn't overlap with node's VPC ip-address
- Plan for future cluster growth
- Document CIDR allocations
### VPC Configuration
+
- Use clear, descriptive VPC names
- Configure proper VPC security settings
- Ensure proper API permissions
diff --git a/docs/configuration/session-affinity.md b/docs/configuration/session-affinity.md
index 78683c90..9f209bdd 100644
--- a/docs/configuration/session-affinity.md
+++ b/docs/configuration/session-affinity.md
@@ -1,3 +1,9 @@
+---
+layout: default
+title: Session Affinity
+parent: Configuration Guide
+nav_order: 7
+---
# Session Affinity
## Overview
@@ -9,6 +15,7 @@ Session affinity (also known as sticky sessions) ensures that requests from the
### Basic Setup
Enable session affinity by setting `service.spec.sessionAffinity` to `ClientIP`:
+
```yaml
apiVersion: v1
kind: Service
@@ -27,6 +34,7 @@ spec:
### Setting Timeout
Configure the maximum session sticky time using `sessionAffinityConfig`:
+
```yaml
apiVersion: v1
kind: Service
@@ -43,10 +51,12 @@ spec:
## Configuration Options
### Session Affinity Types
+
- `None`: No session affinity (default)
- `ClientIP`: Route based on client's IP address. All requests from the same client IP will be directed to the same pod.
### Timeout Configuration
+
- `timeoutSeconds`: Duration to maintain affinity
- Default: 10800 seconds (3 hours)
- Valid range: 1 to 86400 seconds (24 hours)
diff --git a/docs/development/README.md b/docs/development/README.md
index 73814c92..51ea30e4 100644
--- a/docs/development/README.md
+++ b/docs/development/README.md
@@ -1,3 +1,9 @@
+---
+layout: default
+title: Development Guide
+nav_order: 5
+---
+
# Development Guide
## Prerequisites
diff --git a/docs/examples/README.md b/docs/examples/README.md
index 1372afa8..d59e5579 100644
--- a/docs/examples/README.md
+++ b/docs/examples/README.md
@@ -1,3 +1,8 @@
+---
+layout: default
+title: Examples
+nav_order: 4
+---
# Examples
This section provides working examples of common CCM configurations. Each example includes a complete service and deployment configuration.
diff --git a/docs/examples/advanced.md b/docs/examples/advanced.md
index 101acbc2..288ab6e7 100644
--- a/docs/examples/advanced.md
+++ b/docs/examples/advanced.md
@@ -1,3 +1,9 @@
+---
+layout: default
+title: Advanced Configuration
+parent: Examples
+nav_order: 2
+---
# Advanced Configuration
## Custom Health Checks
diff --git a/docs/examples/basic.md b/docs/examples/basic.md
index 84c8b3cb..3b262abe 100644
--- a/docs/examples/basic.md
+++ b/docs/examples/basic.md
@@ -1,3 +1,9 @@
+---
+layout: default
+title: Basic Services
+parent: Examples
+nav_order: 1
+---
# Basic Services
## HTTP LoadBalancer
@@ -144,5 +150,6 @@ spec:
```
For more configuration options, see:
+
- [Service Annotations](../configuration/annotations.md)
- [LoadBalancer Configuration](../configuration/loadbalancer.md)
diff --git a/docs/getting-started/README.md b/docs/getting-started/README.md
index 9850e6d3..65394ab1 100644
--- a/docs/getting-started/README.md
+++ b/docs/getting-started/README.md
@@ -1,12 +1,20 @@
+---
+layout: default
+title: Getting Started
+nav_order: 2
+---
+
# Getting Started
This section will guide you through:
+
- Understanding the CCM's requirements
- Installing the CCM using either Helm or manual installation
- Verifying your installation
- Troubleshooting common issues
Choose the installation method that best suits your needs:
+
- **Helm Installation**: Recommended for most users, provides easier upgrades and configuration
- **Manual Installation**: Offers more control over the deployment process
diff --git a/docs/getting-started/helm-installation.md b/docs/getting-started/helm-installation.md
index 2ac94e72..3d829ee3 100644
--- a/docs/getting-started/helm-installation.md
+++ b/docs/getting-started/helm-installation.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Helm Installation
+parent: Installation
+nav_order: 1
+---
+
# Helm Installation
## Prerequisites
diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md
index ea47f6df..cd187df7 100644
--- a/docs/getting-started/installation.md
+++ b/docs/getting-started/installation.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Installation
+parent: Getting Started
+nav_order: 3
+---
+
# Installation
The CCM can be installed using either Helm (recommended) or by manually applying manifests. Choose the method that best suits your needs:
@@ -5,16 +12,19 @@ The CCM can be installed using either Helm (recommended) or by manually applying
## Installation Methods
### [Helm Installation](helm-installation.md)
+
- Easier to manage and upgrade
- Configurable through values.yaml
- Supports templating for different environments
### [Manual Installation](manual-installation.md)
+
- More control over the deployment
- Better for customized setups
- Useful for understanding the components
## Post-Installation
+
After installing the CCM, proceed to the [Verification](verification.md) section to ensure everything is working correctly.
If you encounter any issues, check the [Troubleshooting](troubleshooting.md) guide.
diff --git a/docs/getting-started/manual-installation.md b/docs/getting-started/manual-installation.md
index 7c4af09e..fb5ee722 100644
--- a/docs/getting-started/manual-installation.md
+++ b/docs/getting-started/manual-installation.md
@@ -1,6 +1,14 @@
+---
+layout: default
+title: Manual Installation
+parent: Installation
+nav_order: 2
+---
+
# Manual Installation
## Prerequisites
+
- kubectl configured to access your cluster
- Linode API token
- Target region identified
@@ -8,18 +16,22 @@
## Installation Steps
1. Generate the manifest:
+
```bash
./deploy/generate-manifest.sh $LINODE_API_TOKEN $REGION
```
2. Review the generated manifest:
+
The script creates `ccm-linode.yaml` containing:
+
- ServiceAccount
- ClusterRole and ClusterRoleBinding
- Secret with API token
- DaemonSet for the CCM
3. Apply the manifest:
+
```bash
kubectl apply -f ccm-linode.yaml
```
@@ -27,7 +39,9 @@ kubectl apply -f ccm-linode.yaml
## Customization
### Environment Variables
+
You can modify the DaemonSet to include custom environment variables:
+
```yaml
env:
- name: LINODE_INSTANCE_CACHE_TTL
@@ -37,7 +51,9 @@ env:
```
### Resource Limits
+
Adjust compute resources as needed:
+
```yaml
resources:
requests:
@@ -61,6 +77,7 @@ Linode API calls can be monitored using `ccm_linode_client_requests_total` metri
## Uninstalling
To remove the CCM:
+
```bash
kubectl delete -f ccm-linode.yaml
```
diff --git a/docs/getting-started/overview.md b/docs/getting-started/overview.md
index eeb805ca..37069369 100644
--- a/docs/getting-started/overview.md
+++ b/docs/getting-started/overview.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Overview
+parent: Getting Started
+nav_order: 1
+---
+
# Overview
The Linode Cloud Controller Manager provides several key features that enable a fully supported Kubernetes experience on Linode infrastructure.
diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md
index 463d4bc3..b9fe2f8c 100644
--- a/docs/getting-started/requirements.md
+++ b/docs/getting-started/requirements.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Requirements
+parent: Getting Started
+nav_order: 2
+---
+
# Requirements
Before installing the Linode Cloud Controller Manager, ensure your environment meets the following requirements.
@@ -5,11 +12,14 @@ Before installing the Linode Cloud Controller Manager, ensure your environment m
## Kubernetes Cluster Requirements
### Version Compatibility
+
- Kubernetes version 1.22 or higher
- Kubernetes cluster running on Linode infrastructure
### Kubernetes Components Configuration
+
The following Kubernetes components must be started with the `--cloud-provider=external` flag:
+
- Kubelet
- Kube Controller Manager
- Kube API Server
@@ -17,7 +27,9 @@ The following Kubernetes components must be started with the `--cloud-provider=e
## Linode Requirements
### API Token
+
You need a Linode APIv4 Personal Access Token with the following scopes:
+
- Linodes - Read/Write
- NodeBalancers - Read/Write
- IPs - Read/Write
@@ -27,6 +39,7 @@ You need a Linode APIv4 Personal Access Token with the following scopes:
- VLANs - Read/Write (if using VLAN features)
To create a token:
+
1. Log into the [Linode Cloud Manager](https://cloud.linode.com)
2. Go to your profile
3. Select the "API Tokens" tab
@@ -35,20 +48,25 @@ To create a token:
6. Set an expiry (optional)
### Region Support
+
Your cluster must be in a [supported Linode region](https://api.linode.com/v4/regions).
## Network Requirements
### Private Networking
+
- If using NodeBalancers, nodes must have private IP addresses
- VPC or VLAN configurations require additional network configuration
### Firewall Considerations
+
- Ensure required ports are open for Kubernetes components
- If using Cloud Firewalls, ensure the API token has firewall management permissions
## Resource Quotas
+
Ensure your Linode account has sufficient quota for:
+
- NodeBalancers (if using LoadBalancer services)
- Additional IP addresses (if using shared IP features)
- Cloud Firewalls (if using firewall features)
diff --git a/docs/getting-started/troubleshooting.md b/docs/getting-started/troubleshooting.md
index 5e613f8d..30389210 100644
--- a/docs/getting-started/troubleshooting.md
+++ b/docs/getting-started/troubleshooting.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Troubleshooting
+parent: Getting Started
+nav_order: 5
+---
+
# Troubleshooting
## Common Issues and Solutions
@@ -5,23 +12,28 @@
### CCM Pod Issues
#### Pod Won't Start
+
```bash
kubectl get pods -n kube-system -l app=ccm-linode
kubectl describe pod -n kube-system -l app=ccm-linode
```
Common causes:
+
- Invalid API token
- Missing RBAC permissions
- Resource constraints
#### Pod Crashes
+
Check the logs:
+
```bash
kubectl logs -n kube-system -l app=ccm-linode
```
Common causes:
+
- API rate limiting
- Network connectivity issues
- Configuration errors
@@ -29,17 +41,21 @@ Common causes:
### LoadBalancer Service Issues
#### Service Stuck in Pending
+
```bash
kubectl describe service
```
Check for:
+
- API token permissions
- NodeBalancer quota limits
- Network configuration
#### Health Checks Failing
+
Verify:
+
- Backend pod health
- Service port configuration
- Health check path configuration
@@ -47,17 +63,21 @@ Verify:
### Node Issues
#### Missing Node Labels
+
```bash
kubectl get nodes --show-labels
```
Verify:
+
- CCM node controller logs
- Node annotations
- API permissions
#### Network Problems
+
Check:
+
- Private IP configuration
- VPC/VLAN setup
- Firewall rules
@@ -65,6 +85,7 @@ Check:
## Gathering Information
### Useful Commands
+
```bash
# Get CCM version
kubectl get pods -n kube-system -l app=ccm-linode -o jsonpath='{.items[0].spec.containers[0].image}'
@@ -77,7 +98,9 @@ kubectl logs -n kube-system -l app=ccm-linode --timestamps
```
### Debug Mode
+
Set the following environment variable in the CCM deployment:
+
```yaml
env:
- name: LINODE_DEBUG
@@ -87,6 +110,7 @@ env:
## Getting Help
If issues persist:
+
1. Join #linode on [Kubernetes Slack](https://kubernetes.slack.com)
2. Check [GitHub Issues](https://github.com/linode/linode-cloud-controller-manager/issues)
3. Submit a new issue with:
diff --git a/docs/getting-started/verification.md b/docs/getting-started/verification.md
index 22e7c046..0692c54a 100644
--- a/docs/getting-started/verification.md
+++ b/docs/getting-started/verification.md
@@ -1,3 +1,10 @@
+---
+layout: default
+title: Verification
+parent: Getting Started
+nav_order: 4
+---
+
# Verification
After installing the CCM, follow these steps to verify it's working correctly.
@@ -5,17 +12,20 @@ After installing the CCM, follow these steps to verify it's working correctly.
## Check CCM Pod Status
1. Verify the CCM pods are running:
+
```bash
kubectl get pods -n kube-system -l app=ccm-linode
```
Expected output:
-```
+
+```text
NAME READY STATUS RESTARTS AGE
ccm-linode-xxxxx 1/1 Running 0 2m
```
2. Check CCM logs:
+
```bash
kubectl logs -n kube-system -l app=ccm-linode
```
@@ -25,11 +35,13 @@ Look for successful initialization messages and no errors.
## Verify Node Configuration
1. Check node annotations:
+
```bash
kubectl get nodes -o yaml
```
Look for:
+
- Proper region labels
- Node addresses
- Provider ID
@@ -37,6 +49,7 @@ Look for:
## Test LoadBalancer Service
1. Create a test service:
+
```yaml
apiVersion: v1
kind: Service
@@ -51,6 +64,7 @@ spec:
```
2. Verify NodeBalancer creation:
+
```bash
kubectl get svc test-lb
```
@@ -58,6 +72,7 @@ kubectl get svc test-lb
The service should receive an external IP address.
## Common Issues
+
- Pods in CrashLoopBackOff: Check logs for API token or permissions issues
- Service stuck in 'Pending': Verify API token has NodeBalancer permissions
- Missing node annotations: Check CCM logs for node controller issues
diff --git a/index.md b/index.md
new file mode 100644
index 00000000..7b5b2c1d
--- /dev/null
+++ b/index.md
@@ -0,0 +1,15 @@
+---
+layout: default
+title: Kubernetes Cloud Controller Manager for Linode
+nav_order: 1
+---
+
+{%- capture readme -%}
+{%- include_relative README.md -%}
+{%- endcapture -%}
+
+{{ readme
+ | replace: ".md)", ".html)"
+ | replace: ".md#", ".html#"
+ | replace: "](.github/CONTRIBUTING.html)", "]()"
+}}
diff --git a/mise.toml b/mise.toml
index cbda06d8..8b9b2a66 100644
--- a/mise.toml
+++ b/mise.toml
@@ -117,3 +117,11 @@ run = "make run-debug"
[tasks.test]
description = "Run unit tests"
run = "make test"
+
+[tasks.serve-docs]
+description = "Serve the documentation site locally with live reload"
+run = "make serve-docs"
+
+[tasks.build-docs]
+description = "Build the documentation site the way GitHub Pages does"
+run = "make build-docs"