How to build docker images using a Declarative Jenkinsfile - jenkins

I'm new to using Jenkins....
I'm trying to automate the production of an image (to be stashed in a repo) using a declarative Jenkinsfile. I find the documentation to be confusing (at best). Simply put, how can I convert the following scripted example (from the docs)
node {
checkout scm
def customImage = docker.build("my-image:${env.BUILD_ID}")
customImage.push()
}
to a declarative Jenkinsfile....

You can use scripted pipeline blocks in a declarative pipeline as a workaround
pipeline {
agent any
stages {
stage('Build image') {
steps {
echo 'Starting to build docker image'
script {
def customImage = docker.build("my-image:${env.BUILD_ID}")
customImage.push()
}
}
}
}
}

I'm using following approach:
steps {
withDockerRegistry([ credentialsId: "<CREDENTIALS_ID>", url: "<PRIVATE_REGISTRY_URL>" ]) {
// following commands will be executed within logged docker registry
sh 'docker push <image>'
}
}
Where:
CREDENTIALS_ID stands for key in Jenkis under which you store credentials to your docker registry.
PRIVATE_REGISTRY_URL stands for url of your private docker registry. If you are using docker hub then it should be empty.

I cannot recommend the declarative syntax for building a Docker image bcos it seems that every important step requires falling back to the old scripting syntax. But if you must, a hybrid approach seems to work.
First a detail about the scm step: when I defined the Jenkins "Pipeline script from SCM" project that fetches my Jenkinsfile with a declarative pipline from git, Jenkins cloned the repo as the first step in the pipeline even tho I did not define a scm step.
For the build and push steps, I can only find solutions that are a hybrid of old-style scripted pipeline steps inside the new-style declarative syntax. For example see gustavoapolinario's work at Medium:
https://medium.com/#gustavo.guss/jenkins-building-docker-image-and-sending-to-registry-64b84ea45ee9
which has this hybrid pipeline definition:
pipeline {
environment {
registry = "gustavoapolinario/docker-test"
registryCredential = 'dockerhub'
dockerImage = ''
}
agent any
stages {
stage('Cloning Git') {
steps {
git 'https://github.com/gustavoapolinario/microservices-node-example-todo-frontend.git'
}
}
stage('Building image') {
steps{
script {
dockerImage = docker.build registry + ":$BUILD_NUMBER"
}
}
}
stage('Deploy Image') {
steps{
script {
docker.withRegistry( '', registryCredential ) {
dockerImage.push()
}
}
}
}
stage('Remove Unused docker image') {
steps{
sh "docker rmi $registry:$BUILD_NUMBER"
}
}
}
}
Because the first step here is a clone, I think he built this example as a standalone pipeline project in Jenkins (not a Pipeline script from SCM project).

Related

Jenkins concurrent builds interfering each other

