processorDeployment.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import * as k8s from '@pulumi/kubernetes'
  2. import * as pulumi from '@pulumi/pulumi'
  3. import { PostgresServiceDeployment } from 'pulumi-common'
  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. * This class deploys a db, a migration job, graphql server and processor
  8. */
  9. export class ProcessorServiceDeployment extends pulumi.ComponentResource {
  10. public readonly deployment: k8s.apps.v1.Deployment
  11. public readonly service: k8s.core.v1.Service
  12. public readonly endpoint: string
  13. constructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {
  14. super('processor:service:ProcessorServiceDeployment', name, {}, opts)
  15. // Name passed in the constructor will be the endpoint for accessing the service
  16. this.endpoint = 'graphql-server'
  17. const processorDbName = 'processor-db'
  18. const processorDb = new PostgresServiceDeployment(
  19. processorDbName,
  20. {
  21. namespaceName: args.namespaceName,
  22. env: [
  23. { name: 'POSTGRES_USER', value: process.env.DB_USER! },
  24. { name: 'POSTGRES_PASSWORD', value: process.env.DB_PASS! },
  25. { name: 'POSTGRES_DB', value: process.env.DB_NAME! },
  26. ],
  27. storage: args.storage,
  28. },
  29. { parent: this }
  30. )
  31. const processorMigrationJob = new k8s.batch.v1.Job(
  32. 'processor-db-migration',
  33. {
  34. metadata: {
  35. namespace: args.namespaceName,
  36. },
  37. spec: {
  38. backoffLimit: 0,
  39. template: {
  40. spec: {
  41. containers: [
  42. {
  43. name: 'db-migration',
  44. image: args.joystreamAppsImage,
  45. imagePullPolicy: 'IfNotPresent',
  46. resources: { requests: { cpu: '100m', memory: '100Mi' } },
  47. env: [
  48. {
  49. name: 'WARTHOG_DB_HOST',
  50. value: processorDbName,
  51. },
  52. {
  53. name: 'DB_HOST',
  54. value: processorDbName,
  55. },
  56. { name: 'WARTHOG_DB_DATABASE', value: process.env.DB_NAME! },
  57. { name: 'DB_NAME', value: process.env.DB_NAME! },
  58. { name: 'DB_PASS', value: process.env.DB_PASS! },
  59. ],
  60. command: ['/bin/sh', '-c'],
  61. args: ['yarn workspace query-node-root db:prepare; yarn workspace query-node-root db:migrate'],
  62. },
  63. ],
  64. restartPolicy: 'Never',
  65. },
  66. },
  67. },
  68. },
  69. { parent: this, dependsOn: processorDb.service }
  70. )
  71. let appLabels = { appClass: 'graphql-server' }
  72. this.deployment = new k8s.apps.v1.Deployment(
  73. 'graphql-server',
  74. {
  75. metadata: {
  76. namespace: args.namespaceName,
  77. labels: appLabels,
  78. },
  79. spec: {
  80. replicas: 1,
  81. selector: { matchLabels: appLabels },
  82. template: {
  83. metadata: {
  84. labels: appLabels,
  85. },
  86. spec: {
  87. containers: [
  88. {
  89. name: 'graphql-server',
  90. image: args.joystreamAppsImage,
  91. imagePullPolicy: 'IfNotPresent',
  92. env: [
  93. { name: 'DB_HOST', value: processorDbName },
  94. { name: 'DB_PASS', value: process.env.DB_PASS! },
  95. { name: 'DB_USER', value: process.env.DB_USER! },
  96. { name: 'DB_PORT', value: process.env.DB_PORT! },
  97. { name: 'DB_NAME', value: process.env.DB_NAME! },
  98. { name: 'GRAPHQL_SERVER_HOST', value: process.env.GRAPHQL_SERVER_HOST! },
  99. { name: 'GRAPHQL_SERVER_PORT', value: process.env.GRAPHQL_SERVER_PORT! },
  100. { name: 'WS_PROVIDER_ENDPOINT_URI', value: process.env.WS_PROVIDER_ENDPOINT_URI! },
  101. ],
  102. ports: [{ name: 'graph-ql-port', containerPort: Number(process.env.GRAPHQL_SERVER_PORT!) }],
  103. args: ['workspace', 'query-node-root', 'query-node:start:prod'],
  104. },
  105. ],
  106. },
  107. },
  108. },
  109. },
  110. { parent: this, dependsOn: processorMigrationJob }
  111. )
  112. // Create a Service for the GraphQL Server
  113. this.service = new k8s.core.v1.Service(
  114. 'graphql-server',
  115. {
  116. metadata: {
  117. labels: appLabels,
  118. namespace: args.namespaceName,
  119. name: this.endpoint,
  120. },
  121. spec: {
  122. ports: [{ name: 'port-1', port: 8081, targetPort: 'graph-ql-port' }],
  123. selector: appLabels,
  124. },
  125. },
  126. { parent: this }
  127. )
  128. const indexerURL = args.externalIndexerUrl || `http://indexer:4000/graphql`
  129. appLabels = { appClass: 'processor' }
  130. const processorDeployment = new k8s.apps.v1.Deployment(
  131. `processor`,
  132. {
  133. metadata: {
  134. namespace: args.namespaceName,
  135. labels: appLabels,
  136. },
  137. spec: {
  138. replicas: 1,
  139. selector: { matchLabels: appLabels },
  140. template: {
  141. metadata: {
  142. labels: appLabels,
  143. },
  144. spec: {
  145. containers: [
  146. {
  147. name: 'processor',
  148. image: args.joystreamAppsImage,
  149. imagePullPolicy: 'IfNotPresent',
  150. env: [
  151. {
  152. name: 'INDEXER_ENDPOINT_URL',
  153. value: indexerURL,
  154. },
  155. { name: 'TYPEORM_HOST', value: processorDbName },
  156. { name: 'TYPEORM_DATABASE', value: process.env.DB_NAME! },
  157. { name: 'DEBUG', value: 'index-builder:*' },
  158. { name: 'PROCESSOR_POLL_INTERVAL', value: '1000' },
  159. ],
  160. volumeMounts: [
  161. {
  162. mountPath: '/joystream/query-node/mappings/lib/generated/types/typedefs.json',
  163. name: 'processor-volume',
  164. subPath: 'fileData',
  165. },
  166. ],
  167. command: ['/bin/sh', '-c'],
  168. args: ['cd query-node && yarn hydra-processor run -e ../.env'],
  169. },
  170. ],
  171. volumes: [
  172. {
  173. name: 'processor-volume',
  174. configMap: {
  175. name: args.defsConfig,
  176. },
  177. },
  178. ],
  179. },
  180. },
  181. },
  182. },
  183. { parent: this, dependsOn: this.service }
  184. )
  185. }
  186. }
  187. interface Environment {
  188. name: string
  189. value: string
  190. }
  191. export interface ServiceDeploymentArgs {
  192. namespaceName: pulumi.Output<string>
  193. joystreamAppsImage: pulumi.Output<string>
  194. defsConfig: pulumi.Output<string> | undefined
  195. externalIndexerUrl: string | undefined
  196. env?: Environment[]
  197. storage: Number
  198. }