logo

Լրացուցիչ Բլոկների Տեսակներ (EBT) - Դասավորության Կառուցողի նոր փորձառություն❗

Լրացուցիչ Բլոկների Տեսակներ (EBT) - ձևավորված, կարգավորելի բլոկների տեսակներ՝ սլայդշոուներ, ներդիրներ, քարտեր, բացվող ցանկեր և շատ ուրիշներ։ Ներառված կարգավորումներ՝ ֆոնի, DOM տուփի, JavaScript փլագինների համար։ Փորձեք դասավորությունների կառուցման ապագան արդեն այսօր։

EBT մոդուլների ցուցադրական տարբերակներ Ներբեռնել EBT մոդուլները

❗Լրացուցիչ Պարբերությունների Տեսակներ (EPT) - Պարբերությունների նոր փորձառություն

Լրացուցիչ պարբերության տեսակներ (EPT) - անալոգիական պարբերության վրա հիմնված մոդուլների հավաքակազմ։

EPT մոդուլների ցուցադրական տարբերակներ Ներբեռնել EPT մոդուլները

GLightbox is a pure javascript lightbox (Colorbox alternative without jQuery)❗

It can display images, iframes, inline content and videos with optional autoplay for YouTube, Vimeo and even self-hosted videos.

Demo GLightbox Download GLightbox

Scroll

Drupal‑ի CI-ով կառավարվող կոնֆիգուրացիայի կառավարում՝ Jenkins և GitLab CI օգտագործմամբ

16/04/2026, by Ivan

1. Ինչու է CI-ով կառավարվող կոնֆիգուրացիայի կառավարումը կարևոր

Drupal-ի կոնֆիգուրացիայի համակարգը հարթակի ամենամեծ ուժեղ կողմերից մեկն է — և ամենահաճախ ցավ պատճառողներից մեկը։ Կայքի յուրաքանչյուր կոնֆիգուրացիայի մասի արտահանումն ու ներմուծումը YAML ֆայլերի տեսքով հզոր հնարավորություն է, բայց միայն այն դեպքում, երբ բոլորը համաձայն են, թե ով է պատասխանատու այդ ֆայլերը միջավայրերի միջև տեղափոխելու համար։ Թիմերի մեծ մասում այդ համաձայնությունը երբեք լիովին գոյություն չունի։

Դասական խնդիրները լավ հայտնի են յուրաքանչյուրին, ով թողարկել է Drupal կայք․

  • Կոնֆիգուրացիայի շեղում (Config drift) — staging-ը շեղվում է production-ից, production-ը՝ local-ից, և ոչ ոք վստահ չէ, թե որ միջավայրն է հիմնականը։
  • "Աշխատում է staging-ում, բայց ոչ production-ում" — որովհետև ինչ-որ մեկը staging-ում թարմացրել է view կամ field formatter և երբեք չի արտահանել այն։
  • Ձեռքով drush cim-ը կոտրում է բովանդակությունը — գիշերվա 11-ին կատարված շտապ ներմուծումը, որը ջնջել է content type-ի դաշտ, որը դեռևս օգտագործվում էր ակտիվ node-ների կողմից։

Այս բոլոր սցենարների հիմնական պատճառը նույնն է․ մարդն է որոշում՝ երբ և արդյոք կոնֆիգուրացիան պետք է տեղափոխվի։ Մարդիկ մոռանում են։ Սթրեսի տակ բաց են թողնում քայլեր։ Կայացնում են որոշումներ, որոնք հետո պարզվում է սխալ են։

CI-ն չի մոռանում։ Խողովակաշարը (pipeline) կամ անցնում է, կամ ձախողվում է։ Այն չունի standup-ի մասնակցելու անհրաժեշտություն։ Այն չգիտի, որ թողարկումը տեղի կունենա քսան րոպեից։ Այդ դետերմինիզմն է հենց այն, ինչ անհրաժեշտ է կոնֆիգուրացիայի կառավարմանը։

Այս հոդվածը խոստանում է ապահովել հետևյալը․

  • Յուրաքանչյուր կոնֆիգուրացիայի փոփոխություն commit է արվում Git-ում՝ նախքան որևէ ընդհանուր միջավայր հասնելը։
  • Խողովակաշարն է պատասխանատու կոնֆիգուրացիայի վավերացման և ներմուծման համար, ոչ թե ծրագրավորողը։
  • Միջավայրերի միջև տեղափոխումը չի պահանջում ձեռքով քայլեր։
  • Config drift-ը build-ի ձախողում է, ոչ թե Slack հաղորդագրություն։
Ենթադրություններ․ Դուք օգտագործում եք Drupal 10 կամ 11, Git-ի վրա հիմնված workflow՝ feature branch-երով, և տեղակայում եք առնվազն երկու ընդհանուր միջավայրում (օրինակ՝ staging և production)։ Ձեր թիմը օգտագործում է Jenkins կամ GitLab CI — կամ երկուսը միասին։

