postgresql - 在 Jenkins 中使用 docker Container 链接

标签 postgresql docker jenkins jenkins-pipeline flyway

我正在尝试运行适用于数据库迁移脚本的 CI 系统。因此,这可能会阻止我们运行由于语法错误而在迁移时不起作用的 sql 脚本。对于我们的本地设置,我们使用 docker-compose 并一次运行多个容器。不幸的是,这不是我们在 Jenkins 管道中的一个选择
我使用以下策略创建了这个 Jenkinsfile。

  • postgres 容器使用或多或少的默认参数运行
  • 另一个 postgres 容器链接到第一个容器,只是为了使用 pg_isready 命令行等待 DB 准备好接受连接
  • 使用 flyway 容器针对步骤 1 中的 DB 设置运行 DB 迁移。最终计划也使用 Web 应用程序运行 E2E 测试

  • 我的实现基于 documentation here (运行 docker sidecar)。但是,这不起作用,第一个容器(步骤 1)似乎正在停止。我添加了一些额外的调试(try catch)来查看这个容器的日志
    我的内容 Jenkins 文件
    def docker_repository = '<CUSTOM-REGISTRY>'
    def docker_user_credentialsId = '<DOCKER-USER>'
    
    pipeline {
       agent { label 'docker && linux && nonprod' }
    
    options {
        buildDiscarder(logRotator(daysToKeepStr: '90', numToKeepStr: '20', artifactDaysToKeepStr: '90', artifactNumToKeepStr: '20'))
        timeout(time: 20, unit: 'MINUTES') 
    }
    stages {
        stage('build & test') {
            environment {
                POSTGRES_DB = 'mydb'
                POSTGRES_USER = 'postgres'
                POSTGRES_PASSWORD = 'postgres'                
                FLYWAY_URL = 'jdbc:postgresql://localhost:5432/mydb'
                // FLYWAY_URL = 'jdbc:postgresql://db-container:5432/mydb'
                FLYWAY_USER = 'postgres'
                FLYWAY_PASSWORD = 'postgres'
            }
            steps {
                checkout scm
                withCredentials([ usernamePassword(credentialsId: docker_user_credentialsId, passwordVariable: 'ARTIFACTORY_API_TOKEN', usernameVariable: 'ARTIFACTORY_API_USER'),]) {}                                
                script {
                    docker.withRegistry(docker_repository, docker_user_credentialsId) {
                        docker.image('<REGISTRY>/postgres').withRun("--name=db-container -e POSTGRES_PASSWORD=postgres") { c ->
                            try {
                                docker.image('<REGISTRY>/postgres').inside("--link ${c.id}:db") {                                
                                    sh '''
                                        while ! pg_isready -h db -p 5432
                                        do
                                             echo $
                                             echo "$(date) - waiting for database to start"
                                             sleep 10
                                        done
                                    '''
                                }
                                docker.image('<REGISTRY>/flyway/flyway').inside("--link ${c.id}:db") {
                                    sh 'info'
                                    // sh 'migrate'
                                }
                            } catch (exc) {
                                sh "docker logs ${c.id}"
                                throw exc
                            }
                        }
                    }
                }                
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
    
    }
    由于第 2 步在循环中等待并且 暂时删除了第 2 步以获取此日志。 docker 日志
    + docker logs 9d9e8699b57430e288520c485c8333a0261f9283f749aec2832cfb0e5f19ef9e
     The files belonging to this database system will be owned by user "postgres".
     This user must also own the server process.
     The database cluster will be initialized with locale "en_US.utf8".
     The default database encoding has accordingly been set to "UTF8".
     The default text search configuration will be set to "english".
    
     Data page checksums are disabled.
     fixing permissions on existing directory /var/lib/postgresql/data ... ok
      creating subdirectories ... ok
      selecting dynamic shared memory implementation ... posix
      selecting default max_connections ... 100
      selecting default shared_buffers ... 128MB 
      selecting default time zone ... Etc/UTC
      creating configuration files ... ok
      running bootstrap script ... ok
      performing post-bootstrap initialization ... ok
      syncing data to disk ... ok
      Success. You can now start the database server using:
      pg_ctl -D /var/lib/postgresql/data -l logfile start
      initdb: warning: enabling "trust" authentication for local connections
      You can change this by editing pg_hba.conf or using the option -A, or
       --auth-local and --auth-host, the next time you run initdb.
      waiting for server to start....2021-03-31 15:21:29.923 UTC [48] LOG:  starting PostgreSQL 13.2 
      (Debian 13.2-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
      2021-03-31 15:21:29.929 UTC [48] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
      2021-03-31 15:21:29.946 UTC [49] LOG:  database system was shut down at 2021-03-31 15:21:29 UTC
      2021-03-31 15:21:29.951 UTC [48] LOG:  database system is ready to accept connections
      done
    
      server started
    
       /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
       2021-03-31 15:21:30.062 UTC [48] LOG:  received fast shutdown request
       waiting for server to shut down....2021-03-31 15:21:30.064 UTC [48] LOG:  aborting any active transactions
    
       2021-03-31 15:21:30.065 UTC [48] LOG:  background worker "logical replication launcher" (PID 55) 
         exited with exit code 1
    
        2021-03-31 15:21:30.071 UTC [50] LOG:  shutting down
        2021-03-31 15:21:30.099 UTC [48] LOG:  database system is shut down
        done
    
        server stopped
        PostgreSQL init process complete; ready for start up.
    
        2021-03-31 15:21:30.188 UTC [1] LOG:  starting PostgreSQL 13.2 (Debian 13.2-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
    
        2021-03-31 15:21:30.190 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
        2021-03-31 15:21:30.190 UTC [1] LOG:  listening on IPv6 address "::", port 5432
        2021-03-31 15:21:30.196 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
        2021-03-31 15:21:30.203 UTC [67] LOG:  database system was shut down at 2021-03-31 15:21:30 UTC
        2021-03-31 15:21:30.208 UTC [1] LOG:  database system is ready to accept connections
    
    postgres 和 flyway 版本在这里不应该发挥重要作用,但正如在日志中看到的那样,Postgres 版本是 13.2,由默认标签提供。
    这里有什么指点吗?

    最佳答案

    一个可能的根本原因,假设您使用的是 official postgres docker image , 是容器的 entrypoint的脚本失败。
    从图像的 Docker 页面:

    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


    解决方案
    假设入口点进程确实失败了(可能是因为它看到了一个不属于并由 entrypoint 设计的数据库来覆盖它,因为它链接到另一个 postgres 容器),您可以通过设置自己的 entrypoint 来克服这个问题。和 cmd ,从而防止图像尝试创建一个无论如何都不会使用的数据库,即:
    FROM postgres
    
    #Switch back to default entrypoint
    ENTRYPOINT ["/bin/sh"]
    
    #Let the container start and do nothing until the pipeline kicks in
    CMD ["-c","sleep infinity"]
    
    根据上面的 Dockerfile 创建一个新镜像,推送它,并在 Jenkin 的管道中定义它而不是当前(仅适用于 sidecar)。然后你应该有一个稳定的容器,链接到实际的 db 容器,管道可以跳转到。
    最后,关于 sidecar 中启动的命令,我建议使用 localhost而不是 db作为目标主机,关于命令问题的 pg_isready -h db -p 5432 , 产生于:pg_isready -h localhost -p 5432

    关于postgresql - 在 Jenkins 中使用 docker Container 链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66893125/

    相关文章:

    ruby-on-rails-3 - gem install pg 只能作为 sudo

    php - 我在设置 laravel 时发生了什么错误

    nginx - docker —运行nginx并不总是有效

    groovy - Jenkins DSL 插件 : How to create a job in an existing jenkins View?

    sql - 如何拨驼峰柱

    postgresql - 如何要求 Postgres 报告损坏的值(value)?

    python - Postgre/SQLAlchemy UUID 插入但无法比较

    django - docker-compose 有两个容器 : web can not connect to db

    msbuild - 让 StyleCop 和 Jenkins 听从我的命令

    jenkins - 根据参数禁用 Jenkins Build 按钮