Last article I explained how you can build your Mesos infrastructure, so, from here I'd assume you have it working already.
First of all, we are going to build a simple application. It is going to be a Java application running on a Docker container, but, you can deploy whatever you want.
build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.rholder:gradle-one-jar:1.0.4'
}
}
apply plugin: 'java'
apply plugin: 'gradle-one-jar'
repositories {
jcenter()
}
task uberJar(type: OneJar, dependsOn: build) {
mainClass = 'hello.marathon.Main'
archiveName = 'hello-marathon-all.jar'
}
dependencies {
compile 'com.sparkjava:spark-core:2.5'
compile 'org.slf4j:slf4j-api:1.7.14'
testCompile 'junit:junit:4.12'
}
Main class
Our project will have only one class, which is going to expose an endpoint at /health. We are using SparkJava, a micro web framework that runs on top of a Jetty 9, so, we don't need much code:
package hello.marathon;
import static spark.Spark.*;
public class Main {
public static void main(String [] args) {
get("/hello-marathon/health", (req, res) -> "Application is running!");
}
}
Dockerfile
No much to say here. Our Dockerfile will just execute our jar in an Alpine image.
FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD build/libs/hello-marathon-all.jar hello-marathon-all.jar
RUN sh -c 'touch /hello-marathon-all.jar'
ENTRYPOINT ["java", "-jar", "hello-marathon-all.jar"]
EXPOSE 4567
Building your jar
After creating your Main class, all you have to do is build your jar using:
gradle uberJar
Building your image and pushing it into a repository
Assuming you have a private repository, you need to set all the variables to push your image into your docker registry:
docker login your-docker-registry.com
docker build -t your-docker-registry.com/your-company/hello-marathon .
docker push your-docker-registry.com/your-company/hello-marathon
Configuring your Mesos slaves to run Docker containers
First of all, you need to install docker in all your slave machines:
sudo yum check-update
sudo curl -fsSL https://get.docker.com/ | sh
Then you must start it:
sudo systemctl start docker
After that, you should configure your slave machines to also be able to run docker containers:
echo 'docker,mesos' > /etc/mesos-slave/containerizers
And increase the executor timeout for a possible delay in downloading an image:
echo '5mins' > /etc/mesos-slave/executor_registration_timeout
Configuring your Mesos slaves to use a private docker registry
If you want to set up Marathon to run your Docker images, you need to do the following steps:
docker login your-docker-registry.com
After login in, you need to tar your credentials:
cd ~ && tar czf docker.tar.gz .docker
Somehow you need to make Marathon access this docker.tar.gz file, which contains your credentials. For this tutorial, let's assume you only copied this docker.tar.gz and put it into /etc/ in each one of the Marathon machines. You can also expose this file via HTTP if you want to.
Deploying your application into Marathon
Finally, all you have to do now is deploy your application.
curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{
"id": "/hello-marathon",
"cpus": 0.25,
"mem": 256,
"disk": 128,
"instances": 2,
"constraints": [
[
"hostname",
"UNIQUE"
]
],
"container": {
"type": "DOCKER",
"volumes": [],
"docker": {
"image": "your-docker-registry.com/your-company/hello-marathon",
"network": "BRIDGE",
"portMappings": [
{
"containerPort": 4567,
"hostPort": 0,
"servicePort": 0,
"protocol": "tcp",
"labels": {}
}
],
"privileged": false,
"parameters": [],
"forcePullImage": true
}
},
"healthChecks": [
{
"path": "/hello-marathon/health",
"protocol": "HTTP",
"portIndex": 0,
"gracePeriodSeconds": 30,
"intervalSeconds": 1,
"timeoutSeconds": 5,
"maxConsecutiveFailures": 1,
"ignoreHttp1xx": false
}
],
"portDefinitions": [
{
"port": 0,
"protocol": "tcp",
"labels": {}
}
],
"uris": [
"file:///etc/docker.tar.gz"
]
}' "http://marathon-1:8080/v2/apps"
A few information:
- Our app will have two instances.
- Each instance will use 0.25 of a CPU.
- Each instance will use 256mb of memory.
- Using the "constraints" field, we inform Mesos that only one instance will run per host. So, since we asked Marathon to run our app in two instances, our app will run in two different Mesos slave hosts.
- There is a health check in /hello-marathon/health.
- Our application will run in a random port.
Now you should check in Marathon if our app is deploying...
...and then running:
So, once again, assuming you followed the last article, I'd expect you already have Nixy and Nginx working for the service discovery of our app, or at least an alternative, so, all you have to do now is check if our app is available in any proxy machine:
curl -X GET http://proxy-n/hello-marathon/health
And that's all.
I hope this post was helpful to you.
Questions? Please, leave a comment!