2. Հիմնական սկզբունքներ՝ իրական նախագծերից ստացված

Կոնֆիգուրացիան՝ որպես կոդ

Եթե այն փոխում է կայքի վարքը, այն պետք է պահվի Git-ում։ Վերջակետ։ View, content type, performance setting, image style — այս ամենը կոդ է։ Կոնֆիգի ֆայլերին վերաբերվեք նույն կարգապահությամբ, ինչ PHP ֆայլերին․ վերանայեք դրանք, version-ավորեք, երբեք մի խմբագրեք անմիջապես ընդհանուր միջավայրում։

Ընդհանուր միջավայրերում ձեռքով drush cim — ոչ

Խողովակաշարն է ներմուծում կոնֆիգուրացիան, ոչ թե ծրագրավորողները։ Այս կանոնը ծայրահեղ է թվում, մինչև առաջին անգամ ինչ-որ մեկը գործարկի drush cim-ը production-ում՝ իր աշխատող թղթապանակում չcommit արված փոփոխություններով։

Խողովակաշարերը պետք է արագ ձախողվեն config drift-ի դեպքում

Կոնֆիգուրացիան ներմուծելուց և անմիջապես հետո այն արտահանելուց հետո չպետք է առաջանա որևէ diff։ Եթե առաջանում է, build-ը ձախողվում է։ Միայն այս կանոնը բռնում է ավելի շատ սխալներ, քան ցանկացած այլ ստուգում, որը մենք ավելացրել ենք։

Ավագ ծրագրավորողը production-ում դեբագում էր դանդաղ աշխատող որոնման էջը։ Նա UI-ի միջոցով փոփոխեց Search API ինդեքսի կարգավորումները, հաստատեց, որ կատարողականը բարելավվել է, և փակեց թիկեթը։ Երկու շաբաթ անց թողարկումը Git-ից ներմուծեց կոնֆիգուրացիան՝ վերագրելով նրա UI փոփոխությունները, և որոնման կատարողականը նվազեց։ Երեք օր շարունակ ոչ ոք կապ չտեսավ։ Այդ միջադեպից հետո մենք կանոնը հստակեցրինք․ յուրաքանչյուր UI փոփոխություն, որը անմիջապես չի արտահանվում և commit արվում, համարվում է կորած։
Մեդիա-ծանր կայքում core.extension.yml-ը չէր ներառվում արտահանումներում, որովհետև «մոդուլները միևնույն է կառավարվում են Composer-ով»։ Երեք ամիս անց hotfix-ը կրկին ակտիվացրեց մի մոդուլ, որը նպատակային անջատված էր production-ում։ Hotfix-ը ճիշտ էր — բայց հետագա config import-ը լուռ կրկին անջատեց մոդուլը։ Այդ միջադեպից հետո մենք core.extension.yml-ը համարում ենք ամենավտանգավոր ֆայլը, որը կարելի է անտեսել։

3. Բարձր մակարդակի ճարտարապետություն

👨‍💻 Ծրագրավորող
drush cex
📁 Git պահոց
config/sync
⚙ CI խողովակաշար
վավերացում + ներմուծում
🌐 Զարգացում
🌐 Ստեյջինգ
🌐 Արտադրական

Կոնֆիգուրացիան հոսում է միայն մեկ ուղղությամբ՝ ծրագրավորողի տեղական արտահանումից, Git-ի միջոցով, CI խողովակաշարով, և դեպի յուրաքանչյուր միջավայր։

Հիմնական գաղափարը պատասխանատվությունների բաժանումն է․

ԴերակատարՊատասխանատվությունԵրբեք պատասխանատու չէ համար
ԾրագրավորողԿոնֆիգի արտահանում, commit Git-ում, MR/PR-ի բացումԿոնֆիգի ներմուծում որևէ ընդհանուր միջավայրում
CI խողովակաշարՎավերացում, ներմուծում, ստուգում, տեղափոխումԿոնֆիգի ֆայլերի ստեղծում կամ խմբագրում
ՄիջավայրԿայքի գործարկումԿոնֆիգի ստեղծում, պահպանում կամ արտահանում

Միջավայրերը կոնֆիգուրացիայի սպառողներ են, երբեք արտադրողներ։ Այն պահից, երբ միջավայրը դառնում է կոնֆիգի ճշմարտության աղբյուր, շեղումն անխուսափելի է։

4. Պահոցի կառուցվածք, որը մասշտաբավորվում է