I have a declare pipeline, shown as follow:
pipeline{
agent any
stages{
stage("Pull Souce Code"){
steps{
checkout(...)
}
}
stage("Build and Push image"){
steps{
script{
docker.withRegistry(...){
def image = docker.build(...)
image.push()
}
}
}
}
}
}
The pipeline is running on the Jenkins Master(I don't build any jenkins slave).
When I run this task concurrently, sometimes the Dockerfile referenced does not match the GitLab project.
I notice the current pipeline have 2 Jenkins workspace:
/var/lib/jenkins/workspace/job_name and /var/lib/jenkins/workspace/job_name#2
Their Git files don't match their Dockerfile files.
I have to disable concurrent build now. What should I do?

Kubernetes cloud agent for Jenkins always offline during pipeline execution

I try to deploy microservices into k8s pod using Jenkins pipeline and k8s cloud agent.
I configured my agent on Jenkins but during execution I always have message saying my agent is offline.
You could find my Jenkins configuration and my Jenkins file.
Regards,
Jenkinsfile
pipeline {
environment {
MAVEN_SETTINGS = ''
MAVEN_ENV = 'maven-3.6.3'
JDK_ENV = 'jdk-1.2'
GIT_URL = 'PRIVATE REPO'
}
agent any
parameters{
booleanParam(name:"RELEASE",
description:"Release",
defaultValue:false
)
}
stages {
stage ('build & deploy'){
when{
expression {!params.RELEASE}
}
steps{
withMaven(
maven: env.MAVEN_ENV,
mavenSettingsConfig: env.MAVEN_SETTINGS,
jdk: env.JDK_ENV) {
sh "mvn clean deploy -U"
}
}
}
stage ('create image'){
steps{
script {
docker.withRegistry('https://registry.digitalocean.com', 'images-credential') {
def customImage = docker.build("images-repo:${params.IMAGE_VERSION}","./target")
customImage.push("${params.IMAGE_VERSION}")
}
}
}
}
stage ('Deploy Pod') {
agent { label 'kubepod' }
steps {
script {
kubernetesDeploy(configs: "/kubernetes/pod.yml", kubeconfigId: "mykubeconfig")
kubernetesDeploy(configs: "/kubernetes/services.yml", kubeconfigId: "mykubeconfig")
}
}
}
}
}
Kubernetes agent config
Pod template config
Jenkins global security config
Build log
Use TCP port for inbound agents: Fixed and put 50000
You do not have to create direction connection.Please go to Kubernetes cloud details and add your service token and ssl of that token to make connection. you have a issue in your pipeline.Please correct it like
stage(test){
agent{
cloud 'cloud name'
yaml"""
"""
}
}
Please follow this article to start from the basic details.

Jenkins using docker agent with environment declarative pipeline

I would like to install maven and npm via docker agent using Jenkins declarative pipeline. But When I would like to use below script Jenkins throws an error as below. It might be using agent none but how can I use node with docker agent via declarative pipeline jenkins.
ERROR: Attempted to execute a step that requires a node context while
‘agent none’ was specified. Be sure to specify your own ‘node { ... }’
blocks when using ‘agent none’.
I try to set agent any but this time I received an error "Still waiting to schedule task
Waiting for next available executor"
pipeline {
agent none
// environment{
proxy = https://
// stable_revision = sh(script: 'curl -H "Authorization: Basic $base64encoded"
// }
stages {
stage('Build') {
agent {
docker { image 'maven:3-alpine'}
}
steps {
sh 'mvn --version'
echo "$apigeeUsername"
echo "Stable Revision: ${env.stable_revision}"
}
}
stage('Test') {
agent { docker { image 'maven:3-alpine' image 'node:8.12.0' } }
environment {
HOME = '.'
}
steps {
script{
try{
sh 'npm install'
sh 'node --version'
//sh 'npm test/unit/*.js'
}catch(e){
throw e
}
}
}
}
// stage('Policy-Code Analysis') {
// steps{
// sh "npm install -g apigeelint"
// sh "apigelint -s wiservice_api_v1/apiproxy/ -f codeframe.js"
// }
// }
stage('Promotion'){
steps{
timeout(time: 2, unit: 'DAYS') {
input 'Do you want to Approve?'
}
}
}
stage('Deployment'){
steps{
sh "mvn -f wiservice_api_v1/pom.xml install -Ptest -Dusername=${apigeeUsername} -Dpassword=${apigeePassword} -Dapigee.config.options=update"
//sh "mvn apigee-enterprise:install -Ptest -Dusername=${apigeeUsername} -Dpassword=${apigeePassword} "
}
}
}
}
Basically your error message tells you everything you need to know:
ERROR: Attempted to execute a step that requires a node context while
‘agent none’ was specified. Be sure to specify your own ‘node { ... }’
blocks when using ‘agent none’.
so what is the issue here? You use agent none for your pipeline which means you do not specify a specific agent for all stages. An agent executes a specific stage. If a stage has no agent it can't be executed and this is your issue here.
The following 2 stage have no agent which means no docker-container / server or whatever where it can be executed.
stage('Promotion'){
steps{
timeout(time: 2, unit: 'DAYS') {
input 'Do you want to Approve?'
}
}
}
stage('Deployment'){
steps{
sh "mvn -f wiservice_api_v1/pom.xml install -Ptest -Dusername=${apigeeUsername} -Dpassword=${apigeePassword} -Dapigee.config.options=update"
//sh "mvn apigee-enterprise:install -Ptest -Dusername=${apigeeUsername} -Dpassword=${apigeePassword} "
}
}
so you have to add agent { ... } to both stage seperately or use a global agent like following and remove the agent from your stages:
pipeline {
agent {
docker { image 'maven:3-alpine'}
} ...
For further information see guide to set up master and agent machines or distributed jenkins builds or the official documentation.
I think you meant to add agent any instead of agent none, because each stage requires at least one agent (either declared at the top for the pipeline or per stage).
Also, I see some more issues.
Your Test stage specifies two images for the same stage.
agent { docker { image 'maven:3-alpine' image 'node:8.12.0' } } although, your stage is executing only npm commands. I believe only one of the image will be downloaded.
To clarify bit more on mkemmerz answer, your Promotion stage is designed correctly. If you plan to have an input step in the pipeline, do not add an agent for the pipeline because input steps block the executor context. See this link https://jenkins.io/blog/2018/04/09/whats-in-declarative/

Jenkins pipeline job start by hook by release

I have a Bitbucked repo, and I want to satrt my Jenkins pipeline job only afrer commit with tag like "release-1.0.*"
So, I seted my job up with pipeline script:
pipeline {
agent any
stages {
stage ('Prepare') {
when {
tag "release*"
}
steps {
git branch: 'tag1', url: 'git#bitbucket.org:m*********ny/tests.git'
}
}
stage ('Deploy') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: "JenkinsSrv", transfers: [sshTransfer(execCommand: 'pwd')])])
}
}
}
post ('POST BUILD'){
always {
echo 'This is post action!!!'
}
}
}
Also, I turned on Bitbucked webhook plugin, than my repo notify Jenkins about new changes.
But my solution doesn't work. Help me resolve this case.
enter image description here
According to the official documentation for a Jenkins pipeline, the option you are looking for is the changelog condition inside the when directive. For example:
when { changelog 'release*' }

