cvat Docker & Self-Hosted Deployment

GitHub

Computer Vision Annotation Tool (CVAT) is a leading platform for building high-quality visual datasets for vision AI. It offers open-source, cloud, and...

RAW Compose
1. Pull Image (DOCKERHUB) docker pull library/postgres
2. Docker Run (1-Click Launch) docker run -d --name cvat -p 8080:8080 --restart always postgres:15-alpine
3. Podman Run podman run -d --name cvat -p 8080:8080 --restart always postgres:15-alpine
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://docker.io/library/postgres:15-alpine
5. ORAS Pull (OCI Artifact) oras pull postgres:15-alpine
6. Compose Deployment docker compose up -d
docker-compose.yml
Download .yml
# Copyright (C) 2018-2022 Intel Corporation
# Copyright (C) CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT

name: cvat

x-backend-env: &backend-env
  CVAT_POSTGRES_HOST: cvat_db
  CVAT_REDIS_INMEM_HOST: cvat_redis_inmem
  CVAT_REDIS_INMEM_PORT: 6379
  CVAT_REDIS_ONDISK_HOST: cvat_redis_ondisk
  CVAT_REDIS_ONDISK_PORT: 6666
  CVAT_LOG_IMPORT_ERRORS: 'true'
  CVAT_ALLOW_STATIC_CACHE: '${CVAT_ALLOW_STATIC_CACHE:-no}'
  CVAT_DEFAULT_BACKING_CS_ID:
  CVAT_NUM_PROXIES: '${CVAT_NUM_PROXIES:-1}'
  DJANGO_LOG_SERVER_HOST: vector
  DJANGO_LOG_SERVER_PORT: 8282
  no_proxy: clickhouse,grafana,vector,nuclio,opa,${no_proxy:-}
  SMOKESCREEN_OPTS: ${SMOKESCREEN_OPTS:-}

x-backend-deps: &backend-deps
  cvat_redis_inmem:
    condition: service_started
  cvat_redis_ondisk:
    condition: service_started
  cvat_db:
    condition: service_started
  cvat_clickhouse:
    condition: service_started

x-clickhouse-env: &clickhouse-env
  CLICKHOUSE_HOST: clickhouse
  CLICKHOUSE_PORT: 8123
  CLICKHOUSE_DB: cvat
  CLICKHOUSE_USER: user
  CLICKHOUSE_PASSWORD: user

