# Docker

You can run EventStoreDB in Docker container as a single node, using insecure mode. It's good enough in most cases to try out the product and for local development purposes.

It's also possible to run a three-node cluster with or without SSL using Docker Compose. Such a setup is closer to what you'd run in production.

# Run with Docker

EventStoreDB has a Docker image available for any platform that supports Docker.

The following command will start the EventStoreDB node using default HTTP port, without security. You can then connect to it using one of the gRPC clients and esdb://localhost:2113?tls=false connection string. The Admin UI will be accessible, but the Stream Browser won't work (it needs AtomPub to be enabled).

docker run --name esdb-node -it -p 2113:2113 -p 1113:1113 \
    eventstore/eventstore:latest --insecure --run-projections=All

If you want to start the node with legacy protocols enabled (TCP and AtomPub), you need to add a couple of other options:

docker run --name esdb-node -it -p 2113:2113 -p 1113:1113 \
    eventstore/eventstore:latest --insecure --run-projections=All \
    --enable-external-tcp --enable-atom-pub-over-http

The command above would run EventStoreDB as a single node without SSL and with the legacy TCP protocol enabled, so you can try out your existing apps with the latest database version.

Then, you'd be able to connect to EventStoreDB with gRPC and TCP clients. Also, the Stream Browser will work in the Admin UI.

In order to sustainably keep the data, we also recommend mapping the database and index volumes.

# Use Docker Compose

You can also run a single-node instance or a three-node secure cluster locally using Docker Compose.

# Insecure single node

You can use Docker Compose to run EventStoreDB in the same setup as the docker run command mentioned before.

Create file docker-compose.yaml with following content:

version: '3.4'

services:
  eventstore.db:
    image: eventstore/eventstore:20.6.1-buster-slim
    environment:
      - EVENTSTORE_CLUSTER_SIZE=1
      - EVENTSTORE_RUN_PROJECTIONS=All
      - EVENTSTORE_START_STANDARD_PROJECTIONS=true
      - EVENTSTORE_EXT_TCP_PORT=1113
      - EVENTSTORE_EXT_HTTP_PORT=2113
      - EVENTSTORE_INSECURE=true
      - EVENTSTORE_ENABLE_EXTERNAL_TCP=true
      - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
    ports:
      - "1113:1113"
      - "2113:2113"
    volumes:
      - type: volume
        source: eventstore-volume-data
        target: /var/lib/eventstore
      - type: volume
        source: eventstore-volume-logs
        target: /var/log/eventstore

volumes:
  eventstore-volume-data:
  eventstore-volume-logs:

Run the instance:

docker-compose up

The command above would run EventStoreDB as a single node without SSL and with the legacy TCP protocol enabled. You also get AtomPub protocol enabled, so you can get the stream browser to work in the Admin UI.

# Secure cluster

With Docker Compose, you can also run a three-node cluster with security enabled. That kind of setup is something you'd expect to use in production.

Create file docker-compose.yaml with following content:

version: '3.5'

