Բոլոր դասերը
DevOps և ամպՄիջին11 րոպե ընթերցումԱրժե իմանալ

GitLab CI/CD

Pipeline-ներ՝ նկարագրված .gitlab-ci.yml-ում․ stage-եր, job-եր, runner-ներ և environment-ներ՝ ներկառուցված GitLab-ում։

  • Pipelines
  • Stages
  • Runners
  • Environments
Քայլ 1/6
Ծրագրավորողը push է անում կոդը։ CI/CD pipeline-ը արթնանում է, և առաջինը linter-ն է ստուգում ոճը։ Կանաչ է։

30 վայրկյանում

GitLab CI/CD-ն GitLab-ում ներկառուցված ավտոմատացման շարժիչն է։ Ռեպոզիտորիայում .gitlab-ci.yml կոչվող ֆայլը նկարագրում է pipeline՝ job-եր, որոնք խմբավորված են stage-երում, օրինակ՝ build, test և deploy։ GitLab Runner-ները՝ GitLab-ի ենթակառուցվածքում կամ քո սեփական սերվերներում, կատարում են այդ job-երը, սովորաբար Docker container-ների ներսում։ Environment-ները, հաստատումները և deploy-ների պատմությունը նույն պրոդուկտի մասն են, ուստի կոդը, merge request-ները և deploy-ները բոլորը մեկ տեղում են։

Իմ ամենօրյա stack-ում չէ․ գիտեմ հիմնական գաղափարները և մանրամասները կսովորեմ, երբ նախագիծը դա պահանջի։

Ինչու է սա կարևոր

  • Սա մեկ պրոդուկտ է ամբողջ կյանքի ցիկլի համար՝ ռեպոզիտորիա, merge request-ներ, pipeline-ներ, container registry, environment-ներ և անվտանգության scan-եր, ինչը հարմար է այն թիմերին, որոնք ուզում են ավելի քիչ գործիքներ։
  • Self-managed GitLab-ը քո սեփական runner-ների հետ հասուն տարբերակ է այն ընկերությունների համար, որոնք պետք է կոդը և build-երը պահեն իրենց ենթակառուցվածքում։
  • Pipeline-ները պարզապես YAML են՝ include-ներով, template-ներով և CI/CD component-ներով, ուստի պլատֆորմային թիմը կարող է ստանդարտացնել pipeline-ները հարյուրավոր նախագծերում։
  • Environment-ները հետևում են, թե ինչն է որտեղ deploy արված՝ ձեռքով դարպասներով, պաշտպանված environment-ներով և նախորդ deploy-ին մեկ սեղմումով rollback-ով։

Ինչպես է աշխատում

01Pipeline-ներ, stage-եր և job-եր

Pipeline-ը ամբողջական run-ն է, որը գործարկվում է push-ով, merge request-ով, tag-ով, ժամանակացույցով կամ API կանչով։ Այն կազմված է job-երից, և յուրաքանչյուր job .gitlab-ci.yml-ում անվանված բլոկ է script:-ով՝ աշխատեցվող shell հրամաններով։ Job-երը խմբավորվում են stage-երում, որոնք հերթականությամբ թվարկված են stages:-ի տակ։ Մեկ stage-ի բոլոր job-երը աշխատում են զուգահեռ, հաջորդ stage-ը սկսվում է միայն այն ժամանակ, երբ ընթացիկ stage-ի բոլոր job-երը հաջող են ավարտվել։ Պատկերացրու հավաքման գիծ կայաններով․ build կայանի բոլոր աշխատողները պետք է ավարտեն, մինչև մասերը տեղափոխվեն test կայան։ Յուրաքանչյուր job աշխատում է նոր միջավայրում, հաճախ image:-ով ընտրված Docker container-ում, ուստի ֆայլերը չեն փոխանցվում, եթե դրանք չհայտարարես որպես artifact-ներ կամ cache։ Եթե stage նշված չէ, job-ը հայտնվում է test-ում։ Նախապես սահմանված .pre և .post stage-երը միշտ աշխատում են առաջինը և վերջինը։

yaml
stages: [build, test, deploy]
 
default:
  image: node:24-alpine
 
build:
  stage: build
  script:
    - npm ci
    - npm run build
  artifacts:
    paths: [dist/]
    expire_in: 1 week
 
unit-tests:
  stage: test
  script:
    - npm ci
    - npm test

02Runner-ներ և executor-ներ

