The next thing I wanted to learn and get my hands dirty on, is how to use Jenkins and Angular for CI/CD. In the past I played around with creating pipelines for Angular deployment with Travis and Google Cloud, but companies rarely decide to put their code on cloud. More often, they want their application to be developed, tested and run in protected environments where the company has full control and where it costs less money.
If that’s the case Jurica’s article can help you setting up Nginx reverse proxy for GitLab, Jira and Jenkins.
Jenkins enables just that. It can be downloaded and used within a protected network and it costs no extra money – so my next step was to get to know Jenkins.
These are the steps I wanted to perform (but they weren't as easy as they sound):
1. Download and Install Jenkins,
2. Create an Angular application,
3. Create an account on GitLab.com for my source code,
4. When a new merge request is created, notify Jenkins to run a build,
5. When the merge request is accepted, deploy the Angular App on another machine.
This isn’t the usual setup for real CI/CD projects, but I wanted to get a feel of Jenkins without spending a lot of time on it and with installing as few things as possible on my local machine.
How it actually went can perhaps illustrate what a normal day for a DevOps engineer looks like. I’ll insert >>DECISION<< to the points in time where I decided to change my strategy to save time and proceeded with getting to know Jenkins because of reoccurring difficulties.
1. Download and Install Jenkins
Went to the Jenkins download URL. The first thing I noticed when I scrolled down to the download links is a button popping out saying Deploy to Azure. Now I know I said no cloud, but having an instance on Azure would allow me to have the near environment showing what it would look like on a Linux machine instead of having to install it locally on my Windows machine, and I can feel you saying go for it.
So, I went for it.
- Created my free trial account on Azure.
- Created a Jenkins instance following a template (with everything set up for Jenkins).
- Started up Jenkins on the newly created URL and bam, my first problems:
- There were problems with permissions for Jenkins and accessing files on the newly created instance.
- There was no https support out of the box, so I had to use port forwarding localhost:8080 to login to Jenkins safely.
- Tried to install some additional plugins and Jenkins crashed with a white screen of whatever.
- Before that, Jenkins also crashed when I selected the remember me checkbox on login. Something was fishy.
I didn’t want to spend more time struggling with Azure, so I decided I was going to play it safe. Installed Jenkins on my Windows machine.
Install and setup went well, everything worked.
2. Create an Angular application
Created a dummy Angular with Angular CLI application with no problems. Going for GitLab.
3. Create an account on GitLab
Created an account with a test repository, pushed my code to repository.
4. When a new merge request is created, notify Jenkins to run a build
Created a GitLab hook to notify Jenkins when there are events connected to a merge request and another bam:
GitLab does not allow sending hooks to localhost:8080 – which is exactly the Jenkins URL on my Windows machine.
I decided to give Azure another try. Azure suggested using port forwarding localhost:8080 to login securely, but I laid my hopes on successfully setting up https on the Jenkins instance and using a valid URL instead of localhost:8080.
Removed the previously crashed instance and created a new Jenkins instance in less than 10 minutes. How about that. This time the installation worked without problems.
To pull repo on Jenkins build, I had to setup a GitLab connection.
For Jenkins to be able to react on GitLab hooks, I had to setup GitLab user credentials.
Created a test build on Jenkins with the following steps:
- pulls repo,
- runs npm install,
- runs ng lint,
- runs ng test,
- runs ng build --prod.
The next step was to setup https so we can use the domain name in URL and enable GitLab hooks.
All steps for configuring on this URL worked well, except for another bam:
- Let's Encrypt refused to configure nginx with an error complaining about an invalid character. Turned out quotes in the comment of the nginx config left by the Azure team were causing some trouble. Removed the troublesome quotes and the https was successfully set up.
At this phase everything worked:
When I push code to my repo,
And create a new merge request on GitLab
Then GitLab notifies Jenkins to run a build
And Jenkins starts a build
And Jenkins posts the build status on the GitLab merge request page when done.
(If you find the structure of above text neat read about Gherkin.)
5. Deploy the Angular App when the merge request is accepted.
Another problem arose: Azure wanted me to pay extra money for the Nginx instance from template.
I don’t want to pay extra money, so I remembered my always-free plan on Google Cloud.
Google Cloud in its always free tier offers an f1-micro instance with enough resources to deploy a small Angular app and serve it with a Nginx server.
I created a new deploy-build on Jenkins consisting of these steps:
- pulls repo,
- runs npm install,
- runs ng build --prod.
- copies build with scp command to the Google Cloud instance
I created a new hook on GitLab which will run deploy-build on Jenkins once the merge request is accepted. And voila, the cloud journey is complete.
With a few difficulties resolved, Angular application has undertaken a cloud voyage starting from our local computer through Gitlab, Jenkins on Azure and ended up in production on Google Cloud instance.
This article is all about the journey. If you are interested in what the exact configuration looks like, read my article Configuring Angular, Jenkins, and GitLab for CI/CD.