Initial commit: Spicy CDK automation framework
Jenkins shared library and CDK constructs for AWS infrastructure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
219
vars/dockerUtils.groovy
Normal file
219
vars/dockerUtils.groovy
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Docker utilities for Spicy CDK pipelines
|
||||
* Pushes images to Nexus repository (Sonatype)
|
||||
*/
|
||||
|
||||
// Default Nexus configuration
|
||||
def getDefaultConfig() {
|
||||
return [
|
||||
registry: 'nexus.kodeniks.com',
|
||||
repository: 'docker-hosted',
|
||||
credentialsId: 'kodeniks-nexus-repository'
|
||||
]
|
||||
}
|
||||
|
||||
def getImageRef(Map args, String tag) {
|
||||
def config = getDefaultConfig() + args
|
||||
return "${config.registry}/${config.repository}/${args.imageName}:${tag}"
|
||||
}
|
||||
|
||||
def getImageTag(Map args) {
|
||||
return args.imageTag ?: gitUtils.getShortSHA()
|
||||
}
|
||||
|
||||
def getImageRefSHA(Map args) {
|
||||
return getImageRef(args, getImageTag(args))
|
||||
}
|
||||
|
||||
def getImageRefLatest(Map args) {
|
||||
return getImageRef(args, 'latest')
|
||||
}
|
||||
|
||||
def copyFromImage(Map args) {
|
||||
sh(
|
||||
script: """#!/bin/bash +x
|
||||
set -e
|
||||
IMG_ID=\$(dd if=/dev/urandom bs=1k count=1 2> /dev/null | LC_CTYPE=C tr -cd "a-z0-9" | cut -c 1-22)
|
||||
docker create --name \${IMG_ID} ${args.imageID}
|
||||
docker cp \${IMG_ID}:${args.dockerPath} ${args.jenkinsPath}
|
||||
docker rm \${IMG_ID}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
def getContainerName(Map args) {
|
||||
return "${args.imageName}-${gitUtils.getShortSHA()}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Docker image
|
||||
* @param args.imageName - Name of the image
|
||||
* @param args.dockerfile - Path to Dockerfile (default: 'Dockerfile')
|
||||
* @param args.context - Build context (default: '.')
|
||||
* @param args.buildArgs - Map of build arguments (optional)
|
||||
*/
|
||||
def buildImage(Map args) {
|
||||
def containerName = getContainerName(args)
|
||||
def dockerfile = args.dockerfile ?: 'Dockerfile'
|
||||
def context = args.context ?: '.'
|
||||
|
||||
def buildArgsString = ''
|
||||
if (args.buildArgs) {
|
||||
buildArgsString = args.buildArgs.collect { k, v -> "--build-arg ${k}=${v}" }.join(' ')
|
||||
}
|
||||
|
||||
sh("docker build -t ${containerName} -f ${dockerfile} ${buildArgsString} ${context}")
|
||||
return containerName
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag image for Nexus registry
|
||||
* @param args.imageName - Name of the image
|
||||
* @param args.tagLatest - Whether to also tag as 'latest' (default: true on main branch)
|
||||
*/
|
||||
def tagImage(Map args) {
|
||||
def containerName = getContainerName(args)
|
||||
def tagLatest = args.tagLatest != null ? args.tagLatest : gitUtils.isMain()
|
||||
|
||||
def shaImageRef = getImageRefSHA(args)
|
||||
sh("docker tag ${containerName} ${shaImageRef}")
|
||||
if (tagLatest) {
|
||||
// Tag latest from the SHA-tagged image to ensure they point to the same image
|
||||
sh("docker tag ${shaImageRef} ${getImageRefLatest(args)}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push image to Nexus registry
|
||||
* Optionally compares with remote 'latest' to skip push if unchanged
|
||||
* @param args.imageName - Name of the image
|
||||
* @param args.credentialsId - Jenkins credentials ID for Nexus (default: 'kodeniks-nexus-repository')
|
||||
* @param args.registry - Nexus registry URL (default: 'nexus.kodeniks.com')
|
||||
* @param args.repository - Nexus repository name (default: 'docker-hosted')
|
||||
* @param args.tagLatest - Whether to also push 'latest' tag (default: true on main branch)
|
||||
* @param args.compareWithLatest - Skip push if image matches remote 'latest' (default: true)
|
||||
*/
|
||||
def pushImage(Map args) {
|
||||
def config = getDefaultConfig() + args
|
||||
def tagLatest = args.tagLatest != null ? args.tagLatest : gitUtils.isMain()
|
||||
def compareWithLatest = args.compareWithLatest != null ? args.compareWithLatest : true
|
||||
|
||||
def localImageId = sh(
|
||||
script: "docker inspect -f '{{.Id}}' ${getImageRefSHA(args)}",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
echo "Local image ID: ${localImageId}"
|
||||
|
||||
def remoteImageId = ""
|
||||
if (compareWithLatest && tagLatest) {
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: config.credentialsId,
|
||||
usernameVariable: 'NEXUS_USER',
|
||||
passwordVariable: 'NEXUS_PASS'
|
||||
)]) {
|
||||
try {
|
||||
sh "echo \$NEXUS_PASS | docker login ${config.registry} -u \$NEXUS_USER --password-stdin"
|
||||
sh "docker pull ${getImageRefLatest(args)}"
|
||||
remoteImageId = sh(
|
||||
script: "docker inspect -f '{{.Id}}' ${getImageRefLatest(args)}",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
echo "Remote (latest) image ID: ${remoteImageId}"
|
||||
} catch (Exception e) {
|
||||
echo "Could not pull remote 'latest' image (might be the first build): ${e.getMessage()}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteImageId && localImageId == remoteImageId) {
|
||||
echo "No changes detected (new image is identical to remote 'latest'). Skipping push."
|
||||
return false
|
||||
}
|
||||
|
||||
// Re-tag latest from SHA image right before pushing
|
||||
// This ensures latest points to the new image even if we pulled the old remote latest for comparison
|
||||
if (tagLatest) {
|
||||
sh("docker tag ${getImageRefSHA(args)} ${getImageRefLatest(args)}")
|
||||
}
|
||||
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: config.credentialsId,
|
||||
usernameVariable: 'NEXUS_USER',
|
||||
passwordVariable: 'NEXUS_PASS'
|
||||
)]) {
|
||||
sh "echo \$NEXUS_PASS | docker login ${config.registry} -u \$NEXUS_USER --password-stdin"
|
||||
sh "docker push ${getImageRefSHA(args)}"
|
||||
if (tagLatest) {
|
||||
sh "docker push ${getImageRefLatest(args)}"
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and push a Docker image to Nexus
|
||||
* @param args.imageName - Name of the image (required)
|
||||
* @param args.dockerfile - Path to Dockerfile (default: 'Dockerfile')
|
||||
* @param args.context - Build context (default: '.')
|
||||
* @param args.buildArgs - Map of build arguments (optional)
|
||||
* @param args.credentialsId - Jenkins credentials ID for Nexus (default: 'kodeniks-nexus-repository')
|
||||
* @param args.registry - Nexus registry URL (default: 'nexus.kodeniks.com')
|
||||
* @param args.repository - Nexus repository name (default: 'docker-hosted')
|
||||
* @param args.tagLatest - Whether to also tag/push 'latest' (default: true on main branch)
|
||||
* @param args.compareWithLatest - Skip push if image matches remote 'latest' (default: true)
|
||||
* @return The full image reference (registry/repo/name:tag)
|
||||
*/
|
||||
def buildAndPush(Map args) {
|
||||
buildImage(args)
|
||||
tagImage(args)
|
||||
pushImage(args)
|
||||
|
||||
return getImageRefSHA(args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune dangling Docker images
|
||||
* @param args.pruneCache - Whether to also prune build cache (default: false)
|
||||
*/
|
||||
def prune(Map args = [:]) {
|
||||
def pruneCache = args.pruneCache ?: false
|
||||
echo "Cleaning up dangling Docker images..."
|
||||
if (pruneCache) {
|
||||
sh 'docker system prune -f'
|
||||
} else {
|
||||
// Only prune dangling images, not build cache
|
||||
sh 'docker image prune -f'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to Nexus registry
|
||||
*/
|
||||
def login(Map args = [:]) {
|
||||
def config = getDefaultConfig() + args
|
||||
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: config.credentialsId,
|
||||
usernameVariable: 'NEXUS_USER',
|
||||
passwordVariable: 'NEXUS_PASS'
|
||||
)]) {
|
||||
sh "echo \$NEXUS_PASS | docker login ${config.registry} -u \$NEXUS_USER --password-stdin"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull an image from Nexus
|
||||
*/
|
||||
def pullImage(Map args) {
|
||||
def config = getDefaultConfig() + args
|
||||
def tag = args.tag ?: 'latest'
|
||||
def imageRef = getImageRef(args, tag)
|
||||
|
||||
login(config)
|
||||
sh "docker pull ${imageRef}"
|
||||
|
||||
return imageRef
|
||||
}
|
||||
|
||||
return this
|
||||
Reference in New Issue
Block a user