loading...

Docker – Building, testing, and pushing Docker images inside Dockerized build nodes

How to Create MySQL Users Accounts and Grant Privileges

To wrap up this chapter on Docker and Jenkins, let’s walk through the steps of creating a template for a real-world Dockerized node application. The following is what we will do:

Prepare our application:

  • Create a new repo on GitHub
  • Clone the repo to our development workstation
  • Create our application files
  • Push our application files up to GitHub

Create and test the Jenkins job that will build our Dockerized node application:

  • Create a new Jenkins job that utilizes the GitHub repo 
  • Test our Jenkins job that will pull the repo, build the app, test it, and publish the image
  • Celebrate our success!

Let’s begin by preparing our application.

The first thing we want to do is create our application repo on GitHub. Browse and log into github.com, go to your repositories page, and click on the Create New Repo button. Enter a name for the new repository. For our example, I used dqs-example-app. Enter an appropriate description. You can make your repo public or private. For this example, I am keeping it public for the simplicity of not needing to authenticate to pull the repo later. Check the Initialize the repository checkbox so you can immediately clone the empty repo on your workstation. You can select the project type to use when creating the .gitignore file. I selected Node. When you have entered and selected all this, it will look much like the following:

Click on the Create repository button to create your new application repo. Now that it is created on GitHub, you will want to clone it to your workstation. Use the Clone or download button and then the copy button to copy the repo’s URL for the cloning step:

Now, return to your workstation and, in the location where you keep your local repos, clone the new (mostly) empty repo. Then change directory into the new repo’s folder. For me, that looked like the following:

Now we are going to create the application’s scaffolding. This will consist of creating a Dockerfile, a Jenkinsfile, the main.js and test.js files, and the package.json file. Use your favorite editor to create each of these files in your application folder. The following are the contents for the files: 

The following are the contents of the Dockerfile file:

FROM node:10-alpine
COPY . .
RUN npm install
EXPOSE 8000
CMD npm start

The following are the contents of the Jenkinsfile file:

node {
   def app
   stage('Clone repository') {
      /* Clone the repository to our workspace */
      checkout scm
   }
   stage('Build image') {
      /* Builds the image; synonymous to docker image build on the command line */
      /* Use a registry name if pushing into docker hub or your company registry, like this */
      /* app = docker.build("earlwaud/jenkins-example-app") */
      app = docker.build("jenkins-example-app")
   }
   stage('Test image') {
      /* Execute the defined tests */
      app.inside {
         sh 'npm test'
      }
   }
   stage('Push image') {
      /* Now, push the image into the registry */
      /* This would probably be docker hub or your company registry, like this */
      /* docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') */

      /* For this example, We are using our jenkins-stack service registry */
      docker.withRegistry('https://ubuntu-node01:5000') {
         app.push("latest")
      }
   }
}

The following are the contents of the main.js file:

// load the http module
var http = require('http');

// configure our HTTP server
var server = http.createServer(function (request, response) {
   response.writeHead(200, {"Content-Type": "text/plain"});
   response.end("Hello Docker Quick Start\n");
});

// listen on localhost:8000
server.listen(8000);
console.log("Server listening at http://127.0.0.1:8000/");

The following are the contents of the package.json file:

{
   "name": "dqs-example-app",
   "version": "1.0.0",
   "description": "A Docker Quick Start Example HTTP server",
   "main": "main.js",
   "scripts": {
      "test": "node test.js",
      "start": "node main.js"
   },
   "repository": {
      "type": "git",
      "url": "https://github.com/earlwaud/dqs-example-app/"
   },
   "keywords": [
      "node",
      "docker",
      "dockerfile",
      "jenkinsfile"
   ],
   "author": "earlwaud@hotmail.com",
   "license": "ISC",
   "devDependencies": { "test": ">=0.6.0" }
}

And finally, the following are the contents of the test.js file:

var assert = require('assert')

function test() {
   assert.equal(1 + 1, 2);
}

