The goal of this session is to use Jenkins on DCOS to build a very basic continuous integration and continuous delivery pipeline that builds an application and deploys it to Marathon.
- Docker Hub account
- GitHub account
- DCOS cluster
- Installed DCOS CLI
- gem, bundler (optional)
We're going to install an instance of Jenkins onto DCOS. The Jenkins package for DCOS is available in the Mesosphere Universe. Before we install it, we want to set some options.
First, go to the DCOS UI and grab the hostname of one of your private agent nodes. This is one which doesn't have the attribute public_ip true, e.g.:
Create a local JSON file with the following contents, called jenkins.json
, replacing 1.2.3.4
with your own hostname:
{
"jenkins": {
"pinned-hostname": "1.2.3.4"
}
}
Then install Jenkins using the DCOS CLI:
dcos package install --yes --options=jenkins.json jenkins
Wait a few minutes and the Jenkins instance should come up!
The Marathon plugin provides an easy way to deploy an application to Marathon.
To install it:
- Download the
.hpi
file for the latest Marathon plugin here: https://github.com/mesosphere/jenkins-marathon-plugin/releases - Visit the Jenkins plugin manager and install via the "Advanced" tab.
We're going to set up a new instance of Marathon. It's generally recommended that the Marathon that ships with DCOS isn't used to run "userland" applications, like the Jekyll web server we'll deploy in this tutorial.
Create a local JSON file with the following contents, called marathon.json
:
{
"marathon": {
"framework-name": "marathon-dcos-bootcamp",
"mesos-role": "slave_public"
}
}
Then install Marathon using the DCOS CLI:
dcos package install --yes --options=marathon.json marathon
Wait a few minutes and the Marathon instance should come up! While you're in the DCOS Marathon UI, grab the IP address and port of the newly running Marathon framework - we'll need this at the very end.
This is shown underneath the task ID of the one running task.
Begin by creating a new public GitHub repository, e.g. ssk2/dcos-bootcamp-cd. Initialise this with a README and clone it to your computer.
When this is done, you can either generate a new site from scratch or re-use our existing site.
Follow the instructions provided by GitHub to create a basic site outline:
-
Let's go to your new repository:
cd dcos-bootcamp-cd
-
Install bundler if you don't have it:
gem install bundler
-
Install Jekyll if you don't have it:
gem install jekyll
-
Initialise the site:
jekyll new site
-
Add these files to your repository:
git add site/* git commit -m "Site files" git push
-
Let's go to your new repository:
cd dcos-bootcamp-cd
-
Copy the entire "site" folder over to your repo:
cp -R cd-demo/site dcos-bootcamp-cd/site
-
Push this up to your repository:
git add site/* git commit -m "Site files" git push
Create a new public DockerHub repository, e.g. ssk2/dcos-bootcamp-cd.
Let's create a very simple Dockerfile
that reuses a Jekyll base image and adds our files to it:
nano Dockerfile
And paste the following two lines into it:
FROM jekyll/jekyll
ADD site /srv/jekyll
Commit and push this file:
git add Dockerfile
git commit -m "Add Dockerfile"
git push
Now we'll add a file that describes how this application should run on Marathon.
Create marathon.json
in the root of your repository:
nano marathon.json
Now put the following JSON into it. This specifies how the application should run, and will be used when we deploy to Marathon.
Don't forget to change the Docker image to point to your newly created Docker Hub repository.
{
"id": "cd-demo-app",
"container": {
"type": "DOCKER",
"docker": {
"image": "ssk2/dcos-bootcamp-cd:latest",
"network": "BRIDGE",
"portMappings": [
{
"hostPort": 80,
"containerPort": 80,
"protocol": "tcp"
}
]
}
},
"acceptedResourceRoles": [
"slave_public"
],
"labels": {
"lastChangedBy": "[email protected]"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"healthChecks": [
{
"protocol": "TCP",
"gracePeriodSeconds": 600,
"intervalSeconds": 30,
"portIndex": 0,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 2
}
],
"upgradeStrategy": {
"minimumHealthCapacity": 0
}
}
Commit and push this file:
git add marathon.json
git commit -m "Add marathon.json"
git push
We will create a couple of jobs that depend on each other to create a basic build and deploy pipeline.
Go to the Credentials link on the left hand side, click on Global credentials and again on Add Credentials. Put your Docker Hub credentials in here.
Go to the running instance of Jenkins on your DCOS cluster and click on the "New Item" link.
Create a "Freestyle project" and give it a meaningful name.
We'll set up our new git repo. Make sure you use the HTTPS URL.
Then, let's set up Jenkins to poll the repo, using the * * * * *
schedule, which will poll every minute.
Now we need to bind our username and password to environment variables.
Next, add three "Execute shell" build steps to login, build and push the image respectively. We will tag it with the Git commit SHA. Don't forget to put #!/bin/bash
at the top of each of these commands.
Step 1:
docker login -u ${DOCKER_HUB_USERNAME} -p ${DOCKER_HUB_PASSWORD} -e [email protected]
Step 2:
docker build -t ssk2/dcos-bootcamp-cd:${GIT_COMMIT} .
Step 3:
docker push ssk2/dcos-bootcamp-cd:${GIT_COMMIT}
Finally, let's add a "Marathon Deployment" post build action. We'll use the IP address and hostname for the Marathon instance you installed earlier, e.g. http://1.2.3.4:5678
(replacing 1.2.3.4 with the task's IP address and 5678 with the task's port).
Hit save! Within the next minute, Jenkins will automatically build your project for the first time. (If you've already saved it, you'll need to hit "Build now" or commit a change for Jenkins to build the project again.)
The application definition we used earlier specifies that Marathon should deploy to a DCOS agent with the role slave_public
- i.e. a node with a public IP address.
You can check the status of the deployment from the dashboard of the Marathon instance you installed (accessible via the Services page of the DCOS UI). The first time you run it, it may take a bit of time to start as Docker pulls all the layers of the image - but subsequent deployments should be much quicker.
If you only have one public node, simply go to that node's DNS address in your browser to see our new Jekyll site running!