Թղթապանակների կառուցվածք նախագծի արմատ
project-root/
├── composer.json
├── composer.lock
├── Jenkinsfile
├── .gitlab-ci.yml
│
├── ci/
│   ├── drupal-config-check.sh   # Վերաօգտագործվող վավերացման սկրիպտ
│   ├── drupal-deploy.sh
│   └── drupal-install.sh
│
├── config/
│   ├── sync/                        # Կոնֆիգը այստեղ է — commit արված Git-ում
│   │   ├── core.extension.yml
│   │   ├── system.site.yml
│   │   └── ...
│   └── splits/                      # config_split override-ներ՝ ըստ միջավայրի
│       ├── development/
│       ├── staging/
│       └── production/
│
└── web/
    ├── sites/
    │   └── default/
    │       ├── settings.php          # Commit արված, առանց գաղտնի տվյալների
    │       ├── settings.local.php    # Gitignore-ում, տեղական override-ներ
    │       └── settings.env.php      # Բեռնվում է CI-ի կողմից՝ env փոփոխականներից
    └── ...

Ինչ է տեղակայվում config/sync-ում

Բոլոր կոնֆիգուրացիայի YAML ֆայլերը, որոնք գեներացվում են drush cex-ի միջոցով։ Այս թղթապանակը կայքի կոնֆիգուրացիայի ճշմարտության միակ աղբյուրն է։ Այն commit է արվում, վերանայվում և տեղակայվում այնպես, ինչպես ցանկացած այլ կոդ։

Ինչը երբեք չպետք է ներառվի կոնֆիգում

  • Միջավայրին հատուկ hostname-ներ, API key-եր կամ հավատարմագրեր — օգտագործեք միջավայրի փոփոխականներ և settings.env.php։
  • Ցանկացած տեսակի գաղտնի տվյալներ — ներարկեք ձեր CI գաղտնիքների պահոցից (Jenkins Credentials կամ GitLab CI Variables)։
  • Բովանդակություն — մի օգտագործեք Default Content module-ը որպես լուծում այն բանի համար, ինչը պետք է լինի կոնֆիգ։
PHP web/sites/default/settings.php
// settings.php — commit արված Git-ում, միջավայրից անկախ
$settings['config_sync_directory'] = DRUPAL_ROOT . '/../config/sync';

// Բեռնում է միջավայրին հատուկ արժեքները, որոնք ներարկվել են CI-ի կամ հոսթի կողմից։
if (file_exists($app_root . '/' . $site_path . '/settings.env.php')) {
  include $app_root . '/' . $site_path . '/settings.env.php';
}

// Բեռնում է կամընտիր տեղական override-ները (gitignored)։
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
  include $app_root . '/' . $site_path . '/settings.local.php';
}
PHP web/sites/default/settings.env.php
// Գեներացվում է CI-ի կողմից՝ միջավայրի փոփոխականներից — երբեք չի commit արվում։
$databases['default']['default'] = [
  'driver'   => 'mysql',
  'host'     => getenv('DB_HOST'),
  'database' => getenv('DB_NAME'),
  'username' => getenv('DB_USER'),
  'password' => getenv('DB_PASS'),
  'port'     => getenv('DB_PORT') ?: 3306,
  'prefix'   => '',
];

$settings['hash_salt'] = getenv('DRUPAL_HASH_SALT');

// Տեղեկացնում ենք config_split-ին, թե որ միջավայրում ենք գտնվում։
$config['config_split.config_split.production']['status'] =
  (getenv('APP_ENV') === 'production');

5. Drupal-ի կոնֆիգուրացիայի աշխատանքային հոսք

5.1 Տեղական մշակում

Տեղական workflow-ը միակ վայրն է, որտեղ UI փոփոխությունների և կոնֆիգի արտահանման միջև հետադարձ կապը պետք է լինի արագ և սովորական։ Նախագծի յուրաքանչյուր ծրագրավորող հետևում է նույն կանոններին․

  • Տեղական մակարդակում կատարեք UI կամ կոդի փոփոխություններ։
  • Անմիջապես գործարկեք drush cex — ոչ թե օրվա վերջում։
  • Վերանայեք տարբերությունները git diff config/sync-ով։
  • Կամ commit արեք փոփոխությունները, կամ մերժեք դրանք՝ օգտագործելով git checkout -- config/sync։
  • Միջանկյալ վիճակ չի կարող գոյություն ունենալ։
Shell Տեղական մշակման workflow
# Drupal UI-ի միջոցով կամ install hook-երով կոնֆիգի փոփոխություն կատարելուց հետո՝
drush cex --yes

# Վերանայեք փոփոխությունները — վերաբերվեք դրան ինչպես ցանկացած կոդի փոփոխության․
git diff config/sync

# Stage արեք և commit՝ feature կոդի հետ միասին․
git add config/sync
git commit -m "feat(search): add fulltext search API index config"

# Կամ մերժեք, եթե փոփոխությունը փորձարարական էր և դեռ պատրաստ չէ․
git checkout -- config/sync

Մենք դա պարտադրում ենք թեթև Git pre-commit hook-ով, որը զգուշացնում է (բայց չի արգելափակում), երբ PHP կամ template ֆայլերը stage են արված առանց համապատասխան փոփոխության config/sync-ում․

