Как сделать так, чтобы мой проект автоматически развертывался из dev в промежуточную версию и вручную в производство в Jenkins, используя только ветку master git - PullRequest
6 голосов
/ 03 мая 2019

У меня около 30 веб-сайтов Wordpress, поэтому способ настройки Jenkins таков: у меня есть работа для каждого веб-сайта.Процесс разработки выглядит следующим образом (я не знаю, является ли он оптимальным, но у нас это так):

  1. Поскольку у нас есть сторонние разработчики, у них есть собственный репозиторий, размещенный в их собственном репозитории.хостинг провайдер.Всякий раз, когда код готов к QA, они фиксируют все свои изменения в нашем репозитории в основной ветке.
  2. Затем я запускаю задание Jenkins вручную с файлом jenkins, как показано ниже.
  3. Рабочий процесс должен быть следующим: развертывание в среде разработки, если и только в случае успешного предыдущего развертывания развертывание на этапе.Здесь мы должны остановиться и позволить специалистам по контролю качества проверять веб-сайт на наличие неработающих ссылок, ошибок и т. Д.
  4. Если все выглядит так, как мы ожидали, и ошибок не обнаружено, то наконец разверните в производственной среде.

ПРИМЕЧАНИЕ : Некоторые люди предлагали мне только постановку и постановку.Причина, по которой у нас нет такой конфигурации, заключается в том, что среда разработки недоступна в сети, а причина в том, что я использую эту среду для тестирования внутренней конфигурации (например, apache conf и т. Д.).

Кроме того, некоторые другие люди предложили создать ветку для каждой среды, что в теории имеет смысл, но я думаю, что это изменит способ, которым наши разработчики по аутсорсингу передают код в хранилище, я имею в виду, что они всегда должны будут фиксироватькод для ветки dev, а затем слияние с веткой stage для развертывания на stage, что, на мой взгляд, не очень хорошо.

Теперь шаги 2-4 выглядят следующим образом: чтобы дать вам пример того, как выглядит этот процесс, у нас будет пример веб-сайта и задания под названием «Bearitos»:

enter image description here

Внутри этой работы под названием "Bearitos" есть проект под названием "Bearitos to any"

enter image description here

, что в основном означает, что внутри этого проекта у меня есть конвейер, сконфигурированный с тремя этапами: dev, staging и prod, которые параметризованы следующими параметрами: DEPLOY_TO: Dev / staging / prod и DEPLOY_DB: Yes / No.Таким образом, в зависимости от того, что выберет пользователь, Jenkins будет развертывать в той конкретной среде, которая, я думаю, даже не нужна, чтобы эти параметры были правильными, поскольку правильный поток развертывания должен быть dev -> staging -> prod, сценария быть не должногде dev или staging будут пропущены, а затем развернуты прямо рядом с производством, поэтому, по моему мнению, это должно быть обновлено лучше

enter image description here

Внутри Jenkinsfile Iопределили три этапа Dev, Staging или Prod, а также параметры, если было выбрано создание БД или нет, ниже приведен пример того, как выглядит мой Jenkinsfile:

