See artikkel on huvitav nii testijatele kui ka arendajatele, kuid on peamiselt suunatud automatiseerijatele, kes on kokku puutunud GitLab CI/CD seadistamise probleemiga integreerimistestide läbiviimiseks piiratud infrastruktuuriliste ressursside ja/või konteinerite orkestreerimislava puudumise tingimustes. Selgitan, kuidas seadistada testitud keskkondade käivitamist docker compose abil üheainsa GitLabi shell runner'i peal nii, et mitme keskkonna käivitamisel teenused üksteist ei segaks.
Sisukord
Eeldused
Minu praktikas on sageli juhtunud, et olen "ravinud" integreerimistestimist projektides. Ja tihti on esimene ja kõige olulisem probleem CI pipeliner, kus integreerimistestimine arendatav teenus(e) viiakse läbi dev/stage keskkonnas. See on tekitanud mitmeid probleeme:
- Teenuse defektide tõttu võib integreerimistestimise käigus testkontuur puruneda katki andmete tõttu. On olnud juhtumeid, kus katki JSON-formaadiga päringu saatmine nuhtles teenust, mis viis seisu täielikku töövõimetusse.
- Testkontuuri töö aeglustumine testandmete kasvu korral. Arvan, et ei ole mõtet kirjeldada andmebaasi puhastamise/tagasitõmbamise näidet. Oma praktikas ei ole ma kohanud projekti, kus see protseduur oleks sujunud tõrgeteta.
- Risk, et testkontuuri töövõime häiritakse süsteemi ühiste seadete testimise käigus. Näiteks kasutaja/rühm/parool/rakenduse poliitika.
- Autotestide testandmed segavad käsitsi testijate tööd.
Mõni ütleb, et head autotestid peaksid pärast endid andmed puhastama. Mul on sellele argumente vastu:
- Dünaamilised standid on kasutamiseks väga mugavad.
- Mitte kõiki objekte ei saa süsteemist API kaudu kustutada. Näiteks objekti kustutamise kutsumine ei ole teostatav, kuna see on vastuolus äri loogikaga.
- Objekti loomisel API kaudu võib tekkida tohutul hulgal metaandmeid, mida on keeruline kustutada.
- Kui testidel on omavahelised sõltuvused, muutub testide täitmise järel andmete puhastamise protsess peavaluks.
- Lisaks on (minu arvates põhjendamatud) kutset API-le.
- Ja peamine argument: kui testandmed hakkavad otse andmebaasist puhastuma. See muutub tõeliseks PK/FK tsirkuseks! Arendajate käest kuuleb: „Ma lisasin/eemaldasin/ümbernimee ainult tabeli, miks 100500 integreerimise testimist läks?"
Minu arvates on kõige optimaalsem lahendus dünaamiline keskkond.
- Paljud kasutavad docker-compose'i testkeskkonnaga käivitamiseks, kuid vähe kasutasid docker-compose'i integreerimistestimise käigus CI/CD-s. Ja ma ei arvestagi kubernetese, swarm'i ja teiste konteinerite orkestreerimise platvormidega. Need ei pruugi igas ettevõttes olla. Hea oleks, kui docker-compose.yml oleks universaalne.
- Kui meil on oma QA runner, kuidas tagada, et docker-compose kaudu käivitatavad teenused ei segaks üksteist?
- Kuidas koguda testitavate teenuste logisid?
- Kuidas runnerit puhastada?
Mul on oma GitLabi runner oma projektide jaoks ja nendega seotud küsimustega olen kokku puutunud arendamise käigus. jaoks . Täpsemalt integreerimistestide käivitamise korral. Edasi lahendame need küsimused näidete kaudu sellest projektist.
GitLab Shell Runner
Runneri jaoks soovitan Linuxi virtuaalmasinat, millel on 4 vCPU, 4 GB RAM, 50 GB HDD.
Internetis on palju teavet gitlab-runner'i seadistamise kohta, seega lühidalt:
- Logi sisse masinasse SSH kaudu
Kui teil on vähem kui 8 GB RAM, siis soovitan , et OOM killer ei tulnud ja ei tapnud meie ülesandeid RAM-i puudumise tõttu. See võib juhtuda, kui käivitatakse samal ajal rohkem kui 5 ülesannet. Ülesanded kulgevad aeglasemalt, kuid stabiilselt.
Näide OOM killerist
Kui te näete ülesande logides
bash: line 82: 26474 Killed, siis täitke lihtsalt runnerissudo dmesg | grep 26474[26474] 1002 26474 1061935 123806 339 0 0 java Out of memory: Tapetud protsess 26474 (java) hinded 127 või ohver laps Tapetud protsess 26474 (java) kogus-vm:4247740kB, anon-rss:495224kB, file-rss:0kB, shmem-rss:0kBJa kui pilt näeb välja umbes nii, siis kas lisage swap või suurendage RAM-i.
- Paigaldame , , , tee.
- Lisame kasutaja
gitlab-runnergruppidockersudo groupadd docker sudo usermod -aG docker gitlab-runner - gitlab-runneri.
Avame redigeerimiseks
/etc/gitlab-runner/config.tomlja lisameconcurrent=20 [[runners]] request_concurrency = 10See võimaldab ühel runneril käivitada samaaegseid ülesandeid. Täpsemalt lugeda. .
Kui teil on võimsam masin, näiteks 8 vCPU, 16 GB RAM, siis saab neid numbreid vähemalt kahekordistada. Kuid kõik sõltub sellest, mida konkreetselt käivitatakse antud runner'is ja kui suures koguses.
Seda on piisavalt.
docker-compose.yml ettevalmistamine
Peamine ülesanne on universaalne docker-compose.yml, mida arendajad/testijad saavad kasutada nii kohapeal kui ka CI torujuhtmes.
Esiteks loome unikaalsed teenuste nimetused CI jaoks. Ü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:
- kui
CI_JOB_IDei ole määratud keskkonnamuutujates,
on teenuse nimiservice-local - kui
CI_JOB_IDmäära keskkonnamuutujates (näiteks 123),
on teenuse nimiservice-123
Teiseks loome jagatud võrgu käivitatavate teenuste jaoks. See annab meile isolatsiooni võrgu tasandil, kui käivitame mitu testimist keskkonda.
networks:
default:
external:
name: service-network-${CI_JOB_ID:-local}See on tegelikult esimene samm eduni =)
Minu docker-compose.yml näide kommentaaridega
version: "3"
# Korrektselt töötamiseks web (php) ja fmt on vajalik,
# et konteineritel oleks ühine täidetav sisu.
# Meie puhul on see kaust /var/www/testrail
volumes:
static-content:
# Isoleerime keskkonna võrgu tasemel
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 TR_HTTP_PORT või TR_HTTPS_PORTS muutujaid ei ole määratud,
# tõuseb teenus vastavalt 80 ja 443 sadamatesse.
ports:
- ${TR_HTTP_PORT:-80}:80
- ${TR_HTTPS_PORT:-443}:443
volumes:
- static-content:/var/www/testrail
links:
- db
- fpm
networks:
- defaultKohaliku käivitamise 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 käivitamine pole sugugi nii lihtne.
Makefile ettevalmistamine
Kasutame Makefile'i, kuna see on väga mugav nii kohalikuks keskkonna haldamiseks kui ka CI jaoks. Edasi on kommentaarid reavahetusega.
# У меня в проектах все вспомогательные вещи лежат в директории `.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
Töötleb testrail-web-local ... valmis
Töötleb testrail-fpm-local ... valmis
Töötleb testrail-mysql-local ... valmis
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
Alaadimine db ... valmis
Alaadimine migration ... valmis
Alaadimine fpm ... valmis
Alaadimine web ... valmis
docker-compose -f ${CI_JOB_ID:-.indirect}\/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Taaskäivitamine testrail-mysql-local ... valmis
Taaskäivitamine testrail-fpm-local ... valmis
Taaskäivitamine testrail-migration-local ... valmis
Taaskäivitamine testrail-web-local ... valmis
docker ps
KONTROLLERID PORTID NIMED
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: ei saa luua kausta ‘.\/logs’: Kaal olemas
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
Integreerimiste testide käivitamine
Integratsioon:
etapp: test
sildid:
- my-shell-runner
enne_script:
# Autentimine registris
- docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
# Genereerime pseudo-unikaalsed 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 ülesande identifikaatoriga
- mkdir ${CI_JOB_ID}
# kopeerime loodud kausta meie docker-compose.yml
# et kontekst oleks igas ülesandes erinev
- cp .indirect\/docker-compose.yml ${CI_JOB_ID}\/docker-compose.yml
script:
# tõstame meie keskkonna üles
- make docker-up
# käivitame testid .jar-failis (mina teen nii)
- 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
aegub: 30 päevaSelle ülesande käivitamise tulemusena sisaldab artefaktide kaust logs teenuste ja testide logisid. Mis on väga mugav vigade ilmnemisel. Iga test kirjutab oma logi paralleelselt, kuid sellest räägin eraldi.

