@chimoney.io/iaas-k8s-deployment
Version:
Kubernetes Infrastructure as a Service deployment package for streamlined multi-cloud environments
476 lines (441 loc) • 13.9 kB
text/typescript
import * as gcp from "@pulumi/gcp";
import * as pulumi from "@pulumi/pulumi";
import { ClusterLookupResult } from "../types/index.js";
// Define configurations for different environments for GKE
interface GkeConfig {
machineType: pulumi.Input<string>;
initialNodeCount: pulumi.Input<number>; // This will be used for the node pool
minNodeCount: pulumi.Input<number>;
maxNodeCount: pulumi.Input<number>;
}
const devGkeConfig: GkeConfig = {
machineType: "e2-standard-2", // 2 vCPUs, 8GB RAM - more suitable for workloads
initialNodeCount: 2,
minNodeCount: 2,
maxNodeCount: 4,
};
const prodGkeConfig: GkeConfig = {
machineType: "e2-standard-4", // 4 vCPUs, 16GB RAM for production
initialNodeCount: 2,
minNodeCount: 2,
maxNodeCount: 6,
};
// Function to create a GKE cluster
export function createGkeCluster(name: string, stack: string) {
const config = stack === "prod" ? prodGkeConfig : devGkeConfig;
const gcpConfig = new pulumi.Config("gcp");
const project = gcpConfig.require("project");
const region = gcpConfig.get("region") || "us-central1";
const zone = gcpConfig.get("zone") || "us-central1-a";
const credentials = gcpConfig.get("credentials");
pulumi.log.info(
`Using GCP project: ${project}, region: ${region}, zone: ${zone}`
);
// Create a GCP provider with explicit credentials if available
const gcpProvider = credentials
? new gcp.Provider("gcp-provider", {
project: project,
region: region,
zone: zone,
credentials: credentials,
})
: new gcp.Provider("gcp-provider", {
project: project,
region: region,
zone: zone,
});
const staticIp = new gcp.compute.GlobalAddress(
"rafiki-global-ip",
{
project: project,
description: "Static IP for GKE Ingress",
},
{ provider: gcpProvider }
);
pulumi.log.info(
`Using ${stack} configuration for GKE cluster. Machine type (for default-pool): ${config.machineType}`
);
// Use a specific Kubernetes version that meets Helm chart requirements (>=1.25.0)
const engineVersion = gcp.container
.getEngineVersions({ project, location: zone }, { provider: gcpProvider })
.then((v: gcp.container.GetEngineVersionsResult) => {
// Find a version that meets our minimum requirement of 1.25.0
const validVersions = v.validMasterVersions.filter(
(version) =>
version.startsWith("1.25.") ||
version.startsWith("1.26.") ||
version.startsWith("1.27.") ||
version.startsWith("1.28.") ||
version.startsWith("1.29.") ||
version.startsWith("1.30.") ||
version.startsWith("1.31.") ||
version.startsWith("1.32.") ||
version.startsWith("1.33.") ||
version.startsWith("1.34.")
);
if (validVersions.length === 0) {
// Fallback to latest master version if no valid versions found
pulumi.log.warn(
"No Kubernetes versions >=1.25.0 found, using latest master version"
);
return v.latestMasterVersion;
}
// Use the latest valid version
const selectedVersion = validVersions[0];
pulumi.log.info(
`Selected Kubernetes version: ${selectedVersion} (meets Helm chart requirement >=1.25.0)`
);
return selectedVersion;
});
const cluster = new gcp.container.Cluster(
`${name}-gke-cluster`,
{
project: project,
location: zone,
minMasterVersion: engineVersion,
removeDefaultNodePool: true,
initialNodeCount: 1, // This is required but will be removed since removeDefaultNodePool is true
deletionProtection: false, // Allow deletion of the cluster
},
{ provider: gcpProvider }
);
// Create a separate node pool
const nodePool = new gcp.container.NodePool(
`${name}-node-pool`,
{
project: project,
location: zone,
cluster: cluster.name,
initialNodeCount: config.initialNodeCount,
version: engineVersion,
autoscaling: {
minNodeCount: config.minNodeCount,
maxNodeCount: config.maxNodeCount,
},
management: {
autoRepair: true,
autoUpgrade: true,
},
nodeConfig: {
machineType: config.machineType,
oauthScopes: ["https://www.googleapis.com/auth/cloud-platform"],
},
},
{ provider: gcpProvider }
);
const kubeconfig = pulumi
.all([
cluster.name,
cluster.endpoint,
cluster.masterAuth,
pulumi.output(project),
pulumi.output(zone),
])
.apply(
([clusterNameValue, endpoint, masterAuth, projectValue, zoneValue]) => {
const context = `${projectValue}_${zoneValue}_${clusterNameValue}`;
return `
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${masterAuth.clusterCaCertificate}
server: https://${endpoint}
name: ${context}
contexts:
- context:
cluster: ${context}
user: ${context}
name: ${context}
current-context: ${context}
kind: Config
preferences: {}
users:
- name: ${context}
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: gke-gcloud-auth-plugin
installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
provideClusterInfo: true
`;
}
);
return {
kubeconfig: kubeconfig,
clusterName: cluster.name,
gcpProject: project,
gcpZone: zone,
staticIpName: staticIp.name,
};
}
// Function to look up existing shared GKE cluster and static IP (using Pulumi data sources)
export function lookupSharedGkeClusterSync(
sharedClusterName: string
): pulumi.Output<ClusterLookupResult> {
const gcpConfig = new pulumi.Config("gcp");
const configProject = gcpConfig.require("project");
const region = gcpConfig.get("region") || "us-central1";
const zone = gcpConfig.get("zone") || "us-central1-a";
pulumi.log.info(
`Looking up shared GKE cluster: ${sharedClusterName} in project: ${configProject}, zone: ${zone}`
);
// Look for existing GKE cluster using Pulumi data source
const clusterLookup = gcp.container
.getCluster(
{
name: sharedClusterName,
location: zone,
project: configProject,
},
{ async: true }
)
.then((existingCluster) => {
if (existingCluster) {
pulumi.log.info(
`Found existing shared GKE cluster: ${sharedClusterName}`
);
// Look for existing static IP
return gcp.compute
.getGlobalAddress(
{
name: "rafiki-global-ip",
project: configProject,
},
{ async: true }
)
.then((existingStaticIp) => {
const staticIpName = existingStaticIp
? existingStaticIp.name
: undefined;
if (staticIpName) {
pulumi.log.info(`Found existing static IP: ${staticIpName}`);
} else {
pulumi.log.info(
"No existing static IP found, will create new one if needed"
);
}
// Generate kubeconfig for existing cluster
const context = `${configProject}_${zone}_${existingCluster.name}`;
const kubeconfig = `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${existingCluster.masterAuths?.[0]?.clusterCaCertificate}
server: https://${existingCluster.endpoint}
name: ${context}
contexts:
- context:
cluster: ${context}
user: ${context}
name: ${context}
current-context: ${context}
kind: Config
preferences: {}
users:
- name: ${context}
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: gke-gcloud-auth-plugin
installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
provideClusterInfo: true
`;
return {
exists: true,
kubeconfig: kubeconfig,
clusterName: existingCluster.name,
staticIpName: staticIpName,
region: region,
zone: zone,
project: configProject,
};
})
.catch(() => {
// Static IP lookup failed but cluster exists
const context = `${configProject}_${zone}_${existingCluster.name}`;
const kubeconfig = `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${existingCluster.masterAuths?.[0]?.clusterCaCertificate}
server: https://${existingCluster.endpoint}
name: ${context}
contexts:
- context:
cluster: ${context}
user: ${context}
name: ${context}
current-context: ${context}
kind: Config
preferences: {}
users:
- name: ${context}
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: gke-gcloud-auth-plugin
installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
provideClusterInfo: true
`;
return {
exists: true,
kubeconfig: kubeconfig,
clusterName: existingCluster.name,
staticIpName: undefined,
region: region,
zone: zone,
project: configProject,
};
});
} else {
return {
exists: false,
project: configProject,
region: region,
zone: zone,
};
}
})
.catch(() => {
pulumi.log.info(
`Shared GKE cluster ${sharedClusterName} not found, will create new one`
);
return {
exists: false,
project: configProject,
region: region,
zone: zone,
};
});
return pulumi.output(clusterLookup);
}
// Function to look up existing shared GKE cluster and static IP
export async function lookupSharedGkeCluster(
sharedClusterName: string,
cloudProvider: string = "gcp",
project?: string
): Promise<ClusterLookupResult> {
try {
const gcpConfig = new pulumi.Config("gcp");
const configProject = project || gcpConfig.require("project");
const region = gcpConfig.get("region") || "us-central1";
const zone = gcpConfig.get("zone") || "us-central1-a";
pulumi.log.info(
`Looking up shared GKE cluster: ${sharedClusterName} in project: ${configProject}, zone: ${zone}`
);
try {
// Look for existing GKE cluster
const existingCluster = await gcp.container.getCluster({
name: sharedClusterName,
location: zone,
project: configProject,
});
if (existingCluster) {
pulumi.log.info(
`Found existing shared GKE cluster: ${sharedClusterName}`
);
// Look for existing static IP
let staticIpName: string | undefined;
try {
const existingStaticIp = await gcp.compute.getGlobalAddress({
name: "rafiki-global-ip",
project: configProject,
});
staticIpName = existingStaticIp.name;
pulumi.log.info(`Found existing static IP: ${staticIpName}`);
} catch (ipError) {
pulumi.log.info(
"No existing static IP found, will create new one if needed"
);
}
// Generate kubeconfig for existing cluster
const context = `${configProject}_${zone}_${existingCluster.name}`;
const kubeconfig = `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${existingCluster.masterAuths?.[0]?.clusterCaCertificate}
server: https://${existingCluster.endpoint}
name: ${context}
contexts:
- context:
cluster: ${context}
user: ${context}
name: ${context}
current-context: ${context}
kind: Config
preferences: {}
users:
- name: ${context}
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: gke-gcloud-auth-plugin
installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
provideClusterInfo: true
`;
return {
exists: true,
kubeconfig: kubeconfig,
clusterName: existingCluster.name,
staticIpName: staticIpName,
region: region,
zone: zone,
project: configProject,
};
}
} catch (error) {
pulumi.log.info(
`Shared GKE cluster ${sharedClusterName} not found, will create new one`
);
}
return {
exists: false,
project: configProject,
region: region,
zone: zone,
};
} catch (error) {
pulumi.log.warn(`Error looking up shared GKE cluster: ${error}`);
return {
exists: false,
};
}
}
// Function to look up or create static IP for shared deployments
export function getOrCreateStaticIp(
name: string,
project: string,
gcpProvider: gcp.Provider
) {
try {
// Try to get existing static IP
const existingIp = gcp.compute.getGlobalAddress({
name: name,
project: project,
});
return existingIp.then((ip) => {
pulumi.log.info(`Using existing static IP: ${ip.name}`);
return {
name: ip.name,
address: ip.address,
};
});
} catch (error) {
// Create new static IP if it doesn't exist
pulumi.log.info(`Creating new static IP: ${name}`);
const staticIp = new gcp.compute.GlobalAddress(
name,
{
project: project,
description: "Static IP for shared GKE Ingress",
},
{ provider: gcpProvider }
);
return {
name: staticIp.name,
address: staticIp.address,
};
}
}