|
@@ -0,0 +1,80 @@
|
|
|
|
+import * as k8s from '@pulumi/kubernetes'
|
|
|
|
+import * as k8stypes from '@pulumi/kubernetes/types/input'
|
|
|
|
+import * as pulumi from '@pulumi/pulumi'
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * ServiceDeployment is an example abstraction that uses a class to fold together the common pattern of a
|
|
|
|
+ * Kubernetes Deployment and its associated Service object.
|
|
|
|
+ */
|
|
|
|
+export class ServiceDeployment extends pulumi.ComponentResource {
|
|
|
|
+ public readonly deployment: k8s.apps.v1.Deployment
|
|
|
|
+ public readonly service: k8s.core.v1.Service
|
|
|
|
+ public readonly ipAddress?: pulumi.Output<string>
|
|
|
|
+
|
|
|
|
+ constructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {
|
|
|
|
+ super('k8sjs:service:ServiceDeployment', name, {}, opts)
|
|
|
|
+
|
|
|
|
+ const labels = { app: name }
|
|
|
|
+ const currentEnv = args.env || []
|
|
|
|
+ currentEnv.push({ name: 'GET_HOSTS_FROM', value: 'dns' })
|
|
|
|
+
|
|
|
|
+ const container: k8stypes.core.v1.Container = {
|
|
|
|
+ name,
|
|
|
|
+ image: args.image,
|
|
|
|
+ resources: args.resources || { requests: { cpu: '100m', memory: '100Mi' } },
|
|
|
|
+ env: currentEnv,
|
|
|
|
+ ports: args.ports && args.ports.map((p) => ({ containerPort: p })),
|
|
|
|
+ }
|
|
|
|
+ this.deployment = new k8s.apps.v1.Deployment(
|
|
|
|
+ name,
|
|
|
|
+ {
|
|
|
|
+ spec: {
|
|
|
|
+ selector: { matchLabels: labels },
|
|
|
|
+ replicas: args.replicas || 1,
|
|
|
|
+ template: {
|
|
|
|
+ metadata: { labels: labels },
|
|
|
|
+ spec: { containers: [container] },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ { parent: this }
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ this.service = new k8s.core.v1.Service(
|
|
|
|
+ name,
|
|
|
|
+ {
|
|
|
|
+ metadata: {
|
|
|
|
+ name: name,
|
|
|
|
+ labels: this.deployment.metadata.labels,
|
|
|
|
+ },
|
|
|
|
+ spec: {
|
|
|
|
+ ports: args.ports && args.ports.map((p) => ({ port: p, targetPort: p })),
|
|
|
|
+ selector: this.deployment.spec.template.metadata.labels,
|
|
|
|
+ // Minikube does not implement services of type `LoadBalancer`; require the user to specify if we're
|
|
|
|
+ // running on minikube, and if so, create only services of type ClusterIP.
|
|
|
|
+ type: args.allocateIpAddress ? (args.isMinikube ? 'ClusterIP' : 'LoadBalancer') : undefined,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ { parent: this }
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ if (args.allocateIpAddress) {
|
|
|
|
+ this.ipAddress = args.isMinikube ? this.service.spec.clusterIP : this.service.status.loadBalancer.ingress[0].ip
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+interface EnvironmentType {
|
|
|
|
+ name: string
|
|
|
|
+ value: string
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export interface ServiceDeploymentArgs {
|
|
|
|
+ image: string
|
|
|
|
+ resources?: k8stypes.core.v1.ResourceRequirements
|
|
|
|
+ replicas?: number
|
|
|
|
+ ports?: number[]
|
|
|
|
+ env?: EnvironmentType[]
|
|
|
|
+ allocateIpAddress?: boolean
|
|
|
|
+ isMinikube?: boolean
|
|
|
|
+}
|