Runneri puhastamine
Ülesanne käivitub ainult ajakava järgi.
etapid:
- puhastamine
- ehitamine
- testimine
Puhastamise jooksja:
etapp: puhastamine
ainult:
- ajakavad
sildid:
- my-shell-runner
script:
- make docker-cleanJätkame meie GitLab projekti -> CI/CD -> Ajakavad -> Uus ajakava ja lisame uue ajakavasse
Tulemus
Käivitame 4 ülesannet GitLab CI-s
Viimase integreerimistestimise ülesande logides näeme erinevate ülesannete konteinerit
KONTEINERI 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}
HOIA! Kommimine --password käsureal on ebaturvaline. Kasutage --password-stdin.
HOIA! Teie parool salvestatakse krüpteerimata failis /home/gitlab-runner/.docker/config.json.
Konfigureerige mandaadi abi, et eemaldada see hoiatus. Vaadake
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õrguskeemi 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
Laadin web ... tehtud
Laadin fpm ... tehtud
Laadin migration ... tehtud
Laadin db ... tehtud
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Loome koha "204645172_static-content" vaikimisi juhtimisega
Loome testrail-mysql-204645172 ...
Loome testrail-mysql-204645172 ... tehtud
Loome testrail-migration-204645172 ... tehtud
Loome testrail-fpm-204645172 ... tehtud
Loome testrail-web-204645172 ... tehtud
docker ps
KONTROLLI ID PILDID KÄSKU LOO VIIMASE KORRA 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 artefaktide seas on teenuste ja testide logid
Tundub, et kõik on korras, kuid on üks nüanss. Pipeline'i saab sunniviisiliselt lõpetada integreerimistestide käigus, ja sel juhul käivitatud konteinerid ei peatata. Aeg-ajalt on vajalik runneri puhastamine. Kahjuks on ülesanne parandamiseks GitLab CE-s endiselt staatuse all
Kuid 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
Kokkuvõtteks:
- Meil on üks shell runner.
- Ülesannete ja keskkonna vahel konflikte ei esine.
- Käivitame ülesanded paralleelselt integreerimistestidega.
- Integreerimisteste saab käivitada nii kohapeal kui ka konteineris.
- Teenuste ja testide logid kogutakse ja kinnitatakse pipeline'i ülesandele.
- On võimalus puhastada runnerit vanadest docker-piltidest.
Seadistusaeg — ~2 tundi.
Siin see on. Olen tagasisidest rõõmus.
Allikas: habr.com
