MAPDL and Docker#

You can run MAPDL within a Docker container on any OS and connect to it via PyMAPDL.

There are several advantages to running MAPDL in a containerized environment such as Docker (or Singularity):

  • Consistent environment regardless of the host OS

  • Portability and ease of install

  • Large-scale cluster deployment using Kubernetes

  • Genuine app isolation through containerization

When running MAPDL in a Docker container, you use your local Python installation to connect to this instance.

Requirements#

You must have access to a Docker image with MAPDL in it. For more information on how to create your own Docker image, see Create your own MAPDL docker container.

Once you have created and uploaded your Docker image to a registry, you can start to pull and use the image on other devices.

Warning

MAPDL Docker images are not allowed to be shared in public or free-to-access repositories or registries. Doing so violates Ansys policy.

Configure Docker to access a private GitHub registry#

If you have created a Docker image and uploaded it to a GitHub private repository, you must authorize your Docker installation to access this private package by using a personal access token.

For information on creating a GitHub personal access token with packages read permissions, see GitHub’s Creating a personal access token.

Save that token to a file with this command:

echo MY_GITHUB_TOKEN_WITH_PACKAGE_READ_PERMISSION > GH_TOKEN.txt

This lets you send the token to Docker without leaving the token value in your history. Next, authorize Docker to access this repository with code like this:

GH_USERNAME=<my-github-username>
cat GH_TOKEN.txt | docker login ghcr.io -u $GH_USERNAME --password-stdin

Run an MAPDL Docker image#

You can now launch MAPDL from Docker using the command line, a docker compose file, or a script that gather the commands given to the command line.

Your Docker image should have a valid MAPDL license configuration. The easiest way is to have an environment variable, ANSYSLMD_LICENSE_FILE, pointing to a valid license server. This environment variable can be already included in the Docker image. However, this is not recommended because it could expose the license server if the Docker image is leaked. The recommended approach is to set that environment variable when running the container.

To instantiate an MAPDL Docker container from an image hosted at ghcr.io/myuser/myrepo/mymapdldockerimage, use code like in the following examples.

$env:ANSYSLMD_LICENSE_FILE="1055@MY_LICENSE_SERVER_IP"
$env:LOCAL_MAPDL_PORT=50053
$env:MAPDL_DOCKER_REGISTRY_URL="ghcr.io/myuser/myrepo/mymapdldockerimage"