Shell .git/hooks/pre-commit
#!/bin/bash
# Զգուշացրեք, եթե module/theme կոդը փոփոխվել է, բայց config/sync-ը՝ ոչ։
CHANGED_CODE=$(git diff --cached --name-only | grep -E '\.(php|module|theme|install)$')
CHANGED_CONFIG=$(git diff --cached --name-only | grep '^config/sync')

if [[ -n "$CHANGED_CODE" ]] && [[ -z "$CHANGED_CONFIG" ]]; then
  echo "⚠  Զգուշացում․ PHP/module ֆայլերը stage են արված, բայց config/sync փոփոխություններ չկան։"
  echo "   Գուցե մոռացել եք գործարկել՝ drush cex ?"
  echo "   Ամեն դեպքում շարունակվում է — բայց կրկնակի ստուգեք։"
fi
exit 0

5.2 Feature Branch-եր

Կոնֆիգուրացիան պահվում է նույն branch-ում և նույն pull/merge request-ում այն կոդի հետ, որը պահանջում է այն։ Նոր content type ավելացնող feature-ը պետք է ներառի և՛ PHP install hook-ը (եթե կա), և՛ այդ content type-ի YAML ֆայլերը նույն commit-ում։

Վաղ փուլում կոտրված կախվածությունների հայտնաբերում․ Եթե A branch-ը ավելացնում է նոր field, իսկ B branch-ը փոխում է նույն field-ի ցուցադրումը, B-ն A-ից առաջ merge անելն առաջացնելու է config import-ի սխալ։ Սա ճիշտ արդյունքն է — ցանկանում եք, որ խողովակաշարը դա հայտնաբերի branch-ում, ոչ թե production-ում։

6. CI-ի պատասխանատվությունները՝ ինչ պետք է վերահսկի խողովակաշարը

Յուրաքանչյուր խողովակաշար, որը շփվում է ընդհանուր Drupal միջավայրի հետ, պետք է հաջորդականորեն կատարի հետևյալ քայլերը․

  1. Տեղադրել կամ վերականգնել տվյալների բազան — մաքուր տեղադրում կամ production-ի սանիտարացված snapshot։
  2. Գործարկել տվյալների բազայի թարմացումներըdrush updb։
  3. Ներմուծել կոնֆիգուրացիանdrush cim --yes։
  4. Վերաարտահանել կոնֆիգուրացիանdrush cex --yes։
  5. Հաստատել, որ diff չկա — եթե որևէ YAML ֆայլ փոխվել է, build-ը պետք է ձախողվի։

4-րդ և 5-րդ քայլերը միասին ամենակարևորներն են։ Ներմուծումը և անմիջապես վերաարտահանումը պետք է հանգեցնեն դատարկ diff-ի։ Եթե դա այդպես չէ, ապա հետևյալներից մեկը ճիշտ է․

  • Module-ը ներմուծման ընթացքում գեներացնում է կոնֆիգ (հաճախ module-ում առկա bug)։
  • Կոնֆիգ entity-ի UUID-ը չի համապատասխանում տվյալների բազայում եղածին։
  • Կոնֆիգի schema-ն ամբողջական չէ, որի պատճառով Drupal-ը նորմալացնում է արժեքները այլ կերպ, քան արտահանման ժամանակ։
  • Ծրագրավորողը ձեռքով խմբագրել է կոնֆիգի ֆայլերը և առաջացրել անհամապատասխանություններ։
Shell ci/drupal-config-check.sh
#!/bin/bash
set -euo pipefail

echo "=== Գործարկվում են Drupal տվյալների բազայի թարմացումները ==="
drush updb --yes

echo "=== Կոնֆիգուրացիայի ներմուծում config/sync-ից ==="
drush cim --yes

echo "=== Վերաարտահանում՝ սպասվող փոփոխությունների բացակայությունը ստուգելու համար ==="
drush cex --yes

echo "=== Config drift-ի ստուգում ==="
if ! git diff --exit-code config/sync; then
  echo ""
  echo "❌ ՍԽԱԼ։ Հայտնաբերվել է կոնֆիգուրացիայի շեղում!"
  echo "   Git-ում գտնվող կոնֆիգը չի համապատասխանում Drupal-ի կողմից import+export-ից հետո ստեղծվածին։"
  echo "   Տարբերությունները վերևում են։ Տեղականում ուղղեք 'drush cex'-ով և commit արեք։"
  exit 1
fi

echo "✅ Կոնֆիգուրացիան մաքուր է — շեղում չի հայտնաբերվել։"
Ինչու է ներմուծումից հետո վերաարտահանումը չքննարկվող քայլ․ Առանց վերաարտահանման՝ դուք միայն գիտեք, որ ներմուծումը հաջողվել է։ Դուք չգիտեք՝ ներմուծված կոնֆիգը համապատասխանում է արդյոք այն բանին, ինչ Drupal-ը իրականում պահպանել է ներսում։ Միայն վերաարտահանումն ու diff-ը փակում են այդ բացը։
 