services:
  cvat_db:
    container_name: cvat_db
    image: postgres:15-alpine
    restart: always
    environment:
      POSTGRES_USER: root
      POSTGRES_DB: cvat
      POSTGRES_HOST_AUTH_METHOD: trust
    volumes:
      - cvat_db:/var/lib/postgresql/data
    networks:
      - cvat

  cvat_redis_inmem:
    container_name: cvat_redis_inmem
    image: redis:7.2.11-alpine
    restart: always
    command: [
      "redis-server",
      "--save", "60", "100",
      "--appendonly", "yes",
    ]
    volumes:
      - cvat_inmem_db:/data
    networks:
      - cvat

  cvat_redis_ondisk:
    container_name: cvat_redis_ondisk
    image: apache/kvrocks:2.15.0
    restart: always
    # The kvrocks image a) has a healthcheck command, and b) has a root process
    # that doesn't reap children, so it's susceptible to the problem described here:
    # <https://stackoverflow.com/a/77109064>. Kvrocks also uses a tiny timeout for
    # its healthcheck command (1s), which makes the problem more likely to manifest.
    # Use a separate init process as a workaround.
    init: true
    volumes:
      - cvat_cache_db:/var/lib/kvrocks
    networks:
      - cvat
    command: [
      "--compact-cron", "0 3 * * *",
      ]

  cvat_server:
    container_name: cvat_server
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on:
      <<: *backend-deps
      cvat_opa:
        condition:
          service_started
    environment:
      <<: [*backend-env, *clickhouse-env]
      DJANGO_MODWSGI_EXTRA_ARGS: ''
      ALLOWED_HOSTS: '*'
      ADAPTIVE_AUTO_ANNOTATION: 'false'
      NUMPROCS: 2
      CVAT_ANALYTICS: 1
      CVAT_BASE_URL:
      ONE_RUNNING_JOB_IN_QUEUE_PER_USER:
    command: init run server nginx
    labels:
      traefik.enable: "true"
      traefik.http.services.cvat.loadbalancer.server.port: "8080"
      traefik.http.routers.cvat.rule:
        Host(`${CVAT_HOST:-localhost}`) &&
        (PathPrefix(`/api/`) || PathPrefix(`/static/`) || PathPrefix(`/admin`)
          || PathPrefix(`/django-rq`))
      traefik.http.routers.cvat.entrypoints: web
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      cvat:
        aliases:
          - cvat-server

  cvat_worker_utils:
    container_name: cvat_worker_utils
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      CVAT_REDIS_INMEM_PASSWORD: ''
      NUMPROCS: 1
    command: run worker notifications cleaning
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_import:
    container_name: cvat_worker_import
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      NUMPROCS: 2
    command: run worker import --with-scheduler
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_export:
    container_name: cvat_worker_export
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: [*backend-env, *clickhouse-env]
      NUMPROCS: 2
    command: run worker export --with-scheduler
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_annotation:
    container_name: cvat_worker_annotation
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      NUMPROCS: 1
    command: run worker annotation
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_webhooks:
    container_name: cvat_worker_webhooks
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      NUMPROCS: 1
    command: run worker webhooks --with-scheduler
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_quality_reports:
    container_name: cvat_worker_quality_reports
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      NUMPROCS: 1
    command: run worker quality_reports
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_chunks:
    container_name: cvat_worker_chunks
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      NUMPROCS: 2
    command: run worker chunks
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_worker_consensus:
    container_name: cvat_worker_consensus
    image: cvat/server:${CVAT_VERSION:-dev}
    restart: always
    depends_on: *backend-deps
    environment:
      <<: *backend-env
      NUMPROCS: 1
    command: run worker consensus
    volumes:
      - cvat_data:/home/django/data
      - cvat_keys:/home/django/keys
      - cvat_logs:/home/django/logs
    networks:
      - cvat

  cvat_ui:
    container_name: cvat_ui
    image: cvat/ui:${CVAT_VERSION:-dev}
    restart: always
    depends_on:
      - cvat_server
    labels:
      traefik.enable: "true"
      traefik.http.services.cvat-ui.loadbalancer.server.port: "8000"
      traefik.http.routers.cvat-ui.rule: Host(`${CVAT_HOST:-localhost}`)
      traefik.http.routers.cvat-ui.entrypoints: web
    networks:
      - cvat

  traefik:
    image: traefik:v3.6
    container_name: traefik
    restart: always
    ports:
      - 8080:8080
      - 8090:8090
    environment:
      CVAT_HOST: ${CVAT_HOST:-localhost}
      DJANGO_LOG_VIEWER_HOST: grafana
      DJANGO_LOG_VIEWER_PORT: 3000

      TRAEFIK_ACCESSLOG_FORMAT: json
      TRAEFIK_ACCESSLOG_FIELDS_DEFAULTMODE: drop
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_ClientHost: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_DownstreamContentSize: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_DownstreamStatus: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_Duration: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_RequestHost: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_RequestMethod: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_RequestPath: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_RequestPort: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_RequestProtocol: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_RouterName: keep
      TRAEFIK_ACCESSLOG_FIELDS_NAMES_StartUTC: keep

      TRAEFIK_LOG_FORMAT: json
      TRAEFIK_ENTRYPOINTS_web_ADDRESS: :8080
      TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: "false"
      TRAEFIK_PROVIDERS_DOCKER_NETWORK: cvat
      TRAEFIK_PROVIDERS_FILE_DIRECTORY: /etc/traefik/rules
    # Uncomment to get Traefik dashboard
    #   TRAEFIK_API_DASHBOARD: "true"
    #   TRAEFIK_ENTRYPOINTS_dashboard_ADDRESS: :8090
    # labels:
    #   traefik.enable: "true"
    #   traefik.http.routers.dashboard.entrypoints: dashboard
    #   traefik.http.routers.dashboard.service: api@internal
    #   traefik.http.routers.dashboard.rule: Host(`${CVAT_HOST:-localhost}`)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./components/analytics/grafana_conf.yml:/etc/traefik/rules/grafana_conf.yml:ro
    networks:
      - cvat
    logging:
      driver: "json-file"
      options:
        max-size: 100m
        max-file: "10"

  cvat_opa:
    container_name: cvat_opa
    image: openpolicyagent/opa:1.12.2
    restart: always
    networks:
      cvat:
        aliases:
          - opa
    command:
      - run
      - --server
      - --addr=:8181
      - --log-level=error
      - --set=services.cvat.url=http://cvat-server:8080
      - --set=bundles.cvat.service=cvat
      - --set=bundles.cvat.resource=/api/auth/rules
      - --set=bundles.cvat.polling.min_delay_seconds=5
      - --set=bundles.cvat.polling.max_delay_seconds=15

  cvat_clickhouse:
    container_name: cvat_clickhouse
    image: clickhouse/clickhouse-server:23.11-alpine
    restart: "always"
    environment:
      <<: *clickhouse-env
    networks:
      cvat:
        aliases:
          - clickhouse
    volumes:
      - cvat_events_db:/var/lib/clickhouse/

  cvat_vector:
    container_name: cvat_vector
    image: timberio/vector:0.26.0-alpine
    user: "1000:1000" # Workaround for <https://github.com/vectordotdev/vector/issues/1599>.
    restart: always
    depends_on:
      - cvat_clickhouse
    environment:
      <<: *clickhouse-env
    networks:
      cvat:
        aliases:
          - vector
    volumes:
      - type: bind
        source: ./components/analytics/vector/vector.toml
        target: /etc/vector/vector.toml
        read_only: true
      - type: tmpfs
        target: /vector-data-dir

  cvat_grafana:
    image: grafana/grafana-oss:10.1.2
    restart: always
    container_name: cvat_grafana
    environment:
      <<: *clickhouse-env
      GF_PATHS_PROVISIONING: /etc/grafana/provisioning
      GF_AUTH_BASIC_ENABLED: false
      GF_AUTH_ANONYMOUS_ENABLED: true
      GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
      GF_AUTH_DISABLE_LOGIN_FORM: true
      GF_SERVER_ROOT_URL: http://${CVAT_HOST:-localhost}/analytics
      GF_INSTALL_PLUGINS: 'grafana-clickhouse-datasource 4.8.2'
      GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH: /var/lib/grafana/dashboards/all_events.json
    volumes:
      - ./components/analytics/grafana/dashboards/:/var/lib/grafana/dashboards/:ro
    entrypoint:
      - sh
      - -euc
      - |
        mkdir -p /etc/grafana/provisioning/datasources
        cat << 'EOF' > /etc/grafana/provisioning/datasources/ds.yaml
        apiVersion: 1
        datasources:
          - name: 'ClickHouse'
            type: 'grafana-clickhouse-datasource'
            isDefault: true
            jsonData:
              defaultDatabase: $${CLICKHOUSE_DB}
              port: $${CLICKHOUSE_PORT}
              server: $${CLICKHOUSE_HOST}
              username: $${CLICKHOUSE_USER}
              tlsSkipVerify: false
              protocol: http
            secureJsonData:
              password: $${CLICKHOUSE_PASSWORD}
            editable: true
        EOF
        mkdir -p /etc/grafana/provisioning/dashboards
        cat << EOF > /etc/grafana/provisioning/dashboards/dashboard.yaml
        apiVersion: 1
        providers:
          - name: cvat-logs
            type: file
            updateIntervalSeconds: 30
            options:
              path:  /var/lib/grafana/dashboards
              foldersFromFilesStructure: true
        EOF
        exec /run.sh
    networks:
      cvat:
        aliases:
          - grafana

volumes:
  cvat_db:
  cvat_data:
  cvat_keys:
  cvat_logs:
  cvat_inmem_db:
  cvat_events_db:
  cvat_cache_db:

networks:
  cvat: