Running Mathematica on Docker

Updated answer with Dockerfile

After the release of wolfram engine I thought it is a good time to revisit this old answer and refine it a bit.

First install docker on your machine. Follow docker setup from old answer.

Dockerfile

Create a file named Dockerfile with following content.

FROM ubuntu

LABEL version = "1.0"
LABEL description = "Docker image for the Wolfram Engine"

ENV DEBIAN_FRONTEND noninteractive
ENV DEBCONF_NONINTERACTIVE_SEEN true

RUN apt update -yq \
    && apt-get install -yq curl gcc tzdata musl-dev python3-dev python3-pip clang \
    && dpkg-reconfigure tzdata \
    && apt-get 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-get clean \
    && apt-get autoremove -y

RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen

RUN wget https://account.wolfram.com/download/public/wolfram-engine/desktop/LINUX \
    && sudo bash LINUX -- -auto -verbose && rm LINUX

CMD ["/usr/bin/wolframscript"]

Note:

If you are installing full Mathematica just replace in the last line wolframscript with wolfram. Also in case of full Mathematica you can downlaod the large installer and have a COPY command to link your Matheamtica .sh installer in the dockerfile in place of the RUN wget ... part. Rest all remains same.

Build the base image

Go to the directory where you saved the above Dockerfile and use it to build the wolfram engine docker image. All necessary requirements are included (nodejs and python3, mqtt) along with base image Ubuntu.

Remove packages from dockerfile if not needed. Replace your_name with whatever you prefer.

docker build -t your_name/mmadocker .

After this we can use the docker image later on.

Run first time and persist license

docker run -it your_name/mmadocker

On the first run the user will need to login and get the free wolfram engine activated. Copy the license info from the container shell.

  • Copy License Info by typing this on the activation dialog
$PasswordFile // FilePrint

Now save the above data visible in console output in a file named mathpass which should be located in the host system so that we can access it later via docker volume option. We need to do this as docker run are forgetful.

Run later

Once we have a the mathpass file in host system (say in the folder named host_system_folder) we can always run it as follows.

docker run -it -v /host_system_folder:/root/.WolframEngine/Licensing your_name/mmadocker

Old answer

Can be still valid. However check the updated Dockerfile based solution above. It uses the new Wolfram Engine.

Dockerizing Wolfram Mathematica

In case you have docker in your system you can just pull the base image from here and jump to section (Install Wolfram on the base image). To keep things self contained, in the following I build the base image from scratch and install docker on Linux.

Set up Docker in your system

  1. Update the apt package index:
sudo apt-get update
  1. Install packages to allow apt to use a repository over HTTPS:
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
  1. Add Docker’s official GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Add The Docker Repository

For latest Ubuntu LTS 18.04 there was no stable version. Create a new file for the Docker repository at /etc/apt/sources.list.d/docker.list. In that file, place one of the following lines choosing either stable, nightly or edge builds:

STABLE (NOT YET AVAILABLE!), please check availability before using:

deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable
EDGE:
deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic edge
NIGHTLY:
deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic nightly
Install Docker CE

You can simply install the Docker CE package.

sudo apt install docker-ce

Done. Check for docker version:

docker --version
Docker version 18.03.0-ce, build 0520e24

Create a base image for Wolfram

To create the docker group and add your user:

  1. Create the docker group.
sudo groupadd docker
  1. Add your user to the docker group.
sudo usermod -a -G docker $USER
  1. Log out and log back in so that your group membership is re-evaluated.

    If testing on a virtual machine, it may be necessary to restart the virtual machine for changes to take effect. Now we do a docker pull of this image here. It comes with ssh installed and latest Ubuntu 18.04. Check the run example and log into docker console.

  2. Once inside the docker console, now we install some necessary packages to make the wolfram base image. Also to directly run a command over ssh one can use sshpass.

    apt-get -y install \
        build-essential \
        mosquitto \
        mosquitto-clients \
        avahi-daemon \ 
        avahi-discover \
        avahi-utils \
        libnss-mdns \
        mdns-scan \
        sshpass
    
  3. Install Node.js and pip3 for Python 3.6.5 inf you want the ExternalEvaluate to work in Wolfram Mathematica 11.3.0.

    curl -sL https://deb.nodesource.com/setup_10.x | bash -
    

    You can successfully add Node.js PPA to Ubuntu system. Now execute the below command install Node on and Ubuntu using apt-get.

    apt-get install nodejs
    apt-get install python3-pip
    
  4. Activate avahi-daemon systemctl enable avahi-daemon.