How to use an environment variable in the agent section of a Jenkins Declarative Pipeline?

I'm building a Docker image for an application based in node.js where some of the dependencies requires an NPM token for a private NPM registry, but when building the image the variable containing the token is null, e.g.
docker build -t 3273e0bfe8dd329a96070382c1c554454ca91f96 --build-args NPM_TOKEN=null -f Dockerfile
a simplified pipeline is:
pipeline {
environment {
NPM_TOKEN = credentials('npm-token')
}
agent {
dockerfile {
additionalBuildArgs "--build-args NPM_TOKEN=${env.NPM_TOKEN}"
}
}
stages {
stage('Lint') {
steps {
sh 'npm run lint'
}
}
}
}
Is there a way to use the env variable in that section or it is not currently supported?
BTW, I've followed the suggestions in Docker and private modules related to how to use a NPM token to build a docker image
This is definitely a bug with the declarative pipeline. You can track the issue related to this here: https://issues.jenkins-ci.org/browse/JENKINS-42369
If you move away from using the declarative pipeline and use the scripted pipelines instead, this won't occur, although your Jenkinsfile will be "wordier"
found a solution for this. Use credentials manager to add NPM_TOKEN. Then you can do
pipeline {
agent {
docker {
image 'node:latest'
args '-e NPM_TOKEN=$NPM_TOKEN'
}
}
stages {
stage('npm install') {
steps {
sh 'npm install'
}
}
stage('static code analysis') {
steps {
sh 'npx eslint .'
}
}
}
}
I came up with a workaround for this and it still uses declarative pipeline.
I'm using this technique to download private github repos with pip.
// Workarounds for https://issues.jenkins-ci.org/browse/JENKINS-42369
// Warning: The secret will show up in your build log, and possibly be in your docker image history as well.
// Don't use this if you have a super-confidential codebase
def get_credential(name) {
def v;
withCredentials([[$class: 'StringBinding', credentialsId: name, variable: 'foo']]) {
v = env.foo;
}
return v
}
def get_additional_build_args() {
return "--build-arg GITHUB_ACCESS_TOKEN=" + get_credential("mysecretid")
}
pipeline {
agent {
dockerfile {
filename 'Dockerfile.test'
additionalBuildArgs get_additional_build_args()
}
}

Resources