7. Jenkins-ի իրականացում (փորձարկված մարտական պայմաններում)

7.1 Jenkinsfile կառուցվածք

Մենք օգտագործում ենք բացառապես դեկլարատիվ pipeline-ներ։ Scripted pipeline-ները առաջարկում են ավելի մեծ ճկունություն, բայց դեկլարատիվ pipeline-ները ավելի հեշտ են ընթեռնելի, ավելի հեշտ են lint-վում jenkins-cli declarative-linter-ով և ավելի հասկանալի են թիմի նոր անդամների համար։


pipeline {
  agent { label 'drupal-php82' }

  options {
    buildDiscarder(logRotator(numToKeepStr: '20'))
    timeout(time: 30, unit: 'MINUTES')
    disableConcurrentBuilds()
  }

  environment {
    DRUPAL_ROOT       = "${WORKSPACE}/web"
    COMPOSER_HOME     = "${WORKSPACE}/.composer"
    APP_ENV           = 'ci'
    DB_CREDS          = credentials('drupal-ci-db') // Jenkins secret
  }

  stages {

    stage('Checkout') {
      steps {
        checkout scm
        sh 'git log --oneline -5'
      }
    }

    stage('Composer Install') {
      steps {
        sh '''
          composer install \
            --no-interaction \
            --prefer-dist \
            --optimize-autoloader
        '''
      }
    }

    stage('Write Settings') {
      steps {
        // Generate settings.env.php from Jenkins credentials/env vars
        sh '''
          cat > web/sites/default/settings.env.php < 'mysql',
  'host'     => '127.0.0.1',
  'database' => 'drupal_ci',
  'username' => '${DB_CREDS_USR}',
  'password' => '${DB_CREDS_PSW}',
  'port'     => 3306,
  'prefix'   => '',
];
\\$settings['hash_salt'] = '${DRUPAL_HASH_SALT}';
EOF
        '''
      }
    }

    stage('Site Install') {
      steps {
        sh '''
          drush site-install minimal \
            --yes \
            --existing-config \
            --account-name=admin \
            --account-pass="${DRUPAL_ADMIN_PASS}"
        '''
      }
    }

    stage('Validate Config') {
      steps {
        sh 'bash ci/drupal-config-check.sh'
      }
      post {
        failure {
          sh 'git diff config/sync || true'
          archiveArtifacts artifacts: 'config/sync/**/*.yml', allowEmptyArchive: true
        }
      }
    }

    stage('Deploy') {
      when {
        anyOf {
          branch 'main'
          branch 'release/*'
        }
      }
      steps {
        sh 'bash ci/drupal-deploy.sh'
      }
    }

  }

  post {
    always {
      sh 'drush cr || true'
      cleanWs()
    }
    failure {
      emailext(
        subject: "[FAIL] ${JOB_NAME} #${BUILD_NUMBER}",
        body: "Config validation failed. See: ${BUILD_URL}",
        recipientProviders: [[$class: 'DevelopersRecipientProvider']]
      )
    }
  }
}

7.2 Jenkins-ին հատուկ նկատառումներ

Shared Libraries

Երբ կառավարում եք ավելի քան երկու կամ երեք Drupal կայք, Drupal pipeline-ի տրամաբանությունը տեղափոխեք Jenkins Shared Library-ի մեջ։ Յուրաքանչյուր նախագծի Jenkinsfile-ը դառնում է թեթև wrapper։

Groovy Jenkinsfile (shared library օգտագործող թեթև wrapper)
@Library('drupal-pipeline-lib@v2') _

drupalPipeline(
  phpVersion:    '8.2',
  deployBranch:  'main',
  dbCredentials: 'drupal-ci-db',
  slackChannel:  '#deployments'
)

Workspace-ի մաքրում

Միշտ կանչեք cleanWs() ֆունկցիան post { always } բլոկում։ Jenkins agent-ները կուտակում են նախորդ build-երի վիճակը — նախորդ build-ի settings.env.php-ը կամ vendor թղթապանակը կարող են աննկատ ազդել ընթացիկ build-ի վրա։ Եղեք խիստ՝ մաքրեք workspace-ը։

Երբեք մի վերաօգտագործեք տվյալների բազան pipeline-ի գործարկումների միջև, եթե բացահայտորեն չեք թեստավորում թարմացման ուղիները։ Նախորդ build-ից մնացած տվյալների բազան կարող է քողարկել UUID անհամապատասխանություններ, բացակայող migration-ներ և module-ի տեղադրման հերթականության խնդիրներ։

8. GitLab CI-ի իրականացում

