<!-- Provide a brief summary of your changes --> ## Motivation and Context <!-- Why is this change needed? What problem does it solve? --> Seems that per ingress annotations were not working, so had to put them in the ingress configmap. Did tested this manually on staging so it's confirmed it's working (I was getting 429s instead of 503s) and no traffic was getting into the registry pod. ## How Has This Been Tested? <!-- Have you tested this in a real application? Which scenarios were tested? --> ## Breaking Changes <!-- Will users need to update their code or configurations? --> ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [ ] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [ ] My code follows the repository's style guidelines - [ ] New and existing tests pass locally - [ ] I have added appropriate error handling - [ ] I have added or updated documentation as needed ## Additional context <!-- Add any other context, implementation notes, or design decisions --> Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
116 lines
4.1 KiB
Go
116 lines
4.1 KiB
Go
package k8s
|
|
|
|
import (
|
|
"strings"
|
|
|
|
v1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
|
|
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v3"
|
|
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
|
|
|
|
"github.com/modelcontextprotocol/registry/deploy/infra/pkg/providers"
|
|
)
|
|
|
|
// SetupIngressController sets up the NGINX Ingress Controller
|
|
func SetupIngressController(ctx *pulumi.Context, cluster *providers.ProviderInfo, environment string) (*helm.Chart, error) {
|
|
conf := config.New(ctx, "mcp-registry")
|
|
provider := conf.Get("provider")
|
|
if provider == "" {
|
|
provider = "local"
|
|
}
|
|
|
|
// Create namespace for ingress-nginx
|
|
ingressNginxNamespace, err := v1.NewNamespace(ctx, "ingress-nginx", &v1.NamespaceArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("ingress-nginx"),
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Usually we should expose the ingress to a LoadBalancer
|
|
// This works in GCP and most local setups e.g. minikube (with minikube tunnel)
|
|
// Kind unfortunately does not support LoadBalancer type, and hangs indefinitely. This is a workaround for that.
|
|
serviceType := cluster.Name.ApplyT(func(name string) string {
|
|
if name == "kind-kind" {
|
|
return "NodePort"
|
|
}
|
|
return "LoadBalancer"
|
|
}).(pulumi.StringOutput)
|
|
|
|
// Configure replicas based on environment
|
|
// Staging: 1 replica (sufficient for testing, allows brief downtime during deploys)
|
|
// Production: 2 replicas (HA, zero-downtime deploys, node-level resilience)
|
|
replicaCount := 1
|
|
if environment == "prod" {
|
|
replicaCount = 2
|
|
}
|
|
|
|
// Install NGINX Ingress Controller
|
|
ingressNginx, err := helm.NewChart(ctx, "ingress-nginx", helm.ChartArgs{
|
|
Chart: pulumi.String("ingress-nginx"),
|
|
Version: pulumi.String("4.13.0"),
|
|
FetchArgs: helm.FetchArgs{
|
|
Repo: pulumi.String("https://kubernetes.github.io/ingress-nginx"),
|
|
},
|
|
Namespace: ingressNginxNamespace.Metadata.Name().Elem(),
|
|
Values: pulumi.Map{
|
|
"controller": pulumi.Map{
|
|
"replicaCount": pulumi.Int(replicaCount),
|
|
"service": pulumi.Map{
|
|
"type": serviceType,
|
|
"externalTrafficPolicy": pulumi.String("Local"),
|
|
"annotations": pulumi.Map{},
|
|
},
|
|
"config": pulumi.Map{
|
|
// Disable strict path validation, to work around a bug in ingress-nginx
|
|
// https://cert-manager.io/docs/releases/release-notes/release-notes-1.18/#acme-http01-challenge-paths-now-use-pathtype-exact-in-ingress-routes
|
|
// https://github.com/kubernetes/ingress-nginx/issues/11176
|
|
"strict-validate-path-type": pulumi.String("false"),
|
|
|
|
// Do NOT use forwarded headers with L4 load balancer
|
|
// GCP L4 Passthrough Network Load Balancer does not set X-Forwarded-For
|
|
// Real client IP comes from TCP connection source with externalTrafficPolicy: Local
|
|
"use-forwarded-headers": pulumi.String("false"),
|
|
|
|
// Set rate limit rejection status code to 429 (Too Many Requests)
|
|
"limit-req-status-code": pulumi.String("429"),
|
|
},
|
|
},
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Extract ingress IPs from the Helm chart's controller service
|
|
ingressIps := ingressNginx.Resources.ApplyT(func(resources interface{}) interface{} {
|
|
// Look for the ingress-nginx-controller service
|
|
resourceMap := resources.(map[string]pulumi.Resource)
|
|
for resourceName, resource := range resourceMap {
|
|
if strings.Contains(resourceName, "ingress-nginx-controller") &&
|
|
!strings.Contains(resourceName, "admission") &&
|
|
strings.Contains(resourceName, "Service") {
|
|
if svc, ok := resource.(*v1.Service); ok {
|
|
// Return the LoadBalancer ingress IPs
|
|
return svc.Status.LoadBalancer().Ingress().ApplyT(func(ingresses []v1.LoadBalancerIngress) []string {
|
|
var ips []string
|
|
for _, ingress := range ingresses {
|
|
if ip := ingress.Ip; ip != nil && *ip != "" {
|
|
ips = append(ips, *ip)
|
|
}
|
|
}
|
|
return ips
|
|
})
|
|
}
|
|
}
|
|
}
|
|
// Return empty array if no matching service found
|
|
return []string{}
|
|
})
|
|
ctx.Export("ingressIps", ingressIps)
|
|
|
|
return ingressNginx, nil
|
|
}
|