Set Up an Integration + Deployment Pipeline Using Jenkins + Portainer + Traefik + Docker

Global Tool Configuration and scrolling down the section labeled NodeJS.

Add an installation with a name of recent nodeLastly, navigate to the credentials page and create 2 Username with password credentials, one for Portainer using the admin username and password, and one for your Github credentialsExample React App SetupI will be using my react boilerplate repo from a previous post for an example project to be deployed via this pipeline.

ameersami/react-bolierplateContribute to ameersami/react-bolierplate development by creating an account on GitHub.

github.

comReact + Webpack + TypeScript Project SetupLet's get React and TypeScript setup, its a lot easier than you think!medium.

comThe Dockerfile in the repo just creates a simple Docker container which runs the react app on port 8080.

This Dockerfile can, however, be substituted with whatever Dockerfile you want.

The docker-compose.

yml file for the project looks extremely similar to the Portainer service that we created earlier.

In this docker-compose file, the image name on line 6 refers to the docker image that this service will use (remember this for when we configure the Jenkinsfile).

The port on line 14 refers to the port that is exposed, in this case, 8080.

Lastly for the labels section, the “traefik.

docker.

network” refers to the docker swarm network we created earlier, “traefik.

reactboilerplate.

frontend.

rule” defines what URL we want to go to this service, and “traefik.

reactboilerplate.

frontend.

port” is the port we want Traefik to forward to.

JenkinsFile CreationThe Jenkinsfile basically defines a set of commands that Jenkins needs to execute for each job.

In this case, I’ve simply put everything into a single Jenkinsfile but I know it is best practice to separate out running tests, CI, and CD into their own individual Jenkinsfiles.

Portainer exposes a restful API that we will be calling from Jenkins to build our docker images and deploy our application stacks.

The documentation for the Portainer rest API can be found here:Build, Collaborate & Integrate APIs | SwaggerHubJoin thousands of developers who use SwaggerHub to build and design great APIs.

Signup or login today.

app.

swaggerhub.

comIn your Jenkinsfile, inside of the pipeline, we will want to create 7 stages, 3 of which are specific to the react-boilerplate project.

I won’t be walking you through the react-boilerplate specific stages but you can find them here.

The first stage we will need to create is for retrieving the JWT token which we will use to authenticate the rest of the calls in the pipeline.

So if you remember back to the Jenkins config step, we added credentials to Jenkins for Portainer.

The way we access those credentials in a stage is by wrapping whatever section we want to have access to it in a withCredentials method, where we specify the id of the credentials and the variables we want to assign to the username and password as parameters to the method.

On line 12 we create a json variable which contains the JSON body that we will need to send as part of the request.

This is where we will use the username and password for portainer.

On line 15 we create and send the request to our Portainer instance by using the HTTP request plugin.

For the request we specify the following:acceptType to APPLICATION_JSON as we are only expecting a JSON object to be returnedcontentType to APPLICATION_JSON as we are sending a JSON objectvalidResponseCode to 200 as we want this to fail if we get anything other than a 200 returnedhttpMode to POST as this is a post requestignoreSslErrors to true as Jenkins will complain about the certs generated by TraefikconsoleLogResponseBody to true (this is optional as it just logs the response)requestBody to the json variable we created on line 12url to https://portainer.

<yourdomain>.

com/api/auth , obviously, change the URL to whatever URL your Portainer instance is sitting at.

We then use groovy JsonSlurper to parse the returned JSON object and we then create an environment variable on line 17 and set it to the authorization header, Bearer xxxxxxx which we will use in subsequent stages.

Next, we will send a request to Portainer to build the docker image for us from the Github repoSimilar to the last stage, we access the credentials stored in Jenkins, in this case, the Github credentials.

We then create the request URL, you may note that this is not part of the Portainer API docs as this is making a call to the docker API through Portainer.

This request URL has a number of params:name of the image to build, this should be the same as the image name in the react-boilerplate docker-compose.

yml, in this case, reactApp:latestremote is the URL to the Github repo where the Dockerfile used to create the image is located, at the beginning of the URL, we pass the Github username and password so that this can work for private repos as well.

dockerfile is the location of the dockerfile in the reponocache is set to true so that Docker does not use the cache when building the imageThe next stage will delete the old stack if it already exists, we must do this as Portainer does not properly support redeploying stacks as of writing.

All we are doing here is calling the Portainer API to get a list of stacks that already exist and checking if the one for this project is in that list.

If it is then we make another call to the Portainer API to delete the stackLastly, we deploy the stack to PortainerWe use the withCredentials again to access the Github credentials which will be used for the request body.

First, we make a call to Portainer to retrieve the Docker swarm ID.

We then create a JSON object in a variable which has the following properties:Name ????.name of the stackSwarmId ????.swarm which we want to deploy toRepositoryURL ????.URL to the Github repo for the projectComposeFilePathInRepository ????.path to the docker-compose.

yml file in the repoRepositoryAuthentication is set to true so that we authenticate against the repo (this is can be set to false if it is a public repo)RepositoryUsername and RepositoryPassword which are the repo username and password to be used when authenticating (don’t need these if RepositoryAuthentication is set to false)We then make sure that the JSON object was created and then we make a request to Portainer to deploy the stackOof ok well if you kept the final JenkinsFile should look like the following:Jenkins Job CreationLast step I promise….

Go to your Jenkins and create a new job and configure the following options:Check Github project and set the Project url to the URL of the Github repoSpecify your build trigger under the Build Triggers sectionIn the Pipeline section select Pipeline script from SCM which tells Jenkins to pull the Jenkinsfile from the Github repoIn the Pipeline section select Git for the SCM sectionIn the Pipeline section under Repositories put the Github repo URL and select the Github credentials from the Credentials dropdownIn the Pipeline section for the Script Path put the path in the repo to the JenkinsfileSummaryAwesome!.You should now have a functional pipeline which automatically runs the tests for your project, creates a new Docker image for said project, and deploy/redeploys it all in one fell swoop.

Useful Linkshttps://gist.

github.

com/deviantony/77026d402366b4b43fa5918d41bc42f8https://blog.

ssdnodes.

com/blog/traefik-multiple-ssl-websites/http://blog.

francoisfaubert.

com/2018/06/11/dockerized-jenkins-with-traefik-3.

htmlhttps://getintodevops.

com/blog/building-your-first-docker-image-with-jenkins-2-guide-for-developers.. More details

Leave a Reply