Search code examples
dockerdocker-composedockerfiledocker-machine

Integrate two docker apps - Docker compose and Docker run


I am trying to integrate two apps. Currently I have a docker-compose file with two services and another docker - run command to start another service. Based on my configuration below, I expect OHIF Viewer running at port 3030 and Orthanc running at 8042 to be interconnected. I mean if I upload an image in Orthanc, I should be able to see them in OHIF viewer. Currently I am able to view both Orthanc and OHIF viewer in their respective ports but I don't see any interaction between them. ex: I don't see my image (uploaded in Orthanc) in OHIF Viewer.

I thought the dockersupport-app.json file is responsible for this interaction as it has info regarding port 8042 and being used in "Volumes" section of docker-compose.yml file.

Here is my docker-compose file

version: '3.6'
  services:
     mongo:
   image: "mongo:latest"
   container_name: ohif-mongo
   ports:
     - "27017:27017"

  viewer:
     image: ohif/viewer:latest
     container_name: ohif-viewer
     ports:
       - "3030:80"
     environment:
       - MONGO_URL=mongodb://mongo:27017/ohif
     extra_hosts:
      - "pacsIP:172.xx.xxx.xxx"
     volumes:
      - ./dockersupport-app.json:/app/app.json

The dockersupport-app.json looks like as shown below

  {
 "apps" : [{
 "name"        : "ohif-viewer",
  "script"      : "main.js",
  "watch"       : true,
  "merge_logs"  : true,
  "cwd"         : "/app/bundle/",
  "env": {
  "METEOR_SETTINGS": {
          "servers": {
            "dicomWeb": [
                                {
                "name": "Orthanc",
                "wadoUriRoot": "http://pacsIP:8042/wado", # these ports 
                "qidoRoot": "http://pacsIP:8042/dicom-web", #these ports
                "wadoRoot": "http://pacsIP:8042/dicom-web", #these ports
                "qidoSupportsIncludeField": false,
                "imageRendering": "wadouri",
                "thumbnailRendering": "wadouri",
                "requestOptions": {
                  "auth": "orthanc:orthanc",
                  "logRequests": true,
                  "logResponses": false,
                                 "logTiming": true
                    }
                  }
                ]
              },
              "defaultServiceType": "dicomWeb",
              "public": {
                            "ui": {
                                    "studyListDateFilterNumDays": 1
                            }
                    },
              "proxy": {
                "enabled": true
              }
            }
              }
           }]
    }

My docker run command to start Orthanc in port 8042 looks like as shown below

docker run -p 4242:4242 -p 8042:8042 --rm --name orthanc -v 
 $(pwd)/orthanc/config/orthanc.json:/etc/orthanc/orthanc.json -v 
 $(pwd)/orthanc/config/orthanc-db:/var/lib/orthanc/orthanc-db 
  jodogne/orthanc- 
   plugins /etc/orthanc --verbose

Can you please help me as to how can I integrate these two? The above all files/codes is the info I have.