services:
  setup:
    image: eventstore/es-gencert-cli:1.0.2
    entrypoint: bash
    user: "1000:1000"
    command: >
      -c "mkdir -p ./certs && cd /certs
      && es-gencert-cli create-ca
      && es-gencert-cli create-node -out ./node1 --dns-names node1.eventstore
      && es-gencert-cli create-node -out ./node2 --dns-names node2.eventstore
      && es-gencert-cli create-node -out ./node3 --dns-names node3.eventstore
      && find . -type f -print0 | xargs -0 chmod 666"
    container_name: setup
    volumes:
      - ./certs:/certs

  node1.eventstore: &template
    image: eventstore/eventstore:20.6.1-buster-slim
    container_name: node1.eventstore
    env_file:
      - vars.env
    environment:
      - EVENTSTORE_EXT_HOST_ADVERTISE_AS=node1.eventstore
      - EVENTSTORE_INT_HOST_ADVERTISE_AS=node1.eventstore
      - EVENTSTORE_GOSSIP_SEED=node2.eventstore:2113,node3.eventstore:2113
      - EVENTSTORE_CERTIFICATE_FILE=/certs/node1/node.crt
      - EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/certs/node1/node.key
      - EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2111
      - EVENTSTORE_ADVERTISE_TCP_PORT_TO_CLIENT_AS=1111
    healthcheck:
      test:
        [
            'CMD-SHELL',
            'curl --fail --insecure https://node1.eventstore:2113/health/live || exit 1',
        ]
      interval: 5s
      timeout: 5s
      retries: 24
    ports:
      - 1111:1113
      - 2111:2113
    volumes:
      - ./certs:/certs
    depends_on:
      - setup
    restart: always

  node2.eventstore:
    <<: *template
    container_name: node2.eventstore
    environment:
      - EVENTSTORE_EXT_HOST_ADVERTISE_AS=node2.eventstore
      - EVENTSTORE_INT_HOST_ADVERTISE_AS=node2.eventstore
      - EVENTSTORE_GOSSIP_SEED=node1.eventstore:2113,node3.eventstore:2113
      - EVENTSTORE_CERTIFICATE_FILE=/certs/node2/node.crt
      - EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/certs/node2/node.key
      - EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2112
      - EVENTSTORE_ADVERTISE_TCP_PORT_TO_CLIENT_AS=1112
    healthcheck:
      test:
        [
            'CMD-SHELL',
            'curl --fail --insecure https://node2.eventstore:2113/health/live || exit 1',
        ]
      interval: 5s
      timeout: 5s
      retries: 24
    ports:
      - 1112:1113
      - 2112:2113

  node3.eventstore:
    <<: *template
    container_name: node3.eventstore
    environment:
      - EVENTSTORE_EXT_HOST_ADVERTISE_AS=node3.eventstore
      - EVENTSTORE_INT_HOST_ADVERTISE_AS=node3.eventstore
      - EVENTSTORE_GOSSIP_SEED=node1.eventstore:2113,node2.eventstore:2113
      - EVENTSTORE_CERTIFICATE_FILE=/certs/node3/node.crt
      - EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/certs/node3/node.key
      - EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2113
      - EVENTSTORE_ADVERTISE_TCP_PORT_TO_CLIENT_AS=1113
    healthcheck:
      test:
        [
            'CMD-SHELL',
            'curl --fail --insecure https://node3.eventstore:2113/health/live || exit 1',
        ]
      interval: 5s
      timeout: 5s
      retries: 24
    ports:
      - 1113:1113
      - 2113:2113

Quite a few settings are shared between the nodes and we use the env file to avoid repeating those settings. So, add the vars.env file to the same location:

EVENTSTORE_CLUSTER_SIZE=3
EVENTSTORE_RUN_PROJECTIONS=All
EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/certs/ca
EVENTSTORE_DISCOVER_VIA_DNS=false
EVENTSTORE_ENABLE_EXTERNAL_TCP=true
EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
EVENTSTORE_ADVERTISE_HOST_TO_CLIENT_AS=localhost

Containers will use the shared volume using the local ./certs directory for certificates. However, if you let Docker to create the directory on startup, the container won't be able to get write access to it. Therefore, create the certs directory manually. You only need to do it once.

mkdir certs

Now you are ready to start the cluster.

docker-compose up

Check the log messages, after some time the elections process completes and you'd be able to connect to each node using the Admin UI. Nodes should be accessible on the loopback address (127.0.0.1) over HTTP and TCP, using ports specified below:

Node TCP port HTTP port
node1 1111 2111
node2 1112 2112
node3 1113 2113

You have tell your client to use secure connection for both TCP and gRPC.

Protocol Connection string
TCP GossipSeeds=localhost:1111,localhost:1112,localhost:1113;ValidateServer=False;UseSslConnection=True
gRPC esdb://localhost:2111,localhost:2112,localhost:2113?tls=true&tlsVerifyCert=false

As you might've noticed, both connection strings have a setting to disable the certificate validation. It would prevent the invalid certificate error since the cluster uses self-signed certificates. However, we do not recommend using this setting in production. Instead, you can either add the CA certificated to the trusted root CA store or instruct your application to use such a certificate.

Last Updated: 10/27/2020, 5:29:44 PM