Skip to content

Commit

Permalink
Merge pull request #1224 from uselagoon/jenkins_declarative
Browse files Browse the repository at this point in the history
build: use declarative syntax for Jenkins
  • Loading branch information
tobybellwood authored Feb 10, 2025
2 parents eaff6ac + 0dbf07d commit e51beb6
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 111 deletions.
257 changes: 148 additions & 109 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,94 +1,128 @@
node ('lagoon-images') {
withCredentials([
string(credentialsId: 'SKIP_IMAGE_PUBLISH', variable: 'SKIP_IMAGE_PUBLISH')
]) {
try {
env.CI_BUILD_TAG = env.BUILD_TAG.replaceAll('%2f','').replaceAll("[^A-Za-z0-9]+", "").toLowerCase()
env.SAFEBRANCH_NAME = env.BRANCH_NAME.replaceAll('%2f','-').replaceAll("[^A-Za-z0-9]+", "-").toLowerCase()
env.SYNC_MAKE_OUTPUT = 'target'
// make/tests will synchronise (buffer) output by default to avoid interspersed
// lines from multiple jobs run in parallel. However this means that output for
// each make target is not written until the command completes.
//
// See `man -P 'less +/-O' make` for more information about this option.
//
// Uncomment the line below to disable output synchronisation.
// env.SYNC_MAKE_OUTPUT = 'none'

stage ('env') {
sh "env"
}

deleteDir()
def skipRemainingStages = false

pipeline {
agent { label 'lagoon-images' }
environment {
// configure build params
SAFEBRANCH_NAME = env.BRANCH_NAME.replaceAll('%2F','-').replaceAll('[^A-Za-z0-9]+', '-').toLowerCase()
SAFEBRANCH_AND_BUILDNUMBER = (env.SAFEBRANCH_NAME+env.BUILD_NUMBER).replaceAll('%2f','').replaceAll('[^A-Za-z0-9]+', '').toLowerCase();
CI_BUILD_TAG = 'lagoon'.concat(env.SAFEBRANCH_AND_BUILDNUMBER.drop(env.SAFEBRANCH_AND_BUILDNUMBER.length()-26));
NPROC = "${sh(script:'getconf _NPROCESSORS_ONLN', returnStdout: true).trim()}"
SKIP_IMAGE_PUBLISH = credentials('SKIP_IMAGE_PUBLISH')
SYNC_MAKE_OUTPUT = 'target'
}

stage ('Checkout') {
def checkout = checkout scm
env.GIT_COMMIT = checkout["GIT_COMMIT"]
stages {
stage ('env') {
steps {
sh 'env'
}
}

// in order to have the newest images from upstream (with all the security updates) we clean our local docker cache on tag deployments
// we don't do this all the time to still profit from image layer caching
// but we want this on tag deployments in order to ensure that we publish images always with the newest possible images.
if (env.TAG_NAME || env.SAFEBRANCH_NAME == 'main') {
stage ('clean docker image cache') {
sh script: "make docker-buildx-remove", label: "removing leftover buildx"
sh script: "docker image prune -af", label: "Pruning images"
sh script: "docker buildx prune -af", label: "Pruning builder cache"
}
// in order to have the newest images from upstream (with all the security
// updates) we clean our local docker cache on tag deployments
// we don't do this all the time to still profit from image layer caching
// but we want this on tag deployments in order to ensure that we publish
// images always with the newest possible images.
stage ('clean docker image cache') {
when {
buildingTag()
}
steps {
sh script: "make docker-buildx-remove", label: "removing leftover buildx"
sh script: "docker image prune -af", label: "Pruning images"
sh script: "docker buildx prune -af", label: "Pruning builder cache"
}
}

stage ('build images') {
stage ('build images') {
steps {
sh script: "docker run --privileged --rm tonistiigi/binfmt --install all", label: "setting binfmt correctly"
sh script: "make docker-buildx-configure", label: "Configuring buildx for multi-platform build"
env.SCAN_IMAGES = 'true'
sh script: "make docker_pull", label: "Ensuring fresh upstream images"
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 build", label: "Building images"
}
}

stage ('show built images') {
stage ('show built images') {
steps {
sh 'cat build.txt'
sh 'docker image ls | grep ${CI_BUILD_TAG} | sort -u'
}
}

stage ('Copy examples down') {
sh script: "git clone https://github.com/uselagoon/lagoon-examples.git tests"
dir ('tests') {
sh script: "git submodule sync && git submodule update --init"
sh script: "mkdir -p ./all-images && cp ../helpers/*docker-compose.yml ./all-images/ && cp ../helpers/TESTING_*_dockercompose.md ./all-images/"
sh script: "sed -i '/image: uselagoon/ s/uselagoon/${CI_BUILD_TAG}/' ./all-images/*-docker-compose.yml"
sh script: "yarn install"
sh script: "docker network inspect amazeeio-network >/dev/null || docker network create amazeeio-network"
stage ('prepare tests and images') {
parallel {
stage ('Copy examples down') {
steps {
sh script: "rm -rf tests || echo 'no tests directory to remove'"
sh script: "git clone https://github.com/uselagoon/lagoon-examples.git tests"
dir ('tests') {
sh script: "git submodule sync && git submodule update --init"
sh script: "mkdir -p ./all-images && cp ../helpers/*docker-compose.yml ./all-images/ && cp ../helpers/TESTING_*_dockercompose.md ./all-images/"
sh script: "sed -i '/image: uselagoon/ s/uselagoon/${CI_BUILD_TAG}/' ./all-images/*-docker-compose.yml"
sh script: "yarn install"
sh script: "docker network inspect amazeeio-network >/dev/null || docker network create amazeeio-network"
}
}
}
stage ('push amd64 branch images to testlagoon/*') {
environment {
PASSWORD = credentials('amazeeiojenkins-dockerhub-password')
}
when {
not {
environment name: 'SKIP_IMAGE_PUBLISH', value: 'true'
}
}
steps {
sh script: 'docker login -u amazeeiojenkins -p $PASSWORD', label: "Docker login"
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 publish-testlagoon-baseimages BRANCH_NAME=${SAFEBRANCH_NAME} PLATFORM='linux/amd64'", label: "Publishing built amd64 images to testlagoon"
}
}
}
}

parallel (
'build and push images to testlagoon dockerhub': {
stage ('push branch images to testlagoon/*') {
withCredentials([string(credentialsId: 'amazeeiojenkins-dockerhub-password', variable: 'PASSWORD')]) {
try {
if (env.SKIP_IMAGE_PUBLISH != 'true') {
sh script: 'docker login -u amazeeiojenkins -p $PASSWORD', label: "Docker login"
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 publish-testlagoon-baseimages BRANCH_NAME=${SAFEBRANCH_NAME}", label: "Publishing built images to testlagoon"
if (env.SAFEBRANCH_NAME == 'main') {
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=testlagoon TAG_ONE=${SAFEBRANCH_NAME} REGISTRY_TWO=testlagoon TAG_TWO=latest", label: "Publishing built images to testlagoon main&latest images"
} else if (env.SAFEBRANCH_NAME == 'arm64-images') {
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=testlagoon TAG_ONE=${SAFEBRANCH_NAME} REGISTRY_TWO=testlagoon TAG_TWO=multiarch", label: "Publishing built images to testlagoon arm images"
} else {
sh script: 'echo "No multi-arch images required for this build"', label: "Skipping image publishing"
}
} else {
sh script: 'echo "skipped because of SKIP_IMAGE_PUBLISH env variable"', label: "Skipping image publishing"
}
} catch (e) {
echo "Something went wrong, trying to cleanup"
cleanup()
throw e
}
stage ('test and push images') {
parallel {
stage ('push main branch images to testlagoon/*') {
environment {
PASSWORD = credentials('amazeeiojenkins-dockerhub-password')
}
when {
branch 'main'
not {
environment name: 'SKIP_IMAGE_PUBLISH', value: 'true'
}
}
},
'Run all the tests on the local images': {
stage ('running test suite') {
steps {
retry(3) {
sh script: 'docker login -u amazeeiojenkins -p $PASSWORD', label: "Docker login"
sh script: "timeout 60m make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=testlagoon TAG_ONE=${SAFEBRANCH_NAME} REGISTRY_TWO=testlagoon TAG_TWO=latest PLATFORM='linux/arm64/v8'", label: "Publishing built arm64 images to testlagoon main&latest images"
}
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=testlagoon TAG_ONE=${SAFEBRANCH_NAME} REGISTRY_TWO=testlagoon TAG_TWO=latest PLATFORM='linux/amd64,linux/arm64/v8'", label: "Publishing built digest to testlagoon main&latest images"
}
}
stage ('push arm64-images branch images to testlagoon/*') {
environment {
PASSWORD = credentials('amazeeiojenkins-dockerhub-password')
}
when {
branch 'arm64-images'
not {
environment name: 'SKIP_IMAGE_PUBLISH', value: 'true'
}
}
steps {
retry(3) {
sh script: 'docker login -u amazeeiojenkins -p $PASSWORD', label: "Docker login"
sh script: "timeout 60m make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=testlagoon TAG_ONE=${SAFEBRANCH_NAME} REGISTRY_TWO=testlagoon TAG_TWO=multiarch PLATFORM='linux/arm64/v8'", label: "Publishing built arm64 images to testlagoon multiarch images"
}
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=testlagoon TAG_ONE=${SAFEBRANCH_NAME} REGISTRY_TWO=testlagoon TAG_TWO=multiarch PLATFORM='linux/amd64,linux/arm64/v8'", label: "Publishing built digest to testlagoon multiarch images"
}
}
stage ('running test suite') {
steps {
dir ('tests') {
sh script: "docker buildx use default", label: "Ensure to use default builder"
sh script: "grep -rl uselagoon . | xargs sed -i '/^FROM/ s/uselagoon/${CI_BUILD_TAG}/'"
Expand All @@ -101,56 +135,61 @@ node ('lagoon-images') {
}
}
}
)
}
}

stage ('publish experimental image tags to testlagoon') {
if (env.SAFEBRANCH_NAME == 'main' || env.CHANGE_ID && pullRequest.labels.contains("experimental")) {
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 publish-testlagoon-experimental-baseimages BRANCH_NAME=${SAFEBRANCH_NAME}", label: "Publishing experimental images to testlagoon"
} else {
sh script: 'echo "not a PR or main branch push"', label: "Skipping experimantal image publishing"
stage ('push branch images to uselagoon/*') {
environment {
PASSWORD = credentials('amazeeiojenkins-dockerhub-password')
}
when {
buildingTag()
not {
environment name: 'SKIP_IMAGE_PUBLISH', value: 'true'
}
}

if (env.TAG_NAME && env.SKIP_IMAGE_PUBLISH != 'true') {
stage ('push branch images to uselagoon/*') {
withCredentials([string(credentialsId: 'amazeeiojenkins-dockerhub-password', variable: 'PASSWORD')]) {
try {
if (env.SKIP_IMAGE_PUBLISH != 'true') {
sh script: 'docker login -u amazeeiojenkins -p $PASSWORD', label: "Docker login"
sh script: "make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=uselagoon TAG_ONE=${TAG_NAME} REGISTRY_TWO=uselagoon TAG_TWO=latest", label: "Publishing built images to uselagoon"
} else {
sh script: 'echo "skipped because of SKIP_IMAGE_PUBLISH env variable"', label: "Skipping image publishing"
}
} catch (e) {
echo "Something went wrong, trying to cleanup"
cleanup()
throw e
}
}
steps {
retry(3) {
sh script: 'docker login -u amazeeiojenkins -p $PASSWORD', label: "Docker login"
sh script: "timeout 60m make -O${SYNC_MAKE_OUTPUT} -j8 build PUBLISH_IMAGES=true REGISTRY_ONE=uselagoon TAG_ONE=${TAG_NAME} REGISTRY_TWO=uselagoon TAG_TWO=latest", label: "Publishing built images to uselagoon"
}
}
}

if (env.TAG_NAME || env.SAFEBRANCH_NAME == 'main' || env.SAFEBRANCH_NAME == 'testing-scans' ) {
stage ('scan built images') {
sh script: 'make scan-images', label: "perform scan routines"
sh script: 'find ./scans/*trivy* -type f | xargs tail -n +1', label: "Show Trivy vulnerability scan results"
sh script: 'find ./scans/*grype* -type f | xargs tail -n +1', label: "Show Grype vulnerability scan results"
sh script: 'find ./scans/*syft* -type f | xargs tail -n +1', label: "Show Syft SBOM results"
stage ('scan built images') {
when {
anyOf {
branch 'main'
buildingTag()
}
not {
environment name: 'SKIP_IMAGE_PUBLISH', value: 'true'
}
}
steps {
sh script: 'make scan-images', label: "perform scan routines"
sh script: 'find ./scans/*trivy* -type f | xargs tail -n +1', label: "Show Trivy vulnerability scan results"
sh script: 'find ./scans/*grype* -type f | xargs tail -n +1', label: "Show Grype vulnerability scan results"
sh script: 'find ./scans/*syft* -type f | xargs tail -n +1', label: "Show Syft SBOM results"
}
}
}

} catch (e) {
currentBuild.result = 'FAILURE'
echo "Something went wrong, trying to cleanup"
throw e
} finally {
post {
always {
cleanup()
notifySlack(currentBuild.result)
deleteDir()
}
success {
notifySlack('SUCCESS')
}
failure {
notifySlack('FAILURE')
}
aborted {
notifySlack('ABORTED')
}

cleanup()
}

}

def cleanup() {
Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ BRANCH_NAME :=
# Only set this to false when ready to push images to dockerhub
PUBLISH_IMAGES ?= false

PLATFORM ?= linux/amd64

# Init the file that is used to hold the image tag cross-reference table
$(shell >build.txt)
$(shell >scan.txt)
Expand All @@ -79,7 +81,7 @@ docker_build_local = DOCKER_BUILDKIT=1 docker build $(DOCKER_BUILD_PARAMS) \

docker_buildx_two = docker buildx build $(DOCKER_BUILD_PARAMS) \
--builder ci-local \
--platform linux/amd64,linux/arm64/v8 \
--platform $(PLATFORM) \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg LAGOON_VERSION=$(LAGOON_VERSION) \
--build-arg IMAGE_REPO=localhost:5000/testlagoon \
Expand All @@ -93,7 +95,7 @@ docker_buildx_two = docker buildx build $(DOCKER_BUILD_PARAMS) \

docker_buildx_three = docker buildx build $(DOCKER_BUILD_PARAMS) \
--builder ci-local \
--platform linux/amd64,linux/arm64/v8 \
--platform $(PLATFORM) \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg LAGOON_VERSION=$(LAGOON_VERSION) \
--build-arg IMAGE_REPO=localhost:5000/uselagoon \
Expand Down

0 comments on commit e51beb6

Please sign in to comment.