@chimoney.io/iaas-k8s-deployment
Version:
Kubernetes Infrastructure as a Service deployment package for streamlined multi-cloud environments
747 lines (701 loc) • 20.1 kB
text/typescript
import type { Logger, DeploymentOptions } from "../../types/index.js";
import { TierCalculator } from "../../utils/tier-calculator.js";
import { PlanTier } from "../../types/plans.js";
// =============================================================================
// Helm Chart Values Generation
// =============================================================================
interface HelmChartValues {
companyName: string;
namespace?: string;
deploymentType: "shared" | "dedicated";
planTier?: string;
rafikiAuth: {
enabled: boolean;
name: string;
image: {
repository: string;
tag: string;
pullPolicy: string;
};
hpa?: {
enabled: boolean;
minReplicas?: number;
maxReplicas?: number;
targetCPUUtilizationPercentage?: number;
};
ports: {
main: number; // Main service port
grant: number; // Grant service port
admin: number; // Admin service port
};
service: {
type: string; // Service type (e.g., ClusterIP, LoadBalancer)
ports: {
main: number; // Main service port
grant: number; // Grant service port
admin: number; // Admin service port
};
};
secrets: {
name: string; // Name of the Kubernetes secret for Rafiki Auth
};
};
rafikiBackend: {
enabled: boolean;
name: string;
image: {
repository: string;
tag: string;
pullPolicy: string;
};
hpa?: {
enabled: boolean;
minReplicas?: number;
maxReplicas?: number;
targetCPUUtilizationPercentage?: number;
};
ports: {
openPayments: number;
graphql: number;
connector: number;
admin: number;
autopeering: number;
};
service: {
type: string; // Service type (e.g., ClusterIP, LoadBalancer)
ports: {
openPayments: number;
graphql: number;
connector: number;
admin: number;
autopeering: number;
};
};
secrets: {
name: string; // Name of the Kubernetes secret for Rafiki Auth
};
};
nginx: {
enabled: boolean;
name: string;
image: {
repository: string;
tag: string;
pullPolicy: string;
};
hpa?: {
enabled: boolean;
minReplicas?: number;
maxReplicas?: number;
targetCPUUtilizationPercentage?: number;
};
ports: {
http: number; // HTTP port
};
service: {
type: string;
port: number;
};
config?: {
serverNameIlp: string; // Open Payments hostname
serverNameAuth: string; // Rafiki Auth hostname
serverNameConnector: string; // Rafiki Connector hostname
graphqlAllowedIps: Array<string>;
};
configMap: {
name: string;
};
};
redis: {
enabled: boolean;
name: string;
image: {
repository: string;
tag: string;
pullPolicy: string;
};
ports: {
redis: number; // HTTP port
};
service: {
type: string;
port: number;
};
};
ingress: {
enabled: boolean;
name: string;
className: string;
annotations: Record<string, string>;
hosts: {
[key: string]: {
host: string;
paths: Array<{
path: string;
pathType: string;
serviceNameSuffix: string;
servicePort: number;
}>;
};
};
};
networkPolicy?: {
enabled: boolean;
allowIngressFrom?: Array<Record<string, any>>;
allowEgressTo?: Array<{
cidr?: string;
namespaceSelector?: Record<string, any>;
ports?: Array<{
port: number;
protocol: string;
}>;
}>;
allowEgressPorts?: Array<{
port: number;
protocol: string;
}>;
};
// Phase 1 Critical Parameter Generation
monitoring?: {
dashboards: {
enabled: boolean;
};
};
// Tier-specific configurations (only for shared deployments)
tierConfig?: Record<string, any>;
tierResources?: {
cpu?: string;
memory?: string;
};
tierResourceQuota?: {
enabled?: boolean;
requests?: Record<string, string>;
limits?: Record<string, string>;
claims?: Record<string, string>;
};
gcp?: {
backendConfig?: {
healthCheck: {
checkIntervalSec: number;
port: number;
type: string;
requestPath: string;
};
};
managedCertificate?: {
enabled: boolean;
domains: string[];
};
};
aws?: {
loadBalancer?: {
healthCheck: {
enabled: boolean;
intervalSeconds: number;
path: string;
port: string;
protocol: string;
timeoutSeconds: number;
unhealthyThresholdCount: number;
healthyThresholdCount: number;
};
};
};
kubernetesSecrets?: {
rafikiAuth: {
create: boolean;
name: string;
stringData: Record<string, any>;
};
rafikiBackend: {
create: boolean;
name: string;
stringData: Record<string, any>;
};
};
}
export function generateDynamicHelmValues(
options: DeploymentOptions,
logger: Logger
): HelmChartValues {
logger.info("Generating dynamic Helm chart values");
// Construct hostnames
const defaultDomain = options.defaultDomain || "example.com";
const openPaymentsHostname =
options.openPaymentsDomain || `ilp.${defaultDomain}`;
const authHostname = options.authDomain || `auth-ilp.${defaultDomain}`;
const connectorHostname =
options.connectorDomain || `ilp-connector.${defaultDomain}`;
const getHostPrefix = (hostDomain: string, defaultDomain: string) => {
return hostDomain.replace(defaultDomain, "");
};
const helmValues: HelmChartValues = {
companyName: options.companyName,
namespace: options.namespace,
deploymentType: options.deploymentType,
// Only set planTier for shared deployments or if explicitly provided
...(options.deploymentType === "shared" || options.planTier
? {
planTier:
options.planTier ||
(options.deploymentType === "shared" ? "basic" : undefined),
}
: {}),
rafikiAuth: {
enabled: options.enableRafikiAuth ?? true,
name: "rafiki-auth",
image: {
repository:
options.rafikiAuthImage?.repository ??
"ghcr.io/interledger/rafiki-auth",
tag: options.rafikiAuthImage?.tag ?? "v1.0.0-alpha.20",
pullPolicy: options.rafikiAuthImage?.pullPolicy ?? "IfNotPresent",
},
ports: {
main: 3006,
grant: 3009,
admin: 3001,
},
service: {
type: "ClusterIP",
ports: {
main: 3006,
grant: 3009,
admin: 3001,
},
},
secrets: {
name: "rafiki-auth-secrets",
},
},
rafikiBackend: {
enabled: options.enableRafikiBackend ?? true,
name: "rafiki-backend",
image: {
repository:
options.rafikiBackendImage?.repository ??
"ghcr.io/interledger/rafiki-backend",
tag: options.rafikiBackendImage?.tag ?? "v1.0.0-alpha.20",
pullPolicy: options.rafikiBackendImage?.pullPolicy ?? "IfNotPresent",
},
ports: {
openPayments: 80,
graphql: 3001,
connector: 3002,
admin: 3003,
autopeering: 3004,
},
service: {
type: "ClusterIP",
ports: {
openPayments: 80,
graphql: 3001,
connector: 3002,
admin: 3003,
autopeering: 3004,
},
},
secrets: {
name: "rafiki-backend-secrets",
},
},
nginx: {
enabled: options.enableNginx ?? true,
name: "nginx",
image: {
repository: options.nginxImage?.repository ?? "nginx",
tag: options.nginxImage?.tag ?? "latest",
pullPolicy: options.nginxImage?.pullPolicy ?? "IfNotPresent",
},
ports: {
http: 80,
},
service: {
type: "ClusterIP",
port: 80,
},
config: {
serverNameIlp: openPaymentsHostname,
serverNameAuth: authHostname,
serverNameConnector: connectorHostname,
graphqlAllowedIps: options.graphqlAllowedIps || [],
},
configMap: {
name: "nginx-config",
},
},
redis: {
enabled: options.enableRedis ?? true,
name: "redis",
image: {
repository: options.redisImage?.repository ?? "redis",
tag: options.redisImage?.tag ?? "7-alpine",
pullPolicy: options.redisImage?.pullPolicy ?? "IfNotPresent",
},
ports: {
redis: 6379,
},
service: {
type: "ClusterIP",
port: 6379,
},
},
ingress: {
enabled: true,
name: "rafiki-ingress",
className: options.ingressClassName ?? "gce",
annotations: {},
hosts: {
ilp: {
host: openPaymentsHostname,
paths: [
{
path: "/",
pathType: "Prefix",
serviceNameSuffix: "nginx",
servicePort: 80,
},
],
},
auth: {
host: authHostname,
paths: [
{
path: "/",
pathType: "Prefix",
serviceNameSuffix: "nginx",
servicePort: 80,
},
],
},
connector: {
host: connectorHostname,
paths: [
{
path: "/",
pathType: "Prefix",
serviceNameSuffix: "nginx",
servicePort: 80,
},
],
},
},
},
};
// Configure ingress annotations based on options
if (options.cloudProvider === "gcp") {
helmValues.ingress.annotations = {
"kubernetes.io/ingress.class": "gce",
"kubernetes.io/ingress.global-static-ip-name": "rafiki-global-ip",
"kubernetes.io/ingress.allow-http": "true",
"cloud.google.com/neg": '{"ingress": true}',
};
} else if (options.cloudProvider === "aws") {
helmValues.ingress.annotations = {
"kubernetes.io/ingress.class": "alb",
"alb.ingress.kubernetes.io/scheme": "internet-facing",
"alb.ingress.kubernetes.io/listen-ports": JSON.stringify([
{ HTTP: 80 },
{ HTTPS: 443 },
]),
"alb.ingress.kubernetes.io/target-type": "ip",
};
}
// Configure HPA for dedicated deployments
if (options.deploymentType === "dedicated") {
const hpaEnabled = options.dedicatedDeploymentHpaEnabledByDefault ?? true;
if (hpaEnabled) {
logger.info("Enabling HPA for dedicated deployment components");
helmValues.rafikiAuth.hpa = {
enabled: true,
minReplicas: 1,
maxReplicas: 5,
targetCPUUtilizationPercentage: 80,
};
helmValues.rafikiBackend.hpa = {
enabled: true,
minReplicas: 1,
maxReplicas: 5,
targetCPUUtilizationPercentage: 80,
};
helmValues.nginx.hpa = {
enabled: true,
minReplicas: 1,
maxReplicas: 5,
targetCPUUtilizationPercentage: 80,
};
}
}
// Configure network policies for shared deployments
if (options.deploymentType === "shared") {
const networkPolicyEnabled =
options.sharedDeploymentNetworkPolicyEnabled ?? true;
if (networkPolicyEnabled) {
logger.info("Configuring network policies for shared deployment");
helmValues.networkPolicy = {
enabled: true,
allowIngressFrom: [
{
name: options.ingressControllerNamespace ?? "ingress-nginx",
...(options.ingressControllerPodSelectorLabels ?? {
"app.kubernetes.io/name": "ingress-nginx",
}),
},
],
allowEgressTo: options.allowedExternalEgressRules ?? [
{
cidr: "0.0.0.0/0",
ports: [
{ port: 53, protocol: "UDP" }, // DNS
{ port: 53, protocol: "TCP" }, // DNS over TCP
{ port: 443, protocol: "TCP" }, // HTTPS
{ port: 5432, protocol: "TCP" }, // PostgreSQL
{ port: 6379, protocol: "TCP" }, // Redis
],
},
],
};
} else {
helmValues.networkPolicy = { enabled: false };
}
} else {
// Disable network policies for dedicated deployments
helmValues.networkPolicy = { enabled: false };
}
// Add monitoring dashboard configuration
const monitoring = {
dashboards: {
enabled:
options.deploymentType === "shared" ||
options.deploymentType === "dedicated",
},
};
// Tier-specific configurations (only for shared deployments)
let tierConfig = {};
let tierResources = {};
let tierResourceQuota = {};
if (options.deploymentType === "shared") {
// Initialize tier calculator for monitoring and resource calculations
const tierCalculator = new TierCalculator(logger);
const tier = (options.planTier as PlanTier) || PlanTier.BASIC;
// Add tier configuration for monitoring dashboards
tierConfig = {
basic: {
cpu: "2",
memory: "4Gi",
storage: "20Gi",
maxReplicas: 2,
},
standard: {
cpu: "8",
memory: "16Gi",
storage: "100Gi",
maxReplicas: 5,
},
premium: {
cpu: "32",
memory: "64Gi",
storage: "500Gi",
maxReplicas: 10,
},
enterprise: {
cpu: "128",
memory: "256Gi",
storage: "2Ti",
maxReplicas: 50,
},
};
// Add tier resources for monitoring dashboards
tierResources = {
cpu: tierCalculator.getTierCpuLimits(tier),
memory: tierCalculator.getTierMemoryLimits(tier),
};
// Add resource quota configuration for shared deployments
tierResourceQuota = {
enabled: true,
requests: {
cpu: tierCalculator.getTierResourceQuota(tier, "cpu", "requests"),
memory: tierCalculator.getTierResourceQuota(tier, "memory", "requests"),
storage: tierCalculator.getTierResourceQuota(
tier,
"storage",
"requests"
),
},
limits: {
cpu: tierCalculator.getTierResourceQuota(tier, "cpu", "limits"),
memory: tierCalculator.getTierResourceQuota(tier, "memory", "limits"),
storage: tierCalculator.getTierResourceQuota(tier, "storage", "limits"),
},
claims: {
"persistent-volume-claims": tierCalculator.getTierResourceQuota(
tier,
"storage",
"claims"
),
},
};
} else {
// For dedicated deployments, disable tier-based resource quotas and provide basic monitoring defaults
tierResourceQuota = {
enabled: false,
};
// Set basic defaults for monitoring dashboards for dedicated deployments
tierResources = {
cpu: "4", // Default CPU limit for dedicated
memory: "8Gi", // Default memory limit for dedicated
};
tierConfig = {
default: {
cpu: "4",
memory: "8Gi",
storage: "100Gi",
maxReplicas: 3,
},
};
}
// Add enhanced network policy configuration
if (helmValues.networkPolicy && helmValues.networkPolicy.enabled) {
helmValues.networkPolicy.allowIngressFrom = [
{ namespaceSelector: { matchLabels: { name: "kube-system" } } },
{ namespaceSelector: { matchLabels: { name: "monitoring" } } },
{ namespaceSelector: { matchLabels: { name: "ingress-nginx" } } },
];
helmValues.networkPolicy.allowEgressTo = [
{ namespaceSelector: { matchLabels: { name: "kube-system" } } },
];
helmValues.networkPolicy.allowEgressPorts = [
{ port: 443, protocol: "TCP" },
{ port: 53, protocol: "UDP" },
{ port: 53, protocol: "TCP" },
{ port: 5432, protocol: "TCP" },
{ port: 6379, protocol: "TCP" },
];
}
// Add cloud-specific configurations
const gcp = {
...(options.cloudProvider === "gcp"
? {
backendConfig: {
healthCheck: {
checkIntervalSec: 60,
port: 8080,
type: "HTTP",
requestPath: "/health",
},
},
managedCertificate: {
enabled: options.managedCertificateEnabled ?? true,
domains: [defaultDomain, `*.${defaultDomain}`],
},
}
: {}),
};
const aws = {
...(options.cloudProvider === "aws"
? {
loadBalancer: {
healthCheck: {
enabled: true,
intervalSeconds: 30,
path: "/health",
port: "traffic-port",
protocol: "HTTP",
timeoutSeconds: 5,
unhealthyThresholdCount: 2,
healthyThresholdCount: 2,
},
},
}
: {}),
};
// Add Kubernetes secrets configuration
const kubernetesSecrets = {
rafikiAuth: {
create: options.createKubernetesSecrets ?? true,
name: "rafiki-auth-secrets",
stringData: {}, // Will be populated by secrets manager
},
rafikiBackend: {
create: options.createKubernetesSecrets ?? true,
name: "rafiki-backend-secrets",
stringData: {}, // Will be populated by secrets manager
},
};
// Merge all new configurations into helmValues
const enhancedHelmValues = {
...helmValues,
monitoring,
tierConfig,
tierResources,
tierResourceQuota,
gcp,
aws,
kubernetesSecrets,
};
logger.info(
"Dynamic Helm chart values generated successfully with enhanced parameter coverage"
);
return enhancedHelmValues;
}
export function mergeHelmValues(
baseValues: HelmChartValues,
tierValues: any,
logger: Logger
): any {
logger.info("Merging Helm values: base + tier");
// Start with base values
let mergedValues = JSON.parse(JSON.stringify(baseValues));
// Merge tier values (tier resource allocations take precedence for resource limits/requests)
if (tierValues && Object.keys(tierValues).length > 0) {
logger.info("Applying tier-based resource allocations");
// Deep merge tier values, preserving resource allocations
mergedValues = {
...mergedValues,
...tierValues,
// Preserve base configuration for services but merge resources
rafikiAuth: {
...mergedValues.rafikiAuth,
...tierValues.rafikiAuth,
image: mergedValues.rafikiAuth?.image, // Preserve image config from base
hpa: mergedValues.rafikiAuth?.hpa || tierValues.rafikiAuth?.hpa, // Preserve HPA config from base if set
resources:
tierValues.rafikiAuth?.resources ||
mergedValues.rafikiAuth?.resources, // Tier resources take precedence
},
rafikiBackend: {
...mergedValues.rafikiBackend,
...tierValues.rafikiBackend,
image: mergedValues.rafikiBackend?.image,
hpa: mergedValues.rafikiBackend?.hpa || tierValues.rafikiBackend?.hpa,
resources:
tierValues.rafikiBackend?.resources ||
mergedValues.rafikiBackend?.resources,
},
nginx: {
...mergedValues.nginx,
...tierValues.nginx,
image: mergedValues.nginx?.image,
config: mergedValues.nginx?.config, // Preserve hostname config
hpa: mergedValues.nginx?.hpa || tierValues.nginx?.hpa,
resources: tierValues.nginx?.resources || mergedValues.nginx?.resources,
},
redis: {
...mergedValues.redis,
...tierValues.redis,
image: mergedValues.redis?.image,
resources: tierValues.redis?.resources || mergedValues.redis?.resources,
},
// Preserve network policy and ingress from base
networkPolicy: mergedValues.networkPolicy,
ingress: mergedValues.ingress,
// Ensure tier-specific labels are preserved
labels: {
...mergedValues.labels,
...tierValues.labels,
},
};
}
logger.info("Helm values merging completed");
return mergedValues;
}