***

title: "Using docker"
metaTitle: "Running Vendure with Docker, Docker Compose, and Kubernetes"
metaDescription: "Containerize your Vendure server and worker with Docker, orchestrate services using Docker Compose, deploy on Kubernetes, and configure health check endpoints."
order: 3
--------

[Docker](https://docs.docker.com/) is a technology which allows you to run your Vendure application inside a [container](https://docs.docker.com/get-started/#what-is-a-container).
The default installation with `@vendure/create` includes a sample Dockerfile. For production, a multi-stage Dockerfile keeps build-time dependencies out of the final image:

```dockerfile title="Dockerfile"
FROM node:22-bookworm-slim AS builder

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
RUN npm run build:dashboard
RUN npm prune --omit=dev

FROM node:22-bookworm-slim AS runtime

WORKDIR /usr/src/app
ENV NODE_ENV=production

COPY --from=builder /usr/src/app/package*.json ./
COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/static ./static

CMD ["npm", "run", "start:server"]
```

New projects created with `@vendure/create` include the `build:dashboard` script. If your project does not use the Dashboard, remove the `RUN npm run build:dashboard` line.

This Dockerfile can then be built into an "image" using:

```bash
docker build -t vendure .
```

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

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

# Run the worker
docker run -d --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.

The worker command does not publish port 3000 because the worker does not serve the Vendure API. If you enable the worker health check server, publish that health check port instead.

## Docker Compose

Managing multiple docker containers can be made easier using [Docker Compose](https://docs.docker.com/compose/). In the below example, we use
the same Dockerfile defined above, and we also define a Postgres database to connect to:

```yaml
version: "3"
services:
  server:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    command: ["npm", "run", "start:server"]
    depends_on:
      - database
    environment:
      DB_HOST: database
      DB_PORT: 5432
      DB_NAME: vendure
      DB_USERNAME: postgres
      DB_PASSWORD: password
      COOKIE_SECRET: change-me
      SUPERADMIN_USERNAME: superadmin
      SUPERADMIN_PASSWORD: change-me
  worker:
    build:
      context: .
      dockerfile: Dockerfile
    command: ["npm", "run", "start:worker"]
    depends_on:
      - database
    environment:
      DB_HOST: database
      DB_PORT: 5432
      DB_NAME: vendure
      DB_USERNAME: postgres
      DB_PASSWORD: password
      COOKIE_SECRET: change-me
      SUPERADMIN_USERNAME: superadmin
      SUPERADMIN_PASSWORD: change-me
  database:
    image: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: vendure

volumes:
  postgres_data:
```

## Kubernetes

[Kubernetes](https://kubernetes.io/) is used to manage multiple containerized applications.
This deployment starts the Vendure image we created above as both worker and server.

```yaml
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
```

## 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`.

```text
REQUEST: GET http://localhost:3000/health
```

```json
{
  "status": "ok",
  "info": {
    "database": {
      "status": "up"
    }
  },
  "error": {},
  "details": {
    "database": {
      "status": "up"
    }
  }
}
```

You can also add your own health checks by creating plugins that make use of the [HealthCheckRegistryService](/current/core/reference/typescript-api/health-check/health-check-registry-service/).

### 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:

```ts
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:

```text
REQUEST: GET http://localhost:3020/health
```

```json
{
  "status": "ok"
}
```