Commit the base image

Now exit from bash and commit the image and name it wolfram-base

docker commit f750854c1c60 wolfram-base

Install Wolfram on the base image

Run it with a host directory /host/directory/installer mounted where the Mathematica installation file (Mathematica_11.3.0_LINUX.sh) is. The installer now will be available in the mounted directory /mma inside the docker container:

docker run -d -P -v "/host/directory/installer:/mma" wolfram-base

Now we should check the container ID (6daa3df35b93) and go to Ubuntu bash and install Mathematica inside the container.

$ docker ps
$ docker exec -it 6daa3df35b93 bash
$ cd /mma
$ bash ./Mathematica_11.3.0_LINUX.sh
Register Node.js and Python tag and commit docker image

If the Node.js and Python binding needs to be installed by default we can register them at this stage. Our base image was made to support this feature. Type wolfram in the terminal and evaluate the following and quit wolfram.

FindExternalEvaluators["NodeJS"]
FindExternalEvaluators["Python"]

We should now exit from the bash and do a docker commit to save the state of the image.

$ docker commit 6daa3df35b93 wolfram-docker-11.3.0

At this point we will have these images.

$ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
wolfram-docker-11.3.0    latest              6daa3df35b93        2 minutes ago       10.9GB
wolfram-base             latest              dcd0a3d55be0        About an hour ago   685MB
rastasheep/ubuntu-sshd   18.04               08f01ce8fd9f        15 hours ago        234MB

Now just login( assuming userid) to docker and tag your image and push it to the docker hub.

$ docker tag wolfram-docker-11.3.0:latest userid/wolfram-docker-11.3.0
$ docker push userid/wolfram-docker-11.3.0

Push your image to docker hub

Once the image is ready we should now tag it and push to docker hub. Docker may ask you to login if you have not already. The image is 11 GB and it can take time to upload to docker hub.

$ docker tag wolfram-docker-11.3.0:latest userid/wolfram-docker-11.3.0
$ docker push userid/wolfram-docker-11.3.0:latest

Now you can pull this docker image and run on may machine that has docker.

Test it!

We can run now our docker container in a detached mode. Use docker ps to note the container id. Note that we are mounting the host /home directory as /mma inside our docker. We will host networking here.

$ docker run -dti -P --network host  -v "/home:/mma" wolfram-docker-11.3.0:latest bash

Now time to login to the console of the docker container.

$ docker exec -ti 602c2dbd8dce bash

Write some Wolfram language code.

  1. To test the Python external connection a bit of code from doc section.

    script=FileNameJoin[{$TemporaryDirectory,"functions.py"}];
    Export[script,"def stringreverse(s):
        return s[::-1]
    def stringallcaps(s):
        return s.upper()
    ","Text"];
    session=StartExternalSession["Python"];
    ExternalEvaluate[session,File[script]];
    
  2. To test the Node.js connection a bit of code from doc section. Starting a server on port 8070.

    webServerSession=StartExternalSession["NodeJS"->"String"];
    ExternalEvaluate[webServerSession,"var http = require('http'); var url = require('url');"];
    ExternalEvaluate[webServerSession,"var res = http.createServer(function (req, res) {
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('Date from Node.js server on 8070 inside docker:  '+url.parse(req.url,true).query.time);
    }).listen(8070);"];
    
  3. Now a small greetings service using the new SocketListen functionality of 11.3.

    image=ImageCollage[{Import["https://i.stack.imgur.com/EhQlR.png"],GeoImage[Here,"StreetMap"]}];
    listener=SocketListen[8080,Function[{assoc},
    With[{client=assoc["SourceSocket"]},
    WriteString[client,
        ExportString[
        HTTPResponse@
        TemplateApply[XMLTemplate["<h1><wolfram:slot id=1/></h1><wolfram:slot id=2/><h5><wolfram:slot id=3/></h5><h5><wolfram:slot id=4/></h5><wolfram:slot id=5/>"],
        {"A Docker Hello from the Wolfram Language \[HappySmiley]️\[HappySmiley]️\n",
        "<body>Today's date is :  "<>DateString[]<>"</body>"<>"<h2>You are here with docker! </h2>",
        "Reverse capitalized date from python inside docker : "<>ExternalEvaluate[session,"stringallcaps(stringreverse('"<>DateString[]<>"'))"<>"\n"],
        URLRead[URLBuild["localhost:8070",<|"time"->DateString[]|>],"Body"],
        image }]
        ,
        "HTTPResponse"
        ]
        ];
    Close[client]
    ]
    ]
    ]
    
  4. Save the above code in a file hello.wl anywhere in your /home folder as we have mounted it in our docker run command.

  5. Going back to the console of the docker we can cd to the /mma directory and navigate to the directory in the host where we have saved the above Mathematica code as hello.wl. Now in the docker console we can run wolfram and load the hello.wl file.

    <<hello.wl
    

    1526917324800

  6. Now just open http://127.0.0.1:8080 and you will be greeted with something cool ✊ from your docker container. It is a web page served by the Wolfram Mathematica from within your docker container.