// Deployment template for CMS-based websites (Drupal or Wordpress)
// 
//
pipeline {
    agent any

    parameters {
        choice choices: ['Dev', 'Staging', 'Production'], description: "Choose which environment to push changes to.", name: "DEPLOY_TO"
        booleanParam defaultValue: true, "Choose whether to deploy the database.", name: "DEPLOY_DB"
    }

    environment {
         SITEID = "lb"
        NOFLAGS = "0"
        DBNAME = "wpress_myproject"
        DBSERVER = "dbserver"
        DBUSER = "WordpressUser"
        DBPASS = "hiddenpassword"
        EXCLUDE = "domain_commentmeta,domain_comments"  // separate multiple tables with commas
        DEPLOY_TO = "${params.DEPLOY_TO}"
        DEPLOY_DB = "${params.DEPLOY_DB}"
    }

    stages {
        stage("deploy-db-dev") {
            when {
                allOf { 
                    environment ignoreCase: true, name: "DEPLOY_TO", value: "dev"; 
                    environment ignoreCase: true, name: "DEPLOY_DB", value: "true"; 
                }
            }
            steps {
                // this stage only required until we make our dev the master DB
                // copy full dev database from bolwebdev1
                // import latest database dump to dev server
                script {
                    FILENM = sh(script: 'ls -t myproject-s-dump* | head -1', returnStdout: true)
                }
                //Fixing the problem with the collation existing in the sql dump file, refer to: https://stackoverflow.com/questions/42385099/1273-unknown-collation-utf8mb4-unicode-520-ci 
                //apparently, this is due to a version of mysql issue. Once the problem is fixed from the server side we can then remove the following lines. 

                sh """sed -i s/utf8mb4_unicode_520_ci/utf8mb4_unicode_ci/g ${FILENM}
                # The following line was added because the site is pointing to a staging server which we don't have control over, again, once this is fixed we can delete the following line of code. 
                sed -i s/myproject.staging.websites.3pth.com/myproject.example.net/g ${FILENM}
                mysql -h devserver2 -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_dev < ${WORKSPACE}/${FILENM}
                rm -f ${WORKSPACE}/${FILENM}"""
        }
        }
        stage("deploy-dev") {
            when {
                environment ignoreCase: true, name: "DEPLOY_TO", value: "dev"
            }
            steps {
                // copy files to devserver2
                // NOTE: if we move the repo to SVN, we should change httpdocs/ to ${env.SITEID}docs/
                sh """sudo chown jenkins:jenkins *

                #Replace the wp-config.php file with our domain file with our information. 
        /bin/cp httpdocs/wp-config-domain.php httpdocs/wp-config.php

                # prepare the dev server to receive files by changing the owner
                ssh webadmin@devserver2 'sudo chown -R webadmin:webadmin /var/opt/httpd/${env.SITEID}docs/'
                # copy files from control server to dev
                rsync --exclude=Jenkinsfile -rav -e ssh --delete ${WORKSPACE}/httpdocs/ webadmin@devserver2:/var/opt/httpd/${env.SITEID}docs/
                # fix the owner/permissions on the dev server
        ssh webadmin@devserver2 'sudo chown -R apache:${env.SITEID}-web /var/opt/httpd/${env.SITEID}docs/ && sudo chmod -R g+w /var/opt/httpd/${env.SITEID}docs/ && sudo find /var/opt/httpd/${env.SITEID}docs/ -type d -exec chmod g+s {} \\;'"""
            }
        }
        stage("deploy-db-staging") {
            when {
                allOf { 
                    environment ignoreCase: true, name: "DEPLOY_TO", value: "staging"; 
                    environment ignoreCase: true, name: "DEPLOY_DB", value: "true"; 
                }
            }
            steps {
                script {
                    def myexcludes = env.EXCLUDE.split(',').toList()
                    MYFLAGS = "-Q -K -c -e --default-character-set=utf8 "
                    if (env.NOFLAGS == "0") {
                        myexcludes.each {
                            MYFLAGS = "${MYFLAGS} --ignore-table=${env.DBNAME}_dev.${it}"
                        }
                    }
                }
                // pull a backup of the current dev database (may exclude some tables)
                sh """mysqldump -h devserver2 -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_dev ${MYFLAGS} > ${env.DBNAME}_dev.sql
        #Searching and replace for the URL to change from the dev sever to the staging server
                sed -i s/myproject.example.net/stage-myproject.example.net/g ${env.DBNAME}_dev.sql

        # create a backup copy of the current staging database (full backup)
                mysqldump -h ${env.DBSERVER} -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_stage > ${env.DBNAME}_stage_bak.sql
                # upload the dev database dump to the staging database
                mysql -h ${env.DBSERVER} -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_stage < ${WORKSPACE}/${env.DBNAME}_dev.sql
                rm -f ${WORKSPACE}/${env.DBNAME}_dev.sql"""
       }
        }
        stage("deploy-staging") {
            when {
                environment ignoreCase: true, name: "DEPLOY_TO", value: "staging"
            }
            steps {
                // copy files from dev to control server
                sh """rsync --exclude=.svn --exclude=.git -rav -e ssh webadmin@devserver2:/var/opt/httpd/${env.SITEID}docs/ /tmp/${env.SITEID}docs/

                #Replace the wp-config.php file with our domain file with our information. 
            /bin/cp httpdocs/wp-config-domain.php httpdocs/wp-config.php

                #prepare the staging server to receive files by changing the owner
                ssh webadmin@stageserver 'sudo chown -R webadmin:webadmin /var/opt/httpd/${env.SITEID}docs/'
                # copy files from control server to staging
                rsync --exclude=.svn --exclude=.git -rav -e ssh --delete /tmp/${env.SITEID}docs/ webadmin@stageserver:/var/opt/httpd/${env.SITEID}docs/
                # fix the owner/permissions on the staging server
                ssh webadmin@stageserver 'sudo chown -R apache:${env.SITEID}-web /var/opt/httpd/${env.SITEID}docs/ && sudo chmod -R g+w /var/opt/httpd/${env.SITEID}docs/ && sudo find /var/opt/httpd/${env.SITEID}docs/ -type d -exec chmod g+s {} \\;'

                #delete the temporary files on the control server
                rm -Rf /tmp/${env.SITEID}docs/
                # clear the Incapsula caches
                if [[ \$( curl -sS -X POST \"http://www.example.net/incapcache.php?api_key=asdaswwGR)feasdsdda&site_id=stage&resource_url=stage-myproject.example.net\" | jq -r .debug_info.id_info) != \"incapsula cache cleared successfuly\" ]]; then exit 255; fi"""
            }
        }
        stage("deploy-db-production") {
            when {
                allOf { 
                    environment ignoreCase: true, name: "DEPLOY_TO", value: "production"; 
                    environment ignoreCase: true, name: "DEPLOY_DB", value: "true"; 
                }
            }
            steps {
                script {
                    def myexcludes = env.EXCLUDE.split(',').toList()
                    MYFLAGS = "-Q -K -c -e --default-character-set=utf8 "
                    if (env.NOFLAGS == "0") {
                        myexcludes.each {
                            MYFLAGS = "${MYFLAGS} --ignore-table=${env.DBNAME}_stage.${it}"
                        }
                    }
                }
                sh """cd ${WORKSPACE}
                # pull a backup of the current staging database (may exclude some tables)
                mysqldump -h ${env.DBSERVER} -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_stage ${MYFLAGS} > ${env.DBNAME}_stage.sql
        #Searching and replace for the URL to change from the stage sever to the prod server
                sed -i s/stage-myproject.example.net/www.myproject.com/g ${env.DBNAME}_stage.sql

                # create a backup copy of the current production database (full backup)
                mysqldump -h ${env.DBSERVER} -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_prod > ${env.DBNAME}_prod_bak.sql
                # upload the staging database dump to the production database
                mysql -h ${env.DBSERVER} -u ${env.DBUSER} --password='${env.DBPASS}' ${env.DBNAME}_prod < ${WORKSPACE}/${env.DBNAME}_stage.sql
                rm -f ${WORKSPACE}/${env.DBNAME}_stage.sql"""
        }
        }
        stage("deploy-production") {
            when {
                environment ignoreCase: true, name: "DEPLOY_TO", value: "production"
            }
            steps {
                // copy files from staging to control server
                sh """rsync --exclude=.svn --exclude=.git -rav -e ssh webadmin@stageserver:/var/opt/httpd/${env.SITEID}docs/ /tmp/${env.SITEID}docs/

                # prepare the production server to receive files by changing the owner
                ssh webadmin@prodserver1 'sudo chown -R webadmin:webadmin /var/opt/httpd/${env.SITEID}docs'
                ssh webadmin@prodserver2 'sudo chown -R webadmin:webadmin /var/opt/httpd/${env.SITEID}docs'
                # copy files from control server to production
                rsync --exclude=.svn --exclude=.git -rav -e ssh --delete /tmp/${env.SITEID}docs/ webadmin@prodserver1:/var/opt/httpd/${env.SITEID}docs/
                rsync --exclude=.svn --exclude=.git -rav -e ssh --delete /tmp/${env.SITEID}docs/ webadmin@prodserver2:/var/opt/httpd/${env.SITEID}docs/
                # fix the owner/permissions on the production server
                ssh webadmin@prodserver1 'sudo chown -R apache:${env.SITEID}-web /var/opt/httpd/${env.SITEID}docs/'
                ssh webadmin@prodserver2 'sudo chown -R apache:${env.SITEID}-web /var/opt/httpd/${env.SITEID}docs/'
                ssh webadmin@prodserver1 'sudo chmod -R g+w /var/opt/httpd/${env.SITEID}docs/'
                ssh webadmin@prodserver2 'sudo chmod -R g+w /var/opt/httpd/${env.SITEID}docs/'
                ssh webadmin@prodserver1 'sudo find /var/opt/httpd/${env.SITEID}docs/ -type d -exec chmod g+s {} \\;'
                ssh webadmin@prodserver2 'sudo find /var/opt/httpd/${env.SITEID}docs/ -type d -exec chmod g+s {} \\;'

                # delete the temporary files on the control server
                rm -Rf /tmp/${env.SITEID}docs/
                # clear the Incapsula caches
                if [[ \$( curl -sS -X POST \"http://www.example.net/incapcache.php?api_key=asdaswwGR)feasdsdda&site_id=088&resource_url=www.myproject.com\" | jq -r .debug_info.id_info) != \"incapsula cache cleared successfuly\" ]]; then exit 255; fi"""
            }
        }
    }
}

