Jenkins Building Docker Image and Sending to Registry

Hi everyone. In this tutorial we will create a docker image with jenkins and send then to dockerhub.

What’s docker?
Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications.

You can learn more about docker in docker website

Why pipeline?
You can reuse everything you did, put your jenkins code inside git project, the change in pipeline is showed in “changes” inside job history

What’s dockerhub?
Dockerhub is a public docker registry to store your docker images inside. If you want a private registry, you can pay for it. We will use it because it is the most easeful docker registry.

What’s docker registy?
Docker registry is a server to distribute versions of docker images.

Jenkins with docker installed

We will use some pipeline codes, the jenkins need have installed docker inside him to find this commands.

I created a docker image of jenkins with docker installed.

Let’s see the Dockerfile:

FROM jenkins/jenkins:ltsUSER rootRUN apt-get update && \
apt-get -y install apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) \
stable" && \
apt-get update && \
apt-get -y install docker-ce
RUN apt-get install -y docker-ceRUN usermod -a -G docker jenkinsUSER jenkins

This Dockerfile is builded from jenkins official image, install docker and give access to user jenkins build dockers.

You can build this image, but is already in dockerhub gustavoapolinario/jenkins-docker.

Running jenkins with docker from host

To run the container, you need add a volume in docker run command.

… -v /var/run/docker.sock:/var/run/docker.sock …

It will share the docker socket (used in your machine) with the container.

The complete run command:

docker run --name jenkins-docker -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock gustavoapolinario/jenkins-docker

After inicialized the jenkins, complete the jenkins startup wizard.

Read this tutorial to complete wizard and install the locale and blueocean plugins: Quick start with jenkins in docker.

Creating a job to test docker command

In home of jenkins, click on “New Item”, select “Pipeline” and put the job name as “docker-test”.

New pipeline Job

Put this script inside of job:

pipeline {  environment {
registry = "docker_hub_account/repository_name"
registryCredential = 'dockerhub'
}
agent any stages {
stage('Building image') {
steps{
script {
docker.build registry + ":$BUILD_NUMBER"
}
}
}
}
}

The screen will be like this:

Image for post
Image for post
Pipeline in job config

Save the job.

Pipeline explanation

In this pipeline, We have 2 environment variables to change the registry and the credential easeful.

environment {
registry = "docker_hub_account/repository_name"
registryCredential = 'dockerhub'
}

The job will have one step. It will run the docker build and use the jenkins build number in docker tag. With build number turn easeful to deploy or rollback based in jenkins.

stages {
stage('Building image') {
steps{
script {
docker.build registry + ":$BUILD_NUMBER"
}
}
}
}

Testing the docker command in job

Click on “Build Now” in job’s menu.

Image for post
Image for post
Job Menu

The job will failure. Don’t worry.

Image for post
Image for post
Build Failure

In job’s home, you can click in circle and see the console output.

Image for post
Image for post
Build History

Or click on build number (#1) and click on “Console Output”.

Image for post
Image for post
Job Build Menu

In Console Output you will see this:

Started by user GUSTAVO WILLY APOLINARIO DOMINGUES
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/docker-test
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Building image)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
[teste234] Running shell script
+ docker build -t docker_hub_account/repository_name:1 .
unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /var/jenkins_home/workspace/docker-test/Dockerfile: no such file or directory
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 1
Finished: FAILURE

The error happens because the Dockerfile is not finded. We will resolve it soon.

The docker command is executed and the jenkins found the command.

Creating a dockerhub repository

Create a dockerhub account, if you don’t have yet.

dockerhub

Logged in dockerhub, click on “Create” > “Create Repository”.

Image for post
Image for post
Dockerhub menu to Create Repository

Put a name for your repository. For this example, use “docker-test”.

Image for post
Image for post
Creating Dockerhub Repository

After docker repository created, get the name to use in our pipeline. In my case, the name is “gustavoapolinario/docker-test”.

Image for post
Image for post
Dockerhub Repository

Creating dockerhub credential

Go to jenkins home, click on “credentials” and “(global)”.

Image for post
Image for post
Credentials

Click on “Add Credentials” in left menu.

Image for post
Image for post

Put your credential and save it.

Image for post
Image for post

Remenber to change the credential environment (registryCredential) if you didn’t put “dockerhub” in Credential ID.

The credential is configured.

Configuring the environment of dockerhub

