🚨 Announcing Vendure v2 Beta

Using Docker

Docker is a technology which allows you to run your Vendure application inside a container. The default installation with @vendure/create includes a sample Dockerfile:

FROM node:16

WORKDIR /usr/src/app

COPY package.json ./
COPY package-lock.json ./
RUN npm install --production
COPY . .
RUN npm run build

This Dockerfile can then be built into an “image” using:

docker build -t vendure .

This same image can be used to run both the Vendure server and the worker:

# Run the server
docker run -dp 3000:3000 --name vendure-server vendure npm run start:server

# Run the worker
docker run -dp 3000:3000 --name vendure-worker vendure npm run start:worker

Here is a breakdown of the command used above:

  • docker run - run the image we created with docker build
  • -dp 3000:3000 - the -d flag means to run in “detached” mode, so it runs in the background and does not take control of your terminal. -p 3000:3000 means to expose port 3000 of the container (which is what Vendure listens on by default) as port 3000 on your host machine.
  • --name vendure-server - we give the container a human-readable name.
  • vendure - we are referencing the tag we set up during the build.
  • npm run start:server - this last part is the actual command that should be run inside the container.

Docker Compose

Managing multiple docker containers can be made easier using Docker Compose. In the below example, we use the same Dockerfile defined above, and we also define a Postgres database to connect to:

version: "3"
services:
  server:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    command: ["npm", "run", "start:server"]
    volumes:
      - /usr/src/app
    environment:
      DB_HOST: database
      DB_PORT: 5432
      DB_NAME: vendure
      DB_USERNAME: postgres
      DB_PASSWORD: password
  worker:
    build:
      context: .
      dockerfile: Dockerfile
    command: ["npm", "run", "start:worker"]
    volumes:
      - /usr/src/app
    environment:
      DB_HOST: database
      DB_PORT: 5432
      DB_NAME: vendure
      DB_USERNAME: postgres
      DB_PASSWORD: password
  database:
    image: postgres
    volumes:
      - /var/lib/postgresql/data
    ports:
      - 5432:5432
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: vendure

Kubernetes

Kubernetes is used to manage multiple containerized applications. This deployment starts the shop container we created above as both worker and server.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vendure-shop
spec:
  selector:
    matchLabels:
      app: vendure-shop
  replicas: 1
  template:
    metadata:
      labels:
        app: vendure-shop
    spec:
      containers:
        - name: server
          image: vendure-shop:latest
          command:
            - node
          args:
            - "dist/index.js"
          env:
          # your env config here
          ports:
            - containerPort: 3000

        - name: worker
          image: vendure-shop:latest
          imagePullPolicy: Always
          command:
            - node
          args:
            - "dist/index-worker.js"
          env:
          # your env config here
          ports:
            - containerPort: 3000

Health/Readiness Checks

If you wish to deploy with Kubernetes or some similar system, you can make use of the health check endpoints.

Server

This is a regular REST route (note: not GraphQL), available at /health.

REQUEST: GET http://localhost:3000/health
{
  "status": "ok",
  "info": {
    "database": {
      "status": "up"
    }
  },
  "error": {},
  "details": {
    "database": {
      "status": "up"
    }
  }
}

Health checks are built on the Nestjs Terminus module. You can also add your own health checks by creating plugins that make use of the HealthCheckRegistryService.

Worker

Although the worker is not designed as an HTTP server, it contains a minimal HTTP server specifically to support HTTP health checks. To enable this, you need to call the startHealthCheckServer() method after bootstrapping the worker:

bootstrapWorker(config)
  .then(worker => worker.startJobQueue())
  .then(worker => worker.startHealthCheckServer({ port: 3020 }))
  .catch(err => {
    console.log(err);
  });

This will make the /health endpoint available. When the worker instance is running, it will return the following:

REQUEST: GET http://localhost:3020/health
{
  "status": "ok"
}