33 KiB
AI Agent Guidelines for kube-router
This document provides comprehensive guidelines for AI coding agents working on the kube-router project. It consolidates project-specific coding standards, best practices, and workflows to ensure consistent, high-quality contributions.
Table of Contents
- Project Overview
- Project Structure
- Build System and Makefile
- Go Coding Standards
- Error Handling
- Logging Practices
- Testing
- Refactoring Guidelines
- Code Review Process
- Development Workflow
- Planning Guidelines
- Markdown Formatting
- Kubernetes-Specific Considerations
- Additional Best Practices
- References
- Support
Project Overview
kube-router is a turnkey solution for Kubernetes networking that provides:
- IPVS/LVS-based Service Proxy: High-performance load balancing using Linux kernel features
- Pod Networking: Direct routing with BGP protocol via GoBGP
- Network Policy Controller: Firewall rules using ipsets and iptables
- Advanced BGP Capabilities: Integration with external networking devices
Key Technologies
- Language: Go
- Kubernetes API: v0.34.2 or latest
- Key Libraries: GoBGP, Netlink, iptables, ipset, IPVS
- Logging: klog/v2
- Testing: Testify, Ginkgo, Gomega
Project Structure
.
├── cmd/ # Main applications
│ └── kube-router/ # Main application entry point
├── pkg/ # Public library code
│ ├── healthcheck/ # Logic for monitoring control loops
│ └── controllers/ # Main control loop logic
│ ├── lballoc/ # LoadBalancer controller IPAM logic
│ ├── netpol/ # NetworkPolicy enforcement logic
│ ├── proxy/ # Services controller logic
│ └── routing/ # Pod & Service routing logic
├── internal/ # Private implementation code
│ ├── nlretry/ # Netlink retry logic
│ └── testutils/ # Internal test utilities
├── testdata/ # Test fixtures and data
├── daemonset/ # Kubernetes deployment manifests
├── cni/ # Kubernetes CNI configuration files
└── docs/ # Documentation in markdown format
File Naming Conventions
- Use snake_case for file names:
// Good
api_handler.go
user_service.go
// Bad
apiHandler.go
UserService.go
- Test files should use _test suffix:
// Good
api_handler_test.go
// Bad
api_handler_tests.go
- Package names should be short and clear:
// Good
package api
package validator
// Bad
package apihandlers
package utility_functions
Build System and Makefile
kube-router uses a comprehensive Makefile for building, testing, linting, and releasing. Always use Makefile targets instead of running commands directly when available.
Common Makefile Targets
Building
make kube-router- Build the kube-router binarymake container- Build the container imagemake gobgp- Build the gobgp binarymake all- Default target: lint, test, build binaries and images
Testing and Formatting
make test- Run all tests with verbose outputmake test-pretty- Run tests with formatted output using gotestsummake gofmt- Check which files need formattingmake gofmt-fix- Automatically fix formatting issues
Linting
make lint- Run golangci-lint and markdownlintmake markdownlint- Run markdown linting on README and docs
Code Generation
make gomoqs- Generate all mock files using moq- Individual mocks:
make pkg/controllers/proxy/linux_networking_moq.go
Release and Distribution
make push- Push container image to registrymake release- Create and push a releasemake clean- Remove build artifacts
Help
make help- Display all available targets with descriptions
Build Configuration
The Makefile supports several environment variables:
BUILD_IN_DOCKER(default: true) - Build inside Docker containerGOARCH- Target architecture (amd64, arm64, arm, s390x, ppc64le, riscv64)IMG_NAMESPACE- Container registry namespaceIMG_TAG- Container image tagDOCKER_BUILD_IMAGE- Docker image for buildingGO_CACHE- Go build cache directoryGO_MOD_CACHE- Go module cache directory
Build Modes
In-Docker Build (default)
By default, builds run inside Docker containers for consistency:
make kube-router # Builds in Docker
make test # Tests in Docker
Local Build
To build locally without Docker:
BUILD_IN_DOCKER=false make kube-router
BUILD_IN_DOCKER=false make test
Multi-Architecture Support
kube-router supports multiple architectures. Specify with GOARCH:
GOARCH=arm64 make kube-router
GOARCH=s390x make container
Supported architectures:
- amd64 (default)
- arm64
- arm
- s390x
- ppc64le
- riscv64
Version Information
The build system automatically injects version information:
GIT_COMMIT- Git commit hash/tagBUILD_DATE- Build timestampGIT_BRANCH- Current Git branch
Mock Generation
When modifying interfaces that have mocks:
- Update the interface in the source file
- Ensure the file has the
//go:generate moqdirective - Run
make gomoqsto regenerate all mocks - Or regenerate a specific mock:
make pkg/controllers/proxy/linux_networking_moq.go
Example from code:
//go:generate moq -out linux_networking_moq.go . LinuxNetworking
type LinuxNetworking interface {
ipvsCalls
netlinkCalls
}
Tool Versions
The Makefile pins specific versions of tools for reproducibility:
- Go: 1.25.1 or latest
- golangci-lint: v2.4.0 or latest
- GoBGP: v3.37.0 or latest
- moq: v0.6.0 or latest
- CNI plugins: v1.8.0 or latest
Makefile Best Practices
- Always use Makefile targets - Don't run
go build,go test, etc. directly - Run tests before committing -
make test-prettyormake test - Lint before submitting -
make lintto catch issues early - Clean before release builds -
make cleanthenmake all - Check formatting -
make gofmtto see what needs fixing - Auto-fix formatting -
make gofmt-fixbefore committing - Regenerate mocks after interface changes -
make gomoqs
Development Workflow with Makefile
# Start development
git checkout -b feature_x
# Make code changes
# ...
# Format code
make gofmt-fix
# Run linters
make lint
# Run tests
make test-pretty
# Build binary
make kube-router
# Build container (if needed)
make container
# Clean up
make clean
Go Coding Standards
Code Organization
- Group related files in packages
- Keep packages focused and cohesive
- Follow standard Go project layout
- Use internal/ for private implementation
- Place reusable code in pkg/
Import Order
Organize imports in the following order:
- Standard library packages
- External dependencies
- Kubernetes dependencies
- Project-internal packages
import (
"context"
"fmt"
"github.com/vishvananda/netlink"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
"github.com/cloudnativelabs/kube-router/v2/pkg/utils"
)
Error Handling
Error Types
- Custom error types for specific errors:
// Good
type ValidationError struct {
Field string
Error string
}
func (v *ValidationError) Error() string {
return fmt.Sprintf("validation failed on %s: %s", v.Field, v.Error)
}
// Usage
if !isValid {
return &ValidationError{
Field: "email",
Error: "invalid format",
}
}
- Error wrapping for context:
// Good
if err := db.QueryRow(query, id).Scan(&user); err != nil {
return fmt.Errorf("fetching user %d: %w", id, err)
}
// Bad
if err := db.QueryRow(query, id).Scan(&user); err != nil {
return err // Lost context
}
Error Handling Patterns
- Handle errors immediately:
// Good
result, err := someFunction()
if err != nil {
return fmt.Errorf("failed to execute someFunction: %w", err)
}
// Use result
// Bad
result, err := someFunction()
// Do other things...
if err != nil { // Too late
return err
}
- Don't panic in libraries:
// Good
func ProcessData(data []byte) error {
if len(data) == 0 {
return errors.New("empty data provided")
}
// Process data
return nil
}
// Bad
func ProcessData(data []byte) {
if len(data) == 0 {
panic("empty data provided")
}
// Process data
}
- Use %v for logging errors, not %w or %s:
// Good
result, err := someFunction()
if err != nil {
klog.Errorf("failed to execute someFunction: %v", err)
}
// Bad
result, err := someFunction()
if err != nil {
klog.Errorf("failed to execute someFunction: %w", err)
}
Sentinel Errors
Use sentinel errors for expected error conditions:
var (
ErrNotFound = errors.New("resource not found")
ErrInvalid = errors.New("invalid input")
)
Error Groups
Use error groups for concurrent operations:
g := new(errgroup.Group)
for _, item := range items {
item := item
g.Go(func() error {
return processItem(item)
})
}
if err := g.Wait(); err != nil {
return fmt.Errorf("processing items: %w", err)
}
Logging Practices
kube-router uses klog from the Kubernetes project for logging.
Basic Logging
import (
"k8s.io/klog/v2"
)
func main() {
klog.Info("Application started")
klog.Infof("User created: %v", userID)
klog.V(1).Infof("Found %d routes for interface %s, deleting them...", len(routes), iface.Attrs().Name)
}
Logging Best Practices
- Add the logger at the top of the file or as a package/global variable
- Do not use global context for sensitive or user-specific data
- Avoid logging sensitive information (passwords, tokens, keys)
- Use appropriate log levels:
klog.Info(): General informational messagesklog.V(1).Info(): Verbose/debug informationklog.Warning(): Warning messagesklog.Error(): Error messagesklog.Fatal(): Fatal errors (use sparingly)
Testing
Test Structure
- Use table-driven tests:
func TestCalculate(t *testing.T) {
tests := []struct {
name string
input int
want int
wantErr bool
}{
{
name: "positive number",
input: 5,
want: 10,
wantErr: false,
},
{
name: "negative number",
input: -5,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Calculate(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("Calculate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got != tt.want {
t.Errorf("Calculate() = %v, want %v", got, tt.want)
}
})
}
}
- Use subtests for better organization:
func TestService(t *testing.T) {
t.Run("Create", func(t *testing.T) {
// Test creation
})
t.Run("Update", func(t *testing.T) {
// Test update
})
t.Run("Delete", func(t *testing.T) {
// Test deletion
})
}
Test Helpers
Create test utilities with proper helper marking:
func setupTestDB(t *testing.T) (*sql.DB, func()) {
t.Helper() // Mark as helper function
db, err := sql.Open("postgres", "test-connection-string")
if err != nil {
t.Fatalf("setting up test db: %v", err)
}
return db, func() {
db.Close()
}
}
// Usage
func TestDatabase(t *testing.T) {
db, cleanup := setupTestDB(t)
defer cleanup()
// Run tests
}
Mocking
- Use interfaces for testability:
type UserRepository interface {
GetUser(id int) (*User, error)
}
// Mock implementation
type mockUserRepo struct {
users map[int]*User
}
func (m *mockUserRepo) GetUser(id int) (*User, error) {
user, ok := m.users[id]
if !ok {
return nil, ErrNotFound
}
return user, nil
}
- Small mocks (< 200 lines): Use testify mock library
import "github.com/stretchr/testify/mock"
See pkg/utils/node_test.go for examples.
- Large mocks (> 200 lines): Use moq to generate mock files
//go:generate moq -out linux_networking_moq.go . LinuxNetworking
type LinuxNetworking interface {
ipvsCalls
netlinkCalls
}
Assertions
Use the Testify library for assertions:
import "github.com/stretchr/testify/assert"
if testcase.err != nil {
assert.EqualError(t, err, testcase.err.Error())
}
Fail Fast Pattern
Use t.Fatalf() for conditions that would stop a test from executing:
t.Run(testcase.name, func(t *testing.T) {
clientset := fake.NewSimpleClientset()
_, err := clientset.CoreV1().Nodes().Create(context.Background(), testcase.existingNode, metav1.CreateOptions{})
if err != nil {
t.Fatalf("failed to create existing nodes for test: %v", err)
}
})
Test Fixtures
Use test fixtures for large amounts of test data (>100 lines):
// testdata/users.json
// Place test data in testdata directory
See testdata/ipset_test_1/ for examples.
Parallel Tests
Use parallel tests when possible:
func TestParallel(t *testing.T) {
tests := []struct{
name string
// test cases
}{
// test cases here
}
for _, tt := range tests {
tt := tt // Capture range variable
t.Run(tt.name, func(t *testing.T) {
t.Parallel() // Mark test as parallel
// Test implementation
})
}
}
Test Coverage
- Run tests with coverage:
go test -cover ./...
- Generate coverage report:
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
- Test race conditions:
go test -race ./...
- Target 70% test coverage for new code with emphasis on:
- Business logic cases
- Corner cases
- Boundary conditions
- Poorly defined input handling
Integration Tests
Use build tags for integration tests:
// +build integration
package integration
func TestIntegration(t *testing.T) {
// Integration test implementation
}
Refactoring Guidelines
When refactoring code, ensure the following:
Function Size
- Try to ensure functions are a maximum of 50 lines
- Prefer function sizes of approximately 30 lines or less
- Don't create functions for code that is less than 5 lines long
- Ensure that all functions created encapsulate related logic while obeying max lengths
- If you can't follow these guidelines, ask for guidance rather than assuming
Code Quality
- For any hard-coded variables encountered during a refactor, consider whether they should be added as constants
- Prioritize keeping code as DRY (Don't Repeat Yourself) as possible and minimize repetition
- If you find elements of code that are reused in the current file, refactor those as well to use the refactored functions
Constants
Extract magic numbers and repeated strings:
// Good
const (
MaxRetries = 3
DefaultTimeout = 30 * time.Second
)
// Bad
if retries > 3 { // Magic number
// ...
}
Code Review Process
When conducting code reviews (when explicitly asked), address the following sections:
1. Summary
Review the code changes in the indicated range and summarize in four sentences or less the general purpose of the code.
2. Obvious Problems
Identify any obvious problems:
- Anything that would stop it from running or accomplishing its intent
- Obvious violations of programming design or functionality
Format as a bulleted list with sub-bullets for recommended remediation.
3. Code Style Analysis
Compare the changed code with surrounding code and other committed code in the repository. Provide a brief assessment of how well the code fits with the structure of the existing code.
Provide a score (1-10): 1 = not matching at all, 10 = matching very well.
4. Potential Code Duplication
Audit the rest of the codebase for any code duplication introduced by the changes. Focus on utility functions that might not have been used.
5. Refactoring Potential
Identify obvious wins that would:
- Greatly improve readability
- Be significantly more conformant with generally accepted standards
- Greatly improve performance/memory structure
Don't be pedantic; focus on obvious improvements.
6. Test Coverage
Identify any obvious tests that are missing. New code should seek 70% test coverage, with emphasis on:
- Business logic cases
- Corner cases
- Boundary conditions
- Poorly defined input handling
Provide a test coverage score (1-10): 1 = no unit tests, 10 = 100% test coverage.
7. Security Implications
List any obvious security problems related to the indicated code. Format as a bulleted list with sub-bullets for recommended remediation.
8. Documentation Opportunities
Review existing documentation in /docs and check if:
- Code changes require documentation updates that weren't made
- Any documentation has spelling/grammar issues or readability problems
Format as a bulleted list with sub-bullets for recommended remediation.
9. Upstream Reviews
If a URL is provided (likely a related issue or PR):
- Fetch the content remotely and analyze it
- If it's a PR with comments/feedback, check if they were resolved
Format as a bulleted list with sub-bullets for recommended remediation.
10. Code Quality Score
Provide a code quality score (1-10): 1 = lowest quality, 10 = highest quality.
11. Compare with Previous Reviews
Check if a previous review exists in .reviews/<branch_name>/. If it exists, compare the current review to it in terms
of:
- Fixed issues
- Remaining issues
- New issues found
Review Output Location
Save all review output to:
.reviews/<branch_name>/<branch_name>-<integer_increment>.md
Where:
<branch_name>is the name of the current git branch<integer_increment>is an integer to ensure unique filenames
Development Workflow
Git Workflow
- Fork the repository
- Create a feature branch:
git checkout -b feature_x - Make changes and commit with descriptive messages
- Keep branch up-to-date with upstream:
git checkout master
git fetch upstream
git rebase upstream/master
git checkout feature_x
git rebase master
- Push to your fork:
git push origin feature_x - Create a pull request
Commit Messages
This project uses Conventional Commits. Every commit message must follow this format:
<type>(<scope>): <description>
Where <type> is one of:
- feat: A new feature or enhancement
- fix: A bug fix
- doc: Documentation-only changes
- test: Adding or updating tests
- build: Changes to the build system or dependencies (e.g.
build(deps)) - chore: Maintenance tasks that don't modify src or test files
- fact (refactor): Code restructuring without behavior changes
The <scope> is optional but encouraged. It should identify the component or file affected (e.g. gobgp,
aws.go, Makefile). Use the following abbreviations for the main controllers:
- NSC -- Network Services Controller (
pkg/controllers/proxy/) - NRC -- Network Routes Controller (
pkg/controllers/routing/) - NPC -- Network Policy Controller (
pkg/controllers/netpol/)
Additional guidelines:
- Keep the description concise and lowercase
- Explain the "why" rather than the "what"
- Keep commits focused on a single logical change
Examples from this repository:
feat(gobgp): add kube_router_bgp_peer_info metric
fix(aws.go): load region before attempting to assume a role
test(NSC): add comprehensive TCPMSS unit tests
build(deps): bump golang.org/x/net from 0.49.0 to 0.51.0
doc(metrics.md): replace controller_bgp_peers -> bgp_peer_info
Code Quality Tools
Run the following before submitting:
# Linting
golangci-lint run
# Static analysis
staticcheck ./...
# Error checking
errcheck ./...
# Tests
go test ./...
# Race detection
go test -race ./...
Planning Guidelines
When asked to create plans for complex features or changes, follow this structured approach to ensure clarity and thoroughness.
Plan Location
Create a new directory inside <git_root>/.plans. The name of the directory should be 3 words or less that briefly
summarizes the task. It should be camel case and not contain any spaces.
Example:
.plans/IpsetRefactor/.plans/BgpPeerConfig/.plans/MetricsController/
Plan Layout
The primary artifact is a PLAN.md file that contains markdown documenting the plan. This is a living document that
should be continuously updated during execution. It should contain the following sections with each top level list item
being a heading:
Original Prompt
This should be the original prompt or request verbatim.
Summary
A paragraph summary of the approach that will be taken.
Detail
A markdown list of what will be done in order. Later during implementation, check off items as they are completed and keep the list updated.
Example:
## Detail
- [x] Analyze existing ipset implementation
- [x] Identify refactoring opportunities
- [ ] Create new ipset helper functions
- [ ] Update network policy controller to use new helpers
- [ ] Add unit tests for new functionality
- [ ] Update integration tests
Problems Encountered
This section is filled out during implementation to describe any particular problems encountered while trying to execute the plan as provided in the details section.
Example:
## Problems Encountered
- **Netlink compatibility**: Found that some ipset operations don't work consistently across kernel versions.
Implemented fallback logic to handle this.
- **Test fixtures**: Existing test fixtures didn't cover edge cases. Created new fixtures in testdata/ipset_test_2/
Files Changed
List the files that are expected to need changes. Update this list as the plan evolves.
Example:
## Files Changed
- pkg/controllers/netpol/ipset.go
- pkg/utils/ipset.go
- pkg/controllers/netpol/network_policy_controller.go
- pkg/controllers/netpol/ipset_test.go
Tests Changed
In general, tests should be additive to ensure compatibility is maintained. However, if existing test changes are unavoidable, detail what will be changed and why.
Example:
## Tests Changed
- pkg/controllers/netpol/ipset_test.go
- Updated TestIpsetCreate to use new helper functions
- Added new test cases for error handling
- No breaking changes to existing tests
Plan Formatting
All plans must abide by the markdown formatting standards described in the Markdown Formatting section. Lines should be no more than 120 characters long.
Plan Clarification
If any questions arise when creating the plan, ask for clarification rather than making assumptions unless the assumptions are small and clearly reasonable.
Plan Updates
As implementation progresses:
- Check off completed items in the Detail section
- Add any new tasks discovered during implementation
- Document problems in the Problems Encountered section
- Update Files Changed and Tests Changed as needed
- Keep the plan synchronized with actual work
When to Create Plans
Create plans for:
- Complex multi-file refactorings
- New feature implementations
- Major architectural changes
- Changes that affect multiple controllers or subsystems
- Work that will take multiple sessions to complete
Do not create plans for:
- Simple bug fixes
- Single-file changes
- Documentation-only updates
- Trivial refactorings
Markdown Formatting
kube-router uses markdownlint to enforce consistent markdown formatting across all documentation. All markdown files must pass markdownlint checks before being committed.
Running Markdownlint
Use the Makefile target to check markdown files:
make markdownlint
This will lint both the README and all files in the /docs directory.
Markdownlint Configuration
The project's markdownlint rules are defined in .markdownlint.yaml:
- MD046: Code blocks must use fenced style (triple backticks) instead of indented style
- MD013: Line length limited to 120 characters (200 for code blocks)
- MD045: Images must have alt text (disabled in this project)
Formatting Rules
Line Length (MD013)
- Keep lines under 120 characters
- Code blocks can extend to 200 characters
- Break long sentences and paragraphs naturally at punctuation
Good:
This is a reasonably long sentence that explains a complex concept but stays within the 120 character limit by
breaking at a natural point.
Bad:
This is an extremely long sentence that goes on and on without any breaks and exceeds the maximum line length of 120 characters which will cause markdownlint to fail.
Code Blocks (MD046)
Always use fenced code blocks with language identifiers:
Good:
```bash
make test
```
```golang
func main() {
fmt.Println("Hello")
}
```
Bad:
make test
func main() {
fmt.Println("Hello")
}
Headings
- Use ATX-style headings (with #):
# Heading 1
## Heading 2
### Heading 3
-
One H1 per document - Only use a single
#heading at the top of the file -
No skipping levels - Don't jump from
##to#### -
Space after hash - Always include a space:
## Headingnot##Heading
Lists
- Consistent markers - Use
-for unordered lists throughout:
Good:
- Item 1
- Item 2
- Nested item
- Another nested item
- Item 3
Bad:
* Item 1
- Item 2
+ Item 3
- Proper indentation - Use 2 spaces for nested lists:
- Top level
- Nested level
- Double nested
- Ordered lists - Use
1.for all items (auto-numbering):
1. First item
1. Second item
1. Third item
Links
- No bare URLs - Always use link syntax:
Good:
See the [User Guide](/docs/user-guide.md) for details.
Visit [GitHub](https://github.com/cloudnativelabs/kube-router).
Bad:
See /docs/user-guide.md for details.
Visit https://github.com/cloudnativelabs/kube-router.
- Reference-style links - Use for repeated or long URLs:
Check out [kube-router and [Kubernetes][k8s].
[kr]: https://github.com/cloudnativelabs/kube-router
[k8s]: https://kubernetes.io
Emphasis
- Bold - Use
**double asterisks**:
**Important**: This is critical information.
- Italic - Use
*single asterisks*:
This is *emphasized* text.
- Code - Use backticks for inline code:
The `kubectl` command is used to interact with Kubernetes.
Use the `--help` flag for more information.
Tables
Ensure tables are properly formatted:
| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Cell 1 | Cell 2 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 |
Blank Lines
- Around headings - One blank line before and after:
Some text here.
## New Section
More text here.
- Around code blocks - One blank line before and after:
Some explanation here.
` ``bash
command here
` ``
More explanation here.
- Around lists - One blank line before and after:
Paragraph text.
- List item 1
- List item 2
More paragraph text.
File Structure
- Start with H1 - Every markdown file should start with a level 1 heading
- No trailing spaces - Remove spaces at the end of lines
- End with newline - Files should end with a single newline character
- No multiple blank lines - Use only single blank lines
Common Markdownlint Errors
MD009: Trailing Spaces
Problem: Lines ending with spaces
Fix: Remove trailing whitespace from all lines
MD012: Multiple Blank Lines
Problem: More than one consecutive blank line
Fix: Replace multiple blank lines with a single blank line
MD022: Headings Should Be Surrounded by Blank Lines
Problem: No blank line before/after heading
Fix: Add blank lines around all headings
MD025: Multiple H1 Headings
Problem: More than one # heading in the document
Fix: Use only one H1 at the document start; use ## for sections
MD031: Fenced Code Blocks Should Be Surrounded by Blank Lines
Problem: No blank line before/after code block
Fix: Add blank lines around all code blocks
MD040: Fenced Code Blocks Should Have a Language Specified
Problem: Code block without language identifier
Fix: Add language after opening backticks:
```bash
command here
```
Markdown Best Practices
- Always run markdownlint before committing - Use
make markdownlint - Use language identifiers on all code blocks - Helps with syntax highlighting
- Keep lines under 120 characters - Improves readability in all editors
- Use fenced code blocks - Never use indented code blocks
- Consistent list markers - Always use
-for unordered lists - One blank line between sections - Don't use multiple blank lines
- Proper heading hierarchy - Don't skip heading levels
- No trailing whitespace - Configure your editor to remove it automatically
Editor Integration
Configure your editor to show/remove:
- Line length guides at 120 characters
- Trailing whitespace
- End-of-file newlines
Popular editors with markdownlint support:
- VS Code: Install the "markdownlint" extension
- Vim: Use ALE or vim-markdown
- Emacs: Use markdown-mode with flycheck
Kubernetes-Specific Considerations
Working with Kubernetes Objects
- Use typed clients when possible:
clientset.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
- Handle API errors properly:
node, err := clientset.CoreV1().Nodes().Get(context.Background(), nodeName, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return fmt.Errorf("node %s not found: %w", nodeName, err)
}
return fmt.Errorf("failed to get node %s: %w", nodeName, err)
}
- Use informers for watching resources:
// Prefer informers over direct watches
informerFactory.Core().V1().Nodes().Informer().AddEventHandler(...)
Network Programming
- Use netlink library for Linux networking:
import "github.com/vishvananda/netlink"
link, err := netlink.LinkByName("eth0")
if err != nil {
return fmt.Errorf("failed to get link: %w", err)
}
- Handle iptables carefully:
import "github.com/coreos/go-iptables/iptables"
ipt, err := iptables.New()
if err != nil {
return fmt.Errorf("failed to initialize iptables: %w", err)
}
- Use ipsets efficiently:
// Batch operations when possible
// Clean up sets when no longer needed
Performance Considerations
- Minimize API calls - use informers and caching
- Batch netlink operations when possible
- Use ipsets for large rule sets instead of individual iptables rules
- Profile code for performance bottlenecks in hot paths
- Be mindful of goroutine leaks in long-running controllers
Resource Cleanup
Always clean up resources properly:
func (c *Controller) Run(stopCh <-chan struct{}) {
defer c.cleanup()
// Controller logic
<-stopCh
}
func (c *Controller) cleanup() {
// Clean up iptables rules
// Clean up ipsets
// Clean up netlink resources
}
Additional Best Practices
Context Usage
Always propagate context for cancellation and timeouts:
func (s *Service) ProcessItem(ctx context.Context, item Item) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
// Process item
}
}
Concurrency
- Use sync primitives appropriately
- Avoid goroutine leaks
- Handle context cancellation
- Use errgroup for managing multiple goroutines
Dependencies
- Keep dependencies up to date
- Be mindful of Kubernetes version compatibility
- Test with multiple Kubernetes versions when making API changes
Documentation
- Document exported functions and types
- Keep documentation up to date with code changes
- Use godoc conventions
- Update
/docsfor user-facing changes
References
Support
- Slack: #kube-router on Kubernetes Slack
- Issues: GitHub Issues