From 6e272c4b9e8b25240d020ae4eff820376058790d Mon Sep 17 00:00:00 2001 From: jmpenn Date: Wed, 1 Mar 2023 15:44:46 -0600 Subject: [PATCH] Add a HOWTO: How-To-Containerize-Trick-with-Docker. (#1462) * Add a HOWTO: How-To-Containerize-Trick-with-Docker. * describe operating the cannon graohics client. * Fix review issues. --- .../How-To-Containerize-Trick-with-Docker.md | 380 ++++++++++++++++++ docs/howto_guides/How-To-Guides.md | 1 + docs/howto_guides/images/cannon_display.png | Bin 0 -> 22132 bytes 3 files changed, 381 insertions(+) create mode 100644 docs/howto_guides/How-To-Containerize-Trick-with-Docker.md create mode 100755 docs/howto_guides/images/cannon_display.png diff --git a/docs/howto_guides/How-To-Containerize-Trick-with-Docker.md b/docs/howto_guides/How-To-Containerize-Trick-with-Docker.md new file mode 100644 index 00000000..529a1c77 --- /dev/null +++ b/docs/howto_guides/How-To-Containerize-Trick-with-Docker.md @@ -0,0 +1,380 @@ +# How to "Containerize" Trick With Docker + +This HOWTO assumes that we building our Docker images on a Linux system. If you're using +MacOS or Windows, the translation should hopefully be fairly straight forward. + +**Contents** + +* [Containerize a Basic Trick Environment](#containerize-a-basic-trick-environment) +* [Containerize a Trick Simulation](#containerize-a-trick-simulation) + +*** + +## Prerequisites: + +* Docker is installed on your machine. +* A basic familiarity with Docker. ["A Docker Tutorial for Beginners"](https://docker-curriculum.com) is an excellent way. +* A basic familiarity with bash shell scripting. + +## Create a Place to Build Our Docker Images + +For this HOWTO we'll try to stay organized by first creating a directory in +which we can build our Docker images. Let's also create and environment +variable for this directory. + +* Create the **DockerPlayGround** directory and **DOCKER_PLAYGROUND** environment variable. + +```bash +mkdir DockerPlayGround +export DOCKER_PLAYGROUND="`pwd`/DockerPlayGround" +``` + +## Containerize a Basic Trick Environment + +In this example we'll build a Docker image, based on Ubuntu 18.04, with Trick 19.5.1 +installed. + +### Dockerfile + +```docker +# ------------------------------------------------------------------------------ +# The image we are building with THIS Dockerfile is based on the ubuntu:18.04 +# Docker image from dockerhub (hub.docker.com). +# ------------------------------------------------------------------------------ +FROM ubuntu:18.04 + +# ------------------------------------------------------------------------------ +# Install Trick Dependencies identified at +# https://nasa.github.io/trick/documentation/install_guide/Install-Guide#ubuntu +# ------------------------------------------------------------------------------ +RUN apt-get update && apt-get install -y \ +bison \ +clang \ +flex \ +git \ +llvm \ +make \ +maven \ +swig \ +cmake \ +curl \ +g++ \ +libx11-dev \ +libxml2-dev \ +libxt-dev \ +libmotif-common \ +libmotif-dev \ +python3-dev \ +zlib1g-dev \ +llvm-dev \ +libclang-dev \ +libudunits2-dev \ +libgtest-dev \ +openjdk-11-jdk \ +zip + +ENV PYTHON_VERSION=3 + +# ------------------------------------------------------------------------------ +# Get Trick version 19.5.1 from GitHub, configure and build it. +# ------------------------------------------------------------------------------ +# We want to clone Trick into the /apps directory of our image. +WORKDIR /apps +# Get the 19.5.1 branch (an official release) of Trick from Github. +RUN git clone -b 19.5.1 https://github.com/nasa/trick.git +# cd into the directory we just created and .. +WORKDIR /apps/trick +# configure and make Trick. +RUN ./configure && make + +# ------------------------------------------------------------------------------ +# Add ${TRICK_HOME}/bin to the PATH variable. +# ------------------------------------------------------------------------------ +ENV TRICK_HOME="/apps/trick" +RUN echo "export PATH=${PATH}:${TRICK_HOME}/bin" >> ~/.bashrc + +CMD ["/bin/bash"] +``` + +### Building the docker image: + +* Create a directory for building this docker image: + + ```bash + cd ${DOCKER_PLAYGROUND} + mkdir TRICK_19_5_1 + cd TRICK_19_5_1 + ``` + +* Create a file named ```Dockerfile``` that contains the content listed above. + +* Build the Docker image by executing: ```docker build --tag trick:19.5.1 .``` + + :exclamation: This may take a few minutes. + +* When the build completes, execute : ```docker images```. + + You should see a record of the image that you just created: + + ``` + REPOSITORY TAG IMAGE ID CREATED SIZE + trick 19.5.1 1023a17d7b78 2 minutes ago 2.61GB + ``` + +### Running the docker image: +To Instantiate a container from the image: ```docker run --rm -it trick:19.5.1``` + +You should see the bash shell prompt from your container. Something like: + +``` +root@8615d8bf75c5:/apps/trick# +``` + +Execute: ```ls``` at the prompt to see that it contains Trick. + +``` +CMakeLists.txt Makefile autoconf configure lib test_overrides.mk trickops.py +CMakeModules. README.md bin docs libexec test_sims.yml trigger +CMakeTestFiles TrickLogo.png config.log doxygen share trick_sims +LICENSE TrickLogo_darkmode.png. config.status include test trick_source +root@8615d8bf75c5:/apps/trick# +``` + +This docker container contains a full Trick development environment. You can't run GUI applications on it but you can build a simulation. + + +## Containerize a Trick Simulation + +### Prerequisites: + +* The trick:19.5.1 docker image described above. + +## Introduction + +In this example, we'll create a docker image from which we can run (a version of) ```SIM_cannon_numeric```, +one of the variants of Trick's Cannon Ball simulation. This image will be based on the Trick:19.5.1 image the we previously built. + +Our containerized simulation won't start any variable server clients like the sim-control panel or graphics clients, because we can't easily run graphics clients from __within__ the container. But, we __can__ easily connect graphics clients running on the host machine to our containerized simulation. + +### Creating a Docker friendly version of ```SIM_cannon_numeric``` + +* Create a directory for building this docker image: + + ```bash + cd ${DOCKER_PLAYGROUND} + mkdir SIM_cannon_docker_build + cd SIM_cannon_docker_build + ``` + +* Create a directory for our version of SIM_cannon. + + ```bash + mkdir SIM_cannon_docker + cd SIM_cannon_docker + ``` + +* Copy the ```SIM_cannon_numeric``` **S_define** file into the current directory. + + ```bash + curl -O https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/SIM_cannon_numeric/S_define + ``` + +* Copy ```SIM_cannon_numeric``` include files. + + ```bash + curl --create-dirs --output models/cannon/gravity/include/cannon.h \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/include/cannon.h + curl --create-dirs --output models/cannon/gravity/include/cannon_numeric.h \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/include/cannon_numeric.h + ``` + +* Copy ```SIM_cannon_numeric``` source files. + + ```bash + curl --create-dirs --output models/cannon/gravity/src/cannon_init.c \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/src/cannon_init.c + curl --create-dirs --output models/cannon/gravity/src/cannon_numeric.c \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/src/cannon_numeric.c + ``` + +* Create a file named ```S_overrides.mk ``` that contains the following content: + + ```make + TRICK_CFLAGS += -Imodels + TRICK_CXXFLAGS += -Imodels + ``` + +* Create and enter a directory named ```RUN_demo``` and enter it: + + ```bash + mkdir RUN_demo + cd RUN_demo + ``` + +* Create a file named ```input.py ``` that contains the following content: + + ```python + trick.real_time_enable() + trick.exec_set_software_frame(0.1) + trick.itimer_enable() + trick.var_server_set_port(9001) + ``` + + :exclamation: Notice that we are NOT starting a SIM-control-panel, or the graphics client. + + :exclamation: Notice that we are explicitly setting the variable server listen port. + + +### The Graphics Client + + Even though the simulation won't be starting the graphics clients, we will be starting and connecting the graphics clients to the containerized simulation. + + * Download the graphics client's source and Makefile. + + ```bash + cd ${DOCKER_PLAYGROUND}/SIM_cannon_docker_build/SIM_cannon_docker + curl --create-dirs --output models/graphics/src/CannonDisplay.java \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/graphics/src/CannonDisplay.java + curl --create-dirs --output models/graphics/Makefile \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/graphics/Makefile + ``` + + * Down-load the graphics client's sound files. + + There are two sound files necessary to build the graphics client, 1) **CannonBoom.wav**, and 2) **Explosion.wav** . + They both need to be placed into ```models/graphics/resources/```. + + * Create the resources directory. + + ``` + mkdir -p models/graphics/resources + ``` + * Down-load the sound files. + + Unfortunately, binary files are more difficult to down-load from Github than text files. + + For each, we have to go to their respective Github pages and click the "Download" button. + + * Download CannonBoom.wav from [here](https://github.com/nasa/trick/blob/master/trick_sims/Cannon/models/graphics/resources/CannonBoom.wav). + * Download Explosion.wav from [here](https://github.com/nasa/trick/blob/master/trick_sims/Cannon/models/graphics/resources/Explosion.wav). + + :exclamation: When you download the wave files from Github, their names may be set to a flattened version of their full pathnames. So, we have to rename them to their real names. + + * Rename the down-loaded wave files to **CannonBoom.wav**, and **Explosion.wav** respectively, and move them both to ```models/graphics/resources/```. + + + +* Build the cannon graphics client. + + ```bash + cd ${DOCKER_PLAYGROUND}/SIM_cannon_docker_build/SIM_cannon_docker/models/graphics + make + ``` + +### Building the Docker Image + + +#### Dockerfile + +``` +# ------------------------------------------------------------------------------ +# The image we are building with THIS Dockerfile is based on the trick:19.5.1 +# Docker image that we built previously. +# ------------------------------------------------------------------------------ +FROM trick:19.5.1 + +# ------------------------------------------------------------------------------ +# Copy the simulation source code into the image and build it. +# ------------------------------------------------------------------------------ +# Set current working directory to the directory where we want our SIM code. +WORKDIR /apps/SIM_cannon +# Copy the simulation source code from our (host) image-build directory into our +# image. +COPY SIM_cannon_docker . +# Build the SIM. +RUN /apps/trick/bin/trick-CP + +# In out simulation, we decided to use port 9001 for our +# variable server port. We did this by adding +# "trick.var_server_set_port(9001)" to our input file. + +#Expose the variable server port. +EXPOSE 9001/tcp + +# Make a script to run SIM_cannon from the /apps directory. +RUN echo "#! /bin/bash" >> /apps/run_sim.sh +RUN echo "cd /apps/SIM_cannon" >> /apps/run_sim.sh +RUN echo "./S_main_Linux_7.5_x86_64.exe RUN_demo/input.py" >> /apps/run_sim.sh +RUN chmod +x /apps/run_sim.sh + +CMD ["/apps/run_sim.sh"] +``` + +* Make sure you're in the right directory. + +```bash + cd ${DOCKER_PLAYGROUND}/SIM_cannon_docker_build +``` + +* Create a file named ```Dockerfile``` that contains the content listed above. + +* Build the Docker image by executing: ```docker build --tag sim_cannon_docker .``` + +* When the build completes, execute : ```docker images```. + + You should see a record of the image that you just created: + + ``` + REPOSITORY TAG IMAGE ID CREATED SIZE + sim_cannon_docker latest d4547502c2a4 13 seconds ago 2.61GB + trick 19.5.1 1023a17d7b78 2 minutes ago 2.61GB + ``` + +### Running the docker image: +To instanciate a container from the image: ```docker run --name misterbill --rm -P sim_cannon_docker &``` + +* In a host terminal (not in the container) execute: + + ```bash + docker port misterbill + ``` + +to see what host-port container-port 9001 has been mapped to. + +You should see something like: + +``` + 9001/tcp -> 0.0.0.0:32783 + 9001/tcp -> [::]:32783 +``` + +This shows that port 9001 in our container has been mapped to port 32783 +on our host computer. So, in this case we would connect our (host) +java client to port 32783. + +To connect the CannonDisplay variable-server client to the containerized simulation: + +```bash +java -jar SIM_cannon_docker/models/graphics/dist/CannonDisplay.jar & +``` + +:warning: Don't just copy and paste. If you don't put the right port number it won't work. + + +![](images/cannon_display.png) + +* Click **RELOAD**. This re-initializes the cannon. Then click **FIRE**. The cannon will fire. +* Adjust the the controls on the left hand side of the graphics client. **RELOAD** and **FIRE**. +* Do this until you're bored. + +If Trick is installed on your host then you can also connect : + +```bash +trick-simcontrol localhost & +``` + +You can shut down the sim from the trick-simcontrol panel when you're done. +or if you don't have Trick installed, just use: ```docker kill misterbill```. + +# THE END + diff --git a/docs/howto_guides/How-To-Guides.md b/docs/howto_guides/How-To-Guides.md index 118afcaf..db099956 100644 --- a/docs/howto_guides/How-To-Guides.md +++ b/docs/howto_guides/How-To-Guides.md @@ -8,3 +8,4 @@ 01. [How do I create a model library to save compilation time?](/trick/documentation/building_a_simulation/Trickified-Project-Libraries) 01. [How do I use inherited templates in the input file?](How-To-Use-Inherited-Templates) 01. [How to Dump a Core-file on MacOS](How-to-dump-core-file-on-MacOS) +01. [How to Containerize Trick with Docker](How-To-Containerize-Trick-with-Docker) \ No newline at end of file diff --git a/docs/howto_guides/images/cannon_display.png b/docs/howto_guides/images/cannon_display.png new file mode 100755 index 0000000000000000000000000000000000000000..5f70b7d48962b9241bdfbca8733a912b95bf1c8e GIT binary patch literal 22132 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 aaU-KA$Y}LACGCraaNf