Deploying via Docker

Last updated on 16th July 2024

Building via Docker

Before you begin make sure your model is added inside org.models package, and registered inside the main class. You should also confirm being able to run locally before deploying.

If Maven was chosen to set up the project, go to 'Building Using Maven' below. If sbt was chosen, please refer to the section 'Building using SBT'.

Building using Maven

The first step is to make a few changes to your pom.xml (if not pulling from the quickstart repo). Make sure you add the jodatime and junit versions to your properties section.

pom.xml

<properties>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <jodatime.version>2.10.1</jodatime.version>
  <junit.version>5.3.2</junit.version>
</properties>

You will then want to add the jodatime and junit dependencies to the section starting with ''

previous dependency used junit, this has been replace with the junit-jupiter-api.

pom.xml

<dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>${jodatime.version}</version>
</dependency>

Finally you will add the plugins for assembling and dockerize-ing the project.

pom.xml

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.2.1</version>
  <executions>
    <execution>
    <phase>package</phase>
    <goals>
      <goal>shade</goal>
    </goals>
    <configuration>
      <shadedArtifactAttached>true</shadedArtifactAttached>
      <shadedClassifierName>allinone</shadedClassifierName>
      <artifactSet>
        <includes>
          <include>*:*</include>
        </includes>
      </artifactSet>
      <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
          <resource>reference.conf</resource>
        </transformer>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
          <main-Class>Main</main-Class>
        </transformer>
      </transformers>
    </configuration>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>com.spotify</groupId>
  <artifactId>docker-maven-plugin</artifactId>
  <version>1.0.0</version>
  <configuration>
    <imageName>simudyne-maven-docker</imageName>
    <baseImage>simudyne/scala-sbt:2.11.12.1.0.4</baseImage>
    <entryPoint>["java", "-jar", "/${project.build.finalName}-allinone.jar"]</entryPoint>
    <!-- copy the service's jar file from target into the root directory of the image -->
    <resources>
      <resource>
        <targetPath>/</targetPath>
        <directory>${project.build.directory}</directory>
        <include>${project.build.finalName}-allinone.jar</include>
      </resource>
      <resource>
        <targetPath>/root</targetPath>
        <directory>.</directory>
        <include>licenseKey</include>
      </resource>
      <resource>
        <targetPath>/</targetPath>
        <directory>.</directory>
        <include>simudyneSDK.properties</include>
      </resource>
    </resources>
  </configuration>
</plugin>

License file

The pom.xml above expect the license file to be named licenseKey and to be present in the root of the project directory, as simudyneSDK.properties. You need to update these path if you use a different location to ensure the license file is added to the docker image. If not, an error will be thrown at runtime as the license will not be present.

Properties File

If you are using the default 'simudyneSDK.properties' file you can proceed. If however, you are using multiple '.properties' files (such as a different setting for working with Spark) you will need to change a few things:
  1. Change the name of the targeted property file (default to `simudyneSDK.properties`)with the name and location of your own.
  2. Edit the entryPoint field to add the '-DsimudyneConfigFile' and '-DsimudyneConfigDir' as you would normally do for running.

Building the image

Build the image by running 'mvn clean package docker:build -s settings.xml' inside the project's folder. This will create a docker image using the dockerfile generated by mvn in the way defined inside 'pom.xml'.

You can now proceed to 'Pushing with Docker Hub'

Building using SBT

The first step is to add the docker & assembly plugin to your environment. You can do this by going to your .sbt directory. Choosing the correct version you will see a 'plugins.sbt' file (this step should be familiar if using SBT and Eclipse; however, if the file/folder is missing you will need to add them) and add the following.

plugins.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")

addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.5.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.3")

To build in SBT make sure you have properly configured your build.sbt file. You'll need to add the below section to both enable the docker plugin, and configure how it will build your docker image.

build.sbt

//*** SBT ASSEMBLY ***