docker run -e ANSYSLMD_LICENSE_FILE=$env:ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $env:LOCAL_MAPDL_PORT`:50052   $env:MAPDL_DOCKER_REGISTRY_URL -smp
ANSYSLMD_LICENSE_FILE=1055@MY_LICENSE_SERVER_IP
LOCAL_MAPDL_PORT=50053
MAPDL_DOCKER_REGISTRY_URL=ghcr.io/myuser/myrepo/mymapdldockerimage
docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $LOCAL_MAPDL_PORT:50052 $MAPDL_DOCKER_REGISTRY_URL -smp > log.txt

The first time you instantiate the container, Docker logins into the registry and pulls the required image. This can take some time, depending on the size of the image.

To rerun it, you should restart the container with this command:

(.venv) PS C:\Users\user\pymapdl> docker start mapdl
(.venv) user@machine:~$ docker start mapdl

Or you can delete the container and run it again using these commands:

(.venv) PS C:\Users\user\pymapdl> docker rm -f mapdl
(.venv) PS C:\Users\user\pymapdl> docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $LOCAL_MAPDL_PORT:50052   $MAPDL_DOCKER_REGISTRY_URL -smp > log.txt
(.venv) user@machine:~$ docker rm -f mapdl
(.venv) user@machine:~$ docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $LOCAL_MAPDL_PORT:50052   $MAPDL_DOCKER_REGISTRY_URL -smp > log.txt

You can append the Docker flag --rm to automatically clean up the container when it exits.

The preceding commands create a log file (log.txt) in your current directory location. However, you can remove > log.txt if you don’t want to create this file. In this case, the command output is redirected to the console, which is kept blocked until the Docker image exits. You can detach the console from the Docker container output by appending -d to the docker run command. (Always add this before the Docker image URL.)

If you don’t want to block the console, the best approach is to pipe the output to a file as mentioned earlier so that you can inspect the output of that file.

Notice that the MAPDL Docker image gRPC port (50052) is being mapped to a different host port (50053) to avoid port conflicts with local MAPDL instances running on the host or other Docker images. You could additionally launch more Docker containers in different ports if you want to run multiple simulations at the same time.

The Create a pool of MAPDL instances module does not work when you are connecting to a remote MAPDL Docker image. It also does not work when connected to Docker containers. If you decide to launch multiple MAPDL instances, you must manage these instances yourself.

Note

Ensure that port 50053 is open in your local firewall.

You can provide additional MAPDL command line parameters to MAPDL by simply appending them to the end of the command.

For example, you can increase the number of processors (up to the number available on the host machine) with the -np switch:

(.venv) PS C:\Users\user\pymapdl> docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always -d --name mapdl -p $LOCAL_MAPDL_PORT:50052 $MAPDL_DOCKER_REGISTRY_URL -smp -np 8 | Out-File -FilePath .\log.txt
(.venv) user@machine:~$ docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always -d --name mapdl -p $LOCAL_MAPDL_PORT:50052 $MAPDL_DOCKER_REGISTRY_URL -smp -np 8 > log.txt

For additional command line arguments, see the Notes section in the description for the launch_mapdl() function.

You can use a script file (batch ".bat" or PowerShell ".ps"). to run the preceding commands all at once.

Once you have launched MAPDL, you should see the following content in your console (or the output file):

Start GRPC Server

##############################
### START GRPC SERVER      ###
##############################

Server Executable   : MapdlGrpc Server
Server listening on : 0.0.0.0:50052

Note

Notice that the port specified in the console is the internal Docker container port. This port has been mapped to the value specified for the LOCAL_MAPDL_PORT environment variable.

Using docker-compose to launch MAPDL#

You can also use the docker-compose command to launch MAPDL configured in a docker-compose file. This is useful if you want to load an already configured environment, or if you want to launch multiple instances of MAPDL or services.

For your convenience, the docker directory contains configured docker-compose files that you can use.

Using the docker-compose.yml file is recommended. This is the base configuration file for launching an instance of MAPDL that you can connect to remotely.

Connect to the MAPDL container from Python#

You can connect to an MAPDL instance as indicated in Connect to the local MAPDL instance. You do not need to specify an IP address because Docker maps the ports to the local host.

Additional considerations#

Use --restart policy with MAPDL products#

By default, MAPDL creates a LOCK file in the working directory when it starts, and it deletes this file if it exits normally. The file is used to avoid overwriting files such as database (DB) files or result (RST) files when starting MAPDL after an abnormal termination.

Because of this behavior, when using the Docker --restart flag in the docker run command, you might enter into an infinite loop after crashing if you specify the Docker image to reboot after an abnormal termination. When there is an abnormal termination (MAPDL crashes), the LOCK file is kept on the working directory. Since MAPDL has exited, the container also exits.

This triggers the Docker restart policy, which attempts to restart MAPDL container and the MAPDL process with it. But because of the presence of the LOCK file, MAPDL exits in an attempt to not overwrite the files from the previous crash. This is the start of an infinite loop, where Docker keeps restarting the MAPDL container and MAPDL keeps exiting to avoid overwrite the previous files.

In such cases, you should not use the --restart option. If you really need to use this option, you can avoid MAPDL checks and create the LOCK file by starting the process with the ANSYS_LOCK environment variable set to "OFF".

This code shows how to do this in your docker run command:

(.venv) PS C:\Users\user\pymapdl> docker run `
    --restart always `
    -e ANSYSLMD_LICENSE_FILE=1055@$LICENSE_SERVER `
    -e ANSYS_LOCK="OFF" `
    -p 50052:50052 `
    $IMAGE
(.venv) user@machine:~$ docker run \
    --restart always \
    -e ANSYSLMD_LICENSE_FILE=1055@$LICENSE_SERVER \
    -e ANSYS_LOCK="OFF" \
    -p 50052:50052 \
    $IMAGE

Get useful files after abnormal termination#

In some cases, the MAPDL container might crash after the MAPDL process experiences an abnormal termination. In these cases, you can retrieve log files and output files using the tools that Docker provides.

First, get the Docker container name:

