A strange reluctance to be critical

How to build a staging server with Docker, Jenkins and Traefik

~ Chapter 4 ~

Completing the project configuration

This guide is largely outdated at this point. You should instead consider installing Jenkins on Kubernetes with Helm.

All that remains is to configure a project’s docker-compose.staging.yml and Jenkinsfile.

For the sake of example, I will show you the configuration I use when building React applications.

First, create a .dockerignore in your project to prevent undesired files from making it into the final image. It could contain something like :


Now, add a base Dockerfile to specify how to build the image. I like to copy the generated static files in an alpine version of httpd.

FROM node:9-alpine as builder
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

FROM httpd:2-alpine
COPY --from=builder build/ /usr/local/apache2/htdocs/

Finally, create the project’s Jenkinsfile which will tie everything together:

pipeline {
	options {
        buildDiscarder(logRotator(numToKeepStr: '5'))
    post { always { deleteDir() } }
	agent any
    stages {
        stage('Build') {
            steps {
                build job: 'image_deploy_job_name/master',  parameters: [
                    string(name: 'SOURCE_DIRECTORY', value: "${WORKSPACE}"),
                    string(name: 'DEPLOY_JOB_NAME', value: "${env.JOB_NAME}")
        stage('Deploy') {
            steps {
                build job: 'image_build_job_name/master',  parameters: [
                    string(name: 'SOURCE_DIRECTORY', value: "${WORKSPACE}"),
                    string(name: 'DEPLOY_JOB_NAME', value: "${env.JOB_NAME}"),
                    string(name: 'REPOSITORY', value: "docker-registry.your_domain"),
                    string(name: 'ENVIRONMENT', value: "staging")

Replace image_build_job_name and image_deploy_job_name with the keys that were generated by Jenkins when you imported the pipelines as part of the previous step.

Commit a new change or manually launch a new build of that project in a desired branch that follows the supported patterns and Jenkins should have published your project at:

  • your_branch.your_project.swarm.your_domain


You may need to do house-cleaning once in a while if your server fills up. The make sure our flimsy server doesn’t blow up, I run the following script as a daily cron job:


echo "==>  Docker Cleanup"

echo "-->  Removing any dangling or unused Docker parts"
docker system prune -af --volumes

echo "-->  Removing any older items from the Registry"
docker exec docker-registry registry garbage-collect /etc/docker/registry/config.yml

echo "==>  Server Cleanup"
echo "-->  Run this as a sudoer if you get permission denied's"

echo "-->  Removing builds directories"
rm -rf /opt/data/jenkins/workspace/*

echo "-->  Pruning caches"
find /opt/data/jenkins/volume-caches/build-cache/bower/local -type d -ctime +5 | xargs rm -rf
find /opt/data/jenkins/volume-caches/build-cache/composer/ -type d -ctime +5 | xargs rm -rf
find /opt/data/jenkins/volume-caches/build-cache/node/npm -type d -ctime +5 | xargs rm -rf
find /opt/data/jenkins/volume-caches/build-cache/node/gyp -type d -ctime +5 | xargs rm -rf
find /opt/data/jenkins/volume-caches/build-cache/node/cache -type d -ctime +5 | xargs rm -rf
find /opt/data/jenkins/volume-caches/build-cache/node/config -type d -ctime +5 | xargs rm -rf

echo "--> Restoring permisssions"
chmod 777 -R /opt/data/jenkins/volume-caches/build-cache
chown root:root -R /opt/data/jenkins/volume-caches/build-cache

That’s it!

Assuming this very lengthy guide was clear enough, you now have the same setup as we have. Once you get your head around each of the moving parts, it remains a rather simple approach with many gains over the manual setup of virtual hosts.

I hope you can get through the setup successfully and that you can get good mileage out of my proposed configuration.

Step completion checklist

  • Added the .dockerignore, Dockerfile and docker-compose.staging.yml files to a Docker-ready project
  • Configured the project’s Jenkinsfile to use the global build and deploy jobs
  • Committed or forced a build on master, develop or a feature* branch
  • Successfully visited the URL for that instance of the project

Read other articles