assemblyMergeStrategy in assembly := {
  case PathList("META-INF", xs @ _*) => MergeStrategy.discard
  //akka configuration files
  case PathList("reference.conf") => MergeStrategy.concat
  case _ => MergeStrategy.first
}
assemblyJarName in assembly := "simudyne-sbt-docker.jar"


//*** SBT DOCKER ***

enablePlugins(sbtdocker.DockerPlugin)
// Generating docker file
dockerfile in docker := {
  val artifact: File = assembly.value
  val artifactTargetPath = s"/${artifact.name}"

  new Dockerfile {
   from("simudyne/scala-sbt:2.11.12.1.0.4")
	 copy(baseDirectory(_ / "simudyneSDK.properties" ).value, s"/simudyneSDK.properties")
   copy(baseDirectory(_ / "licenseKey" ).value, s"/root/licenseKey")
   copy(artifact, artifactTargetPath)
   entryPoint("java", "-jar", artifactTargetPath)
  }
}
imageNames in docker := Seq(
  ImageName(s"${name.value}-$simudyneVersion:latest")
)

Build the image by running 'sbt docker' inside the project's folder. This will create a docker image using the dockerfile generated by sbt in a way defined inside 'build.sbt'.

You can now proceed to 'Pushing with Docker Hub'

License file

The build.sbt above expect the license file to be named licenseKey and to be present in the root of the project directory, as simudyneSDK.properties. You need to update the license file path if you use a different location to ensure it is added to the docker image. If not, an error will be thrown at runtime as the license will not be present.

Properties File

If you are using the default 'simudyneSDK.properties' file you can proceed. If however, you are using multiple '.properties' files (such as a different setting for working with Spark) you will need to change a few things:
  1. Change the name of the targeted property file (default to `simudyneSDK.properties`)with the name and location of your own.
  2. Edit the entryPoint field to add the '-DsimudyneConfigFile' and '-DsimudyneConfigDir' as you would normally do for running.
You can now proceed to 'Pushing with Docker Hub'

Pushing to Docker Hub

You will now push the docker image you have created to the Docker hub. You will want to replace the following things.

  • [build] - This will be the output you get from running the docker command above. It will change based on method and version but should look similar to 'simudyne-sbt-java-2.0.0-beta.2' or 'simudyne-maven-docker' You can confirm the name by running 'docker images' to see the latest created image.
  • [account] - Your account on the docker hub
  • [repo-name] - The name of the repository you've created on the hub.
  • [tag] - Tag is a useful method such that you can pull different files from your repo.

An example of this would be simudyne/simu-repo:demos

sudo docker tag [build] [account]/[repo-name]:[tag]
sudo docker push [account]/[repo-name]

You should be able to navigate to the Docker hub and confirm your image has been updated.

Logging into Docker

You must first run 'docker login' before you can push or pull to a repo. This will automatically ask for your account and password.

Deployment on Server

You must first log into the VM or server which you are deploying on. Please make sure the appropriate firewall and ports are made available based on either your public or intranet settings.

Pull the image using the details you specified above.

sudo docker pull [account]/[repo-name]:[tag]

You will likely already be running a container if not please skip to the next step. However, if you are you need to stop the existing container.

sudo docker ps #to identify the container ID
sudo docker stop <containerID>

You will then look for the exact image name, and then run it with the following configuration options.

  • - get the exact name from the 'docker images' command.
  • - replace with 0.0.0.0 to have it available on all IPs of the host
  • - replace with 80 to have it available on default HTTP port

An example of this would be 'docker run -p 80:80 f3c0fa608b22 0.0.0.0 80'

sudo docker images # to have a look at the available images and get ImageID
sudo docker run -p <port>:<port> <ImageID> <ip> <port>
If you get a connection reset error, or if your log displays only accessible locally you need to update your property file. Set nexus-server.hostname = 0.0.0.0. If you use the default property file (simudyneSDK.properties), simply remove the # that comment the line.

Once completed you should be able to go to the IP or DNS address of the server you've deployed on (mind the port) and see the console as you would locally.