ProHoster > Օրագիր > Վարչակազմը > GitLab Shell Runner. Փորձարկված ծառայությունների մրցակցային գործարկում Docker Compose-ի միջոցով
GitLab Shell Runner. Փորձարկված ծառայությունների մրցակցային գործարկում Docker Compose-ի միջոցով
Այս հոդվածը կհետաքրքրի և՛ փորձարկողներին, և՛ ծրագրավորողներին, բայց նախատեսված է հիմնականում ավտոմատացման մասնագետների համար, ովքեր բախվում են GitLab CI/CD տեղադրման խնդրին ինտեգրացիոն թեստավորման համար՝ անբավարար ենթակառուցվածքային ռեսուրսների և/կամ կոնտեյների բացակայության պայմաններում: նվագախմբային հարթակ. Ես ձեզ կասեմ, թե ինչպես կարելի է կարգավորել թեստային միջավայրերի տեղակայումը docker compose-ի միջոցով մեկ GitLab shell runner-ի վրա և այնպես, որ մի քանի միջավայրեր տեղակայելիս գործարկված ծառայությունները չխանգարեն միմյանց:
Իմ պրակտիկայում հաճախ էր պատահում, որ ինտեգրացիոն թեստավորումը «վերաբերվում էր» նախագծերին: Եվ հաճախ առաջին և ամենակարևոր խնդիրը CI խողովակաշարն է, որտեղ ինտեգրացիոն թեստավորում է կատարվում մշակվում է ծառայություն(ներ)ն իրականացվում է մշակող/փուլային միջավայրում: Սա մի շարք խնդիրներ առաջացրեց.
Ինտեգրման փորձարկման ընթացքում որոշակի ծառայության թերությունների պատճառով փորձարկման սխեման կարող է վնասվել կոտրված տվյալների պատճառով: Եղել են դեպքեր, երբ կոտրված JSON ձևաչափով հարցում ուղարկելիս ծառայությունը խափանվել է, ինչի պատճառով ստենդը լիովին անգործունակ է դարձել։
Փորձարկման շրջանի դանդաղեցում, քանի որ փորձարկման տվյալները մեծանում են: Կարծում եմ՝ անիմաստ է տվյալների բազան մաքրելու/հետ գլորելու օրինակ նկարագրել։ Իմ պրակտիկայում ես չեմ հանդիպել մի նախագծի, որտեղ այս ընթացակարգը հարթ ընթանա:
Համակարգի ընդհանուր կարգավորումները ստուգելիս փորձարկման սխեմայի ֆունկցիոնալությունը խաթարելու վտանգ: Օրինակ՝ օգտվող/խումբ/գաղտնաբառ/հավելվածի քաղաքականություն:
Ավտոմատացված թեստերի փորձարկման տվյալները դժվարացնում են ձեռքով փորձարկողների կյանքը:
Ոմանք կասեն, որ լավ ավտոմատ փորձարկումները պետք է մաքրեն տվյալները իրենցից հետո: Ես դեմ փաստարկներ ունեմ.
Դինամիկ ստենդները շատ հարմար են օգտագործման համար։
Ոչ բոլոր օբյեկտները կարող են հեռացվել համակարգից API-ի միջոցով: Օրինակ, օբյեկտը ջնջելու կոչը չի իրականացվել, քանի որ այն հակասում է բիզնես տրամաբանությանը:
API-ի միջոցով օբյեկտ ստեղծելիս կարող են ստեղծվել հսկայական քանակությամբ մետատվյալներ, որոնք խնդրահարույց են ջնջել:
Եթե թեստերը միմյանց միջև կախվածություն ունեն, ապա թեստերը կատարելուց հետո տվյալների մաքրման գործընթացը վերածվում է գլխացավի:
Լրացուցիչ (և, իմ կարծիքով, ոչ հիմնավորված) զանգեր դեպի API:
Եվ հիմնական փաստարկը՝ երբ թեստի տվյալները սկսում են մաքրվել անմիջապես տվյալների բազայից։ Սա վերածվում է իսկական PK/FK կրկեսի: Մենք լսում ենք ծրագրավորողներից. «Ես հենց նոր ավելացրի/հեռացրեցի/վերանվանեցի նշանը, ինչո՞ւ են 100500 ինտեգրման թեստեր բռնել»:
Իմ կարծիքով ամենաօպտիմալ լուծումը դինամիկ միջավայրն է։
Շատ մարդիկ օգտագործում են docker-compose-ը թեստային միջավայր գործարկելու համար, սակայն քչերն են օգտագործում docker-compose-ը CI/CD-ում ինտեգրման թեստավորում իրականացնելիս: Եվ այստեղ ես հաշվի չեմ առնում կուբերնետները, երամները և այլ կոնտեյներային նվագախմբային հարթակներ։ Ոչ բոլոր ընկերություններն ունեն դրանք: Լավ կլիներ, որ docker-compose.yml-ը լիներ ունիվերսալ։
Նույնիսկ եթե մենք ունենք մեր սեփական QA վազորդը, ինչպե՞ս կարող ենք համոզվել, որ docker-compose-ի միջոցով գործարկվող ծառայությունները չեն խանգարում միմյանց:
Ինչպե՞ս հավաքել փորձարկված ծառայությունների մատյանները:
Ինչպե՞ս մաքրել վազորդը:
Ես ունեմ իմ սեփական GitLab վազորդը իմ նախագծերի համար, և ես հանդիպել եմ այս հարցերին զարգացման ընթացքում Java հաճախորդ համար TestRail. Ավելի ճիշտ՝ ինտեգրացիոն թեստեր վարելիս։ Ստորև մենք կլուծենք այս խնդիրները՝ օգտագործելով այս նախագծի օրինակները:
Վազողի համար ես առաջարկում եմ Linux վիրտուալ մեքենա 4 vCPU, 4 ԳԲ RAM, 50 ԳԲ HDD:
Ինտերնետում gitlab-runner-ի ստեղծման մասին շատ տեղեկություններ կան, ուստի հակիրճ.
Մուտք գործեք մեքենա SSH-ի միջոցով
Եթե ունեք 8 ԳԲ-ից պակաս օպերատիվ հիշողություն, ապա խորհուրդ եմ տալիս կատարել փոխանակում 10 ԳԲորպեսզի OOM մարդասպանը չգա և չսպանի մեր առաջադրանքները RAM-ի բացակայության պատճառով: Դա կարող է տեղի ունենալ, երբ 5-ից ավելի առաջադրանքներ գործարկվեն միաժամանակ: Առաջադրանքները կառաջանան ավելի դանդաղ, բայց կայուն։
Օրինակ OOM մարդասպանի հետ
Եթե տեսնում եք առաջադրանքների տեղեկամատյաններում bash: line 82: 26474 Killed, ապա պարզապես կատարեք վազողի վրա sudo dmesg | grep 26474
[26474] 1002 26474 1061935 123806 339 0 0 java
Out of memory: Kill process 26474 (java) score 127 or sacrifice child
Killed process 26474 (java) total-vm:4247740kB, anon-rss:495224kB, file-rss:0kB, shmem-rss:0kB
Իսկ եթե նկարի տեսքը նման է, ապա կա՛մ ավելացրեք swap, կա՛մ ավելացրեք RAM:
Սա թույլ կտա ձեզ զուգահեռ առաջադրանքներ կատարել մեկ վազորդի վրա: Կարդալ ավելին այստեղ.
Եթե ունեք ավելի հզոր մեքենա, օրինակ՝ 8 vCPU, 16 ԳԲ օպերատիվ հիշողություն, ապա այս թվերը կարող են լինել առնվազն 2 անգամ ավելի մեծ: Բայց ամեն ինչ կախված է նրանից, թե կոնկրետ ինչ կթողարկվի այս վազորդի վրա և ինչ քանակությամբ:
Հիմնական խնդիրը ունիվերսալ docker-compose.yml-ն է, որը մշակողները/փորձարկողները կարող են օգտագործել ինչպես տեղական, այնպես էլ CI խողովակաշարում:
Նախ և առաջ մենք յուրօրինակ ծառայությունների անվանումներ ենք պատրաստում CI-ի համար: GitLab CI-ի եզակի փոփոխականներից մեկը փոփոխականն է CI_JOB_ID. Եթե նշեք container_name արժեքով "service-${CI_JOB_ID:-local}", ապա դեպքում՝
եթե CI_JOB_ID սահմանված չէ շրջակա միջավայրի փոփոխականներում,
ապա ծառայության անունը կլինի service-local
եթե CI_JOB_ID սահմանված է շրջակա միջավայրի փոփոխականներում (օրինակ 123),
ապա ծառայության անունը կլինի service-123
Երկրորդ, մենք ստեղծում ենք միասնական ցանց գործարկված ծառայությունների համար: Սա մեզ տալիս է ցանցի մակարդակի մեկուսացում մի քանի փորձնական միջավայրեր գործարկելիս:
Իմ docker-compose.yml-ի օրինակ մեկնաբանություններով
version: "3"
# Для корректной работы web (php) и fmt нужно,
# чтобы контейнеры имели общий исполняемый контент.
# В нашем случае, это директория /var/www/testrail
volumes:
static-content:
# Изолируем окружение на сетевом уровне
networks:
default:
external:
name: testrail-network-${CI_JOB_ID:-local}
services:
db:
image: mysql:5.7.22
# Каждый container_name содержит ${CI_JOB_ID:-local}
container_name: "testrail-mysql-${CI_JOB_ID:-local}"
environment:
MYSQL_HOST: db
MYSQL_DATABASE: mydb
MYSQL_ROOT_PASSWORD: 1234
SKIP_GRANT_TABLES: 1
SKIP_NETWORKING: 1
SERVICE_TAGS: dev
SERVICE_NAME: mysql
networks:
- default
migration:
image: registry.gitlab.com/touchbit/image/testrail/migration:latest
container_name: "testrail-migration-${CI_JOB_ID:-local}"
links:
- db
depends_on:
- db
networks:
- default
fpm:
image: registry.gitlab.com/touchbit/image/testrail/fpm:latest
container_name: "testrail-fpm-${CI_JOB_ID:-local}"
volumes:
- static-content:/var/www/testrail
links:
- db
networks:
- default
web:
image: registry.gitlab.com/touchbit/image/testrail/web:latest
container_name: "testrail-web-${CI_JOB_ID:-local}"
# Если переменные TR_HTTP_PORT или TR_HTTPS_PORTS не определены,
# то сервис поднимается на 80 и 443 порту соответственно.
ports:
- ${TR_HTTP_PORT:-80}:80
- ${TR_HTTPS_PORT:-443}:443
volumes:
- static-content:/var/www/testrail
links:
- db
- fpm
networks:
- default
Integration:
stage: test
tags:
- my-shell-runner
before_script:
# Аутентифицируемся в registry
- docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
# Генерируем псевдоуникальные TR_HTTP_PORT и TR_HTTPS_PORT
- export TR_HTTP_PORT=$(shuf -i10000-60000 -n1)
- export TR_HTTPS_PORT=$(shuf -i10000-60000 -n1)
# создаем директорию с идентификатором задачи
- mkdir ${CI_JOB_ID}
# копируем в созданную директорию наш docker-compose.yml
# чтобы контекст был разный для каждой задачи
- cp .indirect/docker-compose.yml ${CI_JOB_ID}/docker-compose.yml
script:
# поднимаем наше окружение
- make docker-up
# запускаем тесты исполняемым jar (у меня так)
- java -jar itest.jar --http-port ${TR_HTTP_PORT} --https-port ${TR_HTTPS_PORT}
# или в контейнере
- docker run --network=testrail-network-${CI_JOB_ID:-local} --rm itest
after_script:
# собираем логи
- make docker-logs
# останавливаем окружение
- make docker-kill
artifacts:
# сохраняем логи
when: always
paths:
- logs
expire_in: 30 days
Նման առաջադրանքն իրականացնելու արդյունքում արտեֆակտների տեղեկամատյանների գրացուցակը կպարունակի սպասարկման և փորձարկման տեղեկամատյաններ: Ինչը շատ հարմար է սխալների դեպքում։ Զուգահեռաբար յուրաքանչյուր թեստ գրում է իր սեփական մատյանը, բայց ես այս մասին կխոսեմ առանձին:
$ docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/gitlab-runner/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ export TR_HTTP_PORT=$(shuf -i10000-60000 -n1)
$ export TR_HTTPS_PORT=$(shuf -i10000-60000 -n1)
$ mkdir ${CI_JOB_ID}
$ cp .indirect/docker-compose.yml ${CI_JOB_ID}/docker-compose.yml
$ make docker-up
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml kill
docker network rm testrail-network-${CI_JOB_ID:-local} || true
Error: No such network: testrail-network-204645172
docker network create testrail-network-${CI_JOB_ID:-local}
0a59552b4464b8ab484de6ae5054f3d5752902910bacb0a7b5eca698766d0331
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml pull
Pulling web ... done
Pulling fpm ... done
Pulling migration ... done
Pulling db ... done
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Creating volume "204645172_static-content" with default driver
Creating testrail-mysql-204645172 ...
Creating testrail-mysql-204645172 ... done
Creating testrail-migration-204645172 ... done
Creating testrail-fpm-204645172 ... done
Creating testrail-web-204645172 ... done
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c6b76f9135ed registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 13 seconds ago Up 1 second 0.0.0.0:51148->80/tcp, 0.0.0.0:25426->443/tcp testrail-web-204645172
01d303262d8e registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 16 seconds ago Up 13 seconds 9000/tcp testrail-fpm-204645172
2cdab1edbf6a registry.gitlab.com/touchbit/image/testrail/migration:latest "docker-entrypoint.s…" 16 seconds ago Up 13 seconds 3306/tcp, 33060/tcp testrail-migration-204645172
826aaf7c0a29 mysql:5.7.22 "docker-entrypoint.s…" 18 seconds ago Up 16 seconds 3306/tcp testrail-mysql-204645172
6dbb3fae0322 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 36 seconds ago Up 22 seconds 0.0.0.0:44202->80/tcp, 0.0.0.0:20151->443/tcp testrail-web-204645084
3540f8d448ce registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 38 seconds ago Up 35 seconds 9000/tcp testrail-fpm-204645084
70fea72aa10d mysql:5.7.22 "docker-entrypoint.s…" 40 seconds ago Up 37 seconds 3306/tcp testrail-mysql-204645084
d8aa24b2892d registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" About a minute ago Up 53 seconds 0.0.0.0:31103->80/tcp, 0.0.0.0:43872->443/tcp testrail-web-204644881
6d4ccd910fad registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" About a minute ago Up About a minute 9000/tcp testrail-fpm-204644881
685d8023a3ec mysql:5.7.22 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp testrail-mysql-204644881
1cdfc692003a registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:44752->80/tcp, 0.0.0.0:23540->443/tcp testrail-web-204644793
6f26dfb2683e registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" About a minute ago Up About a minute 9000/tcp testrail-fpm-204644793
029e16b26201 mysql:5.7.22 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp testrail-mysql-204644793
c10443222ac6 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 5 hours ago Up 5 hours 0.0.0.0:57123->80/tcp, 0.0.0.0:31657->443/tcp testrail-web-204567103
04339229397e registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 5 hours ago Up 5 hours 9000/tcp testrail-fpm-204567103
6ae0accab28d mysql:5.7.22 "docker-entrypoint.s…" 5 hours ago Up 5 hours 3306/tcp testrail-mysql-204567103
b66b60d79e43 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 5 hours ago Up 5 hours 0.0.0.0:56321->80/tcp, 0.0.0.0:58749->443/tcp testrail-web-204553690
033b1f46afa9 registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 5 hours ago Up 5 hours 9000/tcp testrail-fpm-204553690
a8879c5ef941 mysql:5.7.22 "docker-entrypoint.s…" 5 hours ago Up 5 hours 3306/tcp testrail-mysql-204553690
069954ba6010 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 5 hours ago Up 5 hours 0.0.0.0:32869->80/tcp, 0.0.0.0:16066->443/tcp testrail-web-204553539
ed6b17d911a5 registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 5 hours ago Up 5 hours 9000/tcp testrail-fpm-204553539
1a1eed057ea0 mysql:5.7.22 "docker-entrypoint.s…" 5 hours ago Up 5 hours 3306/tcp testrail-mysql-204553539
Բոլոր առաջադրանքները հաջողությամբ ավարտվեցին
Առաջադրանքների արտեֆակտները պարունակում են ծառայության և փորձարկման տեղեկամատյաններ
Ամեն ինչ կարծես գեղեցիկ է, բայց կա մի նրբերանգ. Խողովակաշարը կարող է ուժով չեղարկվել ինտեգրման թեստերի ընթացքում, որի դեպքում բեռնարկղերը չեն դադարեցվի: Ժամանակ առ ժամանակ անհրաժեշտ է մաքրել վազորդը: Ցավոք, GitLab CE-ի բարելավման խնդիրը դեռևս գտնվում է կարգավիճակում բաց
Բայց մենք ավելացրել ենք առաջադրանքի մեկնարկը ըստ ժամանակացույցի, և ոչ ոք մեզ չի արգելում այն կատարել ձեռքով:
Գնացեք մեր նախագիծ -> CI/CD -> ժամանակացույցեր և գործարկեք առաջադրանքը Clean runner
Ընդամենը:
Մենք ունենք մեկ պատյանով վազող:
Առաջադրանքների և շրջակա միջավայրի միջև հակասություններ չկան:
Մենք զուգահեռաբար կատարում ենք առաջադրանքներ ինտեգրման թեստերով:
Դուք կարող եք կատարել ինտեգրման թեստեր կամ տեղական կամ կոնտեյներով:
Սպասարկման և փորձարկման մատյանները հավաքվում և կցվում են խողովակաշարի առաջադրանքին:
Հնարավոր է մաքրել վազորդը հին Docker պատկերներից:
Կարգավորման ժամանակը ~ 2 ժամ է:
Այսքանը, իրականում: Ես ուրախ կլինեմ ստանալ արձագանքներ: