Continuous Integration: Part 2 - Setup a Jenkins Slave, Docker Registry, and Jenkinsfile (Pipeline)

July 8, 2017 by Phu Ha <pha@atlassoftwaregroup.com>

Setup a Jenkins Slave / Node

In Part 1, we launched a master Jenkins server. The problem is we can’t build containers within a container. It’s not recommanded to run Docker within Docker. Therefore, we need a Jenkins slave to help us build our containers.

Create a workspace and initialize the Vagrantfile

(local): mkdir jenkins-slave; cd jenkins-slave; vagrant init ubuntu/xenial64

Add this code on line 16 in the Vagrantfile. This will configure our virtual machine with an IP address of 192.168.2.125.

config.vm.network "private_network", ip: "192.168.2.125"
config.vm.network "public_network"

Power up our Jenkins Slave VM.

(local): vagrant up --provider=virtualbox

Copy our Jenkins slave private key into a text editor.

(local): cat .vagrant/machines/default/virtualbox/private_key

Example Output:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyqyBoM39skOHj692Fs4sf11gkN8OP5QaXlBZrzQJIS0v3E4X
emF71frK6+utgZswtJankWUw7wy+wqhcuTZA3R7n9ZSayjnYHa7uPswBVIyZ12TR
SpiPG603C+8JsJu10ZtciiEj1bIzuM1WCEWwIGX54PHVWkckg07VMEb0zBubmLR2
TQP83/CJwD6Bl/5TfnS+BE5L/1pT8y2gNCLMNMqofQUaPp/eCcTy0XoGcWJgMmX0
aJVMf772Vun6OIg96lnFQJQ0wULM3m0q2K5is7uCaRY3MJfV+t72REUS8W3UwFQY
VL87OkD15HXSrEm0SRUHPvpD1NicznSU5Y79OwIDAQABAoIBAHlta2jNod8JCJI0
vNqjAhP4/R8vFNlQwY+aMnF/Cq0+5nrmqrhe6ZPlY2h/1n9dXIwF6zV4XB4NE8mK
...
-----END RSA PRIVATE KEY-----

Log into our VM

(local): vagrant ssh

This command will install Docker and the Rancher CLI tool.

(jenkins-slave): sudo apt-get update; \
sudo apt-get upgrade -y; \
sudo apt-get -y install \
  apt-transport-https \
  ca-certificates \
  curl; \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -; \
sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"; \
sudo apt-get update; \
sudo apt-get -y install docker-ce git default-jdk unzip wget awscli; \
sudo service docker start; \
sudo chown root:ubuntu /var/run/docker.sock; \
sudo bash -c "curl -L https://github.com/docker/compose/releases/download/1.13.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose"; \
sudo chmod +x /usr/local/bin/docker-compose; \
sudo mkdir /rancher; \
sudo wget https://github.com/rancher/cli/releases/download/v0.6.1/rancher-linux-amd64-v0.6.1.tar.gz -P /rancher; \
sudo tar -zxvf /rancher/rancher-linux-amd64-v0.6.1.tar.gz -C /rancher; \
sudo mv /rancher/rancher-v0.6.1/rancher /usr/bin/rancher; \
sudo rm -rf /rancher

Create a daemon.json. This file will allows us to use our local Docker registry without a SSL (https). In production, we will either create a self-signed certificate or use a 3rd party SSL certificate vendor (letsencrypt.org, verisign, etc).

(jenkins-slave): sudo vi /etc/docker/daemon.json

Add this to /etc/docker/daemon.json

{
  "insecure-registries" : ["192.168.2.124:5000"]
}

This fixes the slow outgoing network traffic between the host and Docker.

(jenkins-slave): sudo vi /lib/systemd/system/docker.service

Replace (on line 13)

ExecStart=/usr/bin/dockerd -H fd://

With

ExecStart=/usr/bin/dockerd -H fd:// --mtu=1000

Reload systemd and restart Docker

