I have gone thorough distro hopping like a lot of Linux users do but I have always come back to Linux Mint.
It is so easy to install and it looks beautiful. And the performance is more than satisfactory. I use MATE as its desktop environment. Some people might say I am not geek enough for not using an OS like FreeBSD but I don’t care though I’m a proud geek. I care more about being able use the OS without spending too much time on configuring the OS itself before I can start to use it.
When I use Linux Mint, it’s only a few things I have to configure before I can use it. Linux Mint is a descendant of Ubuntu but it feels it’s lighter than Ubuntu. The ease of use is no comparison. I used to use Cinnamon desktop environment but I got to love MATE.
There are some other popular Linux distro but I have been loving Linux Mint in the past 7 to 8 years.
I sincerely appreciate all the work that Linux Mint engineers do. To show my appreciation, I have donated to them in the past and I intend to do it again very soon.
I use macOS as my work OS but I would like to use Linux Mint in the future. I wonder if my company lets me do that…
If you have not tried Linux Mint, I would highly recommend that you give it a try.
I have a VM in Japan on Oracle Cloud Infrastructure but I cannot seem to reach the target port on a resource.
I tried the following command and the port 22 seems to be open.
nc -zv [my public IP address] 22
The command give me…
Connection to [my public IP address] port 22 [tcp/ssh] succeeded!
But when I try 3128 which is the target port I want to reach, it times out. Hmm the routing may not be going well. I checked the port on the local machine and a process is listening and it is open at the OS level. nc -zv is a useful tool to check if ports are open.
You may be working on a personal project. Maybe your company has a different CI/CD system from what you are used to or it’s hard to be onboarded with the CI/CD system. I’ve come up with a way to create your own personal Jenkins server and agent all in one macOS. The following diagram shows what I am envisioning.
This whole things can easily fit on a laptop or a desktop. Obviously the architecture could be applied to Windows and Linux as well. I have Mac as my main development machine, so I will use Mac as an example here.
Drag and drop the Docker application file to /Applications directory.
Double-click Docker.app file in /Applications directory.
You may have to reboot your machine to get the daemon to work correctly.
Open Terminal.
Execute docker run -d -p 80:80 docker/getting-started
Once it’s successful, it means your Docker installation was successful.
One thing to note is that you don’t have to add your account to docker group so you don’t have to sudo for every docker command to execute and docker-compose is bundled with Docker.app on Mac, which is nicer than the installation process on Linux.
Jenkins Master
We will spin up the Jenkins master using docker-compose. Create a directory such as ~/jenkins.
Copy and paste the following contents in docker-compose.yaml file in ~/jenkins.
Execute the following command to create a network for your Docker containers.
docker network create custom_network
After that, execute the following command from at ~/jenkins
docker-compose up
When you see the output like the following, you have Jenkins up and running
jenkins | This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
jenkins |
jenkins | *************************************************************
jenkins | *************************************************************
jenkins | *************************************************************
jenkins |
jenkins | 2021-01-08 07:21:22.224+0000 [id=44] INFO h.m.DownloadService$Downloadable#load: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller
jenkins | 2021-01-08 07:21:22.231+0000 [id=44] INFO hudson.util.Retrier#start: Performed the action check updates server successfully at the attempt #1
jenkins | 2021-01-08 07:21:22.248+0000 [id=44] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$0: Finished Download metadata. 9,056 ms
jenkins | 2021-01-08 07:21:23.526+0000 [id=31] INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization
jenkins | 2021-01-08 07:21:23.554+0000 [id=20] INFO hudson.WebAppMain$3#run: Jenkins is fully up and running
At this point, you could hit the Jenkins master by navigating your browser to http://localhost:8080 but this is not what I want. I would like to have Dockerized NGINX in front of it and route the traffic to the Jenkins so that it is easy to implement SSL certs for it.
You can Ctrl+C to stop Jenkins and then…
docker-compose down
to completely remove the container.
NGINX as Reverse Proxy
As the diagram indicates, my plan is to have NGINX accept HTTP(S) traffic and route the traffic to the Jenkins instance via the Docker’s virtual network.
Please follow the steps below.
Create a directory like ~/nginx
mkdir ~/nginx
Copy and paste the following YAML to ~/nginx/docker-compose.yaml file and save the file.
Next, paste the following configuration to ~/nginx/conf.d/ssl.conf file.
upstream jenkins_upstream {
server jenkins:8080;
}
server {
server_name jenkins.local;
listen 443 ssl;
ssl_certificate /etc/nginx/conf.d/ssl/jenkins.local.crt;
ssl_certificate_key /etc/nginx/conf.d/ssl/jenkins.local.key;
location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
resolver 127.0.0.11;
#proxy_redirect http:// https://;
proxy_pass http://jenkins_upstream;
# Required for new HTTP-based CLI
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_buffering off; # Required for HTTP-based CLI to work over SSL
# workaround for https://issues.jenkins-ci.org/browse/JENKINS-45651
add_header 'X-SSH-Endpoint' 'jenkins.local:50022' always;
}
}
SSL Support
Since I’m just planning to run this locally, there isn’t a need for SSL but I would like to implement this for a good practice. And you never know, you may want to create a Jenkins instance in a real environment eventually.
I am planning to make the URL https://jenkins.local
Place the following files for SSL support. If you need to know how to create self-signed cert, please take a look my previous article.
To summarize, here are the files you have to create for NGINX to work in the nginx root directory.
Next, let’s edit /etc/hosts file so that https://jenkins.local will resolve to your local NGINX.
sudo vim /etc/hosts
Add the following line in the file.
127.0.0.1 jenkins.local
Now navigate to ~/jenkins and execute the following command.
docker-compose up -d
This starts the instance of Jenkins. Now navigate to ~/nginx and execute the following command.
docker-compose up -d
This starts the instance of NGINX as a reverse proxy that routes the traffic to the containerized Jenkins.
Access Jenkins UI and Initial Configuration
If you open your browser, and navigate it to https://jenkins.local/ you should see the following screen.
Beware that if you try to get the Administrator password from /var/jenkins_home/secrets/initialAdminPassword, your host side does not have the file at that location. Instead, you should cat the file at the following location.
Once you get the admin password from the location, enter it to pass the initial screen to start the containerized Jenkins master.
Connect Jenkins Slave
If you take a look at the UI, you see that the Jenkins master has 2 executors by default. If you want your Mac to run builds, you can do so. Here are the steps.
Navigate to Manage Jenkins -> Manage Nodes and Clouds and then click New Node.
Enter mac for Node name and click Permanent Agent and then click OK.
And click Save on the next screen.
When you go back to Manage Nodes and Clouds, you will see the following screen.
Click mac (or whatever you created) and you will see the following screen.
You can definitely follow the instruction on the screen to connect your mac as a Jenkins slave. First download the agent.jar file from the same page and store it in ~/jenkins-slave directory.
This writes the secret to the secret-file in the directory. And then try to execute the following command to get your mac connected to Jenkins master as a slave.
You would expect that this should be the last step but you would get an error like the following.
ava -jar agent.jar -jnlpUrl https://jenkins.local/computer/mac/slave-agent.jnlp -secret @secret-file -workDir "~/dev/jenkins-slave"
Jan 13, 2021 10:31:43 PM org.jenkinsci.remoting.engine.WorkDirManager initializeWorkDir
INFO: Using ~/dev/jenkins-slave/remoting as a remoting work directory
Jan 13, 2021 10:31:43 PM org.jenkinsci.remoting.engine.WorkDirManager setupLogging
INFO: Both error and output logs will be printed to ~/dev/jenkins-slave/remoting
Exception in thread "main" java.io.IOException: Failed to validate a server certificate. If you are using a self-signed certificate, you can use the -noCertificateCheck option to bypass this check.
at hudson.remoting.Launcher.parseJnlpArguments(Launcher.java:571)
at hudson.remoting.Launcher.run(Launcher.java:347)
at hudson.remoting.Launcher.main(Launcher.java:298)
This means that Java does not trust the self signed SSL certificate you created. I blogged about this in the past, so please refer to this blog article to resolve this issue.
Once the SSL cert issue is resolved, it connects to Jenkins master and it’s ready like the image below.
INFO: Agent discovery successful
Agent address: jenkins.local
Agent port: 50000
Identity: 5c:25:1c:e8:1d:35:f1:e8:d1:34:b6:52:ac:e9:e5:ca
Jan 13, 2021 11:13:33 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Handshaking
Jan 13, 2021 11:13:33 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Connecting to jenkins.local:50000
Jan 13, 2021 11:13:33 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Trying protocol: JNLP4-connect
Jan 13, 2021 11:13:33 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Remote identity confirmed: 5c:25:1c:e8:1d:35:f1:e8:d1:34:b6:52:ac:e9:e5:ca
Jan 13, 2021 11:13:33 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Connected
Recap
It took me a few nights to write up this article. To recap…
Dockerizing Jenkins master
Using NGINX as a reverse proxy
Implementing SSL cert
Jenkins slave
This give you an environment where you can manage your own Jenkins in Docker and do whatever you want!