Docker Configuration

Once we’ve configured the ocs site config file we need to define our Docker environment. We do that with a docker-compose.yaml file. We recommend you keep these files together, in a version controlled repository. These files will differ for each site depending on your hardware setup. Below we cover a simple configuration.

docker-compose.yaml

Docker Compose is used to manage all the containers required to run OCS. The Docker Compose configuration file defines the containers that we will control.

Note

The filename is important here, as the docker-compose.yaml path is the default one parsed by the docker compose tool. A configuration file can be specified with the -f flag.

Details about configuring individual Agents can be found in the Agent Reference section of this documentation. An example docker-compose.yaml file looks something like this (note this does not contain all possibly configured components):

version: '3.7'
volumes:
  grafana-storage:

services:
  # --------------------------------------------------------------------------
  # Grafana for the live monitor.
  # --------------------------------------------------------------------------
  grafana:
    image: grafana/grafana:latest
    restart: always
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - grafana-storage:/var/lib/grafana

  # InfluxDB Backend for Grafana
  influxdb:
    image: influxdb:1.7
    container_name: "influxdb"
    restart: always
    ports:
      - "8086:8086"
    environment:
      - INFLUXDB_HTTP_LOG_ENABLED=false
    volumes:
      - /srv/influxdb:/var/lib/influxdb

  # --------------------------------------------------------------------------
  # Crossbar
  # --------------------------------------------------------------------------
  crossbar:
    image: simonsobs/ocs-crossbar:latest
    ports:
      - "127.0.0.1:8001:8001" # expose for OCS
    environment:
      - PYTHONUNBUFFERED=1

  # --------------------------------------------------------------------------
  # OCS Agents
  # --------------------------------------------------------------------------
  ocs-aggregator:
    image: simonsobs/ocs:latest
    hostname: ocs-docker
    user: "9000"
    environment:
      - INSTANCE_ID=aggregator
    volumes:
      - ${OCS_CONFIG_DIR}:/config:ro
      - "/data:/data"
    depends_on:
      - "crossbar"

  ocs-influx-publisher:
    image: simonsobs/ocs:latest
    hostname: ocs-docker
    environment:
      - INSTANCE_ID=influxagent
    volumes:
      - ${OCS_CONFIG_DIR}:/config:ro

  ocs-LSA99ZZ:
    image: simonsobs/ocs-lakeshore372-agent:latest
    hostname: grumpy-docker
    network_mode: "host"
    environment:
      - INSTANCE_ID=LSA99ZZ
      - SITE_HUB=ws://10.10.10.2:8001/ws
      - SITE_HTTP=http://10.10.10.2:8001/call
    volumes:
      - ${OCS_CONFIG_DIR}:/config:ro

Warning

Bind mounts are a system unique property. This is especially true for ones which use absolute paths. If they exist in any reference configuration file, they will need to be updated for your system.

Understanding what is going on in this configuration file is key to getting a system that is working smoothly. The Docker Compose reference explains the format of the file, for details on syntax you are encouraged to check the official documentation.

In the remainder of this section we will go over our example. The first line defines the version of the docker compose file format, which corresponds to the Docker Engine version you are running. You likely do not have to change this, unless you need a new feature available in a more recent version.

Every block below services: defines a Docker container. Let’s look at one example container configuration. This example does not represent something we would want to actually use, but contains configuration lines relevant to many other container configurations:

example-container-name:
  image: simonsobs/example-docker-image:latest
  restart: always
  hostname: ocs-docker
  user: "9000"
  ports:
    - "127.0.0.1:8001:8001" # expose for OCS
  volumes:
    - /data:/data:ro
    - ./.crossbar:/app/.crossbar
  environment:
      MAX_POINTS: 1000
      SQL_HOST: "database"
      SQL_DB: "files"
  depends_on:
    - "crossbar"
    - "database"

The top line, example-container-name, defines the name of the service to docker compose. These must be unique. image defines the docker image used for the container. Associated with the image is the image tag, in this case “latest”. This defines the version of the image. A container can be thought of as a copy of an image. The container is what actually runs when you startup your docker service. restart allows you to define when a container can be automatically restarted, in this instance, always. hostname defines the hostname internal to the container. This is used in the OCS container configurations in conjunction with the ocs-site-configs file. We recommend appending “-docker” to the hostname to distinguish Agents running within containers from those running directly on the host. user defines the user used inside the container. This is only used on the aggregator agent configuration.

