Using docker Container links in Jenkins
A possible root cause, assuming you are using the official postgres docker image, is that the container's entrypoint
's script is failing.
From the image's Docker page:
Warning: scripts in /docker-entrypoint-initdb.d are only run if you start the container with a data directory that is empty; [...] One common problem is that if one of your /docker-entrypoint-initdb.d scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts
Solution
Assuming that the entrypoint process is indeed failing (probably because it sees a DB that is not owned and is designed by entrypoint
to override it, since it's linked to another postgres container), you can overcome this by setting your own entrypoint
and cmd
, thus preventing the image from trying to create a db that you are not going to use anyway, i.e.:
FROM postgres#Switch back to default entrypointENTRYPOINT ["/bin/sh"]#Let the container start and do nothing until the pipeline kicks inCMD ["-c","sleep infinity"]
Create a new image based on above Dockerfile, push it, and define it in Jenkin's pipeline instead of the current (only for the sidecar). You should then have a stable container, linked to the actual db container, that the pipeline can jump into.
Finally, regarding the command launched in the sidecar, I'd suggest to use localhost
instead of db
as the target host, on command question's pg_isready -h db -p 5432
, reulting in: pg_isready -h localhost -p 5432
After some trial and errors, here is what worked for us. Although it is very similar to the initial set up, the key change is at the choice of using inside
and withRun
. The final Jenkinsfile looks like this.
// credentialsdef docker_user_credentialsId = '<DOCKER-USER>'def docker_repository = '<CUSTOM-REGISTRY>'// docker imagesdef pg = docker.image('postgres:12-alpine')def flyway = docker.image('flyway/flyway:7-alpine')pipeline { agent none options { buildDiscarder(logRotator(daysToKeepStr: '90', numToKeepStr: '20', artifactDaysToKeepStr: '90', artifactNumToKeepStr: '20')) timeout(time: 120, unit: 'MINUTES') } stages { stage('db migration test') { agent { label 'docker && linux' } environment { PGHOST = 'db' PGPORT = '5432' PGDATABASE = 'postgres' PGUSER = 'postgres' PGPASSWORD = 'postgres' } steps { script { docker.withRegistry(docker_repository, docker_user_credentialsId) { def db = pg.withRun( "-v ${WORKSPACE}/docker/init-user-db.sh:/docker-entrypoint-initdb.d/init-user-db.sh -e POSTGRES_USER=${env.PGUSER} -e POSTGRES_PASSWORD=${env.PGPASSWORD} -e POSTGRES_DB=${env.PGDATABASE}" ) { db -> pg.inside("--link ${db.id}:${env.PGHOST}") { sh ''' echo "$(date) - waiting for database to start" while ! pg_isready do sleep 10 done ''' } flyway.withRun("-e FLYWAY_LOCATIONS=filesystem:/tmp/database/server,filesystem:/tmp/database/local -e FLYWAY_URL=jdbc:postgresql://${PGHOST}:${env.PGPORT}/${env.PGDATABASE} -e FLYWAY_USER=${env.PGUSER} -e FLYWAY_PASSWORD=${env.PGPASSWORD} -v ${WORKSPACE}/database/local:/tmp/database/local -v ${WORKSPACE}/database/server:/tmp/database/server --link ${db.id}:db", "migrate") { f -> sh "docker logs -f ${f.id}" def output = sh script: "docker inspect ${f.id} --format='{{.State.ExitCode}}'", returnStdout: true sh "exit ${output}" } } } } } } } }