(jenkins-slave): sudo systemctl daemon-reload; sudo service docker restart

Fix docker.sock permission to allow ubuntu to execute Docker commands

(jenkins-slave): sudo chown root:ubuntu /var/run/docker.sock

Register our Jenkins slave

In the Jenkins UI, go to Manage Jenkins > Manage Nodes > New Node.

  1. Enter “slave-1”, check “Permanent Agent”, and click “OK”.
  2. Enter these values on the next page

    # of executors: 2
    Remote root directory: /home/ubuntu
    Labels: docker
    Usage: Use this node as much as possible
    Launch method: Launch slave agent via SSH
    

    The label docker is used in our Jenkinsfile.

    The node block tells Jenkins to use our Jenkins slave to execute our pipeline commands.

    node('docker') {
    ...
    }
    

    Source: https://github.com/asgpha/node-js-sample/blob/master/Jenkinsfile

  3. Add our Jenkins slave ssh private key

  4. In the launch method, enter these values

    Host: 192.168.2.125
    Credentials: ubuntu
    Host Key Verification Strategy: Non verifying Verification Strategy
    

  5. Click “Save”

  6. Check the slave log and look for “Agent successfully connected and online”. This indicates our slave has been successfully registered.

Launch a Docker Registry

In the Rancher UI, nagivate to Stacks > User, click “Add Stack”.

  1. For name, enter “repository” and click create.
  2. Click “Add Service” on the upper right-hand corner.
  3. Enter the following values and click “Create”:
   Name: registry
   Select Image: registry:2
   Port Map:
     5000 -> 5000

Create a daemon.json. This file will allows us to use our local Docker registry without a SSL (https).

(rancher-host): sudo vi /etc/docker/daemon.json

Add this to /etc/docker/daemon.json

{
  "insecure-registries" : ["192.168.2.124:5000"]
}

Restart Docker

(rancher-host): sudo service docker restart

Jenkinsfile (Pipeline)

We are going to create a pipeline and our Jenkinsfile will define what is in our pipeline. You can find the github project at https://github.com/asgpha/node-js-sample.

There are four important files:

Our Jenkins Pipeline looks like this:

initialize -> build -> publish -> deploy

  • initialize: download our git repository
  • build: tell docker to build our image base off Dockerfile
  • publish: push our built image to our private Docker registry
  • deploy: tell Rancher to upgrade our app/helloworld application

Setup Rancher API keys in Jenkins

To get the Rancher CLI tool working, we need to get our Rancher API keys in the Rancher UI. Navigate to API > Keys and click “Add Account API Key”.

Enter “Jenkins” as the name and copy your Rancher API keys into a text editor.

In the Jenkins UI, we will add the Rancher API keys as environment variables.

Go to Manage Jenkins > Configure System.

Look for “Global properties”, add the following environment variables:

RANCHER_URL: http://192.168.2.123:8080
RANCHER_ACCESS_KEY:
RANCHER_SECRET_KEY:

Note: In production, we would use withCredentials in our Jenkinsfile that would reference the credentials ID.

Save and the Rancher CLI tool should be configured properly.

Create a Pipeline in Jenkins

Go to Jenkins UI > New Item.

For name, enter “helloworld”, select “Pipeline”, and click “OK”.

  1. find “Pipeline”
  2. for Definition, select “Pipeline script from SCM”
  3. in the SCM field, select Git
  4. Repository URL should be https://github.com/asgpha/node-js-sample.git
  5. Branches to build should be */master
  6. Script Path sould be Jenkinsfile

Build and Deploy our Hello World application

In the helloworld Pipeline, on the left hand side, click “Build Now”

To check the build logs, click on the dot next to the #1

What a successful build should look like

Note: To fully automate the deployment, we would need to setup a “Build Trigger” such as a “Poll SCM” or “Trigger builds remotely (e.g., from scripts)”.

View our Hello World Application

In your browser, type http://192.168.2.124:3000.

© 2017 | Atlas Software Group | Hucore theme & Hugo