GitLab Runner-ը agent ծրագիր է, որը GitLab-ից job-եր է խնդրում և կատարում դրանք։ GitLab.com-ում hosted runner-ները հասանելի են Linux-ի, Windows-ի և macOS-ի վրա և վճարվում են compute րոպեներով։ Self-managed runner-ները տեղադրվում են քո սեփական մեքենաներում․ դրանք գրանցում ես նախագծի, խմբի կամ instance-ի կարգավորումներում ստեղծված authentication token-ով։ Executor-ը որոշում է, թե ինչպես է job-ն աշխատում․ shell-ը աշխատում է ուղիղ host-ի վրա (պարզ, բայց առանց մեկուսացման), docker-ը ամեն job-ի համար job-ի image-ից container է գործարկում (տարածված լռելյայն ընտրություն), kubernetes-ը ամեն job-ի համար կլաստերում pod է գործարկում, իսկ docker-autoscaler կամ instance executor-ները ըստ պահանջի ստեղծում են ամպային VM-ներ։ Tag-երը կապում են job-երը runner-ներին․ tags: [gpu] ունեցող job-ը աշխատում է միայն այդ tag-ով գրանցված runner-ների վրա։ Runner-ները կարող են լինել ամբողջ instance-ի, խմբի կամ կոնկրետ նախագծի մակարդակում․ այդպես ես production ցանցի runner-ը հասանելի դարձնում միայն deploy նախագծին։

03Կառավարել, թե երբ են job-երն աշխատում․ rules և workflow

rules:-ը որոշում է, արդյոք job-ը ավելացվում է pipeline-ին։ Կանոնները ստուգվում են վերևից ներքև, և առաջին համընկնումը հաղթում է․ յուրաքանչյուրը կարող է սահմանել when: (on_success, manual, delayed, never) և allow_failure։ Պայմաններում օգտագործվում են նախապես սահմանված փոփոխականներ, օրինակ՝ CI_PIPELINE_SOURCE, CI_COMMIT_BRANCH և CI_DEFAULT_BRANCH, գումարած changes:՝ ֆայլերի ուղիների համար, և exists:՝ ֆայլերի համար։ workflow: rules-ը աշխատում է մեկ մակարդակ վերև և որոշում է, արդյոք pipeline-ն ընդհանրապես ստեղծվում է։ Տարածված pattern է pipeline-ներ աշխատեցնել merge request-ների և լռելյայն branch-ի համար, բայց ոչ նույն commit-ի կրկնակի branch pipeline։ Նախընտրիր rules-ը հին only/except բանալի բառերի փոխարեն, որոնք այլևս խորհուրդ չեն տրվում։ needs:-ը թույլ է տալիս job-ին սկսել հենց կոնկրետ job-երը ավարտվեն՝ անտեսելով stage-երի հերթականությունը, ինչը pipeline-ը դարձնում է ավելի արագ ուղղորդված գրաֆ։

yaml
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
 
e2e-tests:
  stage: test
  needs: [build]
  rules:
    - changes: [src/**/*, package-lock.json]
  script:
    - npm run test:e2e

04Փոփոխականներ, secret-ներ և environment-ներ

CI/CD փոփոխականները սահմանվում են նախագծի, խմբի կամ instance-ի կարգավորումներում, կամ YAML-ում՝ ոչ գաղտնի արժեքների համար։ Զգայուն փոփոխականները նշիր որպես masked (թաքցված լոգերում) և protected (հասանելի միայն պաշտպանված branch-երի և tag-երի pipeline-ներին), որպեսզի feature branch-ը չկարողանա կարդալ production-ի credentials։ File տիպի փոփոխականները արժեքը գրում են ժամանակավոր ֆայլի մեջ և դրա ուղին դնում փոփոխականում, ինչը հարմար է kubeconfig-ների և սերտիֆիկատների համար։ Environment-ը անվանված թիրախ է, օրինակ՝ staging կամ production․ job-երը հայտարարում են environment: name և url, և GitLab-ը գրանցում է յուրաքանչյուր deploy, ուստի տեսնում ես, թե ինչն է որտեղ աշխատում, և կարող ես rollback անել։ Պաշտպանված environment-ները սահմանափակում են, թե ով կարող է deploy անել, իսկ deployment approval-ները ավելացնում են պարտադիր հաստատողներ։ Ամպային մուտքի համար GitLab-ը թողարկում է OIDC ID token-ներ (id_tokens:), որոնք ընդունում են ամպերը և HashiCorp Vault-ը, ինչը լիովին վերացնում է երկարաժամկետ բանալիները։