Warning

Pay attention to your version tags. “latest” is a convention in Docker to roughly mean the “most up to date” image. It is the default if a tag is left off. However, the “latest” image is subject to change. Pulling a “latest” version today will not be guaranteed to get you the same image at another time.

What this means is for reproducability of your deployment, and perhaps for your own sanity, we recommend you use explicit version tags. Tags can be identified on an image’s Docker Hub page.

ports defines the ports exposed from the container to the host. This is used on containers like the crossbar container and the grafana container. volumes defines mounted docker volumes and bind mounts to the host system. The syntax here is /host/system/path:/container/system/path. Alternatively the host system path can be a named docker volume, in which case docker manages the storage. environment defines environment variables inside the container. This is used for configuring behaviors inside the containers. depends_on means Docker Compose will wait for the listed containers to start before starting this container. This does not mean the services will be ready, but the container will be started.

Note

Environment variables can be used within a docker compose configuration file. This is done for the OCS_CONFIG_DIR mount for the OCS agents in the default template. For more information see the docker compose documentation.

If you use this functionality, be aware that environment variables must be explicitly passed to sudo via the -E flag, for example: $ sudo -E docker compose up -d

For more details on configurations for individual containers, see the service documentation pages, for instance in the Agent Reference section.

Considerations for Deployment

The above examples are simple and meant to get you running quickly. However, they might not be the best configuration for deployment. One inconvenient thing is everything is managed in a single docker-compose.yml file. This means when you bring the system down, or restart it, all components are shutdown, this includes Grafana, which is one thing you might want running all the time, even if not actively collecting data with OCS, since you might want to look at past data. To achieve this you can separate the long-running services to different configuration files in separate directories, for instance:

.
├── default.yaml
├── docker-compose.yml
├── influxdb
│   └── docker-compose.yml
└── crossbar
    └── docker-compose.yml

Where the separate compose files would look something like:

# influxdb/docker-compose.yml
version: '3.7'
networks:
  default:
    external:
      name: ocs-net
services:
  influxdb:
    image: "influxdb:1.7"
    container_name: "influxdb"
    restart: always
    ports:
      - "8086:8086"
    environment:
      - INFLUXDB_HTTP_LOG_ENABLED=false
    volumes:
      - /srv/influxdb:/var/lib/influxdb
# crossbar/docker-compose.yml
version: '3.7'
networks:
  default:
    external:
      name: ocs-net
services:
  crossbar:
    image: simonsobs/ocs-crossbar:latest
    restart: always
    ports:
      - "127.0.0.1:8001:8001" # expose for OCS
    environment:
      - PYTHONUNBUFFERED=1
# web/docker-compose.yml
version: '3.7'
networks:
  default:
    external:
      name: ocs-net
volumes:
  grafana-storage:
services:
  grafana:
    image: grafana/grafana:latest
    restart: always
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - grafana-storage:/var/lib/grafana
# docker-compose.yml
version: '3.7'
networks:
  default:
    external:
      name: ocs-net
services:
  ocs-aggregator:
    image: simonsobs/ocs:latest
    hostname: ocs-docker
    user: "9000"
    environment:
      - INSTANCE_ID=aggregator
    volumes:
      - ${OCS_CONFIG_DIR}:/config:ro
      - "/data:/data"
    depends_on:
      - "crossbar"

  ocs-influx-publisher:
    image: simonsobs/ocs:latest
    hostname: ocs-docker
    environment:
      - INSTANCE_ID=influxagent
    volumes:
      - ${OCS_CONFIG_DIR}:/config:ro

  ocs-LSA99ZZ:
    image: simonsobs/ocs-lakeshore372-agent:latest
    hostname: grumpy-docker
    network_mode: "host"
    environment:
      - INSTANCE_ID=LSA99ZZ
      - SITE_HUB=ws://10.10.10.2:8001/ws
      - SITE_HTTP=http://10.10.10.2:8001/call
    volumes:
      - ${OCS_CONFIG_DIR}:/config:ro

Once the separate influxdb, crossbar, and web services are brought up, they should rarely need to be restarted, and are configured to automatically start at boot. This allows one to restart or shutdown the OCS Agents completely separately without worry of bringing down other components of the system.

Note

This uses a Docker network, “ocs-net”, which needs to be configured. Details can be found in Multiple-Configuration Files.