guidelines
Cloud-agnostic Kubernetes infrastructure with Terraform & Helm for homelabs, edge, and production clusters.
Install / Use
npx skills add gannino/tf-kube-any-computeInstalls into whichever agent you are using.
.clinerules
Cline rules
Quality Score
Category
OperationsSupported Platforms
Skill content
View source on GitHubDevelopment Guidelines: tf-kube-any-compute
Code Quality Standards
Terraform Formatting
- Indentation: 2 spaces (consistent across all .tf files)
- Line Length: Prefer 80-120 characters, break long lines logically
- Block Spacing: Single blank line between resource blocks
- Comments: Use
#for single-line, descriptive comments above complex logic - File Organization: Group related resources, use consistent ordering
File Header Pattern
###########################
# Module Name - Purpose #
###########################
Variable Organization
- Alphabetical Order: All variables sorted alphabetically in variables.tf
- Validation Rules: Include validation blocks for critical inputs
- Descriptions: Clear, concise descriptions for all variables
- Defaults: Sensible defaults with optional() for complex objects
- Sensitive Data: Mark passwords/tokens with
sensitive = true
Documentation Standards
- README.md: Every module must have comprehensive README
- terraform-docs: Auto-generated documentation using terraform-docs
- Inline Comments: Explain "why" not "what" for complex logic
- Examples: Provide usage examples in examples/ directory
- Guides: Detailed guides in docs/guides/ for complex features
Structural Conventions
Module Structure
module-name/
├── main.tf # Primary resource definitions
├── variables.tf # Input variables (alphabetical)
├── outputs.tf # Output definitions
├── locals.tf # Local value computations
├── version.tf # Provider requirements
├── values.yaml.tpl # Helm values template
├── templates/ # Additional templates
│ └── {service}-values.yaml.tpl
├── README.md # Module documentation
└── .tflint.hcl # Module-specific linting rules
Naming Conventions
Resources
# Pattern: {service}_{resource_type}
resource "kubernetes_namespace" "traefik_namespace" { }
resource "helm_release" "traefik_release" { }
resource "kubernetes_secret" "traefik_auth_secret" { }
Variables
# Boolean flags
variable "enable_feature" { }
variable "use_option" { }
# Configuration objects
variable "service_config" { }
variable "middleware_config" { }
# Overrides
variable "cpu_arch_override" { }
variable "storage_class_override" { }
Locals
# Computed values
locals {
service_enabled = var.enable_service || var.services.service
effective_cpu_arch = var.cpu_arch != "" ? var.cpu_arch : local.detected_arch
storage_class = local.use_nfs ? "nfs-csi" : "hostpath-storage"
}
Resource Naming Pattern
# Namespace: {environment}-{service}-system
namespace = "prod-traefik-system"
# Release: {environment}-{service}
name = "prod-traefik"
# Labels: Consistent key-value pairs
labels = {
"app.kubernetes.io/name" = "traefik"
"app.kubernetes.io/instance" = "prod-traefik"
"app.kubernetes.io/managed-by" = "terraform"
}
Semantic Patterns
Configuration Hierarchy Pattern
# 1. System defaults
locals {
system_defaults = merge({
cpu_limit = "200m"
memory_limit = "256Mi"
}, var.system_defaults)
}
# 2. Service defaults
locals {
service_defaults = {
traefik = {
cpu_limit = local.system_defaults.cpu_limit
memory_limit = local.system_defaults.memory_limit
}
}
}
# 3. User overrides
locals {
traefik_config = merge(
local.service_defaults.traefik,
var.service_overrides.traefik != null ? var.service_overrides.traefik : {}
)
}
Conditional Resource Creation
# Pattern: Use count for optional resources
resource "kubernetes_ingress_v1" "service_ingress" {
count = var.enable_ingress ? 1 : 0
# ... configuration
}
# Pattern: Use dynamic blocks for optional nested blocks
dynamic "volume" {
for_each = var.enable_persistence ? [1] : []
content {
# ... volume configuration
}
}
Architecture Detection Pattern
# Detect cluster architecture
data "kubernetes_nodes" "all_nodes" {}
locals {
# Extract architectures from all nodes
node_architectures = distinct([
for node in data.kubernetes_nodes.all_nodes.nodes :
lookup(node.status[0].node_info[0], "architecture", "amd64")
])
# Determine if mixed cluster
is_mixed_cluster = length(local.node_architectures) > 1
# Select primary architecture
detected_arch = length(local.node_architectures) > 0 ? local.node_architectures[0] : "amd64"
}
Storage Class Selection Pattern
locals {
# Priority: User override > NFS > HostPath > Default
storage_class = (
var.service_overrides.service.storage_class != null ?
var.service_overrides.service.storage_class :
var.use_nfs_storage ?
"nfs-csi" :
var.use_hostpath_storage ?
"hostpath-storage" :
var.default_storage_class != "" ?
var.default_storage_class :
"default"
)
}
Helm Values Templating Pattern
# values.yaml.tpl - Use templatefile() function
%{ if enable_feature ~}
feature:
enabled: true
config: ${config_value}
%{ endif ~}
# Conditional blocks with proper indentation
resources:
%{ if enable_resource_limits ~}
limits:
cpu: ${cpu_limit}
memory: ${memory_limit}
%{ endif ~}
Module Output Pattern
# Provide comprehensive outputs
output "service_info" {
description = "Complete service information"
value = {
namespace = kubernetes_namespace.service.metadata[0].name
release_name = helm_release.service.name
chart_version = helm_release.service.metadata[0].version
status = helm_release.service.status
values = helm_release.service.metadata[0].values
}
}
Internal API Usage
Kubernetes Provider Patterns
# Namespace creation
resource "kubernetes_namespace" "service" {
metadata {
name = local.namespace
labels = local.common_labels
annotations = local.common_annotations
}
}
# Secret creation with proper encoding
resource "kubernetes_secret" "auth" {
metadata {
name = "${local.release_name}-auth"
namespace = kubernetes_namespace.service.metadata[0].name
}
data = {
username = base64encode(var.username)
password = base64encode(var.password)
}
type = "Opaque"
}
Helm Provider Patterns
# Helm release with comprehensive configuration
resource "helm_release" "service" {
name = local.release_name
namespace = kubernetes_namespace.service.metadata[0].name
repository = "https://charts.example.com"
chart = "service-chart"
version = local.chart_version
# Timeout and wait configuration
timeout = local.helm_timeout
wait = local.helm_wait
wait_for_jobs = local.helm_wait_for_jobs
cleanup_on_fail = local.helm_cleanup_on_fail
# Values from template
values = [
templatefile("${path.module}/values.yaml.tpl", {
namespace = local.namespace
cpu_arch = local.cpu_arch
storage_class = local.storage_class
# ... other variables
})
]
# Explicit dependencies
depends_on = [
kubernetes_namespace.service,
kubernetes_secret.auth
]
}
Random Provider for Password Generation
resource "random_password" "admin" {
length = 32
special = true
# Ensure password meets complexity requirements
min_lower = 1
min_upper = 1
min_numeric = 1
min_special = 1
}
# Use generated password with fallback
locals {
admin_password = var.admin_password != "" ? var.admin_password : random_password.admin.result
}
Code Idioms
Ternary Operator for Defaults
# Pattern: condition ? true_value : false_value
local.cpu_arch = var.cpu_arch != "" ? var.cpu_arch : local.detected_arch
local.storage_class = var.storage_class != null ? var.storage_class : "default"
Null Coalescing with try()
# Safely access nested optional values
local.cpu_limit = try(var.service_overrides.service.cpu_limit, local.default_cpu_limit)
local.memory_limit = try(var.service_overrides.service.memory_limit, local.default_memory_limit)
Merge for Configuration Composition
# Merge multiple configuration sources
locals {
final_config = merge(
local.base_config,
local.environment_config,
var.user_overrides
)
}
For Expressions for Transformation
# Transform list to map
locals {
service_map = {
for service in var.services :
service.name => service.config
}
}
# Filter and transform
locals {
enabled_services = [
for name, config in var.services :
name if config.enabled
]
}
Dynamic Blocks for Conditional Nesting
resource "kubernetes_deployment" "app" {
# ... other configuration
spec {
template {
spec {
# Conditionally add volumes
dynamic "volume" {
for_each = var.enable_persistence ? [1] : []
content {
name = "data"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.data[0].metadata[0].name
}
}
}
# Conditionally add node affinity
dynamic "affinity" {
for_each = local.cpu_arch != "" ? [1] : []
content {
node_affinity {
required_during_scheduling_ignored_during_execution {
node_selector_term {
match_expressions {
key = "kubernetes.io/arch"
operator = "In"
values = [local.cpu_arch]
}
}
}
}
}
}
}
}
}
}
Testing Patterns
Terraform Test Structure
# tests.tftest.hcl
run "validate_architecture_detection" {
command = plan
variables {
cpu_arch = "" # Test auto-detection
}
assert {
condition = local.detected_arch != ""
error_message = "Architecture detection failed"
}
}
run "validate_storage_selection" {
command = plan
variables {
use_nfs_storage = true
nfs_server_address = "192.168.1.100"
}
assert {
condition = local.storage_class == "nfs-csi"
error_message = "Storage class selection incorrect"
}
}
Integration Test Pattern (Bash)
#!/bin/bash
set -euo pipefail
# Test service health
echo "Testing service health..."
kubectl get pods -n prod-traefik-system
kubectl wait --for=condition=ready pod -l app=traefik -n prod-traefik-system --timeout=300s
# Test ingress connectivity
echo "Testing ingress..."
curl -k https://traefik.prod.k3s.example.com/dashboard/
Security Best Practices
Sensitive Data Handling
# Mark sensitive variables
variable "admin_password" {
type = string
sensitive = true
}
# Mark sensitive outputs
output "admin_password" {
value = local.admin_password
sensitive = true
}
RBAC Pattern
resource "kubernetes_service_account" "service" {
metadata {
name = local.service_account_name
namespace = kubernetes_namespace.service.metadata[0].name
}
}
resource "kubernetes_role" "service" {
metadata {
name = "${local.release_name}-role"
namespace = kubernetes_namespace.service.metadata[0].name
}
rule {
api_groups = [""]
resources = ["pods", "services"]
verbs = ["get", "list", "watch"]
}
}
resource "kubernetes_role_binding" "service" {
metadata {
name = "${local.release_name}-binding"
namespace = kubernetes_namespace.service.metadata[0].name
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "Role"
name = kubernetes_role.service.metadata[0].name
}
subject {
kind = "ServiceAccount"
name = kubernetes_service_account.service.metadata[0].name
namespace = kubernetes_namespace.servic
Truncated for display — read the full file on GitHub.
Related Skills
AstrBot
40.8kAI Agent Assistant & development framework that integrates lots of IM platforms, LLMs, plugins and AI feature, and can be your openclaw alternative. ✨
Douyin_TikTok_Download_API
20.2k🚀 Self-hosted TikTok & Douyin scraper and no-watermark video downloader — async REST API, MCP server, CLI and web console for posts, profiles, comments and playlists. Self-healing identity pool, PostgreSQL archive, one docker compose up. 抖音、TikTok 数据采集与无水印视频下载 API,自托管,支持 MCP 调用与 Docker 一键部署。
worldmonitor
87.2kReal-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
nacos
33.4kan easy-to-use dynamic service discovery, configuration and service management platform for building AI cloud native applications.
Security Score
Audited on Invalid Date
