Alright, so if you followed along the previous post, you know I have setup Jenkins to kind of run continuous integration. Well, I have now pushed it a bit further.
I installed a docker image of SonarQube (the community edition) and wow, do I have only one regret: I should have started with all of this setup on day one.
My flow is now this:
So, in a nutshell, what is VERY COOL is that when I push code on my develop branch, this happens automatically:
- unit tests are triggered
- code analysis is triggered
And in SonarQube code analysis, I found bunch of interesting suggestions, enhancements and bug fixes. They were not necessarily product-breaking, but I found many things I was not even aware of. My future code will just be better.
CD pipeline?
I also added a CD pipeline for my test environment. I am not ready yet to put quality gates to automate production deployment, but I am on the right track! Here is my current CD pipeline:
It is quite simple, but it works just perfect!
Now, I was wondering if this would be too much for my server. You know, running all of these:
- Verdaccio docker image (npm private repository)
- Jenkins docker image (CI/CD pipelines)
- SonarQube docker image (code analysis)
- 3 Tests docker images (React frontend, Node backend, Service manager)
- 3 Production docker images (same as just before)
- Nginx docker image (reverse proxy)
- Prometheus & Grafana (directly, not docker images) for system monitoring
Here’s what happens:
More or less: NOTHING.
Well, not enough to be concerned about it yet. Of course, there’s not a lot of users, but I expect even with a few dozen of users, it wouldn’t be so bad. And if this became really serious, the production environments would be hosted on the cloud somewhere for 100% uptime (at least as a target).
To be honest, the tough part was to get the correct Jenkinsfile structure – just because I am not used to it. For safe keeping, I am writing my two pipelines here, and who knows, maybe it can help you too!
CI pipelines – Jenkinsfile
pipeline {
agent any
tools {nodejs "node"}
stages {
stage('Install dependencies') {
steps {
sh 'npm install'
}
}
stage('Unit Tests') {
steps {
sh 'npm run test'
}
}
stage('SonarQube Analysis') {
steps{
script {
def scannerHome = tool 'sonar-scanner';
withSonarQubeEnv('local-sonarqube') {
withCredentials([string(credentialsId: 'sonar-secret', variable: 'SONAR_TOKEN')]) {
sh "${scannerHome}/bin/sonar-scanner -Dsonar.login=\$SONAR_TOKEN"
}
}
}
}
}
}
}
CD Pipeline Jenkinsfile
pipeline {
agent any
stages {
stage('Verify Docker is available') {
steps {
script {
sh 'docker version'
}
}
}
stage('Copy .env and config file') {
steps {
script {
configFileProvider([configFile(fileId: 'frontend-dev.env', variable: 'DEV_ENV')]) {
sh 'cp $DEV_ENV .env'
}
}
script {
configFileProvider([configFile(fileId: 'frontend-custom-config.js', variable: 'DEV_CONFIG')]) {
sh 'cp $DEV_CONFIG ./src/config.js'
}
}
}
}
stage('Build Dev') {
steps {
sh 'docker build -t frontend:develop .'
}
}
stage('Stop and Remove previous Container') {
steps {
sh 'docker stop frontend-develop || true'
sh 'docker rm frontend-develop || true'
}
}
stage('Start Dev') {
steps {
sh 'docker run --name frontend-develop -d -p 3033:3033 -e PORT=3033 frontend:develop'
}
}
}
}
Next step: fixes all the identified issues by SonarQube. When I am done with that, I will begin the CD for prod.