Проблемы, с которыми я столкнулсяВ настоящее время я сталкиваюсь с таким подходом:

  1. Я не могу понять, как сделать развертывание автоматизированным, поскольку это параметризованный конвейер, поэтому я не уверен, как его автоматизировать.Желательным процессом было бы автоматизировать развертывание после того, как Дженкинс будет опрашивать каждые X минут в репозитории git, автоматически развертывать в Dev> Stage (только если развертывание Dev прошло успешно), а затем останавливаться до тех пор, пока мы не развернем вручную в Prod послеQA on Staging.

  2. В текущей конфигурации Git настроена только одна ветвь (master), в которую разработчики вносят изменения, когда они хотят выполнить развертывание в Dev -> Stage ->Prod.Но я думаю, что идеальный сценарий будет иметь ветку dev для развертываний dev, затем ветвь stage для развертывания в среду Stage и затем master для развертывания, когда мы объединяем эти ветки dev и staging с главной веткой.Я не уверен, что это будет оптимальным, поэтому я был бы признателен за любые предложения или идеи по этому поводу.

Желательным подходом будет разрешение упомянутых проблем, а также возможность автоматического развертывания и уведомления об успешном развертывании dev -> staging. Помимо возможности выполнять упомянутый рабочий процесс вручную, как мы делаем сейчас (это не так важно, но было бы неплохо иметь такую ​​функцию).