8.1 .gitlab-ci.yml կառուցվածք

YAML .gitlab-ci.yml
# (CI կոնֆիգը անփոփոխ է թարգմանվում միայն մեկնաբանություններով)
# ── build stage
# ── test stage
# ── validate-config stage
# ── deploy stage

8.2 GitLab CI-ի առավելությունները

GitLab CI-ն ունի մի շարք հնարավորություններ, որոնք այն դարձնում են հատկապես հարմար այս workflow-ի համար․

  • Առաջին կարգի artifact-ներ — ձախողված կոնֆիգի արտահանումները ավտոմատ պահպանվում են և հասանելի են MR UI-ում առանց լրացուցիչ կոնֆիգուրացիայի։
  • Բնական caching՝ հիմնված composer.lock-ի վրա — առաջին գործարկումից հետո Composer install-ը դառնում է արագ։
  • Merge Request pipeline-ի տեսանելիություն — ծրագրավորողները տեսնում են կոնֆիգի վավերացման կարգավիճակը անմիջապես MR-ում մինչև merge-ը։
  • Services բլոկ — MySQL-ը գործարկվում է որպես sidecar՝ առանց ենթակառուցվածքային լրացուցիչ բարդության։
  • Environments + manual gates — production deploy-ի վրա դրված when: manual-ը ապահովում է մեկ սեղմումով տեղափոխում՝ մարդկային հաստատմամբ։
Shell ci/drupal-deploy.sh
#!/bin/bash
set -euo pipefail

TARGET_ENV="${1:-staging}"
echo "=== Տեղակայում դեպի: ${TARGET_ENV} ==="

rsync -az --delete \
  --exclude='.git' \
  --exclude='web/sites/default/files' \
  --exclude='web/sites/default/settings.env.php' \
  ./ "deploy@${TARGET_ENV}.example.com:/var/www/drupal/"

echo "=== Post-deploy հրամանների գործարկում ${TARGET_ENV}-ում ==="
ssh "deploy@${TARGET_ENV}.example.com" bash -s <<'REMOTE'
  set -e
  cd /var/www/drupal
  drush updb --yes
  drush cim --yes
  drush cex --yes
  git diff --exit-code config/sync || (echo "❌ Config drift թիրախում!"; exit 1)
  drush cr
  echo "✅ Տեղակայումն ավարտված է։"
REMOTE

9. Միջավայրին հատուկ կոնֆիգուրացիա՝ առանց խաբելու

Ոչ բոլոր կոնֆիգուրացիոն արժեքները պետք է նույնը լինեն բոլոր միջավայրերում։ Search backend-ները, logging-ի մակարդակը, caching շերտերը և երրորդ կողմի API endpoint-ները լիովին կարող են տարբեր լինել։ Հարցն այն է, թե ինչպես կառավարել այդ տարբերությունները՝ առանց config pipeline-ի ամբողջականությունը խախտելու։

Ճիշտ գործիքներ՝ config_split և config_ignore

config_split-ը թույլ է տալիս սահմանել կոնֆիգուրացիայի հավաքածուներ, որոնք ակտիվ են միայն որոշակի միջավայրերում։

Իրական split օրինակներ

Կոնֆիգի տարրDev splitStage splitProd split
Search API backendՏվյալների բազաSolr (փոքր)Solr (արտադրական կլաստեր)
Error loggingdblog, մանրամասնsyslogsyslog + արտաքին APM
Performance modulesԱնջատվածՄիացվածՄիացված + CDN կոնֆիգ
Mail transportMailhog / null mailerMailpitSMTP / SendGrid

Սխալ մոտեցումներ — մի արեք սա․

  • Կոնֆիգուրացիայի ուղղակի խմբագրում production տվյալների բազայում։
  • settings.php-ում օգտագործել if ($settings['environment'] === 'prod') պայմանականներ՝ config արժեքները փոխելու համար։
  • Յուրաքանչյուր միջավայրի համար առանձին Git branch-երի պահպանում տարբեր config ֆայլերով։

10. Տեղափոխում միջավայրերի միջև

Promotion-ը deployment չէ։ Deployment-ը տեղափոխում է կոդը և կոնֆիգը միջավայր։ Promotion-ը տեղափոխում է վավերացված artifact — ինչ-որ բան, որն արդեն անցել է CI-ը — շղթայի հաջորդ միջավայր։

Գործնականում սա նշանակում է, որ նույն Git SHA-ն, որը վավերացվել է dev-ում, հասնում է production։ Վերջին պահին commit-ներ չկան։ CI-ը շրջանցող hotfix-ներ չկան։ Config ստուգումը շրջանցող cherry-pick-եր չկան։

✅ CI-ը վավերացնում է SHA-ն
feature branch / main-ում
🌐 Dev
auto-deploy merge-ից հետո
🌐 Stage
auto-deploy develop-ից
🌐 Prod
manual gate main-ում

