Explorar el Código

Tidy up indexer and processor into separate modules

Anuj Bansal hace 3 años
padre
commit
088c6998b8

+ 8 - 325
devops/kubernetes/query-node/index.ts

@@ -4,8 +4,9 @@ import * as docker from '@pulumi/docker'
 import * as pulumi from '@pulumi/pulumi'
 import { configMapFromFile } from './configMap'
 import * as k8s from '@pulumi/kubernetes'
-import * as s3Helpers from './s3Helpers'
-import { CaddyServiceDeployment, PostgresServiceDeployment } from 'pulumi-common'
+import { IndexerServiceDeployment } from './indexerDeployment'
+import { ProcessorServiceDeployment } from './processorDeployment'
+import { CaddyServiceDeployment } from 'pulumi-common'
 
 require('dotenv').config()
 
@@ -92,337 +93,19 @@ const defsConfig = new configMapFromFile(
 ).configName
 
 if (!externalIndexerUrl) {
-  const indexerDbName = 'indexer-db'
-  const indexerDb = new PostgresServiceDeployment(
-    indexerDbName,
-    {
-      namespaceName: namespaceName,
-      env: [
-        { name: 'POSTGRES_USER', value: process.env.DB_USER! },
-        { name: 'POSTGRES_PASSWORD', value: process.env.DB_PASS! },
-        { name: 'POSTGRES_DB', value: process.env.INDEXER_DB_NAME! },
-      ],
-      storage: 10,
-    },
-    resourceOptions
-  )
-
-  const indexerMigrationJob = new k8s.batch.v1.Job(
-    'db-migration',
-    {
-      metadata: {
-        namespace: namespaceName,
-      },
-      spec: {
-        backoffLimit: 0,
-        template: {
-          spec: {
-            containers: [
-              {
-                name: 'db-migration',
-                image: joystreamAppsImage,
-                imagePullPolicy: 'IfNotPresent',
-                resources: { requests: { cpu: '100m', memory: '100Mi' } },
-                env: [
-                  {
-                    name: 'WARTHOG_DB_HOST',
-                    value: indexerDbName,
-                  },
-                  {
-                    name: 'DB_HOST',
-                    value: indexerDbName,
-                  },
-                  { name: 'WARTHOG_DB_DATABASE', value: process.env.INDEXER_DB_NAME! },
-                  { name: 'DB_NAME', value: process.env.INDEXER_DB_NAME! },
-                  { name: 'DB_PASS', value: process.env.DB_PASS! },
-                ],
-                command: ['/bin/sh', '-c'],
-                args: ['yarn workspace query-node-root db:prepare; yarn workspace query-node-root db:migrate'],
-              },
-            ],
-            restartPolicy: 'Never',
-          },
-        },
-      },
-    },
-    { ...resourceOptions, dependsOn: indexerDb.service }
-  )
-
-  appLabels = { appClass: 'indexer' }
-
-  const indexerDeployment = new k8s.apps.v1.Deployment(
+  const indexer = new IndexerServiceDeployment(
     'indexer',
-    {
-      metadata: {
-        namespace: namespaceName,
-        labels: appLabels,
-      },
-      spec: {
-        replicas: 1,
-        selector: { matchLabels: appLabels },
-        template: {
-          metadata: {
-            labels: appLabels,
-          },
-          spec: {
-            containers: [
-              {
-                name: 'redis',
-                image: 'redis:6.0-alpine',
-                ports: [{ containerPort: 6379 }],
-              },
-              {
-                name: 'indexer',
-                image: 'joystream/hydra-indexer:3.0.0',
-                env: [
-                  { name: 'DB_HOST', value: indexerDbName },
-                  { name: 'DB_NAME', value: process.env.INDEXER_DB_NAME! },
-                  { name: 'DB_PASS', value: process.env.DB_PASS! },
-                  { name: 'DB_USER', value: process.env.DB_USER! },
-                  { name: 'DB_PORT', value: process.env.DB_PORT! },
-                  { name: 'INDEXER_WORKERS', value: '5' },
-                  { name: 'REDIS_URI', value: 'redis://localhost:6379/0' },
-                  { name: 'DEBUG', value: 'index-builder:*' },
-                  { name: 'WS_PROVIDER_ENDPOINT_URI', value: process.env.WS_PROVIDER_ENDPOINT_URI! },
-                  { name: 'TYPES_JSON', value: 'types.json' },
-                  { name: 'PGUSER', value: process.env.DB_USER! },
-                  { name: 'BLOCK_HEIGHT', value: process.env.BLOCK_HEIGHT! },
-                ],
-                volumeMounts: [
-                  {
-                    mountPath: '/home/hydra/packages/hydra-indexer/types.json',
-                    name: 'indexer-volume',
-                    subPath: 'fileData',
-                  },
-                ],
-                command: ['/bin/sh', '-c'],
-                args: ['yarn db:bootstrap && yarn start:prod'],
-              },
-              {
-                name: 'hydra-indexer-gateway',
-                image: 'joystream/hydra-indexer-gateway:3.0.0',
-                env: [
-                  { name: 'WARTHOG_STARTER_DB_DATABASE', value: process.env.INDEXER_DB_NAME! },
-                  { name: 'WARTHOG_STARTER_DB_HOST', value: indexerDbName },
-                  { name: 'WARTHOG_STARTER_DB_PASSWORD', value: process.env.DB_PASS! },
-                  { name: 'WARTHOG_STARTER_DB_PORT', value: process.env.DB_PORT! },
-                  { name: 'WARTHOG_STARTER_DB_USERNAME', value: process.env.DB_USER! },
-                  { name: 'WARTHOG_STARTER_REDIS_URI', value: 'redis://localhost:6379/0' },
-                  { name: 'WARTHOG_APP_PORT', value: process.env.WARTHOG_APP_PORT! },
-                  { name: 'PORT', value: process.env.WARTHOG_APP_PORT! },
-                  { name: 'DEBUG', value: '*' },
-                ],
-                ports: [{ name: 'hydra-port', containerPort: Number(process.env.WARTHOG_APP_PORT!) }],
-              },
-            ],
-            volumes: [
-              {
-                name: 'indexer-volume',
-                configMap: {
-                  name: defsConfig,
-                },
-              },
-            ],
-          },
-        },
-      },
-    },
-    { ...resourceOptions, dependsOn: indexerMigrationJob }
-  )
-
-  // Create a Service for the Indexer
-  const indexerService = new k8s.core.v1.Service(
-    'indexer',
-    {
-      metadata: {
-        labels: appLabels,
-        namespace: namespaceName,
-        name: 'indexer',
-      },
-      spec: {
-        ports: [{ name: 'port-1', port: 4000, targetPort: 'hydra-port' }],
-        selector: appLabels,
-      },
-    },
+    { namespaceName, storage: 10, defsConfig, joystreamAppsImage },
     resourceOptions
   )
 }
 
 if (!skipProcessor) {
-  const processorDbName = 'processor-db'
-  const processorDb = new PostgresServiceDeployment(
-    processorDbName,
-    {
-      namespaceName: namespaceName,
-      env: [
-        { name: 'POSTGRES_USER', value: process.env.DB_USER! },
-        { name: 'POSTGRES_PASSWORD', value: process.env.DB_PASS! },
-        { name: 'POSTGRES_DB', value: process.env.DB_NAME! },
-      ],
-      storage: 10,
-    },
+  const processor = new ProcessorServiceDeployment(
+    'processor',
+    { namespaceName, storage: 10, defsConfig, joystreamAppsImage, externalIndexerUrl },
     resourceOptions
   )
-
-  const processorMigrationJob = new k8s.batch.v1.Job(
-    'processor-db-migration',
-    {
-      metadata: {
-        namespace: namespaceName,
-      },
-      spec: {
-        backoffLimit: 0,
-        template: {
-          spec: {
-            containers: [
-              {
-                name: 'db-migration',
-                image: joystreamAppsImage,
-                imagePullPolicy: 'IfNotPresent',
-                resources: { requests: { cpu: '100m', memory: '100Mi' } },
-                env: [
-                  {
-                    name: 'WARTHOG_DB_HOST',
-                    value: processorDbName,
-                  },
-                  {
-                    name: 'DB_HOST',
-                    value: processorDbName,
-                  },
-                  { name: 'WARTHOG_DB_DATABASE', value: process.env.DB_NAME! },
-                  { name: 'DB_NAME', value: process.env.DB_NAME! },
-                  { name: 'DB_PASS', value: process.env.DB_PASS! },
-                ],
-                command: ['/bin/sh', '-c'],
-                args: ['yarn workspace query-node-root db:prepare; yarn workspace query-node-root db:migrate'],
-              },
-            ],
-            restartPolicy: 'Never',
-          },
-        },
-      },
-    },
-    { ...resourceOptions, dependsOn: processorDb.service }
-  )
-
-  appLabels = { appClass: 'graphql-server' }
-
-  const graphqlDeployment = new k8s.apps.v1.Deployment(
-    'graphql-server',
-    {
-      metadata: {
-        namespace: namespaceName,
-        labels: appLabels,
-      },
-      spec: {
-        replicas: 1,
-        selector: { matchLabels: appLabels },
-        template: {
-          metadata: {
-            labels: appLabels,
-          },
-          spec: {
-            containers: [
-              {
-                name: 'graphql-server',
-                image: joystreamAppsImage,
-                imagePullPolicy: 'IfNotPresent',
-                env: [
-                  { name: 'DB_HOST', value: processorDbName },
-                  { name: 'DB_PASS', value: process.env.DB_PASS! },
-                  { name: 'DB_USER', value: process.env.DB_USER! },
-                  { name: 'DB_PORT', value: process.env.DB_PORT! },
-                  { name: 'DB_NAME', value: process.env.DB_NAME! },
-                  { name: 'GRAPHQL_SERVER_HOST', value: process.env.GRAPHQL_SERVER_HOST! },
-                  { name: 'GRAPHQL_SERVER_PORT', value: process.env.GRAPHQL_SERVER_PORT! },
-                  { name: 'WS_PROVIDER_ENDPOINT_URI', value: process.env.WS_PROVIDER_ENDPOINT_URI! },
-                ],
-                ports: [{ name: 'graph-ql-port', containerPort: Number(process.env.GRAPHQL_SERVER_PORT!) }],
-                args: ['workspace', 'query-node-root', 'query-node:start:prod'],
-              },
-            ],
-          },
-        },
-      },
-    },
-    { ...resourceOptions, dependsOn: processorMigrationJob }
-  )
-
-  // Create a Service for the GraphQL Server
-  const graphqlService = new k8s.core.v1.Service(
-    'graphql-server',
-    {
-      metadata: {
-        labels: appLabels,
-        namespace: namespaceName,
-        name: 'graphql-server',
-      },
-      spec: {
-        ports: [{ name: 'port-1', port: 8081, targetPort: 'graph-ql-port' }],
-        selector: appLabels,
-      },
-    },
-    resourceOptions
-  )
-
-  const indexerURL = externalIndexerUrl || `http://indexer:4000/graphql`
-  appLabels = { appClass: 'processor' }
-
-  const processorDeployment = new k8s.apps.v1.Deployment(
-    `processor`,
-    {
-      metadata: {
-        namespace: namespaceName,
-        labels: appLabels,
-      },
-      spec: {
-        replicas: 1,
-        selector: { matchLabels: appLabels },
-        template: {
-          metadata: {
-            labels: appLabels,
-          },
-          spec: {
-            containers: [
-              {
-                name: 'processor',
-                image: joystreamAppsImage,
-                imagePullPolicy: 'IfNotPresent',
-                env: [
-                  {
-                    name: 'INDEXER_ENDPOINT_URL',
-                    value: indexerURL,
-                  },
-                  { name: 'TYPEORM_HOST', value: processorDbName },
-                  { name: 'TYPEORM_DATABASE', value: process.env.DB_NAME! },
-                  { name: 'DEBUG', value: 'index-builder:*' },
-                  { name: 'PROCESSOR_POLL_INTERVAL', value: '1000' },
-                ],
-                volumeMounts: [
-                  {
-                    mountPath: '/joystream/query-node/mappings/lib/generated/types/typedefs.json',
-                    name: 'processor-volume',
-                    subPath: 'fileData',
-                  },
-                ],
-                command: ['/bin/sh', '-c'],
-                args: ['cd query-node && yarn hydra-processor run -e ../.env'],
-              },
-            ],
-            volumes: [
-              {
-                name: 'processor-volume',
-                configMap: {
-                  name: defsConfig,
-                },
-              },
-            ],
-          },
-        },
-      },
-    },
-    { ...resourceOptions, dependsOn: graphqlService }
-  )
 }
 
 const caddyEndpoints = [

+ 187 - 0
devops/kubernetes/query-node/indexerDeployment.ts

@@ -0,0 +1,187 @@
+import * as k8s from '@pulumi/kubernetes'
+import * as pulumi from '@pulumi/pulumi'
+import { PostgresServiceDeployment } from 'pulumi-common'
+
+/**
+ * ServiceDeployment is an example abstraction that uses a class to fold together the common pattern of a
+ * Kubernetes Deployment and its associated Service object.
+ * This class deploys a db, a migration job and indexer deployment and service
+ */
+export class IndexerServiceDeployment extends pulumi.ComponentResource {
+  public readonly deployment: k8s.apps.v1.Deployment
+  public readonly service: k8s.core.v1.Service
+
+  constructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {
+    super('indexer:service:IndexerServiceDeployment', name, {}, opts)
+
+    // Name passed in the constructor will be the endpoint for accessing the service
+    const serviceName = name
+    let appLabels = { appClass: 'indexer' }
+
+    const indexerDbName = 'indexer-db'
+    const indexerDb = new PostgresServiceDeployment(
+      indexerDbName,
+      {
+        namespaceName: args.namespaceName,
+        env: [
+          { name: 'POSTGRES_USER', value: process.env.DB_USER! },
+          { name: 'POSTGRES_PASSWORD', value: process.env.DB_PASS! },
+          { name: 'POSTGRES_DB', value: process.env.INDEXER_DB_NAME! },
+        ],
+        storage: args.storage,
+      },
+      { parent: this }
+    )
+
+    const indexerMigrationJob = new k8s.batch.v1.Job(
+      'indexer-db-migration',
+      {
+        metadata: {
+          namespace: args.namespaceName,
+        },
+        spec: {
+          backoffLimit: 0,
+          template: {
+            spec: {
+              containers: [
+                {
+                  name: 'db-migration',
+                  image: args.joystreamAppsImage,
+                  imagePullPolicy: 'IfNotPresent',
+                  resources: { requests: { cpu: '100m', memory: '100Mi' } },
+                  env: [
+                    {
+                      name: 'WARTHOG_DB_HOST',
+                      value: indexerDbName,
+                    },
+                    {
+                      name: 'DB_HOST',
+                      value: indexerDbName,
+                    },
+                    { name: 'WARTHOG_DB_DATABASE', value: process.env.INDEXER_DB_NAME! },
+                    { name: 'DB_NAME', value: process.env.INDEXER_DB_NAME! },
+                    { name: 'DB_PASS', value: process.env.DB_PASS! },
+                  ],
+                  command: ['/bin/sh', '-c'],
+                  args: ['yarn workspace query-node-root db:prepare; yarn workspace query-node-root db:migrate'],
+                },
+              ],
+              restartPolicy: 'Never',
+            },
+          },
+        },
+      },
+      { parent: this, dependsOn: indexerDb.service }
+    )
+
+    this.deployment = new k8s.apps.v1.Deployment(
+      'indexer',
+      {
+        metadata: {
+          namespace: args.namespaceName,
+          labels: appLabels,
+        },
+        spec: {
+          replicas: 1,
+          selector: { matchLabels: appLabels },
+          template: {
+            metadata: {
+              labels: appLabels,
+            },
+            spec: {
+              containers: [
+                {
+                  name: 'redis',
+                  image: 'redis:6.0-alpine',
+                  ports: [{ containerPort: 6379 }],
+                },
+                {
+                  name: 'indexer',
+                  image: 'joystream/hydra-indexer:3.0.0',
+                  env: [
+                    { name: 'DB_HOST', value: indexerDbName },
+                    { name: 'DB_NAME', value: process.env.INDEXER_DB_NAME! },
+                    { name: 'DB_PASS', value: process.env.DB_PASS! },
+                    { name: 'DB_USER', value: process.env.DB_USER! },
+                    { name: 'DB_PORT', value: process.env.DB_PORT! },
+                    { name: 'INDEXER_WORKERS', value: '5' },
+                    { name: 'REDIS_URI', value: 'redis://localhost:6379/0' },
+                    { name: 'DEBUG', value: 'index-builder:*' },
+                    { name: 'WS_PROVIDER_ENDPOINT_URI', value: process.env.WS_PROVIDER_ENDPOINT_URI! },
+                    { name: 'TYPES_JSON', value: 'types.json' },
+                    { name: 'PGUSER', value: process.env.DB_USER! },
+                    { name: 'BLOCK_HEIGHT', value: process.env.BLOCK_HEIGHT! },
+                  ],
+                  volumeMounts: [
+                    {
+                      mountPath: '/home/hydra/packages/hydra-indexer/types.json',
+                      name: 'indexer-volume',
+                      subPath: 'fileData',
+                    },
+                  ],
+                  command: ['/bin/sh', '-c'],
+                  args: ['yarn db:bootstrap && yarn start:prod'],
+                },
+                {
+                  name: 'hydra-indexer-gateway',
+                  image: 'joystream/hydra-indexer-gateway:3.0.0',
+                  env: [
+                    { name: 'WARTHOG_STARTER_DB_DATABASE', value: process.env.INDEXER_DB_NAME! },
+                    { name: 'WARTHOG_STARTER_DB_HOST', value: indexerDbName },
+                    { name: 'WARTHOG_STARTER_DB_PASSWORD', value: process.env.DB_PASS! },
+                    { name: 'WARTHOG_STARTER_DB_PORT', value: process.env.DB_PORT! },
+                    { name: 'WARTHOG_STARTER_DB_USERNAME', value: process.env.DB_USER! },
+                    { name: 'WARTHOG_STARTER_REDIS_URI', value: 'redis://localhost:6379/0' },
+                    { name: 'WARTHOG_APP_PORT', value: process.env.WARTHOG_APP_PORT! },
+                    { name: 'PORT', value: process.env.WARTHOG_APP_PORT! },
+                    { name: 'DEBUG', value: '*' },
+                  ],
+                  ports: [{ name: 'hydra-port', containerPort: Number(process.env.WARTHOG_APP_PORT!) }],
+                },
+              ],
+              volumes: [
+                {
+                  name: 'indexer-volume',
+                  configMap: {
+                    name: args.defsConfig,
+                  },
+                },
+              ],
+            },
+          },
+        },
+      },
+      { parent: this, dependsOn: indexerMigrationJob }
+    )
+
+    // Create a Service for the Indexer
+    this.service = new k8s.core.v1.Service(
+      serviceName,
+      {
+        metadata: {
+          labels: appLabels,
+          namespace: args.namespaceName,
+          name: serviceName,
+        },
+        spec: {
+          ports: [{ name: 'port-1', port: 4000, targetPort: 'hydra-port' }],
+          selector: appLabels,
+        },
+      },
+      { parent: this }
+    )
+  }
+}
+
+interface Environment {
+  name: string
+  value: string
+}
+
+export interface ServiceDeploymentArgs {
+  namespaceName: pulumi.Output<string>
+  joystreamAppsImage: pulumi.Output<string>
+  defsConfig: pulumi.Output<string> | undefined
+  env?: Environment[]
+  storage: Number
+}

+ 210 - 0
devops/kubernetes/query-node/processorDeployment.ts

@@ -0,0 +1,210 @@
+import * as k8s from '@pulumi/kubernetes'
+import * as pulumi from '@pulumi/pulumi'
+import { PostgresServiceDeployment } from 'pulumi-common'
+
+/**
+ * ServiceDeployment is an example abstraction that uses a class to fold together the common pattern of a
+ * Kubernetes Deployment and its associated Service object.
+ * This class deploys a db, a migration job, graphql server and processor
+ */
+export class ProcessorServiceDeployment extends pulumi.ComponentResource {
+  public readonly deployment: k8s.apps.v1.Deployment
+  public readonly service: k8s.core.v1.Service
+  public readonly endpoint: string
+
+  constructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {
+    super('processor:service:ProcessorServiceDeployment', name, {}, opts)
+
+    // Name passed in the constructor will be the endpoint for accessing the service
+    this.endpoint = 'graphql-server'
+
+    const processorDbName = 'processor-db'
+    const processorDb = new PostgresServiceDeployment(
+      processorDbName,
+      {
+        namespaceName: args.namespaceName,
+        env: [
+          { name: 'POSTGRES_USER', value: process.env.DB_USER! },
+          { name: 'POSTGRES_PASSWORD', value: process.env.DB_PASS! },
+          { name: 'POSTGRES_DB', value: process.env.DB_NAME! },
+        ],
+        storage: args.storage,
+      },
+      { parent: this }
+    )
+
+    const processorMigrationJob = new k8s.batch.v1.Job(
+      'processor-db-migration',
+      {
+        metadata: {
+          namespace: args.namespaceName,
+        },
+        spec: {
+          backoffLimit: 0,
+          template: {
+            spec: {
+              containers: [
+                {
+                  name: 'db-migration',
+                  image: args.joystreamAppsImage,
+                  imagePullPolicy: 'IfNotPresent',
+                  resources: { requests: { cpu: '100m', memory: '100Mi' } },
+                  env: [
+                    {
+                      name: 'WARTHOG_DB_HOST',
+                      value: processorDbName,
+                    },
+                    {
+                      name: 'DB_HOST',
+                      value: processorDbName,
+                    },
+                    { name: 'WARTHOG_DB_DATABASE', value: process.env.DB_NAME! },
+                    { name: 'DB_NAME', value: process.env.DB_NAME! },
+                    { name: 'DB_PASS', value: process.env.DB_PASS! },
+                  ],
+                  command: ['/bin/sh', '-c'],
+                  args: ['yarn workspace query-node-root db:prepare; yarn workspace query-node-root db:migrate'],
+                },
+              ],
+              restartPolicy: 'Never',
+            },
+          },
+        },
+      },
+      { parent: this, dependsOn: processorDb.service }
+    )
+
+    let appLabels = { appClass: 'graphql-server' }
+
+    this.deployment = new k8s.apps.v1.Deployment(
+      'graphql-server',
+      {
+        metadata: {
+          namespace: args.namespaceName,
+          labels: appLabels,
+        },
+        spec: {
+          replicas: 1,
+          selector: { matchLabels: appLabels },
+          template: {
+            metadata: {
+              labels: appLabels,
+            },
+            spec: {
+              containers: [
+                {
+                  name: 'graphql-server',
+                  image: args.joystreamAppsImage,
+                  imagePullPolicy: 'IfNotPresent',
+                  env: [
+                    { name: 'DB_HOST', value: processorDbName },
+                    { name: 'DB_PASS', value: process.env.DB_PASS! },
+                    { name: 'DB_USER', value: process.env.DB_USER! },
+                    { name: 'DB_PORT', value: process.env.DB_PORT! },
+                    { name: 'DB_NAME', value: process.env.DB_NAME! },
+                    { name: 'GRAPHQL_SERVER_HOST', value: process.env.GRAPHQL_SERVER_HOST! },
+                    { name: 'GRAPHQL_SERVER_PORT', value: process.env.GRAPHQL_SERVER_PORT! },
+                    { name: 'WS_PROVIDER_ENDPOINT_URI', value: process.env.WS_PROVIDER_ENDPOINT_URI! },
+                  ],
+                  ports: [{ name: 'graph-ql-port', containerPort: Number(process.env.GRAPHQL_SERVER_PORT!) }],
+                  args: ['workspace', 'query-node-root', 'query-node:start:prod'],
+                },
+              ],
+            },
+          },
+        },
+      },
+      { parent: this, dependsOn: processorMigrationJob }
+    )
+
+    // Create a Service for the GraphQL Server
+    this.service = new k8s.core.v1.Service(
+      'graphql-server',
+      {
+        metadata: {
+          labels: appLabels,
+          namespace: args.namespaceName,
+          name: this.endpoint,
+        },
+        spec: {
+          ports: [{ name: 'port-1', port: 8081, targetPort: 'graph-ql-port' }],
+          selector: appLabels,
+        },
+      },
+      { parent: this }
+    )
+
+    const indexerURL = args.externalIndexerUrl || `http://indexer:4000/graphql`
+    appLabels = { appClass: 'processor' }
+
+    const processorDeployment = new k8s.apps.v1.Deployment(
+      `processor`,
+      {
+        metadata: {
+          namespace: args.namespaceName,
+          labels: appLabels,
+        },
+        spec: {
+          replicas: 1,
+          selector: { matchLabels: appLabels },
+          template: {
+            metadata: {
+              labels: appLabels,
+            },
+            spec: {
+              containers: [
+                {
+                  name: 'processor',
+                  image: args.joystreamAppsImage,
+                  imagePullPolicy: 'IfNotPresent',
+                  env: [
+                    {
+                      name: 'INDEXER_ENDPOINT_URL',
+                      value: indexerURL,
+                    },
+                    { name: 'TYPEORM_HOST', value: processorDbName },
+                    { name: 'TYPEORM_DATABASE', value: process.env.DB_NAME! },
+                    { name: 'DEBUG', value: 'index-builder:*' },
+                    { name: 'PROCESSOR_POLL_INTERVAL', value: '1000' },
+                  ],
+                  volumeMounts: [
+                    {
+                      mountPath: '/joystream/query-node/mappings/lib/generated/types/typedefs.json',
+                      name: 'processor-volume',
+                      subPath: 'fileData',
+                    },
+                  ],
+                  command: ['/bin/sh', '-c'],
+                  args: ['cd query-node && yarn hydra-processor run -e ../.env'],
+                },
+              ],
+              volumes: [
+                {
+                  name: 'processor-volume',
+                  configMap: {
+                    name: args.defsConfig,
+                  },
+                },
+              ],
+            },
+          },
+        },
+      },
+      { parent: this, dependsOn: this.service }
+    )
+  }
+}
+
+interface Environment {
+  name: string
+  value: string
+}
+
+export interface ServiceDeploymentArgs {
+  namespaceName: pulumi.Output<string>
+  joystreamAppsImage: pulumi.Output<string>
+  defsConfig: pulumi.Output<string> | undefined
+  externalIndexerUrl: string | undefined
+  env?: Environment[]
+  storage: Number
+}