This includes infra setup for metrics collection and visualisation ## Motivation and Context It is important to have basic observability setup, so that common issues can be identified quickly ## How Has This Been Tested? - Tested on local - Tested on one of the production setup ## Breaking Changes No ## 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) - [X] 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. --> - [X] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [X] My code follows the repository's style guidelines - [X] New and existing tests pass locally - [X] I have added appropriate error handling - [ ] I have added or updated documentation as needed ## Additional context - This includes set up of following components: - Victoriametrics single node cluster for storing metrics data with persistent storage configuration for local and production env. - Vmagent with target discovery for mcp-registry pods with scrape interval of 30s. - Grafana for visualising metrics and setting alerts. - Datasource of victoriametrics is pre-configured as config map - Persistent volume for basic configuration - Sqlite for local and Postgres for production setup for storing dashboard, alerts etc details ## Metrics in action <img width="1422" height="666" alt="Screenshot 2025-08-31 at 4 35 28 AM" src="https://github.com/user-attachments/assets/e54ce846-653c-4fa3-aa7a-fe277f0810e6" /> --------- Co-authored-by: Adam Jones <adamj@anthropic.com> Co-authored-by: adam jones <adamj+git@anthropic.com>
273 lines
8.7 KiB
Go
273 lines
8.7 KiB
Go
package local
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
|
|
appsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apps/v1"
|
|
batchv1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/batch/v1"
|
|
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
|
|
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
|
|
|
"github.com/modelcontextprotocol/registry/deploy/infra/pkg/providers"
|
|
)
|
|
|
|
// Provider implements the ClusterProvider interface for local Kubernetes clusters
|
|
type Provider struct{}
|
|
|
|
// getClusterName attempts to get the current Kubernetes cluster name from kubectl config
|
|
func getClusterName() string {
|
|
cmd := exec.Command("kubectl", "config", "current-context")
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
// Fallback to default if we can't get the context
|
|
return "local"
|
|
}
|
|
return strings.TrimSpace(string(output))
|
|
}
|
|
|
|
// CreateCluster configures access to a local Kubernetes cluster via kubeconfig
|
|
func (p *Provider) CreateCluster(ctx *pulumi.Context, environment string) (*providers.ProviderInfo, error) {
|
|
// Create Kubernetes provider for local cluster
|
|
k8sProvider, err := kubernetes.NewProvider(ctx, "k8s-provider", &kubernetes.ProviderArgs{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get the actual cluster name from kubectl config
|
|
clusterName := getClusterName()
|
|
|
|
return &providers.ProviderInfo{
|
|
Name: pulumi.String(clusterName).ToStringOutput(),
|
|
Provider: k8sProvider,
|
|
}, nil
|
|
}
|
|
|
|
// CreateBackupStorage creates MinIO for S3-compatible backup storage
|
|
func (p *Provider) CreateBackupStorage(ctx *pulumi.Context, cluster *providers.ProviderInfo, environment string) (*providers.BackupStorageInfo, error) {
|
|
// Create MinIO namespace
|
|
minioNamespace, err := corev1.NewNamespace(ctx, "minio", &corev1.NamespaceArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("minio"),
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create MinIO namespace: %w", err)
|
|
}
|
|
|
|
// Create MinIO credentials secret
|
|
minioSecret, err := corev1.NewSecret(ctx, "minio-credentials", &corev1.SecretArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("minio-credentials"),
|
|
Namespace: minioNamespace.Metadata.Name(),
|
|
},
|
|
Type: pulumi.String("Opaque"),
|
|
StringData: pulumi.StringMap{
|
|
"accesskey": pulumi.String("minioadmin"),
|
|
"secretkey": pulumi.String("minioadmin"),
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create MinIO credentials: %w", err)
|
|
}
|
|
|
|
// Create MinIO PVC for data storage
|
|
_, err = corev1.NewPersistentVolumeClaim(ctx, "minio-pvc", &corev1.PersistentVolumeClaimArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("minio-pvc"),
|
|
Namespace: minioNamespace.Metadata.Name(),
|
|
},
|
|
Spec: &corev1.PersistentVolumeClaimSpecArgs{
|
|
AccessModes: pulumi.StringArray{
|
|
pulumi.String("ReadWriteOnce"),
|
|
},
|
|
Resources: &corev1.VolumeResourceRequirementsArgs{
|
|
Requests: pulumi.StringMap{
|
|
"storage": pulumi.String("10Gi"),
|
|
},
|
|
},
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create MinIO PVC: %w", err)
|
|
}
|
|
|
|
// Deploy MinIO
|
|
minioDeployment, err := appsv1.NewDeployment(ctx, "minio", &appsv1.DeploymentArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("minio"),
|
|
Namespace: minioNamespace.Metadata.Name(),
|
|
},
|
|
Spec: &appsv1.DeploymentSpecArgs{
|
|
Replicas: pulumi.Int(1),
|
|
Selector: &metav1.LabelSelectorArgs{
|
|
MatchLabels: pulumi.StringMap{
|
|
"app": pulumi.String("minio"),
|
|
},
|
|
},
|
|
Template: &corev1.PodTemplateSpecArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Labels: pulumi.StringMap{
|
|
"app": pulumi.String("minio"),
|
|
},
|
|
},
|
|
Spec: &corev1.PodSpecArgs{
|
|
Containers: corev1.ContainerArray{
|
|
&corev1.ContainerArgs{
|
|
Name: pulumi.String("minio"),
|
|
Image: pulumi.String("minio/minio:RELEASE.2025-07-23T15-54-02Z"),
|
|
Args: pulumi.StringArray{
|
|
pulumi.String("server"),
|
|
pulumi.String("/data"),
|
|
pulumi.String("--console-address"),
|
|
pulumi.String(":9001"),
|
|
},
|
|
Env: corev1.EnvVarArray{
|
|
&corev1.EnvVarArgs{
|
|
Name: pulumi.String("MINIO_ROOT_USER"),
|
|
ValueFrom: &corev1.EnvVarSourceArgs{
|
|
SecretKeyRef: &corev1.SecretKeySelectorArgs{
|
|
Name: minioSecret.Metadata.Name(),
|
|
Key: pulumi.String("accesskey"),
|
|
},
|
|
},
|
|
},
|
|
&corev1.EnvVarArgs{
|
|
Name: pulumi.String("MINIO_ROOT_PASSWORD"),
|
|
ValueFrom: &corev1.EnvVarSourceArgs{
|
|
SecretKeyRef: &corev1.SecretKeySelectorArgs{
|
|
Name: minioSecret.Metadata.Name(),
|
|
Key: pulumi.String("secretkey"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Ports: corev1.ContainerPortArray{
|
|
&corev1.ContainerPortArgs{
|
|
ContainerPort: pulumi.Int(9000),
|
|
Name: pulumi.String("api"),
|
|
},
|
|
&corev1.ContainerPortArgs{
|
|
ContainerPort: pulumi.Int(9001),
|
|
Name: pulumi.String("console"),
|
|
},
|
|
},
|
|
VolumeMounts: corev1.VolumeMountArray{
|
|
&corev1.VolumeMountArgs{
|
|
Name: pulumi.String("data"),
|
|
MountPath: pulumi.String("/data"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Volumes: corev1.VolumeArray{
|
|
&corev1.VolumeArgs{
|
|
Name: pulumi.String("data"),
|
|
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSourceArgs{
|
|
ClaimName: pulumi.String("minio-pvc"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create MinIO deployment: %w", err)
|
|
}
|
|
|
|
// Create MinIO service
|
|
minioService, err := corev1.NewService(ctx, "minio-service", &corev1.ServiceArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("minio"),
|
|
Namespace: minioNamespace.Metadata.Name(),
|
|
},
|
|
Spec: &corev1.ServiceSpecArgs{
|
|
Selector: pulumi.StringMap{
|
|
"app": pulumi.String("minio"),
|
|
},
|
|
Ports: corev1.ServicePortArray{
|
|
&corev1.ServicePortArgs{
|
|
Name: pulumi.String("api"),
|
|
Port: pulumi.Int(9000),
|
|
TargetPort: pulumi.Int(9000),
|
|
},
|
|
&corev1.ServicePortArgs{
|
|
Name: pulumi.String("console"),
|
|
Port: pulumi.Int(9001),
|
|
TargetPort: pulumi.Int(9001),
|
|
},
|
|
},
|
|
},
|
|
}, pulumi.Provider(cluster.Provider))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create MinIO service: %w", err)
|
|
}
|
|
|
|
// Create a Job to initialize the MinIO bucket
|
|
_, err = batchv1.NewJob(ctx, "minio-bucket-init", &batchv1.JobArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("minio-bucket-init"),
|
|
Namespace: minioNamespace.Metadata.Name(),
|
|
},
|
|
Spec: &batchv1.JobSpecArgs{
|
|
Template: &corev1.PodTemplateSpecArgs{
|
|
Spec: &corev1.PodSpecArgs{
|
|
RestartPolicy: pulumi.String("OnFailure"),
|
|
Containers: corev1.ContainerArray{
|
|
&corev1.ContainerArgs{
|
|
Name: pulumi.String("mc"),
|
|
Image: pulumi.String("minio/mc:latest@sha256:fb8f773eac8ef9d6da0486d5dec2f42f219358bcb8de579d1623d518c9ebd4cc"),
|
|
Command: pulumi.StringArray{
|
|
pulumi.String("/bin/sh"),
|
|
pulumi.String("-c"),
|
|
},
|
|
Args: pulumi.StringArray{
|
|
pulumi.String(`
|
|
until mc alias set myminio http://minio:9000 minioadmin minioadmin; do
|
|
echo 'Waiting for MinIO to be ready...'
|
|
sleep 5
|
|
done
|
|
mc mb -p myminio/k8up-backups
|
|
echo 'Bucket created successfully'
|
|
`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}, pulumi.Provider(cluster.Provider), pulumi.DependsOn([]pulumi.Resource{minioService}))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create bucket initialization job: %w", err)
|
|
}
|
|
|
|
// Create backup credentials secret for S3 access
|
|
backupSecret, err := corev1.NewSecret(ctx, "k8up-backup-credentials", &corev1.SecretArgs{
|
|
Metadata: &metav1.ObjectMetaArgs{
|
|
Name: pulumi.String("k8up-backup-credentials"),
|
|
Namespace: pulumi.String("default"),
|
|
Labels: pulumi.StringMap{
|
|
"k8up.io/backup": pulumi.String("true"),
|
|
"environment": pulumi.String(environment),
|
|
},
|
|
},
|
|
Type: pulumi.String("Opaque"),
|
|
StringData: pulumi.StringMap{
|
|
"AWS_ACCESS_KEY_ID": pulumi.String("minioadmin"),
|
|
"AWS_SECRET_ACCESS_KEY": pulumi.String("minioadmin"),
|
|
},
|
|
}, pulumi.Provider(cluster.Provider), pulumi.DependsOn([]pulumi.Resource{minioDeployment}))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create backup credentials secret: %w", err)
|
|
}
|
|
|
|
return &providers.BackupStorageInfo{
|
|
Endpoint: "http://minio.minio:9000",
|
|
BucketName: "k8up-backups",
|
|
Credentials: backupSecret,
|
|
}, nil
|
|
}
|