Նույն վավերացված artifact-ը անցնում է միջավայրերով։ CI-ը գործարկվում է մեկ անգամ, արդյունքը՝ տարածվում։

Immutable build-երի փիլիսոփայությունը նշանակում է՝ այն, ինչ CI-ը վավերացրել է, հենց դա էլ տեղակայվում է։ Եթե իսկապես անհրաժեշտ է hotfix, այն անցնում է արագացված branch-ով՝ իր սեփական CI run-ով — այն չի շրջանցում վավերացումը։

Վերջին րոպեի hotfix-ների կողմից config ստուգումների շրջանցման կանխարգելում․ Պաշտպանեք ձեր main branch-ը պարտադիր pipeline status check-ով։ GitLab-ի "protected branches"-ը և Jenkins-ի "GitHub Branch Source" plugin-ը աջակցում են դրան։ Եթե pipeline-ը չի անցել, branch-ը չի կարող տեղակայվել production-ում։

11. Սահմանի դեպքերի կառավարում (դուք բախվելու եք դրանց)

UUID անհամապատասխանություններ

Config entity-ները կրում են UUID-ներ։ Եթե տեղադրեք նոր կայք և փորձեք ներմուծել config այլ տեղադրումից, Drupal-ը կհրաժարվի UUID անհամապատասխանության սխալով։ Լուծումն է միշտ տեղադրել --existing-config-ով կամ տեղադրումից հետո սահմանել site UUID-ը։

Shell
# Կարդացեք UUID-ը commit արված config-ից և կիրառեք այն նոր տեղադրմանը՝
SITE_UUID=$(grep "^uuid:" config/sync/system.site.yml | awk '{print $2}')
drush config-set "system.site" uuid "$SITE_UUID" --yes
drush cim --yes

Module enable/disable հերթականություն

Config-ի միջոցով նոր module միացնելիս, Drupal-ը ավտոմատ պահպանում է dependency-ի հերթականությունը drush cim-ի ընթացքում։ Սակայն, եթե module-ի install hook-ը գեներացնում է default config, որը հակասում է config/sync-ում եղածին, կարող է անհրաժեշտ լինել ջնջել այդ default config-ը և կրկին ներմուծել։ Pipeline-ը սա կբռնի որպես drift։

Բովանդակությունից կախված կոնֆիգուրացիա

Որոշ կոնֆիգներ հղում են կատարում բովանդակությանը — օրինակ՝ block, որը հղվում է menu item-ին ըստ ID-ի, կամ view, որը ֆիլտրում է taxonomy term-ով։ Այս հղումները կարող են տարբեր լինել միջավայրերի միջև, եթե բովանդակությունը տարբեր կերպ է ստեղծվել։ Լուծումն է կառավարել այդ բովանդակությունը migration-ների կամ default content module-ների միջոցով, ոչ թե կոնֆիգով։

Multisite առանձնահատկություններ

Multisite միջավայրում յուրաքանչյուր կայք ունի իր config sync թղթապանակը։ CI pipeline-ը պետք է գործարկի config ստուգում յուրաքանչյուր կայքի համար, ոչ միայն հիմնականի։ Օգտագործեք loop։

Shellci/multisite-config-check.sh
#!/bin/bash
set -euo pipefail

