ProHoster > Blog > administratë > GitLab Shell Runner. Nisja konkurruese e shërbimeve të testuara duke përdorur Docker Compose
GitLab Shell Runner. Nisja konkurruese e shërbimeve të testuara duke përdorur Docker Compose
Ky artikull do të jetë me interes si për testuesit ashtu edhe për zhvilluesit, por është menduar kryesisht për specialistët e automatizimit të cilët përballen me problemin e konfigurimit të GitLab CI/CD për testimin e integrimit në kushtet e burimeve të pamjaftueshme të infrastrukturës dhe/ose mungesës së një kontejneri platformë orkestrimi. Unë do t'ju tregoj se si të vendosni vendosjen e mjediseve të testimit duke përdorur docker compose në një ekzekutues të vetëm të guaskës GitLab dhe në mënyrë që kur vendosni disa mjedise, shërbimet e nisura të mos ndërhyjnë me njëra-tjetrën.
Në praktikën time, ka ndodhur shpesh që testimi i integrimit të "trajtohej" në projekte. Dhe shpesh problemi i parë dhe më domethënës është tubacioni CI, në të cilin testohet integrimi duke u zhvilluar shërbimi(et) kryhet në një mjedis dev/fazë. Kjo shkaktoi mjaft probleme:
Për shkak të defekteve në një shërbim të caktuar gjatë procesit të testimit të integrimit, qarku i provës mund të dëmtohet nga të dhënat e prishura. Kishte raste kur dërgimi i një kërkese me format JSON të prishur e prishi shërbimin, gjë që e bëri stendën plotësisht të pafuqishëm.
Ngadalësimi i qarkut të provës ndërsa të dhënat e provës rriten. Mendoj se nuk ka kuptim të përshkruaj një shembull me pastrimin/rikthimin e bazës së të dhënave. Në praktikën time nuk kam hasur në një projekt ku kjo procedurë ka shkuar pa probleme.
Ekziston rreziku i ndërprerjes së funksionalitetit të qarkut të provës kur testoni cilësimet e përgjithshme të sistemit. Për shembull, politika e përdoruesit/grupit/fjalëkalimit/aplikacionit.
Të dhënat e testimit nga testet e automatizuara e bëjnë jetën të vështirë për testuesit manualë.
Disa do të thonë se autotestet e mira duhet të pastrojnë të dhënat pas vetes. Unë kam argumente kundër:
Stendat dinamike janë shumë të përshtatshme për t'u përdorur.
Jo çdo objekt mund të hiqet nga sistemi nëpërmjet API-së. Për shembull, një thirrje për të fshirë një objekt nuk u zbatua sepse bie ndesh me logjikën e biznesit.
Kur krijoni një objekt nëpërmjet API-së, mund të krijohet një sasi e madhe meta të dhënash, e cila është problematike për t'u fshirë.
Nëse testet kanë varësi mes tyre, atëherë procesi i pastrimit të të dhënave pas kryerjes së testeve kthehet në një dhimbje koke.
Thirrje shtesë (dhe, sipas mendimit tim, jo të justifikuara) në API.
Dhe argumenti kryesor: kur të dhënat e testit fillojnë të pastrohen drejtpërdrejt nga baza e të dhënave. Ky po kthehet në një cirk të vërtetë PK/FK! Ne dëgjojmë nga zhvilluesit: "Sapo shtova/ hoqa/riemërova një shenjë, pse u kapën 100500 teste integrimi?"
Sipas mendimit tim, zgjidhja më optimale është një mjedis dinamik.
Shumë njerëz përdorin docker-compose për të ekzekutuar një mjedis testimi, por pak njerëz përdorin docker-compose kur kryejnë testimin e integrimit në CI/CD. Dhe këtu nuk po marr parasysh kubernetet, tufën dhe platformat e tjera të orkestrimit të kontejnerëve. Jo çdo kompani i ka ato. Do të ishte mirë nëse docker-compose.yml do të ishte universale.
Edhe nëse kemi programin tonë të QA-së, si mund të sigurohemi që shërbimet e lançuara nëpërmjet docker-compose të mos ndërhyjnë me njëra-tjetrën?
Si të mblidhni regjistrat e shërbimeve të testuara?
Si të pastroni vrapuesin?
Unë kam drejtuesin tim GitLab për projektet e mia dhe i kam hasur këto pyetje gjatë zhvillimit Klient Java për TestRail. Më saktësisht, gjatë ekzekutimit të testeve të integrimit. Më poshtë do t'i zgjidhim këto çështje duke përdorur shembuj nga ky projekt.
Për një vrapues, unë rekomandoj një makinë virtuale Linux me 4 vCPU, 4 GB RAM, 50 GB HDD.
Ka shumë informacione për vendosjen e gitlab-runner në internet, kështu që shkurtimisht:
Hyni në makinë përmes SSH
Nëse keni më pak se 8 GB RAM, atëherë ju rekomandoj bëj këmbim 10 GBnë mënyrë që vrasësi OOM të mos vijë dhe të na vrasë detyrat për shkak të mungesës së RAM-it. Kjo mund të ndodhë kur më shumë se 5 detyra nisen njëkohësisht. Detyrat do të ecin më ngadalë, por në mënyrë të qëndrueshme.
Shembull me vrasësin OOM
Nëse shihni në regjistrat e detyrave bash: line 82: 26474 Killed, pastaj thjesht ekzekutoni në vrapues 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
Dhe nëse fotografia duket diçka si kjo, atëherë ose shtoni swap ose shtoni RAM.
Kjo do t'ju lejojë të ekzekutoni detyra paralele në një vrapues. Lexo më shumë këtu.
Nëse keni një makinë më të fuqishme, për shembull 8 vCPU, 16 GB RAM, atëherë këta numra mund të bëhen të paktën 2 herë më të mëdhenj. Por gjithçka varet nga ajo që saktësisht do të lëshohet në këtë vrapues dhe në çfarë sasie.
Detyra kryesore është një docker-compose.yml universal, të cilin zhvilluesit/testuesit mund ta përdorin si në nivel lokal ashtu edhe në tubacionin CI.
Para së gjithash, ne bëjmë emra unik shërbimesh për CI. Një nga variablat unike në GitLab CI është ndryshorja CI_JOB_ID. Nëse specifikoni container_name me kuptim "service-${CI_JOB_ID:-local}", atëherë në rastin:
nëse CI_JOB_ID nuk përcaktohet në variablat e mjedisit,
atëherë emri i shërbimit do të jetë service-local
nëse CI_JOB_ID të përcaktuara në variablat e mjedisit (për shembull 123),
atëherë emri i shërbimit do të jetë service-123
Së dyti, ne krijojmë një rrjet të përbashkët për shërbimet e nisura. Kjo na jep izolim në nivel rrjeti kur ekzekutojmë mjedise të shumta testimi.
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
Si rezultat i ekzekutimit të një detyre të tillë, drejtoria e regjistrave në artefakte do të përmbajë regjistrat e shërbimit dhe testimit. E cila është shumë e përshtatshme në rast gabimesh. Çdo test paralelisht shkruan regjistrin e vet, por unë do të flas për këtë veçmas.
$ 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
Të gjitha detyrat u kryen me sukses
Artifaktet e detyrave përmbajnë regjistrat e shërbimit dhe testimit
Gjithçka duket e bukur, por ka një nuancë. Tubacioni mund të anulohet me forcë ndërsa testet e integrimit janë duke u kryer, në të cilin rast kontejnerët që funksionojnë nuk do të ndalen. Herë pas here ju duhet të pastroni vrapuesin. Fatkeqësisht, detyra për përmirësim në GitLab CE është ende në status hapur
Por ne kemi shtuar nisjen e një detyre sipas një plani dhe askush nuk na ndalon ta ekzekutojmë manualisht.
Shkoni te projekti ynë -> CI/CD -> Oraret dhe ekzekutoni detyrën Clean runner
Total:
Ne kemi një vrapues guaskë.
Nuk ka konflikte midis detyrave dhe mjedisit.
Ne kryejmë paralelisht detyrat me teste integruese.
Ju mund të kryeni testet e integrimit ose në nivel lokal ose në një kontejner.
Regjistrat e shërbimit dhe testimit mblidhen dhe i bashkëngjiten detyrës së tubacionit.
Është e mundur të pastrohet vrapuesi nga imazhet e vjetra të Docker.
Koha e konfigurimit është ~ 2 orë.
Kjo është e gjitha, në fakt. Do të jem i lumtur të marr komente.