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.