for SITE_DIR in web/sites/*/; do
  SITE=$(basename "$SITE_DIR")
  [[ "$SITE" == "default" ]] && continue
  [[ "$SITE" == "simpletest" ]] && continue

  echo "--- Կոնֆիգի ստուգում կայքի համար: $SITE ---"
  drush --uri="${SITE}" updb --yes
  drush --uri="${SITE}" cim --yes
  drush --uri="${SITE}" cex --yes

  CONFIG_DIR="config/${SITE}/sync"
  if ! git diff --exit-code "${CONFIG_DIR}"; then
    echo "❌ Config drift կայքում: $SITE"
    exit 1
  fi
done
echo "✅ Բոլոր կայքերը մաքուր են։"

Drupal Core-ի թարմացում կոնֆիգի փոփոխություններով

Core-ի թարմացումները երբեմն ներառում են schema-ի փոփոխություններ, որոնք ազդում են առկա config-ի վրա։ Միշտ գործարկեք drush updb նախքան drush cim-ը և հետո՝ drush cex՝ schema-ի նորմալացված փոփոխությունները գրանցելու համար։ Commit արեք այդ փոփոխությունները core upgrade branch-ում։

12. Օպերացիոն անվտանգության ցանցեր

Read-Only Config Production-ում

Քննարկեք production-ում Config Readonly module-ի միացումը։ Այն արգելում է ցանկացած կոնֆիգի փոփոխություն admin UI-ի միջոցով — կոշտ արգելք, որը ամրապնդում է "ձեռքով փոփոխություններ՝ ոչ" կանոնը հավելվածի մակարդակում։

PHPweb/sites/default/settings.env.php
if (getenv('APP_ENV') === 'production') {
  $settings['config_readonly'] = TRUE;
}

Post-Deploy ստուգում

ShellPost-deploy ստուգումներ
# Ստուգեք, որ deploy-ից հետո չկան սպասվող config փոփոխություններ՝
drush config-status 2>&1 | grep -v 'No differences' && { \
  echo "❌ Անսպասելի config տարբերություններ deploy-ից հետո"; exit 1; \
} || echo "✅ Config կարգավիճակը մաքուր է"

drush cr
drush php-eval "echo \Drupal::state()->get('system.cron_last');"

Rollback ռազմավարություն

Rollback-ը Git գործողություն է, ոչ թե տվյալների բազայի գործողություն։ Եթե deployment-ը խնդիր է առաջացնում՝

  1. Նշեք վերջին լավ commit SHA-ն։
  2. Գործարկեք pipeline-ը այդ SHA-ի վրա։
  3. Pipeline-ը կրկին տեղակայում է նախկինում վավերացված artifact-ը։

Կոնֆիգի ներմուծումը հետ շրջելու համար տվյալների բազայի ձեռքով փոփոխումը երբեք ճիշտ լուծում չէ։

Աուդիտ․ Ո՞վ փոխեց կոնֆիգը, ե՞րբ և ինչո՞ւ

Քանի որ յուրաքանչյուր config փոփոխություն անցնում է Git-ով, ձեր audit trail-ը Git պատմությունն է։ Օգտագործեք իմաստալից commit հաղորդագրություններ և ապահովեք դրանք commit-msg hook-ով կամ CI lint քայլով։

13. Սովորական սխալներ, որոնք այլևս չենք անում

ՍխալԻնչու է վնասակարԼուծում
Ձեռքով drush cim գործարկել staging կամ prod-ումՆերմուծվում է անհայտ վիճակՄիայն pipeline-ը ներմուծում է config-ը
UI փոփոխությունների թույլատրում staging-ումStaging-ը դառնում է ճշմարտության աղբյուրՄիացնել config_readonly
Ծրագրավորողներին "հիշելու" վրա վստահելըՍթրեսի տակ նրանք չեն հիշիPre-commit զգուշացում, CI ձախողում
Config drift-ի անտեսումԿուտակվում է լուռ շեղումdrush cim → cex → git diff --exit-code պարտադիր է
Առանձին branch-եր միջավայրերի համարՄիավորման մղձավանջՄեկ config branch՝ config_split-ով
drush updb-ի բացթողում մինչև drush cimSchema թարմացումները կարող են առաջացնել սխալներՄիշտ՝ updb → cim → cex → diff

14. Արդյունքներ այս մոտեցման կիրառումից հետո

Այս մոտեցումը տարբեր Drupal կայքերում կիրառելուց հետո արդյունքները հետևողական էին։

~80%
Կոնֆիգ-կապված deployment միջադեպերի նվազում
< 1 օր
Նոր ծրագրավորողի onboarding
0
Ձեռքով drush cim production-ում 18 ամսում
100%
Git commit-ին կապվող config փոփոխություններ

Մշակութային փոփոխությունն առավել կարևոր էր։ Config քննարկումները տեղափոխվում են Slack-ից դեպի Git պատմություն։

15. Վերջնական առաջարկություններ

  • Սկսեք խիստ կանոններով, թուլացրեք միայն պատճառներով։
  • Յուրաքանչյուր config diff դիտարկեք որպես build ձախողում։
  • CI-ը deployment-ի ճշմարտության աղբյուրն է։
  • updb → cim → cex → diff հաջորդականությունը խախտելի չէ։
  • Օգտագործեք config_split իրական միջավայրային տարբերությունների համար։
  • Միացրեք config_readonly-ը բոլոր shared միջավայրերում։
  • Արխիվացրեք ձախողված config export-երը որպես CI artifact-ներ։
  • Rollback-ը կատարեք Git-ի միջոցով, ոչ տվյալների բազայով։
Այս մոտեցումը մասշտաբավորվում է։ Անկախ նրանից՝ դուք միայնակ ծրագրավորող եք, թե գործակալություն, կանոնները նույնն են։

Jenkins-ը և GitLab CI-ը հավասարապես ունակ են ապահովելու այս կարգապահությունը։

Նպատակը երբեք կոնֆիգի կառավարումը բարդացնելը չէ։ Նպատակն այն ձանձրալի դարձնելն է՝ գործընթաց, որը միշտ աշխատում է։

Տեխնիկական և ճարտարապետական հարցումներ
Ivan Abramenko, Principal Drupal Architect
ivan.abramenko@drupalbook.org
Ծրագրի վերաբերյալ հարցումներ
projects@drupalbook.orgprojects@drupalbook.org