Milan Smolík
Milan Smolík

Reputation: 149

How do I set up postgres database in Jenkins pipeline?

I am using docker to simulate postgres database for my app. I was testing it in Cypress for some time and it works fine. I want to set up Jenkins for further testing, but I seem stuck.

On my device, I would use commands

docker create -e POSTGRES_DB=myDB -p 127.0.0.1:5432:5432 --name myDB postgres docker start myDB

to create it. How can I simulate this in Jenkins pipeline? I need the DB for the app to work.

I use Dockerfile as my agent, and I have tried putting the ENV variables there, but it does not work. Docker is not installed on the pipeline.

The way I see it is either:

  1. Create an image by using a
  2. Somehow install docker inside the pipeline and use the same commands
  3. Maybe with master/slave nodes? I don't understand them well yet.

Upvotes: 2

Views: 11469

Answers (2)

hakamairi
hakamairi

Reputation: 4678

This might be a use case for sidecar pattern one of Jenkins Pipeline's advanced features.

For example (from the above site):

node {
    checkout scm
    docker.image('mysql:5').withRun('-e "MYSQL_ROOT_PASSWORD=my-secret-pw"') { c ->
        docker.image('mysql:5').inside("--link ${c.id}:db") {
            /* Wait until mysql service is up */
            sh 'while ! mysqladmin ping -hdb --silent; do sleep 1; done'
        }
        docker.image('centos:7').inside("--link ${c.id}:db") {
            /*
             * Run some tests which require MySQL, and assume that it is
             * available on the host name `db`
             */
            sh 'make check'
        }
    }
}

The above example uses the object exposed by withRun, which has the running container’s ID available via the id property. Using the container’s ID, the Pipeline can create a link by passing custom Docker arguments to the inside() method.

Best thing is that the containers should be automatically stopped and removed when the work is done.

EDIT:
To use docker network instead you can do the following (open Jira to support this OOTB). Following helper function

def withDockerNetwork(Closure inner) {
    try {
        networkId = UUID.randomUUID().toString()
        sh "docker network create ${networkId}"
        inner.call(networkId)
    } finally {
        sh "docker network rm ${networkId}"
    }
}

Actual usage

withDockerNetwork{ n ->
   docker.image('sidecar').withRun("--network ${n} --name sidecar") { c->
      docker.image('main').inside("--network ${n}") {
         // do something with host "sidecar"
      }
   }
} 

Upvotes: 3

kivagant
kivagant

Reputation: 1967

For declarative pipelines:

pipeline {
  agent any
  environment {
    POSTGRES_HOST = 'localhost'
    POSTGRES_USER = myuser'
  }

  stages {
    stage('run!') {
      steps {
        script {
            docker.image('postgres:9.6').withRun(
                "-h ${env.POSTGRES_HOST} -e POSTGRES_USER=${env.POSTGRES_USER}"
            ) { db ->
// You can your image here but you need psql to be installed inside
                docker.image('postgres:9.6').inside("--link ${db.id}:db") {
                  sh '''
psql --version
until psql -h ${POSTGRES_HOST} -U ${POSTGRES_USER} -c "select 1" > /dev/null 2>&1 || [ $RETRIES -eq 0 ]; do
  echo "Waiting for postgres server, $((RETRIES-=1)) remaining attempts..."
  sleep 1
done
'''
                  sh 'echo "your commands here"'
                }
              }
            }
      }
    }
  }
}

Related to Docker wait for postgresql to be running

Upvotes: -2

Related Questions