'How to create a server in Mathematica container?
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.
Solution 1:[1]
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.
The difference between 0.0.0.0 and 127.0.0.1 is explained here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |