GitLab CI/CD
Pipeline-ներ՝ նկարագրված .gitlab-ci.yml-ում․ stage-եր, job-եր, runner-ներ և environment-ներ՝ ներկառուցված GitLab-ում։
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-երը միշտ աշխատում են առաջինը և վերջինը։
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-ը դարձնում է ավելի արագ ուղղորդված գրաֆ։
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-ի կանչ։
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 պլատֆորմը։
Լավագույն պրակտիկաներ
- Օգտագործիր rules: և workflow: rules, ոչ թե only/except, և խուսափիր կրկնակի branch և merge request pipeline-ներից։
- Credentials-ը նշիր որպես masked և protected, և պաշտպանիր այն branch-երն ու environment-ները, որոնք deploy են անում։
- Օգտագործիր needs:՝ ուղղորդված գրաֆ կառուցելու համար, որպեսզի job-երը սկսվեն հենց իրենց input-ները պատրաստ լինեն։
- Pipeline-ի տրամաբանությունը կիսիր include:-ով կամ տիպավորված input-ներով CI/CD component-ներով՝ copy-paste-ի փոխարեն։
- Ամրացրու image-ների tag-երը (node:24-alpine, ոչ թե latest) և dependency-ները cache արա lockfile-ով key-ով։
- Deploy job-երում օգտագործիր resource_group, որպեսզի մեկ environment-ի deploy-ները երբեք չհամընկնեն։
- 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 կատալոգի հիմքը։
# 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-ի տևողություն, հերթի ժամանակ և սխալներ։
Իրական իրավիճակներ
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-ի տեսքը դեռ պարզ ցույց է տալիս ամեն ծառայության կարգավիճակը։
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-ում։
Երկու 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-ում։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։