See artikkel on huvitav nii testijatele kui arendajatele, kuid on suunatud peamiselt automatiseerijatele, kes on silmitsi seisnud probleemiga GitLab CI/CD seadistamisel integratsioonitestide läbiviimiseks infrastruktuuri ressursside puuduse ja/või konteinerite orkestreerimise platvormi puudumise tingimustes. Räägin, kuidas seadistada testimise keskkondade juurutamist docker compose abil ühel ainsal GitLab shell runner'il nii, et mitme keskkonna juurutamisel ei segaks käivitatud teenused üksteist.
Sisu
Eeldused
Minu praktikas on tihti juhtunud, et olen "ravinud" integratsioonitestimist projektides. Ja tihti on esimene ja kõige olulisem probleem CI pipeline, kus integratsioonitestimine arendatava teenuse(de) osas toimub dev/stage keskkonnas. See on tekitanud palju probleeme:
- Teenuses esinevate defektide tõttu võib integratsioonitestimise protsessi käigus testimistava rikkuda vigaste andmete tõttu. On juhtunud, et vigase JSON-formaadiga päringu saatmine murdis teenuse, muutes kogu stendi töövõimetuks.
- Testimise töötamise aeg aeglustub testandmete suurenemisega. Arvan, et andmebaasi puhastamise/tagastamise näite kirjeldusega pole mõtet vaeva näha. Oma praktikas pole ma kohanud projekti, kus see protseduur sujuvalt kestaks.
- Oht testimisjoone töövõime rikkumiseks süsteemi ühiste seadete testimise käigus. Näiteks kasutaja/rühm/parool/rakenduse poliitika.
- Testandmed automaatsete testide tõttu segavad käsitsi testijate tööd.
Keegi võib öelda, et head automaatsed testid peaksid oma andmed pärast koristama. Mul on selle vastu argumente:
- Dünaamilised stendid on väga mugavad kasutada.
- Mitte iga objekti ei saa süsteemis API kaudu kustutada. Näiteks ei ole objekti kustutamise kutse ellu viidud, kuna see on vastuolus äriloogikaga.
- API kaudu objekti loomisel võib genereerida tohutu hulga metandmeid, mille kustutamine on probleemne.
- Kui testidel on omavahelised sõltuvused, siis testide täitmise järel andmete puhastamine muutub peavaluks.
- Lisanduvad (ja minu arvates põhjendamatud) kutseid API-le.
- Ja peamine argument: kui testandmeid hakkatakse otse andmebaasist puhastama. See muutub tõeliseks PK/FK tsirkuseks! Arendajatelt kuuleb: "Ma ainult lisasin/kustutasin/ümbernimetas, miks 100500 integratsioonitesti kukkus?"
Minu arvates on kõige optimaalne lahendus dünaamiline keskkond.
- Paljud kasutavad docker-compose'i testkeskkonna käivitamiseks, kuid vähe keegi kasutab docker-compose'i integratsioonitestide läbiviimiseks CI/CD-s. Ja siinkohal ei arvestanud ma kubernetes, swarm ja muid konteinerite orkestreerimise platvorme. Mitte igas ettevõttes pole neid. Hea oleks, kui docker-compose.yml oleks universaalne.
- Isegi kui meil on oma QA runner, kuidas saame tagada, et docker-compose'i kaudu käivitatavad teenused ei segaks üksteist?
- Kuidas koguda testitavate teenuste logisid?
- Kuidas puhastada runnerit?
Mul on oma GitLab runner oma projektide jaoks ja nende küsimustega olen kokku puutunud arendamisel kuna . Täpsemalt integratsioonitestide käivitamisel. Edasi lahendame neid küsimusi selle projekti näidete kaudu.
GitLab Shell Runner
R soovitan Linuxi virtuaalmasinat 4 vCPU, 4 GB RAM, 50 GB HDD.
Internetis on palju teavet gitlab-runner'i seadistamise kohta, seetõttu lühidalt:
- Siseneme masinasse SSH kaudu
Kui teil on vähem kui 8 GB RAM, siis soovitan , et OOM killer ei tuleks ja ei tapaks ülesandeid RAM-i puudumise tõttu. See võib juhtuda, kui samal ajal käivitatakse rohkem kui 5 ülesannet. Ülesanded kulgevad aeglasemalt, kuid stabiilselt.
Näide OOM killerist
Kui näete ülesande logides
bash: line 82: 26474 Killed, siis lihtsalt täitke runnerilsudo 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:0kBJa kui pilt näeb välja umbes selline, siis kas lisage swap või lisage RAM-i.
- Paigaldame , , , make.
- Lisame kasutaja
gitlab-runnergruppidockersudo groupadd docker sudo usermod -aG docker gitlab-runner - gitlab-runner.
Avame redigeerimiseks
/etc/gitlab-runner/config.tomlja lisameconcurrent=20 [[runners]] request_concurrency = 10See võimaldab käivitada mitmeid ülesandeid ühe runneri peal. Lisainfot leiate .
Kui teie masin on võimsam, näiteks 8 vCPU, 16 GB RAM, siis neid numbreid võib teha vähemalt 2 korda rohkem. Kuid kõik sõltub sellest, mida konkrentselt sellel runneril käivitada ja millises koguses.
Seda on piisav.
docker-compose.yml ettevalmistamine
Peamine ülesanne on universaalne docker-compose.yml, mida arendajad/testijad saavad kasutada nii kohapeal kui ka CI pipeline'is.
Esiteks loome CI jaoks unikaalsed teenuste nimed. Üks unikaalne muutuja GitLab CI-s on muutuja CI_JOB_ID. Kui määrata container_name väärtusega "service-${CI_JOB_ID:-local}", siis juhul:
- kui
CI_JOB_IDei ole keskkonnamuutujate seas määratud,
on teenuse nimiservice-local - kui
CI_JOB_IDon määratud keskkonnamuutujates (nt 123),
on teenuse nimiservice-123
Teiseks loome teenuste käitamiseks ühise võrgu. See tagab meile isolatsiooni võrgu tasandil, kui käivitame mitu testkeskkonda.
networks:
default:
external:
name: service-network-${CI_JOB_ID:-local}See on tegelikult esimene samm edu saavutamiseks =)
Minu docker-compose.yml näide kommentaaridega
version: "3"
# Et web (php) ja fmt töötaksid õigesti,
# peavad konteinerid omama ühist teostusmaterjali.
# Meie puhul on see kaust /var/www/testrail
volumes:
static-content:
# Isolate the environment at the network level
networks:
default:
external:
name: testrail-network-${CI_JOB_ID:-local}
services:
db:
image: mysql:5.7.22
# Iga container_name sisaldab ${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}"
# Kui muutujad TR_HTTP_PORT või TR_HTTPS_PORT ei ole määratud,
# siis teenus käivitub vastavalt 80 ja 443 pordil.
ports:
- ${TR_HTTP_PORT:-80}:80
- ${TR_HTTPS_PORT:-443}:443
volumes:
- static-content:/var/www/testrail
links:
- db
- fpm
networks:
- defaultKohaliku käivituse näide
docker-compose -f docker-compose.yml up -d
Starting testrail-mysql-local ... done
Starting testrail-migration-local ... done
Starting testrail-fpm-local ... done
Recreating testrail-web-local ... doneAga CI-s ei ole kõik nii lihtne.
Makefile'i ettevalmistamine
Kasutame Makefile'i, kuna see on mugav nii kohapealse keskkonna haldamiseks kui ka CI-s. Edasi on inline kommentaarid
# У меня в проектах все вспомогательные вещи лежат в директории `.indirect`,
# в том числе и `docker-compose.yml`
# Использовать bash с опцией pipefail
# pipefail - фейлит выполнение пайпа, если команда выполнилась с ошибкой
SHELL=/bin/bash -o pipefail
# Останавливаем контейнеры и удаляем сеть
docker-kill:
docker-compose -f $${CI_JOB_ID:-.indirect}/docker-compose.yml kill
docker network rm network-$${CI_JOB_ID:-testrail} || true
# Предварительно выполняем docker-kill
docker-up: docker-kill
# Создаем сеть для окружения
docker network create network-$${CI_JOB_ID:-testrail}
# Забираем последние образы из docker-registry
docker-compose -f $${CI_JOB_ID:-.indirect}/docker-compose.yml pull
# Запускаем окружение
# force-recreate - принудительное пересоздание контейнеров
# renew-anon-volumes - не использовать volumes предыдущих контейнеров
docker-compose -f $${CI_JOB_ID:-.indirect}/docker-compose.yml up --force-recreate --renew-anon-volumes -d
# Ну и, на всякий случай, вывести что там у нас в принципе запущено на машинке
docker ps
# Коллектим логи сервисов
docker-logs:
mkdir ./logs || true
docker logs testrail-web-$${CI_JOB_ID:-local} >& logs/testrail-web.log
docker logs testrail-fpm-$${CI_JOB_ID:-local} >& logs/testrail-fpm.log
docker logs testrail-migration-$${CI_JOB_ID:-local} >& logs/testrail-migration.log
docker logs testrail-mysql-$${CI_JOB_ID:-local} >& logs/testrail-mysql.log
# Очистка раннера
docker-clean:
@echo Останавливаем все testrail-контейнеры
docker kill $$(docker ps --filter=name=testrail -q) || true
@echo Очистка докер контейнеров
docker rm -f $$(docker ps -a -f --filter=name=testrail status=exited -q) || true
@echo Очистка dangling образов
docker rmi -f $$(docker images -f "dangling=true" -q) || true
@echo Очистка testrail образов
docker rmi -f $$(docker images --filter=reference='registry.gitlab.com/touchbit/image/testrail/*' -q) || true
@echo Очистка всех неиспользуемых volume
docker volume rm -f $$(docker volume ls -q) || true
@echo Очистка всех testrail сетей
docker network rm $(docker network ls --filter=name=testrail -q) || true
docker ps
Kontrollime
make docker-up
$ make docker-up
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml kill
Killing testrail-web-local ... done
Killing testrail-fpm-local ... done
Killing testrail-mysql-local ... done
docker network rm network-${CI_JOB_ID:-testrail} || true
network-testrail
docker network create network-${CI_JOB_ID:-testrail}
d2ec063324081c8bbc1b08fd92242c2ea59d70cf4025fab8efcbc5c6360f083f
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml pull
Pulling db ... done
Pulling migration ... done
Pulling fpm ... done
Pulling web ... done
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Recreating testrail-mysql-local ... done
Recreating testrail-fpm-local ... done
Recreating testrail-migration-local ... done
Recreating testrail-web-local ... done
docker ps
CONTAINER ID PORTS NAMES
a845d3cb0e5a 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp testrail-web-local
19d8ef001398 9000/tcp testrail-fpm-local
e28840a2369c 3306/tcp, 33060/tcp testrail-migration-local
0e7900c23f37 3306/tcp testrail-mysql-local
make docker-logs
$ make docker-logs
mkdir ./logs || true
mkdir: cannot create directory ‘./logs’: File exists
docker logs testrail-web-${CI_JOB_ID:-local} >& logs/testrail-web.log
docker logs testrail-fpm-${CI_JOB_ID:-local} >& logs/testrail-fpm.log
docker logs testrail-migration-${CI_JOB_ID:-local} >& logs/testrail-migration.log
docker logs testrail-mysql-${CI_JOB_ID:-local} >& logs/testrail-mysql.log
.gitlab-ci.yml ettevalmistamine
Integratsioonitestide käivitamine
Integratsioon:
etapp: test
sildid:
- my-shell-runner
enne_script:
# Autentifitseerime registreerimisel
- docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
# Geneerime pseudounikaalsed TR_HTTP_PORT ja TR_HTTPS_PORT
- export TR_HTTP_PORT=$(shuf -i10000-60000 -n1)
- export TR_HTTPS_PORT=$(shuf -i10000-60000 -n1)
# loome kausta töö identifikaatoriga
- mkdir ${CI_JOB_ID}
# kopeerime loodud kausta meie docker-compose.yml
# et kontekstid oleksid erinevad iga ülesande jaoks
- cp .indirect/docker-compose.yml ${CI_JOB_ID}/docker-compose.yml
skript:
# tõstame meie keskkonna
- make docker-up
# käivitame testid käideldava jar-iga (minu puhul niimoodi)
- java -jar itest.jar --http-port ${TR_HTTP_PORT} --https-port ${TR_HTTPS_PORT}
# või konteineris
- docker run --network=testrail-network-${CI_JOB_ID:-local} --rm itest
pärast_script:
# kogume logid
- make docker-logs
# peatame keskkonna
- make docker-kill
artefaktid:
# salvestame logid
kui: alati
teed:
- logs
aegumisaeg: 30 päevaSelle ülesande käivitamise tulemusena sisaldab logs kaust artefaktid teenuste ja testide logide kohta. Mis on väga mugav, kui tekivad vead. Iga test kirjutab oma logi paralleelselt, kuid selle kohta räägin hiljem.

Runneri puhastamine
Ülesanne käivitatakse ainult ajakava alusel.
etapid:
- puhas
- ehitus
- test
Puhastamise jooksja:
etapp: puhas
ainult:
- ajakavad
sildid:
- my-shell-runner
skript:
- make docker-cleanSeejärel liigume oma GitLab projekti -> CI/CD -> Ajakavad -> Uus ajakava ja lisame uue ajakava
Tulemus
Käivitame 4 ülesannet GitLab CI-s
Viimase integratsioonitestide ülesande logides näeme erinevate ülesannete konteinerite nimesid
KONTROLLI ID NIMED
c6b76f9135ed testrail-web-204645172
01d303262d8e testrail-fpm-204645172
2cdab1edbf6a testrail-migration-204645172
826aaf7c0a29 testrail-mysql-204645172
6dbb3fae0322 testrail-web-204645084
3540f8d448ce testrail-fpm-204645084
70fea72aa10d testrail-mysql-204645084
d8aa24b2892d testrail-web-204644881
6d4ccd910fad testrail-fpm-204644881
685d8023a3ec testrail-mysql-204644881
1cdfc692003a testrail-web-204644793
6f26dfb2683e testrail-fpm-204644793
029e16b26201 testrail-mysql-204644793
c10443222ac6 testrail-web-204567103
04339229397e testrail-fpm-204567103
6ae0accab28d testrail-mysql-204567103
b66b60d79e43 testrail-web-204553690
033b1f46afa9 testrail-fpm-204553690
a8879c5ef941 testrail-mysql-204553690
069954ba6010 testrail-web-204553539
ed6b17d911a5 testrail-fpm-204553539
1a1eed057ea0 testrail-mysql-204553539Üksikasjalikum logi
$ docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
HOIATUS! --password kasutamine CLI-s on ebaturvaline. Kasutage --password-stdin.
HOIATUS! Teie parool salvestatakse krüptimata failis /home/gitlab-runner/.docker/config.json.
Konfigureerige volituste abiline, et sellest hoiatust eemaldada. Vaata
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Sisselogimine õnnestus
$ 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
Viga: Sellist võrgusilma ei ole: testrail-network-204645172
docker network create testrail-network-${CI_JOB_ID:-local}
0a59552b4464b8ab484de6ae5054f3d5752902910bacb0a7b5eca698766d0331
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml pull
Laadimine web ... valmis
Laadimine fpm ... valmis
Laadimine migration ... valmis
Laadimine db ... valmis
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Loodud maht "204645172_static-content" vaikejuhendajaga
Loodud testrail-mysql-204645172 ...
Loodud testrail-mysql-204645172 ... valmis
Loodud testrail-migration-204645172 ... valmis
Loodud testrail-fpm-204645172 ... valmis
Loodud testrail-web-204645172 ... valmis
docker ps
KONTROLLI ID PILT KÄSK LOODUD OLEK PORTID NIMED
c6b76f9135ed registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 13 sekundit tagasi Üles 1 sekund 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 sekundit tagasi Üles 13 sekundit 9000/tcp testrail-fpm-204645172
2cdab1edbf6a registry.gitlab.com/touchbit/image/testrail/migration:latest "docker-entrypoint.s…" 16 sekundit tagasi Üles 13 sekundit 3306/tcp, 33060/tcp testrail-migration-204645172
826aaf7c0a29 mysql:5.7.22 "docker-entrypoint.s…" 18 sekundit tagasi Üles 16 sekundit 3306/tcp testrail-mysql-204645172
6dbb3fae0322 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 36 sekundit tagasi Üles 22 sekundit 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 sekundit tagasi Üles 35 sekundit 9000/tcp testrail-fpm-204645084
70fea72aa10d mysql:5.7.22 "docker-entrypoint.s…" 40 sekundit tagasi Üles 37 sekundit 3306/tcp testrail-mysql-204645084
d8aa24b2892d registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" Umbes minut tagasi Üles 53 sekundit 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…" Umbes minut tagasi Üles Umbes minut 9000/tcp testrail-fpm-204644881
685d8023a3ec mysql:5.7.22 "docker-entrypoint.s…" Umbes minut tagasi Üles Umbes minut 3306/tcp testrail-mysql-204644881
1cdfc692003a registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" Umbes minut tagasi Üles Umbes minut 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…" Umbes minut tagasi Üles Umbes minut 9000/tcp testrail-fpm-204644793
029e16b26201 mysql:5.7.22 "docker-entrypoint.s…" Umbes minut tagasi Üles Umbes minut 3306/tcp testrail-mysql-204644793
c10443222ac6 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 5 tundi tagasi Üles 5 tundi 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 tundi tagasi Üles 5 tundi 9000/tcp testrail-fpm-204567103
6ae0accab28d mysql:5.7.22 "docker-entrypoint.s…" 5 tundi tagasi Üles 5 tundi 3306/tcp testrail-mysql-204567103
b66b60d79e43 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 5 tundi tagasi Üles 5 tundi 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 tundi tagasi Üles 5 tundi 9000/tcp testrail-fpm-204553690
a8879c5ef941 mysql:5.7.22 "docker-entrypoint.s…" 5 tundi tagasi Üles 5 tundi 3306/tcp testrail-mysql-204553690
069954ba6010 registry.gitlab.com/touchbit/image/testrail/web:latest "nginx -g 'daemon of…" 5 tundi tagasi Üles 5 tundi 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 tundi tagasi Üles 5 tundi 9000/tcp testrail-fpm-204553539
1a1eed057ea0 mysql:5.7.22 "docker-entrypoint.s…" 5 tundi tagasi Üles 5 tundi 3306/tcp testrail-mysql-204553539Kõik ülesanded on edukalt lõpetatud
Ülesande artefaktides on teenuste ja testide logid
Tundub, et kõik on hästi, kuid on üks nüanss. Pipeline võib integratsioonitestide käigus olla sunnitud tühistama, ja sel juhul ei peatata käivitatud konteinerite tööd. Aeg-ajalt tuleb runner puhastada. Kahjuks on ülesanne GitLab CE arendamiseks endiselt staatuses
Aga meil on lisatud ülesande käivitamine ajakava alusel, ja keegi ei keela meil seda käsitsi käivitada.
Liigume oma projekti -> CI/CD -> Ajakavad ja käivitame ülesande Puhasta runner
Kokku:
- Meil on üks shell runner.
- Ülesannete ja keskkonna vahel ei ole konflikte.
- Meil on paralleelne ülesannete täitmine integratsioonitestidega.
- Integratsioonitestide käivitamine on võimalik nii kohalikult kui ka konteineris.
- Teenuste ja testide logid kogutakse ning lisatakse pipeline-ülesandele.
- On võimalus puhastada runner vanadest docker-piltidest.
Seadistusaeg — umbes 2 tundi.
Nii, et see ongi kõik. Ootan tagasisidet.
Allikas: habr.com
