Home > front end >  How to create a server in Mathematica container?
How to create a server in Mathematica container?

Time:05-03

I try to create a server in a Docker container using Wolfram Language. Docker parameters and Wolfram script, which starts a server inside it, are in the attached files:

  • docker-compose.yml
services:
  wm:
    build: .
    volumes:
      - .:/app:ro
    ports:
      - "61104:8000"
    restart: on-failure
    hostname: wm
    container_name: wm
    working_dir: /app
    entrypoint: wolframscript -file /app/tcp_server.wls
  • Dockerfile
FROM ubuntu:20.04

ENV DEBIAN_FRONTEND noninteractive
ENV DEBCONF_NONINTERACTIVE_SEEN true

RUN apt update -yq \
    && apt install -yq xz-utils curl gcc tzdata musl-dev python3-dev python3-pip clang \
    && dpkg-reconfigure tzdata \
    && apt install -y avahi-daemon wget sshpass sudo locales \
    locales-all ssh nano expect libfontconfig1 libgl1-mesa-glx libasound2 \
    build-essential mosquitto mosquitto-clients libnss-mdns mdns-scan nodejs \
    && apt clean \
    && apt autoremove -y \
    && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen

COPY ./Mathematica_12.1.1_LINUX.sh /root/

WORKDIR /root

RUN ./Mathematica_12.1.1_LINUX.sh --target ./extract --nox11 -- -auto -nodesktop \
    && systemctl enable avahi-daemon \
    && echo '!10.55.229.55' > /usr/local/Wolfram/Mathematica/12.1/Configuration/Licensing/mathpass
  • tcp_server.wls
#!/usr/bin/env wolframscript
(* ::Package:: *)

httpResponseTemplate[text_] := StringTemplate[
  "HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: `2`
Date: Wed, 26 Jun 2013 07:00:56 GMT

`1`"
][text, StringLength[text]];

listener = SocketListen[address,
    Module[{
      socket = #SourceSocket,
      message = #Data,
      func,
      query,
      result
    },
(*      Print[message];*)
      query = StringExtract[message, "\n" -> 1];
      func = StringCases[query, "GET /" ~~ f__ ~~ " HTTP/1.1" :> f, 1][[1]];
      result = ToExpression[func][];
      BinaryWrite[socket,
        httpResponseTemplate[
          "Hello, World!\nYou called the " <> func <> "\nResult is: " <>
              ToString[result] <> "\n"
        ]
      ]
    ]&
];


While[True, Pause[60]]

I found that described Wolfram server has a peculiarity. The first argument of Wolfram function SocketListen can not contain hostname from docker-compose file as a host address. However, absence of the docker hostname leads to inaccessibility of the server from the outside the container.

Need of the indication of the hostname can be proved by a netcat server, created inside the container. For example, the first variant below creates an accessible server, but the others — a server, inaccessible from the outside.

echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l wm 8000
echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l localhost 8000
echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l 127.0.0.1 8000

Variants for Wolfram, similar to the second and third ones, give the same result: inaccessibility from the outside. The tcp_server.wls file contains symbol address. It must be replaced with an exact string or integer before use. Here are Wolfram errors for all variants I've tried below.

"http://wm:8000" -> SocketOpen::addrspec: The host specification http://wm:8000 is wrong because the port number conflicts with the scheme specification

"http://localhost:8000" -> SocketOpen::addrspec: The host specification http://localhost:8000 is wrong because the port number conflicts with the scheme specification

"http://127.0.0.1:8000" -> SocketOpen::addrspec: The host specification http://127.0.0.1:8000 is wrong because the port number conflicts with the scheme specification

"wm:8000" -> SocketOpen::zmqexception: A ZeroMQ exception was thrown - No such device (code 19)

"localhost:8000" -> SocketOpen::zmqexception: A ZeroMQ exception was thrown - No such device (code 19)

"127.0.0.1:8000" -> without errors, but inaccessible from the outside (accessible only from inside)

":8000" -> SocketOpen::addrspec: The host specification :8000 is wrong because it has an invalid domain specification

8000 -> without errors, but inaccessible from the outside (accessible only from inside)

The same was for other ports.

How can I force Wolfram to listen http://wm:8000 or how to change docker settings in the sense of a substitution of an actual hostname by 127.0.0.1 while transfer it via docker network?

Before you build the Mathematica image, you need to change a licensing method inside the Dockerfile to the one you use (currently my network license is used) and download the linux installer Mathematica_12.1.1_LINUX.sh from Wolfram official site and put it into the folder with the three attachments from the beginning of this post.

Note, that this is a draft of a project. The full one will contain other services inside docker-compose.yml, e.g. Go server, that shall be accessible from the outside too.

CodePudding user response:

My friends help to solve my problem.

The first argument of the function SocketListen should be "0.0.0.0:8000". Then, http://wm:61104/f requested from the outside will link to the container.

  • Related