05Image-ների build և deploy

GitLab-ը յուրաքանչյուր նախագծի համար տրամադրում է container registry և այն օգտագործելու նախապես սահմանված փոփոխականներ՝ CI_REGISTRY, CI_REGISTRY_IMAGE և login-ի համար job token։ Ստորև job-ը Docker-in-Docker-ով build է անում image, այն tag-ավորում commit SHA-ով և push անում։ Docker-in-Docker-ը պահանջում է privileged runner․ Kubernetes-ում կամ shared runner-ներում, որտեղ դա թույլատրված չէ, տարածված այլընտրանքներ են rootless builder-ները, օրինակ՝ Buildah-ը կամ BuildKit-ը։ Deploy job-ը լռելյայն branch-ում ձեռքով է, կապված է production environment-ին և օգտագործում է resource_group, որպեսզի երկու deploy երբեք միաժամանակ չաշխատեն։ Deploy հրամանն այստեղ placeholder է․ դա կարող է լինել helm upgrade, SSH հրաման, որը pull է անում image-ը, կամ ամպային CLI-ի կանչ։

yaml
build-image:
  stage: build
  image: docker:28
  services: [docker:28-dind]
  script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
 
deploy-prod:
  stage: deploy
  environment: { name: production, url: https://example.com }
  resource_group: production
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      when: manual
  script:
    - ./scripts/deploy.sh "$CI_COMMIT_SHA"

Օգտագործեք, երբ

  • Կոդդ host արված է GitLab-ում՝ GitLab.com-ում կամ self-managed։
  • Քեզ պետք է ամեն ինչ քո սեփական ենթակառուցվածքում՝ self-managed GitLab և self-managed runner-ներ քո ցանցում։
  • Պլատֆորմային թիմը ուզում է ստանդարտացնել pipeline-ները բազմաթիվ նախագծերում include-ներով և CI/CD component-ներով։
  • Կարևորում ես ներկառուցված environment-ները, deploy-ների պատմությունը, հաստատումները և ամեն նախագծի container registry-ն։

Մի՛ օգտագործեք, երբ

  • Ռեպոզիտորիաներդ GitHub-ում են․ GitHub Actions-ը ավելի բնական է ինտեգրվում։
  • Փոքրիկ ստատիկ կայք առանց թեստերի, որտեղ hosting պլատֆորմի git-push build-ը ավելի պարզ է։
  • Քեզ պետք է էկզոտիկ build-ի կազմակերպում, որը ավելի լավ է սպասարկում առանձնացված համակարգը, օրինակ՝ Buildkite-ը կամ Bazel remote execution-ը։

Այլընտրանքներ

  • GitHub Actions

    Համարժեքը GitHub ռեպոզիտորիաների համար՝ action-ների մեծ Marketplace-ով։

  • Jenkins

    Self-hosted, plugin-ների վրա հիմնված․ հաճախ հանդիպում է հին կամ խիստ հարմարեցված համակարգերում։

  • Argo CD / Flux

    GitOps գործիքներ, որոնք deploy-ները pull են անում Kubernetes-ի մեջ, հաճախ զուգակցված GitLab CI-ի հետ build-երի համար։

  • Tekton

    Kubernetes-native pipeline-ի կառուցվածքային մասեր այն թիմերի համար, որոնք կառուցում են իրենց սեփական CI պլատֆորմը։

Լավագույն պրակտիկաներ

  1. Օգտագործիր rules: և workflow: rules, ոչ թե only/except, և խուսափիր կրկնակի branch և merge request pipeline-ներից։
  2. Credentials-ը նշիր որպես masked և protected, և պաշտպանիր այն branch-երն ու environment-ները, որոնք deploy են անում։
  3. Օգտագործիր needs:՝ ուղղորդված գրաֆ կառուցելու համար, որպեսզի job-երը սկսվեն հենց իրենց input-ները պատրաստ լինեն։
  4. Pipeline-ի տրամաբանությունը կիսիր include:-ով կամ տիպավորված input-ներով CI/CD component-ներով՝ copy-paste-ի փոխարեն։
  5. Ամրացրու image-ների tag-երը (node:24-alpine, ոչ թե latest) և dependency-ները cache արա lockfile-ով key-ով։
  6. Deploy job-երում օգտագործիր resource_group, որպեսզի մեկ environment-ի deploy-ները երբեք չհամընկնեն։
  7. Deploy job-երը աշխատեցրու միայն առանձնացված, tag-ավորված runner-ների վրա, որոնք գտնվում են թիրախին մոտ, և ուրիշ ոչ մի տեղ։

Տարածված սխալներ

  • Production-ի փոփոխականները անպաշտպան թողնել, ուստի ցանկացած branch pipeline կարող է կարդալ և արտահոսել դրանք։
  • Shell executor-ով runner գրանցել ընդհանուր host-ի վրա, որտեղ job-երը կարող են դիպչել իրար ֆայլերին և host-ին։
  • Շփոթել cache-ը և artifact-ները, հետո զարմանալ, թե ինչու build-ի արդյունքը բացակայում է հաջորդ stage-ում։
  • Echo անել secret-ները կամ script-եր աշխատեցնել set -x-ով՝ տպելով արժեքներ, որոնք masking-ը չի բռնում։
  • Հսկայական մեկ ֆայլանոց pipeline-ներ պատճենված job-երով՝ extends:-ի, anchor-ների կամ include-ների փոխարեն։

Խորը վերլուծություն

06CI/CD component-ներ և տիպավորված input-ներ

CI/CD component-ը pipeline-ի կոնֆիգուրացիայի վերօգտագործվող միավոր է, որը պահվում է component նախագծում templates/-ի տակ, թողարկվում է semantic version tag-երով և ցուցակագրված է CI/CD Catalog-ում։ Ֆայլը սկսվում է spec: վերնագրով, որը հայտարարում է input-ներ type-ով (string, number, boolean, array), default-ով, options-ով և regex ստուգումով, և job-երի սահմանումներից բաժանված է --- տողով։ Արժեքները տեղադրվում են $[[ inputs.name ]]-ով pipeline-ի ստեղծման պահին, մինչև որևէ job-ի աշխատելը, ուստի սխալ արժեքը արագ ձախողվում է պարզ սխալով, ոչ թե pipeline-ի կեսին։ Սպառողները այն include են անում include: component:-ով և տարբերակով, որը կարող է լինել ճշգրիտ tag, մասնակի տարբերակ, օրինակ՝ ~latest, կամ commit SHA։ Production pipeline-ների համար օգտագործիր ճշգրիտ տարբերակներ կամ SHA-ներ, և թող bot-ը առաջարկի թարմացումներ։ Component-ները reusable workflow-ների GitLab-յան համարժեքն են և ներքին pipeline կատալոգի հիմքը։

yaml
# templates/node-test/template.yml in the component project
spec:
  inputs:
    node_version:
      default: "24"
    stage:
      default: test
---
node-test:
  stage: $[[ inputs.stage ]]
  image: node:$[[ inputs.node_version ]]-alpine
  script:
    - npm ci
    - npm test
 
# consumer .gitlab-ci.yml
include:
  - component: $CI_SERVER_FQDN/your-group/ci-components/[email protected]
    inputs: { node_version: "22" }

07Parent-child և multi-project pipeline-ներ

Մեծ ռեպոզիտորիաները բախվում են մեկ pipeline-ի սահմանափակումներին՝ չափազանց շատ job-եր, դժվար կարդալ, ամեն ինչ աշխատում է ամեն փոփոխության համար։ Parent-child pipeline-ը թույլ է տալիս job-ին trigger: include:-ով գործարկել առանձին child pipeline նույն նախագծի մեկ այլ YAML ֆայլից։ rules: changes:-ի հետ համատեղ monorepo-ն կարող է աշխատեցնել միայն փոփոխված ծառայության child pipeline-ը։ Child-երը կարող են նույնիսկ դինամիկ գեներացվել․ job-ը YAML ֆայլ է գրում որպես artifact, և trigger job-ը աշխատեցնում է այն․ այդպես թիմերը pipeline-ներ են ստեղծում ամեն հայտնաբերված փաթեթի համար։ Multi-project pipeline-ները գործարկում են pipeline մեկ այլ նախագծում, օրինակ՝ հավելվածի pipeline, որը image-ը հրապարակելուց հետո գործարկում է deploy ռեպոզիտորիայի pipeline-ը։ strategy: depend-ը (կամ ավելի նոր mirror strategy-ն) ստիպում է trigger job-ին արտացոլել downstream-ի արդյունքը, ուստի child-ի ձախողումը երևում է parent-ում։

08Runner-ների պարկի scaling և մեկուսացում

Հերթի ժամանակը CI-ի թաքնված արժեքն է։ Յուրաքանչյուր runner config.toml-ում ունի concurrent (պրոցեսի ընդհանուր job-եր) և ամեն runner-ի limit կարգավորումներ․ դրանք սահմանիր CPU-ի և հիշողության համաձայն, ոչ թե հույսով։ Ալիքաձև ծանրաբեռնվածության համար Kubernetes executor-ը կամ docker-autoscaler executor-ը ամպային fleeting plugin-ով ըստ պահանջի ընդլայնվում են և վերադառնում զրոյի։ Պարկերը բաժանիր ըստ վստահության մակարդակի․ shared runner-ներ սովորական build-երի համար, protected runner-ներ (որոնք job-եր են վերցնում միայն պաշտպանված branch-երից) deploy-ների համար և ցանցից մեկուսացված runner-ներ այն ամենի համար, ինչը դիպչում է production-ին։ Docker-in-Docker-ի privileged ռեժիմը job-ին տալիս է host-ի գրեթե root մուտք․ խուսափիր դրանից shared պարկերում և նախընտրիր rootless builder-ներ։ S3-համատեղելի պահեստում distributed cache-ը թույլ է տալիս autoscale արվող runner-ներին կիսել cache-ը։ Հետևիր runner-ի Prometheus մետրիկաներին՝ job-ի տևողություն, հերթի ժամանակ և սխալներ։

Իրական իրավիճակներ

01

Monorepo, որտեղ ամեն commit աշխատեցնում է ամեն ինչ

Խնդիր

Ռեպոզիտորիան պարունակում է վեբ հավելված, API և երեք worker։ Ամեն commit 40 րոպե աշխատեցնում է բոլոր 60 job-երը, նույնիսկ մեկ ծառայության մեկ տողի փոփոխության համար։

Ինչպես լուծել

Յուրաքանչյուր ծառայությանը տուր իր child pipeline ֆայլը, օրինակ՝ services/api/.gitlab-ci.yml։ Root ֆայլում ավելացրու մեկ trigger job ամեն ծառայության համար trigger: include:-ով այդ ֆայլին և strategy: depend-ով, գումարած rules: changes: services/api/**/* և ընդհանուր ուղիներ, օրինակ՝ lockfile-ը։ Պահիր լռելյայն branch-ի ամբողջական run-ը գիշերը՝ ժամանակացույցով pipeline-ով, որպեսզի բռնես ծառայությունների միջև կոտրվածքները։ Child pipeline-ների ներսում ավելացրու needs:՝ կրիտիկական ուղիները կարճացնելու համար։ Տիպիկ փոփոխությունը հիմա աշխատեցնում է մեկ child pipeline մի քանի րոպեում, իսկ parent-ի տեսքը դեռ պարզ ցույց է տալիս ամեն ծառայության կարգավիճակը։

02

Feature branch-ը արտահոսեց production token

Խնդիր

Ծրագրավորողը feature branch-ում ավելացրեց debug step, որը տպում էր միջավայրի փոփոխականները, և production API token-ը base64-ով կոդավորված հայտնվեց job-ի լոգում։

Ինչպես լուծել

Անմիջապես չեղարկիր և rotate արա token-ը, հետո ջնջիր job-ի լոգը։ Նոր փոփոխականը նշիր որպես protected և masked, որպեսզի այն ներարկվի միայն պաշտպանված branch-երում և թաքցված լինի լոգերում։ Պաշտպանիր main branch-ը և production environment-ը, և deploy credentials-ը տեղափոխիր պաշտպանված environment scope։ Deploy job-երը սահմանափակիր protected runner-ով։ Երկարաժամկետ՝ ստատիկ token-ը փոխարինիր id_tokens-ով և Vault-ից կամ ամպային պրովայդերից կարճաժամկետ credential-ով։ Ավելացրու թիմի համար կարճ նշում․ երբեք մի՛ տպիր միջավայրի փոփոխականները CI-ում։

03

Երկու deploy միաժամանակ աշխատեցին և փչացրին migration-ը

Խնդիր

Երկու merge տեղի ունեցան մեկ րոպե տարբերությամբ։ Երկու deploy job-երն էլ աշխատեցին զուգահեռ, երկուսն էլ սկսեցին տվյալների բազայի migration-ներ, և production-ը հայտնվեց կիսով չափ migrate արված վիճակում։

Ինչպես լուծել

Deploy job-ին ավելացրու resource_group: production, որպեսզի GitLab-ը այդ environment-ին միաժամանակ աշխատեցնի միայն մեկ deploy․ process_mode-ը դիր oldest_first կամ newest_first՝ կախված նրանից, արդյոք ամեն commit պետք է deploy արվի։ Migration-ները բաժանիր առանձին job-ի հավելվածի rollout-ից առաջ և դարձրու հետադարձ համատեղելի (expand, հետո contract), որպեսզի հին և նոր կոդը կարողանան աշխատել անցման ժամանակ։ Միացրու հնացած deploy job-երը կանխելու տարբերակը, որպեսզի հին pipeline-ը չկարողանա deploy անել նորի վրայից։ Գրանցիր ամեն deploy production environment-ում՝ հեշտ rollback-ի համար։

Արագ ուղեցույց

Ստուգել կոնֆիգը լոկալ՝ API-ով
glab ci lint .gitlab-ci.yml
Աշխատեցնել միայն merge request-ների համար
rules: [{ if: '$CI_PIPELINE_SOURCE == "merge_request_event"' }]
Ձեռքով job լռելյայն branch-ում
rules: [{ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH', when: manual }]
Սկսել շուտ, բաց թողնել stage-երի հերթականությունը
needs: [build]
Cache՝ lockfile-ով key-ով
cache: { key: { files: [package-lock.json] }, paths: [.npm/] }
Միաժամանակ մեկ deploy
resource_group: production
OIDC token job-ի համար
id_tokens: { CLOUD_TOKEN: { aud: https://example.com } }
Վերօգտագործել թաքնված template job
.base: { image: node:24-alpine } then test: { extends: .base }
Գրանցել runner
gitlab-runner register --url https://gitlab.example.com --token $RUNNER_TOKEN

Հարցեր և պատասխաններ

Q1Ո՞րն է տարբերությունը stage-երի և needs-ի միջև։

Stage-երը տալիս են պարզ գծային հերթականություն․ մեկ stage-ի բոլոր job-երը պետք է ավարտվեն, մինչև հաջորդ stage-ը սկսվի։ Դա հեշտ է կարդալ, բայց դանդաղ է, երբ stage-ի մեկ job-ը շատ ավելի երկար է մյուսներից, որովհետև ամեն ինչ սպասում է դրան։ needs:-ը հայտարարում է job-երի ուղիղ կախվածություններ, ուստի job-ը սկսվում է հենց իրեն անհրաժեշտ job-երը ավարտվեն, նույնիսկ եթե նախորդ stage-երի այլ job-եր դեռ աշխատում են։ Pipeline-ը դառնում է ուղղորդված ացիկլիկ գրաֆ։ needs-ը նաև կառավարում է, թե ինչ artifact-ներ է job-ը ներբեռնում։ Ես սկսում եմ stage-երով՝ պարզության համար, և ավելացնում needs այնտեղ, որտեղ կրիտիկական ուղին երկար է, օրինակ՝ թույլ տալով deploy-docs-ին սկսել հենց build-docs-ը ավարտվի։

Q2Cache, թե՞ artifact-ներ GitLab-ում։

Artifact-ները job-ի արդյունքներ են, որոնք GitLab-ը պահում և փոխանցում է նույն pipeline-ի հաջորդ job-երին, և որոնք կարող ես ներբեռնել UI-ից՝ build թղթապանակներ, թեստերի հաշվետվություններ, coverage։ Դրանք հուսալի են․ հաջորդ job-ը, որին դրանք պետք են, կստանա դրանք։ Cache-ը best-effort արագացում է այն բաների համար, որոնք կարող ես վերագեներացնել, օրինակ՝ node_modules կամ package manager-ի ներբեռնումների թղթապանակը, որը կիսվում է pipeline-ների միջև և պահվում runner-ի վրա կամ object storage-ում։ Job-ը պետք է ճիշտ աշխատի դատարկ cache-ով։ Օգտագործիր cache:key:files lockfile-ով, որպեսզի cache-ը փոխվի, երբ dependency-ները փոխվում են։ Եթե job-ի ճշտությունը կախված է ֆայլից, օգտագործիր artifact։

Q3Ինչպե՞ս ես պաշտպանում production-ի credentials-ը GitLab CI-ում։

Պահիր դրանք որպես protected և masked նշված CI/CD փոփոխականներ, որպեսզի դրանք ներարկվեն միայն պաշտպանված branch-երում կամ tag-երում աշխատող pipeline-ներում և թաքցված լինեն լոգերում։ Պաշտպանիր main branch-ը, որպեսզի միայն maintainer-ները կարողանան push կամ merge անել։ Production-ը դարձրու պաշտպանված environment՝ deployment approval-ներով, որպեսզի միայն նշված մարդիկ կամ խմբեր կարողանան deploy job-եր աշխատեցնել։ Deploy job-երը աշխատեցրու production ցանցում առանձնացված tag-ավորված runner-ի վրա, ոչ թե shared runner-ների։ Որտեղ հնարավոր է, ընդհանրապես խուսափիր ստատիկ credentials-ից․ օգտագործիր id_tokens՝ job-ին կարճաժամկետ OIDC token տալու համար, որը քո ամպային պրովայդերը կամ Vault-ը փոխանակում է այդ նախագծով և branch-ով սահմանափակված ժամանակավոր credentials-ի հետ։

Q4Ի՞նչ է GitLab Runner executor-ը, և որը կընտրես։

Executor-ը այն ձևն է, թե ինչպես է runner-ը իրականում աշխատեցնում job-ը։ Shell-ը հրամանները աշխատեցնում է ուղիղ runner host-ի վրա․ ամենաարագն է կարգավորելու համար, բայց job-երի միջև մեկուսացում չկա, ուստի ես այն օգտագործում եմ միայն շատ վստահելի, մեկ նպատակի մեքենաների համար։ Docker-ը ամեն job աշխատեցնում է job-ի image-ից նոր container-ում․ լավ մեկուսացում, վերարտադրելիություն և սովորական լռելյայն ընտրություն։ Kubernetes-ը ամեն job-ի համար pod է ստեղծում, ինչը հարմար է այն թիմերին, որոնք արդեն կլաստեր ունեն և ուզում են autoscaling։ Docker-autoscaler կամ instance executor-ները ըստ պահանջի ամպային VM-ներ են գործարկում՝ ամեն job-ի համար ուժեղ մեկուսացմամբ։ Թիմերի մեծ մասի համար ես կընտրեի Docker executor-ը մի երկու VM-ի վրա, հետո կանցնեի Kubernetes-ի կամ autoscaling-ի, երբ հերթի ժամանակը խնդիր դառնա։

Q5Ինչպե՞ս խուսափել pipeline-ի կոդի կրկնությունից նախագծերի միջև։

GitLab-ը մի քանի մակարդակ է առաջարկում։ Մեկ ֆայլի ներսում extends:-ը և YAML anchor-ները վերօգտագործում են job-երի սահմանումները, իսկ թաքնված job-երը (կետով սկսվող անուններով) գործում են որպես template-ներ։ Նախագծերի միջև include:-ը YAML է բերում մեկ այլ նախագծից, հեռավոր URL-ից կամ GitLab-ի սեփական template-ներից։ Ժամանակակից տարբերակը CI/CD component-ներն են՝ տարբերակավորված, վերօգտագործվող pipeline-ի մասեր, որոնք հրապարակված են CI/CD Catalog-ում, spec: input-ներով, որոնք տիպավորված են և ստուգվում են pipeline-ի ստեղծման ժամանակ։ Ծառայությունը այնուհետև գրում է մի քանի տող՝ component-ը որոշակի տարբերակով include անելու և input-ներ փոխանցելու համար։ Ամրացրու տարբերակները, որպեսզի ընդհանուր component-ի փոփոխությունը միանգամից չկոտրի բոլոր նախագծերը։

Սենիոր մակարդակի հարցեր

S1Ինչպե՞ս կնախագծես GitLab CI պլատֆորմ 300 նախագծի համար՝ compliance պահանջներով։

Ես կտրամադրեի CI/CD component-ների փոքր կատալոգ (build, test, scan, deploy), որը սպասարկում է պլատֆորմային թիմը, տարբերակավորված semantic tag-երով և փաստաթղթավորված։ Compliance-ի համար կրիտիկական job-երը, օրինակ՝ SAST-ը, dependency scanning-ը և secret detection-ը, կպարտադրվեին կենտրոնացված՝ pipeline execution policy-ներով կամ compliance framework-ներով, որպեսզի նախագծերը չկարողանան դրանք հեռացնել։ Runner-ների պարկերը բաժանված են ըստ վստահության․ autoscale արվող shared runner-ներ build-երի համար, protected runner-ներ deploy-ների համար, մեկուսացված runner-ներ production ցանցերի ներսում։ Secret-ները գալիս են Vault-ից կամ ամպից OIDC id_tokens-ով, claim-երով՝ կապված նախագծի ուղուն և պաշտպանված ref-երին։ Environment-ները պաշտպանված են հաստատումներով։ Փոխզիջումը ինքնավարությունն է․ թիմերը պետք է կարողանան ընդլայնել ստանդարտ pipeline-ը իրենց job-երով, այլապես նրանք fork կանեն այն, և պլատֆորմը կկորցնի վերահսկողությունը։

S2Push-based deploy-ներ GitLab CI-ից, թե՞ pull-based GitOps Argo CD-ով։

Push-based նշանակում է, որ CI job-ը պահում է կլաստերի credentials և աշխատեցնում kubectl կամ helm։ Դա պարզ է, pipeline-ում տալիս է անմիջական feedback և աշխատում է ինչպես սերվերների, այնպես էլ կլաստերների համար։ Թերությունները․ CI-ին պետք են հզոր credentials, և Git-ի ու կլաստերի միջև drift-ը աննկատ է մնում։ Pull-based GitOps-ը կլաստերի ներսում agent է աշխատեցնում, որը հետևում է կոնֆիգուրացիայի ռեպոզիտորիային և կիրառում փոփոխությունները։ Կլաստերի credentials-ը երբեք դուրս չեն գալիս դրանից, drift-ը հայտնաբերվում և ուղղվում է, իսկ Git-ի պատմությունը աուդիտի հետքն է։ Գինը ևս մեկ համակարգ սպասարկելն է և անուղղակի feedback-ը․ CI-ը միայն թարմացնում է image-ի tag-ը Git-ում։ Մեծ մասշտաբի Kubernetes-ի համար ես հակված եմ GitOps-ին, որտեղ CI-ը build և թեստավորում է image-ները, իսկ մի քանի VM-ի համար protected runner-ից push-based-ը միանգամայն խելամիտ է։

S3Ինչպե՞ս pipeline-ները դարձնել և՛ արագ, և՛ հուսալի, երբ նախագիծը մեծանում է։

Արագությունը գալիս է ավելի քիչ անելուց և զուգահեռ անելուց․ needs: գրաֆներ, rules: changes:՝ չազդված աշխատանքը բաց թողնելու համար, թեստերի sharding parallel:-ով, dependency-ների և Docker շերտերի cache և նախապես build արված CI image-ներ, որոնք արդեն պարունակում են գործիքները։ Հուսալիությունը գալիս է դետերմինիզմից․ ամրացված image-ների տարբերակներ, lockfile-ներ, unit թեստերում արտաքին ծառայություններից կախվածության բացակայություն և retry միայն հայտնի ժամանակավոր ենթակառուցվածքային սխալների համար retry: when:-ով, երբեք ձախողվող թեստերի համար։ Անկայուն թեստերը հետևվում են և մեկուսացվում՝ պատասխանատուով։ Չափիր pipeline analytics-ով և runner-ի մետրիկաներով և սահմանիր բյուջե, օրինակ՝ merge request pipeline-ները տասը րոպեից պակաս՝ մեդիանով։ Փոխզիջումը սպասարկումն է․ ագրեսիվ բաց թողնելը կարող է բաց թողնել ծառայությունների միջև կոտրվածքները, ուստի զուգակցիր այն լռելյայն branch-ի ամբողջական ժամանակացույցով pipeline-ների հետ։

Բառարան

Pipeline
Push-ով, merge request-ով, tag-ով, ժամանակացույցով կամ API կանչով գործարկված բոլոր job-երի մեկ run։
Stage
Job-երի խումբ, որոնք աշխատում են զուգահեռ․ stage-երը աշխատում են թվարկված հերթականությամբ։
Job
Script-ով անվանված աշխատանքի միավոր, որը runner-ը կատարում է նոր միջավայրում։
Runner
Agent, որը GitLab-ից վերցնում է job-եր և աշխատեցնում դրանք՝ ընտրված executor-ով։
Executor
Թե ինչպես է runner-ը աշխատեցնում job-երը․ shell, docker, kubernetes, autoscale արվող VM-ներ և այլն։
Artifact
Ֆայլեր, որոնք job-ը պահում է pipeline-ի հաջորդ job-երի կամ ներբեռնման համար։
Protected variable
CI/CD փոփոխական, որը ներարկվում է միայն պաշտպանված branch-երի կամ tag-երի pipeline-ներում։
Environment
Անվանված deploy թիրախ, որին GitLab-ը հետևում է՝ պատմությամբ, հաստատումներով և rollback-ով։
CI/CD component
Pipeline-ի կոնֆիգի տարբերակավորված, վերօգտագործվող մաս՝ տիպավորված input-ներով, հրապարակված CI/CD Catalog-ում։

Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։

Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։