caddy.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import * as k8s from '@pulumi/kubernetes'
  2. import * as pulumi from '@pulumi/pulumi'
  3. import * as dns from 'dns'
  4. /**
  5. * ServiceDeployment is an example abstraction that uses a class to fold together the common pattern of a
  6. * Kubernetes Deployment and its associated Service object.
  7. */
  8. export class CaddyServiceDeployment extends pulumi.ComponentResource {
  9. public readonly deployment: k8s.apps.v1.Deployment
  10. public readonly service: k8s.core.v1.Service
  11. public readonly hostname?: pulumi.Output<string>
  12. public readonly primaryEndpoint?: pulumi.Output<string>
  13. public readonly secondaryEndpoint?: pulumi.Output<string>
  14. constructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {
  15. super('caddy:service:CaddyServiceDeployment', name, {}, opts)
  16. const labels = { app: name }
  17. let volumes: pulumi.Input<pulumi.Input<k8s.types.input.core.v1.Volume>[]> = []
  18. let caddyVolumeMounts: pulumi.Input<pulumi.Input<k8s.types.input.core.v1.VolumeMount>[]> = []
  19. async function lookupPromise(url: string): Promise<dns.LookupAddress[]> {
  20. return new Promise((resolve, reject) => {
  21. dns.lookup(url, { all: true }, (err: any, addresses: dns.LookupAddress[]) => {
  22. if (err) reject(err)
  23. resolve(addresses)
  24. })
  25. })
  26. }
  27. this.service = new k8s.core.v1.Service(
  28. name,
  29. {
  30. metadata: {
  31. name: name,
  32. namespace: args.namespaceName,
  33. labels: labels,
  34. },
  35. spec: {
  36. type: args.isMinikube ? 'NodePort' : 'LoadBalancer',
  37. ports: [
  38. { name: 'http', port: 80 },
  39. { name: 'https', port: 443 },
  40. ],
  41. selector: labels,
  42. },
  43. },
  44. { parent: this }
  45. )
  46. this.hostname = this.service.status.loadBalancer.ingress[0].hostname
  47. if (args.lbReady) {
  48. let caddyConfig: pulumi.Output<string>
  49. const lbIps: pulumi.Output<dns.LookupAddress[]> = this.hostname.apply((dnsName) => {
  50. return lookupPromise(dnsName)
  51. })
  52. function getProxyString(ipAddress: pulumi.Output<string>) {
  53. let result: pulumi.Output<string> = pulumi.interpolate``
  54. for (const endpoint of args.caddyEndpoints) {
  55. result = pulumi.interpolate`${ipAddress}.nip.io${endpoint}\n${result}`
  56. }
  57. return result
  58. }
  59. caddyConfig = pulumi.interpolate`${getProxyString(lbIps[0].address)}
  60. ${getProxyString(lbIps[1].address)}`
  61. this.primaryEndpoint = pulumi.interpolate`${lbIps[0].address}.nip.io`
  62. this.secondaryEndpoint = pulumi.interpolate`${lbIps[1].address}.nip.io`
  63. const keyConfig = new k8s.core.v1.ConfigMap(
  64. name,
  65. {
  66. metadata: { namespace: args.namespaceName, labels: labels },
  67. data: { 'fileData': caddyConfig },
  68. },
  69. { parent: this }
  70. )
  71. const keyConfigName = keyConfig.metadata.apply((m) => m.name)
  72. caddyVolumeMounts.push({
  73. mountPath: '/etc/caddy/Caddyfile',
  74. name: 'caddy-volume',
  75. subPath: 'fileData',
  76. })
  77. volumes.push({
  78. name: 'caddy-volume',
  79. configMap: {
  80. name: keyConfigName,
  81. },
  82. })
  83. }
  84. this.deployment = new k8s.apps.v1.Deployment(
  85. name,
  86. {
  87. metadata: { namespace: args.namespaceName, labels: labels },
  88. spec: {
  89. selector: { matchLabels: labels },
  90. replicas: 1,
  91. template: {
  92. metadata: { labels: labels },
  93. spec: {
  94. containers: [
  95. {
  96. name: 'caddy',
  97. image: 'caddy',
  98. ports: [
  99. { name: 'caddy-http', containerPort: 80 },
  100. { name: 'caddy-https', containerPort: 443 },
  101. ],
  102. volumeMounts: caddyVolumeMounts,
  103. },
  104. ],
  105. volumes,
  106. },
  107. },
  108. },
  109. },
  110. { parent: this }
  111. )
  112. }
  113. }
  114. export interface ServiceDeploymentArgs {
  115. namespaceName: pulumi.Output<string>
  116. // Endpoints are caddyConfig strings concatenated after IP.nip.io
  117. caddyEndpoints: string[]
  118. lbReady?: boolean
  119. isMinikube?: boolean
  120. }