raspberry-pi-enclosed-in-lego-structure

Building a CI/CD pipeline part 2 on a Raspberry PI Cluster, with JFrog Artifactory as the repository manager


Building a CI/CD pipeline on a Raspberry PI Cluster (Part II)

(Total Setup Time: 40 mins)

Continuing from part I of this guide, I will add JFrog Artifactory to my CI/CD pipeline.

Preparation

(1 min)

Referencing from my previous post on maven agent, let’s configure maven-agent to mount Longhorn volume. Navigate to Manage Jenkins > Manage Nodes and Clouds > Configure Clouds. Expand on Pod Template details and add a volume:

Claim Name: maven-agent-pvc Mount Path: /home/jenkins/.m2

jenkins-add-maven-agent-volume


Installing Artifactory

(13 mins)

First, download the JFrog Artifactory OSS edition. Due to some yq issues on Raspberry PI, I download the older version instead:

mkdir ~/artifactory cd ~/artifactory curl https://releases.jfrog.io/artifactory/bintray-artifactory/org/artifactory/oss/jfrog-artifactory-oss/6.23.21/jfrog-artifactory-oss-6.23.21.zip -o jfrog-artifactory-oss-6.23.21.zip

Second, prepare the Dockerfile for Raspberry PI:

# Copy and paste below into Dockerfile vi Dockerfile
FROM balenalib/raspberrypi4-64-debian-openjdk:11-bullseye EXPOSE 8081 RUN apt-get update \ && apt-get install wget unzip -y WORKDIR /opt COPY jfrog-artifactory-oss-6.23.21.zip /opt RUN mkdir jfrog \ && mv jfrog-artifactory-oss-6.23.21.zip jfrog WORKDIR /opt/jfrog RUN export JFROG_HOME=/opt/jfrog RUN unzip jfrog-artifactory-oss-6.23.21.zip \ && mv artifactory-oss-6.23.21 artifactory \ && cd artifactory/bin WORKDIR /opt/jfrog/artifactory/bin CMD ./artifactoryctl

Third, build and tag the docker image:

docker build -t seehiong/artifactory:1.0 .

Last, create the required Longhorn volumes and prepare the Kubernetes deployment file. NOTE: I add delay in the init-container in order for Longhorn to stabilize. Also note that this directory structure is different from the latest Artifactory versions.

# Copy and paste below into artifactory-deployment.yaml vi artifactory-deployment.yaml
apiVersion: v1 kind: Service metadata: name: artifactory namespace: seehiong annotations: metallb.universe.tf/allow-shared-ip: home-net spec: ports: - port: 8081 targetPort: 8081 nodePort: 30081 name: artifact-http selector: app: artifactory type: LoadBalancer loadBalancerIP: 192.168.100.250 --- apiVersion: apps/v1 kind: Deployment metadata: name: artifactory namespace: seehiong spec: selector: matchLabels: app: artifactory template: metadata: labels: app: artifactory spec: containers: - name: artifactory image: seehiong/artifactory:1.0 imagePullPolicy: Never ports: - containerPort: 8081 name: artifact-http volumeMounts: - name: artifactory-data-persistent-storage mountPath: /opt/jfrog/artifactory/data - name: artifactory-etc-persistent-storage mountPath: /opt/jfrog/artifactory/etc initContainers: - name: init-volume image: arm64v8/busybox command: ['sh', '-c', "sleep 30"] volumes: - name: artifactory-data-persistent-storage persistentVolumeClaim: claimName: artifactory-data-pvc - name: artifactory-etc-persistent-storage persistentVolumeClaim: claimName: artifactory-etc-pvc

Configuring Artifactory

(10 mins)

It takes a while for Artifactory to setup. In my case, I add maven during startup. You may peek at the progress by:

kubectl get po -n seehiong # Get logs (remember to replace with your pod name) kubectl logs -n seehiong artifactory-99b667d47-jqxkv -f # Get inside the container kubectl exec -n seehiong -it artifactory-99b667d47-jqxkv -- bash

First, log into Artifactory using the default admin user and password. Creates your own account. From Admin > Security > Permission menu, adds a permission:

artifactory-permission-users


Second, from Artifacts menu, click on Set Me Up button. Select the maven, enter password and click on Generate Maven Settings button.

artifactory-set-me-up


Third, click on Generate Settings button and scroll down to the settings file. Click on Download Snippet link and copy this settings.xml file to the .m2 folder of the maven-agent-pvc volume. NOTE: Please remember to modify the user and password of your newly created account, which has deploy permission.

artifactory-download-snippet


Lastly, copy the contents of the distribution management and paste into your project’s pom.xml file. NOTE: Depending on your setting, enter either libs-snapshot or libs-release, such as:

<distributionManagement> <repository> <id>central</id> <name>artifactory-99b667d47-gzcwk-releases</name> <url>http://192.168.100.250:8081/artifactory/libs-snapshot</url> </repository> </distributionManagement>

Configuring Jenkins

(1 min)

First, from Manage Jenkins > Manage Plugins, click on Available tab and search for Artifactory. Installs Artifactory plugin.

jenkins-artifactory-plugin


Second, from Manage Jenkins > Configure System, scroll to JFrog section. Enters Artifactory URL and the deployer credential.

jenkins-jfrog-settings


Deploy JAR to Artifactory

(5 mins)

First, configure your project’s Jenkinsfile to include a deploy command. This is my sample file:

pipeline { agent none stages { stage('Build & Deploy') { agent { label 'maven' } steps { checkout scm sh './mvnw -DskipTests clean package deploy' } } } }

Second, when you commit the changes, Jenkins triggers a pipeline. It builds the code and pushes the package to the Artifactory.

jenkins-upload-to-artifactory


Finally! With this setup, you build a CI/CD pipeline on a Raspberry PI Cluster (Part 2), integrating Jenkins and Artifactory.

artifactory-repo-browser


Troubleshooting

Unstable Longhorn Volumes

Perhaps due to my setup, my cluster node reboots by itself and the entire cluster becomes unstable. To resolve this issue, I create few scripts to delete existing Kubernetes deployments. When Longhorn is finally up and running without issues, my deployments are then deployed, one at a time.

Jenkins wrong volume permissions

This happens when user in the container does not have the same userid:groupid as the user on the host, which has access to the volume. To fix this, under the template/spec of deployment.yaml, I create an init container to change the ownership of the volume.

... initContainers: - name: init image: arm64v8/busybox:latest command: ["sh", "-c", "chown -R 1000:1000 /.m2"] volumeMounts: - name: maven-agent-pvc mountPath: /.m2 ...