Final outcome!

Formatting of this post might be a bit crazy as I wrote it in a .md file editor and pasted here.

1526917635091


I created public resources to simplify and automate PlatoManiac's answer for you and all of us:

TLDR

  1. https://account.wolfram.com/access/wolfram-engine/free?operatingSystem=LINUX
echo -n $'[email protected]\nYOUR-WOLFRAM-ID-PASSWORD-HERE\n' | sudo docker run --name my-wolfram-engine-container -i wolframlanguagefan/wolfram-engine-desktop-linux:latest
sudo docker commit my-wolfram-engine-container my-wolfram-engine-image

sudo docker run --rm -ti my-wolfram-engine-image

1. Create a Wolfram ID and Get a License

Visit

  • https://account.wolfram.com/access/wolfram-engine/free?operatingSystem=LINUX
  • OR https://www.wolfram.com/engine/ and press Linux, cancel the download and press "Get your license"

and create or/and log in (with) your Wolfram Account/Wolfram ID.

Press "Get license". You should see

Your license has been created.

Your account can now be used to activate wolfram-engine. No license file or key needs to be downloaded. The license is linked to your account.

License Note from Wolfram Research, Inc.:

The Free Wolfram Engine for Developers is available for non-production software development.

2. Build my-wolfram-engine-image, activated with your Wolfram ID

Fill in the placeholders [email protected] and YOUR-WOLFRAM-ID-PASSWORD-HERE:

echo -n $'[email protected]\nYOUR-WOLFRAM-ID-PASSWORD-HERE\n' | sudo docker run --name my-wolfram-engine-container -i wolframlanguagefan/wolfram-engine-desktop-linux:latest
sudo docker commit my-wolfram-engine-container my-wolfram-engine-image

it should say

Wolfram Engine activated. See https://www.wolfram.com/wolframscript/ for more information.

3. Run

From now on, you can run an interactive session of your registered & activated wolfram-engine container with

sudo docker run --rm -ti my-wolfram-engine-image

example session:

Wolfram Language 12.2.0 Engine for Linux x86 (64-bit)
Copyright 1988-2021 Wolfram Research, Inc.

In[1]:= Solve[a*x^2 + b*x + c == 0, x] //InputForm

Out[1]//InputForm= {{x -> (-b - Sqrt[b^2 - 4*a*c])/(2*a)}, {x -> (-b + Sqrt[b^2 - 4*a*c])/(2*a)}}

PS

This method does not require you to manually/interactively enter anything, or run commands like $PasswordFile // FilePrint and mount /root/.WolframEngine/Licensing/mathpass, so it is probably more suitable for use in automated workflows on remote machines (where allowed by the license).

See:

  • https://hub.docker.com/r/wolframlanguagefan/wolfram-engine-desktop-linux
  • https://github.com/wolframlanguagefan/wolfram-engine-desktop-linux
  • https://mathematica.stackexchange.com/a/173662/76995
  • https://support.wolfram.com/46072