(.venv) PS C:\Users\user\pymapdl> docker ps -a
CONTAINER ID   IMAGE                                   COMMAND                  CREATED          STATUS          PORTS                      NAMES
c14560bff70f   my.registry/myuser/mypackage/mapdl   "/ansys_inc/ansys/bi…"   9 seconds ago    Exited(137)    0.0.0.0:50053->50052/tcp   mapdl
(.venv) user@machine:~$ docker ps -a
CONTAINER ID   IMAGE                                   COMMAND                  CREATED          STATUS          PORTS                      NAMES
c14560bff70f   my.registry/myuser/mypackage/mapdl   "/ansys_inc/ansys/bi…"   9 seconds ago    Exited(137)    0.0.0.0:50053->50052/tcp   mapdl

Then use the name in this command:

(.venv) PS C:\Users\user\pymapdl> docker exec -it mapdl /bin/bash
(.venv) user@machine:~$ docker exec -it mapdl /bin/bash

This command executes the command shell (/bin/bash) of the container and attaches your current terminal to it (interactive -it).

(.venv) PS C:\Users\user\pymapdl> docker exec -it mapdl /bin/bash
[root@c14560bff70f /]#
(.venv) user@machine:~$ docker exec -it mapdl /bin/bash
[root@c14560bff70f /]#

Now you can enter commands inside the Docker container and navigate inside it.

(.venv) PS C:\Users\user\pymapdl> docker exec -it mapdl /bin/bash
[root@c14560bff70f /]# ls
anaconda-post.log  cleanup-ansys-c14560bff70f-709.sh  file0.err   file1.err  file1.page  file2.out   file3.log   home   media  proc  sbin  tmp
ansys_inc          dev                                file0.log   file1.log  file2.err   file2.page  file3.out   lib    mnt    root  srv   usr
bin                etc                                file0.page  file1.out  file2.log   file3.err   file3.page  lib64  opt    run   sys   var
(.venv) user@machine:~$ docker exec -it mapdl /bin/bash
[root@c14560bff70f /]# ls
anaconda-post.log  cleanup-ansys-c14560bff70f-709.sh  file0.err   file1.err  file1.page  file2.out   file3.log   home   media  proc  sbin  tmp
ansys_inc          dev                                file0.log   file1.log  file2.err   file2.page  file3.out   lib    mnt    root  srv   usr
bin                etc                                file0.page  file1.out  file2.log   file3.err   file3.page  lib64  opt    run   sys   var

You can then take note of the files you want to retrieve. For example, you would likely want to retrieve the error and output files (file*.err and file*.out).

Exit the container terminal using the exit command:

[root@c14560bff70f /]# exit
exit
(.venv) PS C:\Users\user\pymapdl>
[root@c14560bff70f /]# exit
exit
(.venv) user@machine:~$

You can then copy the noted files using the docker cp command:

(.venv) PS C:\Users\user\pymapdl> docker cp mapdl:/file0.err .
(.venv) user@machine:~$ docker cp mapdl:/file0.err .

This command copies the files in the current directory. You can specify a different destination using the second argument.

If you want to retrieve multiple files, the most efficient approach is to get back inside the Docker container:

(.venv) PS C:\Users\user\pymapdl> docker exec -it mapdl /bin/bash
[root@c14560bff70f /]#
(.venv) user@machine:~$ docker exec -it mapdl /bin/bash
[root@c14560bff70f /]#

Create a folder where you are going to copy all the desired files:

(.venv) PS C:\Users\user\pymapdl>
[root@c14560bff70f /]# mkdir -p /mapdl_logs
[root@c14560bff70f /]# cp -f /file*.out /mapdl_logs
[root@c14560bff70f /]# cp -f /file*.err /mapdl_logs
[root@c14560bff70f /]# ls mapdl_logs/
file0.err  file1.err  file1.out  file2.err  file2.out  file3.err  file3.out
(.venv) user@machine:~$
[root@c14560bff70f /]# mkdir -p /mapdl_logs
[root@c14560bff70f /]# cp -f /file*.out /mapdl_logs
[root@c14560bff70f /]# cp -f /file*.err /mapdl_logs
[root@c14560bff70f /]# ls mapdl_logs/
file0.err  file1.err  file1.out  file2.err  file2.out  file3.err  file3.out

Then copy the entire folder content at once:

(.venv) PS C:\Users\user\pymapdl> docker cp mapdl:/mapdl_logs/. .
(.venv) user@machine:~$ docker cp mapdl:/mapdl_logs/. .