Solution

  • The configuration is not working mainly because dockersupport-app.json is not read by the application. Below is a working example based on the online documentation of the project.

    Also another problem is the access to the dicomWeb server. You are using pacsIP:8042, which would be ok if the request was initiated from inside the container. But this is a javascript application and the request is initiated by the browser on the host. For this reason "localhost" should be used.

    This is a working configuration:

    version: '3.6'
    
    services:
      mongo:
       image: "mongo:latest"
       container_name: ohif-mongo
       ports:
         - "27017:27017"
    
      viewer:
         image: ohif/viewer:latest
         container_name: ohif-viewer
         ports:
           - "3030:80"
         environment:
           - MONGO_URL=mongodb://mongo:27017/ohif
         volumes:
          - ./config/default.js:/usr/share/nginx/html/config/default.js
         depends_on:
          - mongo
          - proxy
    
      orthanc:
        image: jodogne/orthanc-plugins
        ports:
          - "4242:4242"
          - "8042:8042"
        volumes:
          # Config
          - ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
          # Persist data
          - ./volumes/orthanc-db/:/var/lib/orthanc/db/
        command: "/etc/orthanc --verbose"
    
      proxy:
        image: nginx:1.15-alpine
        ports:
          - 8899:80
        volumes:
          - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
        depends_on: 
          - orthanc
        restart: unless-stopped
    

    In the config folder place the files:

    default.js

    window.config = {
        // default: '/'
        routerBasename: '/',
        // default: ''
        relativeWebWorkerScriptsPath: '',
        servers: {
          dicomWeb: [
            {
              name: 'DCM4CHEE',
              wadoUriRoot: 'http://localhost:8899/wado',
              qidoRoot: 'http://localhost:8899/dicom-web',
              wadoRoot: 'http://localhost:8899/dicom-web',
              qidoSupportsIncludeField: true,
              imageRendering: 'wadouri',
              thumbnailRendering: 'wadouri',
              requestOptions: {
                requestFromBrowser: true,
                auth: "orthanc:orthanc",
                "logRequests": true,
                "logResponses": true,
                 "logTiming": true
              },
            },
          ],
        },
        // Extensions should be able to suggest default values for these?
        // Or we can require that these be explicitly set
        hotkeys: [
          // ~ Global
          {
            commandName: 'incrementActiveViewport',
            label: 'Next Image Viewport',
            keys: ['right'],
          },
          {
            commandName: 'decrementActiveViewport',
            label: 'Previous Image Viewport',
            keys: ['left'],
          },
          // Supported Keys: https://craig.is/killing/mice
          // ~ Cornerstone Extension
          { commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
          { commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
          { commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
          {
            commandName: 'flipViewportVertical',
            label: 'Flip Horizontally',
            keys: ['h'],
          },
          {
            commandName: 'flipViewportHorizontal',
            label: 'Flip Vertically',
            keys: ['v'],
          },
          { commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] },
          { commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] },
          { commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] },
          { commandName: 'resetViewport', label: 'Reset', keys: ['space'] },
          // clearAnnotations
          // nextImage
          // previousImage
          // firstImage
          // lastImage
          {
            commandName: 'nextViewportDisplaySet',
            label: 'Previous Series',
            keys: ['pagedown'],
          },
          {
            commandName: 'previousViewportDisplaySet',
            label: 'Next Series',
            keys: ['pageup'],
          },
          // ~ Cornerstone Tools
          { commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
        ],
      };
    

    nginx.conf

    worker_processes 1;
    
    events { worker_connections 1024; }
    
    http {
    
        upstream orthanc-server {
            server orthanc:8042;
        }
    
        server {
            listen [::]:80 default_server;
            listen 80;
    
            # CORS Magic
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow_Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
    
            location / {
    
                if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' '*';
                    add_header 'Access-Control-Allow_Credentials' 'true';
                    add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
                    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
                }
    
                proxy_pass         http://orthanc:8042;
                proxy_redirect     off;
                proxy_set_header   Host $host;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Host $server_name;
    
                # CORS Magic
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow_Credentials' 'true';
                add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
                add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
            }
        }
    }
    

    orthanc.json

    {
      "Name": "Orthanc inside Docker",
      "StorageDirectory": "/var/lib/orthanc/db",
      "IndexDirectory": "/var/lib/orthanc/db",
      "StorageCompression": false,
      "MaximumStorageSize": 0,
      "MaximumPatientCount": 0,
      "LuaScripts": [],
      "Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"],
      "ConcurrentJobs": 2,
      "HttpServerEnabled": true,
      "HttpPort": 8042,
      "HttpDescribeErrors": true,
      "HttpCompressionEnabled": true,
      "DicomServerEnabled": true,
      "DicomAet": "ORTHANC",
      "DicomCheckCalledAet": false,
      "DicomPort": 4242,
      "DefaultEncoding": "Latin1",
      "DeflatedTransferSyntaxAccepted": true,
      "JpegTransferSyntaxAccepted": true,
      "Jpeg2000TransferSyntaxAccepted": true,
      "JpegLosslessTransferSyntaxAccepted": true,
      "JpipTransferSyntaxAccepted": true,
      "Mpeg2TransferSyntaxAccepted": true,
      "RleTransferSyntaxAccepted": true,
      "UnknownSopClassAccepted": false,
      "DicomScpTimeout": 30,
    
      "RemoteAccessAllowed": true,
      "SslEnabled": false,
      "SslCertificate": "certificate.pem",
      "AuthenticationEnabled": false,
      "RegisteredUsers": {
        "test": "test"
      },
      "DicomModalities": {},
      "DicomModalitiesInDatabase": false,
      "DicomAlwaysAllowEcho": true,
      "DicomAlwaysAllowStore": true,
      "DicomCheckModalityHost": false,
      "DicomScuTimeout": 10,
      "OrthancPeers": {},
      "OrthancPeersInDatabase": false,
      "HttpProxy": "",
    
      "HttpVerbose": true,
    
      "HttpTimeout": 10,
      "HttpsVerifyPeers": true,
      "HttpsCACertificates": "",
      "UserMetadata": {},
      "UserContentType": {},
      "StableAge": 60,
      "StrictAetComparison": false,
      "StoreMD5ForAttachments": true,
      "LimitFindResults": 0,
      "LimitFindInstances": 0,
      "LimitJobs": 10,
      "LogExportedResources": false,
      "KeepAlive": true,
      "TcpNoDelay": true,
      "HttpThreadsCount": 50,
      "StoreDicom": true,
      "DicomAssociationCloseDelay": 5,
      "QueryRetrieveSize": 10,
      "CaseSensitivePN": false,
      "LoadPrivateDictionary": true,
      "Dictionary": {},
      "SynchronousCMove": true,
      "JobsHistorySize": 10,
      "SaveJobs": true,
      "OverwriteInstances": false,
      "MediaArchiveSize": 1,
      "StorageAccessOnFind": "Always",
      "MetricsEnabled": true,
    
      "DicomWeb": {
        "Enable": true,
        "Root": "/dicom-web/",
        "EnableWado": true,
        "WadoRoot": "/wado",
        "Host": "127.0.0.1",
        "Ssl": false,
        "StowMaxInstances": 10,
        "StowMaxSize": 10,
        "QidoCaseSensitive": false
      }
    }
    

    With this configuration in place run:

    docker-compose up -d viewer
    

    Upload images: http://localhost:8899

    View the images in the viewer: http://localhost:3030