如何在 Mathematica 容器中创建服务器?
How to create a server in Mathematica container?
我尝试使用 Wolfram 语言在 Docker 容器中创建一个服务器。 Docker参数和启动服务器的Wolfram脚本在附件中:
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]]
我发现所描述的 Wolfram 服务器有一个特点。 Wolfram 函数 SocketListen
的第一个参数不能包含来自 docker-compose 文件的主机名作为主机地址。但是,缺少 docker 主机名会导致无法从容器外部访问服务器。
主机名指示的需要可以通过在容器内创建的 netcat 服务器来证明。例如,下面的第一个变体创建了一个可访问的服务器,但其他变体创建了一个从外部无法访问的服务器。
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
Wolfram 的变体,类似于第二个和第三个,给出相同的结果:无法从外部访问。 tcp_server.wls
文件包含符号 address
。使用前必须将其替换为确切的字符串或整数。以下是我在下面尝试过的所有变体的 Wolfram 错误。
"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)
其他端口也是如此。
我如何强制 Wolfram 收听 http://wm:8000
或如何在通过 127.0.0.1 替换实际主机名的意义上更改 docker 设置,同时通过docker网络?
在构建 Mathematica 图像之前,您需要将 Dockerfile
中的许可方法更改为您使用的方法(目前使用我的网络许可)并下载 linux 安装程序 Mathematica_12.1.1_LINUX.sh
从Wolfram官网下载,并放入post.
开头三个附件的文件夹中
请注意,这是一个项目草稿。完整的将在 docker-compose.yml
中包含其他服务,例如Go服务器,也应该可以从外部访问。
朋友们帮我解决了问题
函数 SocketListen
的第一个参数应该是 "0.0.0.0:8000"
。然后,从外部请求的 http://wm:61104/f
将 link 到容器。
解释了 0.0.0.0 和 127.0.0.1 之间的区别 here。
我尝试使用 Wolfram 语言在 Docker 容器中创建一个服务器。 Docker参数和启动服务器的Wolfram脚本在附件中:
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]]
我发现所描述的 Wolfram 服务器有一个特点。 Wolfram 函数 SocketListen
的第一个参数不能包含来自 docker-compose 文件的主机名作为主机地址。但是,缺少 docker 主机名会导致无法从容器外部访问服务器。
主机名指示的需要可以通过在容器内创建的 netcat 服务器来证明。例如,下面的第一个变体创建了一个可访问的服务器,但其他变体创建了一个从外部无法访问的服务器。
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
Wolfram 的变体,类似于第二个和第三个,给出相同的结果:无法从外部访问。 tcp_server.wls
文件包含符号 address
。使用前必须将其替换为确切的字符串或整数。以下是我在下面尝试过的所有变体的 Wolfram 错误。
"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)
其他端口也是如此。
我如何强制 Wolfram 收听 http://wm:8000
或如何在通过 127.0.0.1 替换实际主机名的意义上更改 docker 设置,同时通过docker网络?
在构建 Mathematica 图像之前,您需要将 Dockerfile
中的许可方法更改为您使用的方法(目前使用我的网络许可)并下载 linux 安装程序 Mathematica_12.1.1_LINUX.sh
从Wolfram官网下载,并放入post.
请注意,这是一个项目草稿。完整的将在 docker-compose.yml
中包含其他服务,例如Go服务器,也应该可以从外部访问。
朋友们帮我解决了问题
函数 SocketListen
的第一个参数应该是 "0.0.0.0:8000"
。然后,从外部请求的 http://wm:61104/f
将 link 到容器。
解释了 0.0.0.0 和 127.0.0.1 之间的区别 here。