Alter the job pipeline. Go to jenkins home, click on job name (docker-test), click on “Configure” in job menu.

The code you need to change is:

environment {
registry = "docker_hub_account/repository_name"
registryCredential = ‘dockerhub’
}

Change the environment variable “registry” to your repository name. In my case is “gustavoapolinario/docker-test”.

Change the environment variable “registryCredential” if necessary.

My environment is:

environment {
registry = "gustavoapolinario/docker-test"
registryCredential = ‘dockerhub’
}

Building the first docker image

With dockerhub credential and repository created, the jenkins can send the docker image builded to dockerhub (our docker repository).

In this example, let’s build a node.js application. We need a Dockerfile to the build.

Let’s create a new step in pipeline to clone a git repository that have a Dockerfile inside.

stage('Cloning Git') {
steps {
git 'https://github.com/gustavoapolinario/microservices-node-example-todo-frontend.git'
}
}

The pipeline must be (but using your environment):

pipeline {
environment {
registry = "gustavoapolinario/docker-test"
registryCredential = ‘dockerhub’
}
agent any
stages {
stage('Cloning Git') {
steps {
git 'https://github.com/gustavoapolinario/microservices-node-example-todo-frontend.git'
}
}
stage('Building image') {
steps{
script {
docker.build registry + ":$BUILD_NUMBER"
}
}
}
}
}

Save and run it clicking on “Build Now”

The Stage view in jenkins job will change to this:

Deploying the docker image to dockerhub

At this moment, we clone a git and build a docker image.

We need put this image in docker registry to pull it in other machines.

First, create a environment to save docker image informations.

dockerImage = ''

Change the build stage to save build information in environment.

dockerImage = docker.build registry + ":$BUILD_NUMBER"

Ceate a new stage to push the docker image builded to dockerhub.

stage('Deploy Image') {
steps{
script {
docker.withRegistry( '', registryCredential ) {
dockerImage.push()
}
}
}
}

After build and deploy, delete the image to cleanup your server space.

stage('Remove Unused docker image') {
steps{
sh "docker rmi $registry:$BUILD_NUMBER"
}
}

The final code will be (remember, using your environment):

pipeline {
environment {
registry = "gustavoapolinario/docker-test"
registryCredential = 'dockerhub'
dockerImage = ''
}
agent any
stages {
stage('Cloning Git') {
steps {
git 'https://github.com/gustavoapolinario/microservices-node-example-todo-frontend.git'
}
}
stage('Building image') {
steps{
script {
dockerImage = docker.build registry + ":$BUILD_NUMBER"
}
}
}
stage('Deploy Image') {
steps{
script {
docker.withRegistry( '', registryCredential ) {
dockerImage.push()
}
}
}
}
stage('Remove Unused docker image') {
steps{
sh "docker rmi $registry:$BUILD_NUMBER"
}
}
}
}

Save and run it.

Awesome, the build is complete and the image will be send to docker registry.

Complete pipeline to a node.js application

This step is for who did this tutorial: Jenkins Starting with Pipeline doing a Node.js test.

To complete the node.js pipeline, let’s change this pipeline to merging with node.js build and test.

The complete pipeline will be:

pipeline {
environment {
registry = "gustavoapolinario/docker-test"
registryCredential = 'dockerhub'
dockerImage = ''
}
agent any
tools {nodejs "node" }
stages {
stage('Cloning Git') {
steps {
git 'https://github.com/gustavoapolinario/node-todo-frontend'
}
}
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Building image') {
steps{
script {
dockerImage = docker.build registry + ":$BUILD_NUMBER"
}
}
}
stage('Deploy Image') {
steps{
script {
docker.withRegistry( '', registryCredential ) {
dockerImage.push()
}
}
}
}
stage('Remove Unused docker image') {
steps{
sh "docker rmi $registry:$BUILD_NUMBER"
}
}
}
}

Now you have a pipeline for test and create a docker image for your application.

Thanks.

— — — — — — — — — — — — — — —

A special thanks to Matthias Döring, who notify me about the lack of docker cleanup. It is necessary to your server don’t use all disc space. The docker images are usefull bexause they are cache to next build, but use a lot of disc space.

https://medium.com/@cryptolukas/you-should-add-this-as-last-stage-or-post-task-d69fb384a361

Written by

I’m a FullStack Developer, working now with DevOps automations. I previously worked as a front-end, PHP Developer, and DevOps.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store