Creating HTTP/S Routing Rules Programmatically
package main
import (
"context"
"flag"
"fmt"
"log"
"path/filepath"
// Kubernetes API imports
networkingv1 "k8s.io/api/networking/v1" // Import networking v1 package
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// client-go imports
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// --- Setup Kubeconfig and Flags ---
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) kubeconfig path")
} else {
kubeconfig = flag.String("kubeconfig", "", "kubeconfig path")
}
namespace := flag.String("namespace", "default", "namespace to create the ingress in")
ingressName := flag.String("ingress-name", "example-ingress", "name for the new ingress")
ingressClassName := flag.String("ingress-class", "", "(required) name of the IngressClass") // Make class name required
flag.Parse()
if *ingressClassName == "" {
log.Fatal("Error: --ingress-class flag is required")
}
// --- Load Config and Create Clientset ---
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
log.Fatalf("Error building kubeconfig: %s", err.Error())
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatalf("Error creating clientset: %s", err.Error())
}
// --- Define the Ingress Object ---
pathTypePrefix := networkingv1.PathTypePrefix // Define path type constant for clarity
ingressSpec := &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: *ingressName,
Namespace: *namespace,
Annotations: map[string]string{ // Optional: Add annotations if needed by controller
// "nginx.ingress.kubernetes.io/rewrite-target": "/",
},
},
Spec: networkingv1.IngressSpec{
// Link to the specific Ingress Controller
IngressClassName: ingressClassName,
// --- Define Routing Rules ---
Rules: []networkingv1.IngressRule{
// Rule 1: Target app.example.com
{
Host: "app.example.com",
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: []networkingv1.HTTPIngressPath{
// Path 1.1: /login
{
Path: "/login",
PathType: &pathTypePrefix, // Use Prefix match
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "login-service", // Target Service name
Port: networkingv1.ServiceBackendPort{
Name: "http", // Target Service port name
},
},
},
},
// Path 1.2: /api/users
{
Path: "/api/users",
PathType: &pathTypePrefix,
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "user-api-service", // Target Service name
Port: networkingv1.ServiceBackendPort{
Number: 8080, // Target Service port number
},
},
},
},
},
},
},
// Rule 2: Target metrics.example.com
{
Host: "metrics.example.com",
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: []networkingv1.HTTPIngressPath{
// Path 2.1: / (root path)
{
Path: "/",
PathType: &pathTypePrefix,
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "metrics-service",
Port: networkingv1.ServiceBackendPort{
Number: 9090,
},
},
},
},
},
},
},
}, // End of Rules
// --- Define TLS Configuration ---
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{ // Hosts covered by this TLS cert
"app.example.com",
},
SecretName: "app-tls-secret", // Name of the Secret containing TLS cert/key
},
// Could add another entry for metrics.example.com if it needed TLS
// { Hosts: []string{"metrics.example.com"}, SecretName: "metrics-tls-secret",},
}, // End of TLS
}, // End of Spec
} // End of Ingress definition
// --- Create the Ingress Resource ---
fmt.Printf("Creating Ingress '%s' in namespace '%s'...\n", *ingressName, *namespace)
// Access the NetworkingV1 client
ingressClient := clientset.NetworkingV1().Ingresses(*namespace)
createdIngress, err := ingressClient.Create(context.TODO(), ingressSpec, metav1.CreateOptions{})
// --- Handle Errors ---
if err != nil {
if k8serrors.IsAlreadyExists(err) {
log.Printf("Ingress '%s' already exists in namespace '%s'.\n", *ingressName, *namespace)
// Optionally Get/Update existing Ingress
} else {
log.Fatalf("Error creating Ingress '%s': %s\n", *ingressName, err.Error())
}
} else {
fmt.Printf("Successfully created Ingress '%s'.\n", createdIngress.Name)
// Note: It might take a moment for the Ingress Controller to process this
// and for the external endpoint (if using type: LoadBalancer for the controller)
// to become available and reflect in `kubectl get ingress`.
fmt.Printf("Run `kubectl describe ingress %s -n %s` to see details.\n", *ingressName, *namespace)
}
fmt.Println("---------------")
}Last updated
Was this helpful?