if (module == require.main) require('test').run(test);

When you are all done, your repo folder should look something like the following:

Now, let’s push our work up to the GitHub repo. You will use standard git commands to add the files, commit the files, and then push the files up to the repo. The following are the commands I used:

# Initial commit of our application files to the new repo
git add Dockerfile Jenkinsfile main.js package.json test.js
git commit -m "Initial commit"
git push origin master

The following is what that looked like for me:

Now that the initial version of our application has been created and pushed to our GitHub repo, we are ready to create the Jenkins job to pull our repo code, build our application image, test it, and then publish our application’s Docker image. Start off by creating a new Jenkins job, by logging into your Jenkins server and clicking on the New Item link. Next, enter the name you want to use for the job in the Enter an item name input box. I am using dqs-example-app. Select Pipeline for the type of job we are creating, and then click the OK button.

You can, and probably should, provide a meaningful description for the build job we are creating. Just enter it into the Description: input box at the top of the configuration screen. For our example, I have entered the somewhat terse description Build the dqs-example-app using a pipeline script from SCM. You can probably do a lot better.

We are going to set up the Jenkins job to poll the GitHub repo every five minutes to look for changes to the master branch. There are better options where changes to the repo can trigger the build job without scheduled polling, but for the simplicity of this example, we will just use a poll method. So scroll down to the Build Triggers section of the job’s configuration and check Poll SCM. Then in the schedule, enter a value of H/5 * * * *:

Next, we want to set up our pipeline. Unlike the previous examples, this time we will select the Pipeline script from SCM option. We will select Git for our SCM, and then enter the Repository URL for our application’s repo on GitHub. For this example, that URL is https://github.com/EarlWaud/dqs-example-app.git. Make sure that the Branches to build value is set to */master, which is the default value. Your pipeline definition should like a lot like the following:

There is one more key setting for the pipeline, and that is the Script Path. This is the (path and) filename to the Jenkins script file. In our case, that is literally just Jenkinsfile because the name we gave the file is Jenkinsfile and it is in the root of our repo. This is what our example’s input looks like:

That is all the configuration needed at this time. Everything else is already set up in our source files, and they will be pulled from our application repo. All that’s left to do for the configuration is to click the Save button. Back at the job’s page, we are ready to execute our first build. The newly-created job screen looks like this in our example:

Now, just wait. In five minutes or fewer, the first build of the job will kick off automatically because we have set up polling the repo at five-minute intervals. We will take a look at the console log when the job has finished, but first here is our Jenkins job view after the job completes (successfully, of course!):

The following is an edited view of the console log output for reference (the full log output can be found in the source bundle):

Started by an SCM change
Started by user Earl Waud
Obtained Jenkinsfile from git https://github.com/EarlWaud/dqs-example-app.git
[Pipeline] node
Running on agent-00042y2g983xq on docker in /home/jenkins/agent/workspace/dqs-example-app
[Pipeline] { (Clone repository)
Cloning repository https://github.com/EarlWaud/dqs-example-app.git
> git init /home/jenkins/agent/workspace/dqs-example-app # timeout=10
[Pipeline] { (Build image)
+ docker build -t jenkins-example-app .
Successfully built b228cd7c0013
Successfully tagged jenkins-example-app:latest
[Pipeline] { (Test image)
+ docker inspect -f . jenkins-example-app
+ npm test
> node test.js
Passed:1 Failed:0 Errors:0
[Pipeline] { (Push image)
+ docker tag jenkins-example-app ubuntu-node01:5000/jenkins-example-app:latest
+ docker push ubuntu-node01:5000/jenkins-example-app:latest
Finished: SUCCESS

All that is left to do now is celebrate our success:

Seriously, this is a great foundation for creating your own Dockerized applications and building, testing and publishing them using Jenkins. Consider it as a template that you can reuse and build from. You are now ready to utilize Docker with Jenkins in any way you desire.

Comments are closed.

loading...