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-ceRUN 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”.
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:
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.
The job will failure. Don’t worry.
In job’s home, you can click in circle and see the console output.
Or click on build number (#1) and click on “Console Output”.
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.
Logged in dockerhub, click on “Create” > “Create Repository”.
Put a name for your repository. For this example, use “docker-test”.
After docker repository created, get the name to use in our pipeline. In my case, the name is “gustavoapolinario/docker-test”.
Creating dockerhub credential
Go to jenkins home, click on “credentials” and “(global)”.
Click on “Add Credentials” in left menu.
Put your credential and save it.
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