Заранее благодарю за помощь!

Ответы [ 4 ]

2 голосов
/ 06 мая 2019
  1. Избавьтесь от своих параметров, они не нужны (остановит вас от автоматизации).
  2. Ручной ввод на этапе deploy to prod
pipeline {
    agent any
    stages {
        stage('Deploy to prod') {
            input {
                message "Should we continue?"
                ok "Yes, we should."
            }
            steps {
                echo "Deploying."
            }
        }
    }
}
  1. Это должен быть проект многоотраслевого конвейера в Jenkins (поскольку вы хотите, чтобы он был во всех ветвях)
  2. , если вы хотите использовать разные этапы для разных веток, используйте , когда
pipeline {
    agent any
    stages {
        stage('Example Build') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Example Deploy') {
            when {
                branch 'production'
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

Что касается предложений - я бы сказал, что вам нужно сопоставить ваш поток мерзавцев с потоком CI / CD. Каков жизненный цикл данного типа ветки git? Каков результат данного этапа? Вы хотите выполнить этапы для всех ветвей и deploy to prod только для одной ветки?

2 голосов
/ 04 мая 2019

Что нужно для реализации отдельного конвейера развертывания, который способен развертываться во всех средах и параметризован, а также реализовать другой конвейер, который запланирован и запускает конвейер для развертывания в dev (stage dev), а когда это задание успешно выполняется, затем запускает конвейерснова развернуть на этапе (этап qa).Развертывание на Prod может быть сделано вручную.

https://jenkins.io/doc/pipeline/steps/pipeline-build-step/#-build-%20build%20a%20job

1 голос
/ 11 мая 2019

Я бы использовал git tags здесь.

Во-первых, у меня будет задание на сборку Dev , которое настроено на прослушивание моей главной ветки для любых коммитов и начало сборки кода, запуск модульных тестов, развертывание вашего приложения в среде разработчика и т. Д. Если и когда сборка завершится успешно, он пометит репозиторий git определенным номером версии.

Теперь задание на сборку Staging будет настроено в качестве нижестоящего задания к заданию сборки Dev и будет выполняться только в случае успешного выполнения задания сборки Dev. Когда он запускается, он принимает номер версии в качестве аргумента из вышестоящего задания сборки Dev и проверяет код для этой конкретной версии. Если это не удастся, он удалит этот конкретный тег версии из хранилища.

Если вы хотите выполнить ручное тестирование в любой из двух вышеуказанных фаз и пометить сборку как «Pass / Fail» в соответствии с этим, для этого есть Fail сборки Плагин Jenkins для этого. Если вы пометили сборку как «Fail» после выполнения ручного тестирования, вам также следует удалить конкретный тег версии, соответствующий сборке.

После этого вы можете выполнить ручное задание Release , в котором перечислены все теги версий в репозитории git, отмечающие все успешные сборки. Вы можете выбрать любую из версий и запустить задание Release, в результате чего код, относящийся к этой сборке, будет запущен в производство.

1 голос
/ 07 мая 2019
pipeline 
{
        stages 
        {
               stage('Build')
               {
                     steps
                     {
                        echo 'building the codes from the git'
                      }
                }
                stage('developer-branch-stuff')
                {
                   when
                   {
                       branch 'developer'
                   }
                   steps
                   {
                      echo 'run this stage - only if the branch = developer branch'
                   }
                }
        stage('Deliver for development') 
        {
            when 
            {
                branch 'developer'
            }
            steps 
            {
                sh 'your_filename_along_with_your_filepath'
                input message: 'shall we deploy it? (Click "Proceed" to continue)'
            }
        }
        stage('Deploy for production') 
        {
            when
            {
                branch 'developer'
            }
            steps
            {
                sh 'your_filename_along_with_your_filepath'
                input message: 'shall we proceed to production? (Click "Proceed" to continue)'
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...