GitLabシェルランナー。 Docker Composeを使用したテストサービスの競争力のある開始







この記事はテスターと開発者の両方にとって興味深いものになりますが、インフラストラクチャリソースが不十分な場合やコンテナオーケストレーション用のプラットフォームが不足している場合の統合テスト用にGitLab CI / CDを構成する問題に直面しているオートマトンを対象としています。 単一のGitLabシェルランナーでdocker composeを使用してテスト環境の展開を構成し、複数の環境を展開するときに起動されるサービスが互いに干渉しないようにする方法を説明します。









内容







背景



  1. 私の実践では、プロジェクトの統合テストを「修復」することがよくありました。 多くの場合、最も重要な最初の問題はCIパイプラインで、 開発されたサービスの統合テストが開発 /ステージ環境で実行されます。 これにより、かなりの数の問題が発生しました。







    • 特定のサービスの欠陥により、統合テスト中に破損したデータによってテスト回路が破損する場合があります。 壊れたJSON形式のリクエストを送信すると、サービスがハングし、スタンドが完全に機能しなくなる場合がありました。
    • テストデータの増加に伴い、テスト回路の動作が遅くなります。 データベースのクリーニング/ロールバックの例を説明するのは意味がないと思います。 私の練習では、この手順がスムーズに進むプロジェクトに会ったことがありません。
    • 一般的なシステム設定をテストする際のテスト回路の中断のリスク。 たとえば、ユーザー/グループ/パスワード/アプリケーションポリシー。
    • 自動テストからのテストデータは、手動テスターの生存を妨げます。


    優れた自動テストでは、自分でデータを消去する必要があると誰かが言うでしょう。 反対意見があります:







    • ダイナミックスタンドは非常に便利に使用できます。
    • APIを使用してすべてのオブジェクトをシステムから削除できるわけではありません。 たとえば、オブジェクトを削除する呼び出しは、ビジネスロジックと矛盾するため、実装されていません。
    • APIを介してオブジェクトを作成すると、大量のメタデータが作成される可能性があり、これは削除するのに問題があります。
    • テストが相互に依存している場合、テスト完了後のデータクリーニングプロセスは頭痛の種になります。
    • APIへの追加の(そして、私の意見では、正当化されていない)呼び出し。
    • そして主な議論:テストデータがデータベースから直接きれいになり始めるとき。 それは本当のPK / FKサーカスに変わります! 開発者からは、「ネームプレートの追加/削除/名前変更のみを行いましたが、なぜ100500の統合テストが失敗したのですか?」


    私の意見では、最も最適なソリューションは動的な環境です。







  2. 多くの人がdocker-composeを使用してテスト環境を実行しますが、CI / CDで統合テストを実行するときにdocker-composeを使用する人はほとんどいません。 ここでは、kubernetes、swarm、その他のコンテナオーケストレーションプラットフォームを考慮していません。 すべての会社がそれらを持っているわけではありません。 docker-compose.ymlが普遍的であればいいでしょう。
  3. 独自のQAランナーがいる場合でも、docker-composeを介して起動されたサービスが互いに干渉しないようにするにはどうすればよいですか?
  4. テストされたサービスのログを収集する方法は?
  5. ランナーをきれいにする方法は?


私は自分のプロジェクト用に自分のGitLabランナーを持っていますがTestRail用のJavaクライアントを開発するときにこれらの問題に遭遇しました。 むしろ、統合テストを実行するとき。 以下、このプロジェクトの例を使用してこれらの問題を解決します。







コンテンツへ









Gitlabシェルランナー



ランナーには、4つのvCPU、4 GBのRAM、50 GBのHDDを備えたLinux仮想マシンをお勧めします。

インターネットでは、gitlab-runnerの設定に関する多くの情報があります。











それで十分です。







コンテンツへ









docker-compose.ymlの準備



主なタスクはdocker-compose.ymlで、ローカルとCIパイプラインの両方で使用されます。







変数COMPOSE_PROJECT_NAMEは、環境のいくつかのインスタンスを開始するために使用されます( makefileを参照)。







docker-compose.ymlの例







 version: "3" #    web (php)  fmt , #      . #   ,   /var/www/testrail volumes: static-content: services: db: image: mysql:5.7.22 environment: MYSQL_HOST: db MYSQL_DATABASE: mydb MYSQL_ROOT_PASSWORD: 1234 SKIP_GRANT_TABLES: 1 SKIP_NETWORKING: 1 SERVICE_TAGS: dev SERVICE_NAME: mysql migration: image: registry.gitlab.com/touchbit/image/testrail/migration:latest links: - db depends_on: - db 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 web: image: registry.gitlab.com/touchbit/image/testrail/web:latest #   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
      
      





コンテンツへ









メイクファイルの準備



環境のローカル管理とCIの両方で非常に便利なので、Makefileを使用します。







さらなるコメントはインラインです







 #           `.indirect`, #     `docker-compose.yml` #  bash   pipefail # pipefail -   ,      SHELL=/bin/bash -o pipefail #   CI_JOB_ID   ifeq ($(CI_JOB_ID),) #   local CI_JOB_ID := local endif #    export COMPOSE_PROJECT_NAME = $(CI_JOB_ID)-testrail #    , , volumes docker-down: docker-compose -f .indirect/docker-compose.yml down #   docker-down () docker-up: docker-down #     docker-registry docker-compose -f .indirect/docker-compose.yml pull #   # force-recreate -    # renew-anon-volumes -   volumes   docker-compose -f .indirect/docker-compose.yml up --force-recreate --renew-anon-volumes -d #  ,   ,           docker ps #    docker-logs: mkdir -p ./logs docker logs $${COMPOSE_PROJECT_NAME}_web_1 >& logs/testrail-web.log || true docker logs $${COMPOSE_PROJECT_NAME}_fpm_1 >& logs/testrail-fpm.log || true docker logs $${COMPOSE_PROJECT_NAME}_migration_1 >& logs/testrail-migration.log || true docker logs $${COMPOSE_PROJECT_NAME}_db_1 >& logs/testrail-mysql.log || true #   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
      
      





ローカルでの起動を確認
 $ make docker-up docker-compose -f .indirect/docker-compose.yml pull Pulling db ... done Pulling migration ... done Pulling fpm ... done Pulling web ... done docker-compose -f .indirect/docker-compose.yml up --force-recreate --renew-anon-volumes -d Creating network "local-testrail_default" with the default driver Recreating local-testrail_db_1 ... done Recreating local-testrail_migration_1 ... done Recreating local-testrail_fpm_1 ... done Recreating local-testrail_web_1 ... done docker ps CONTAINER ID NAMES 3b8f9d4af29c local-testrail_web_1 5622c7d742d5 local-testrail_fpm_1 b580e3392038 local-testrail_migration_1 e467630bd3a5 local-testrail_db_1
      
      





CI起動の確認
 $ export CI_JOB_ID=123456789 $ make docker-up docker-compose -f .indirect/docker-compose.yml pull Pulling db ... done Pulling migration ... done Pulling fpm ... done Pulling web ... done docker-compose -f .indirect/docker-compose.yml up --force-recreate --renew-anon-volumes -d Creating network "123456789-testrail_default" with the default driver Creating volume "123456789-testrail_static-content" with default driver Creating 123456789-testrail_db_1 ... done Creating 123456789-testrail_fpm_1 ... done Creating 123456789-testrail_migration_1 ... done Creating 123456789-testrail_web_1 ... done docker ps CONTAINER ID NAMES ccf1ad33d0e8 123456789-testrail_web_1 bc079964f681 123456789-testrail_fpm_1 10dc9d4d8f2a 123456789-testrail_migration_1 fe98d43c380e 123456789-testrail_db_1
      
      





ログ収集を確認する
 $ make docker-logs mkdir -p ./logs docker logs ${COMPOSE_PROJECT_NAME}_web_1 >& logs/testrail-web.log || true docker logs ${COMPOSE_PROJECT_NAME}_fpm_1 >& logs/testrail-fpm.log || true docker logs ${COMPOSE_PROJECT_NAME}_migration_1 >& logs/testrail-migration.log || true docker logs ${COMPOSE_PROJECT_NAME}_db_1 >& logs/testrail-mysql.log || true
      
      











コンテンツへ









.gitlab-ci.ymlの準備





統合テストを実行する



 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) 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-down artifacts: #   when: always paths: - logs expire_in: 30 days
      
      





アーティファクトでこのようなタスクを起動した結果、logsディレクトリにはサービスとテストのログが含まれます。 これはエラーの場合に非常に便利です。 私にとって、各テストは並行して独自のログを書き込みますが、これについては個別に説明します。













コンテンツへ









ランナークリーニング



タスクはスケジュールに従ってのみ起動されます。







 stages: - clean - build - test Clean runner: stage: clean only: - schedules tags: - my-shell-runner script: - make docker-clean
      
      





次に、GitLabプロジェクト-> CI / CD->スケジュール->新しいスケジュールに移動し、新しいスケジュールを追加します













コンテンツへ









結果



GitLab CIで4つのタスクを実行する







統合テストを使用した最後のタスクのログには、さまざまなタスクのコンテナーが表示されます







 CONTAINER ID NAMES c6b76f9135ed 204645172-testrail-web_1 01d303262d8e 204645172-testrail-fpm_1 2cdab1edbf6a 204645172-testrail-migration_1 826aaf7c0a29 204645172-testrail-mysql_1 6dbb3fae0322 204645084-testrail-web_1 3540f8d448ce 204645084-testrail-fpm_1 70fea72aa10d 204645084-testrail-mysql_1 d8aa24b2892d 204644881-testrail-web_1 6d4ccd910fad 204644881-testrail-fpm_1 685d8023a3ec 204644881-testrail-mysql_1 1cdfc692003a 204644793-testrail-web_1 6f26dfb2683e 204644793-testrail-fpm_1 029e16b26201 204644793-testrail-mysql_1 c10443222ac6 204567103-testrail-web_1 04339229397e 204567103-testrail-fpm_1 6ae0accab28d 204567103-testrail-mysql_1 b66b60d79e43 204553690-testrail-web_1 033b1f46afa9 204553690-testrail-fpm_1 a8879c5ef941 204553690-testrail-mysql_1 069954ba6010 204553539-testrail-web_1 ed6b17d911a5 204553539-testrail-fpm_1 1a1eed057ea0 204553539-testrail-mysql_1
      
      





より詳細なログ
 $ 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-testrail_static-content" with default driver Creating 204645172-testrail-mysql_1 ... Creating 204645172-testrail-mysql_1 ... done Creating 204645172-testrail-migration_1 ... done Creating 204645172-testrail-fpm_1 ... done Creating 204645172-testrail-web_1 ... 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 204645172-testrail-web_1 01d303262d8e registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 16 seconds ago Up 13 seconds 9000/tcp 204645172-testrail-fpm_1 2cdab1edbf6a registry.gitlab.com/touchbit/image/testrail/migration:latest "docker-entrypoint.s…" 16 seconds ago Up 13 seconds 3306/tcp, 33060/tcp 204645172-testrail-migration_1 826aaf7c0a29 mysql:5.7.22 "docker-entrypoint.s…" 18 seconds ago Up 16 seconds 3306/tcp 204645172-testrail-mysql_1 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 204645084-testrail-web_1 3540f8d448ce registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 38 seconds ago Up 35 seconds 9000/tcp 204645084-testrail-fpm_1 70fea72aa10d mysql:5.7.22 "docker-entrypoint.s…" 40 seconds ago Up 37 seconds 3306/tcp 204645084-testrail-mysql_1 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 204644881-testrail-web_1 6d4ccd910fad registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" About a minute ago Up About a minute 9000/tcp 204644881-testrail-fpm_1 685d8023a3ec mysql:5.7.22 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp 204644881-testrail-mysql_1 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 204644793-testrail-web_1 6f26dfb2683e registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" About a minute ago Up About a minute 9000/tcp 204644793-testrail-fpm_1 029e16b26201 mysql:5.7.22 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp 204644793-testrail-mysql_1 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 204567103-testrail-web_1 04339229397e registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 5 hours ago Up 5 hours 9000/tcp 204567103-testrail-fpm_1 6ae0accab28d mysql:5.7.22 "docker-entrypoint.s…" 5 hours ago Up 5 hours 3306/tcp 204567103-testrail-mysql_1 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 204553690-testrail-web_1 033b1f46afa9 registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 5 hours ago Up 5 hours 9000/tcp 204553690-testrail-fpm_1 a8879c5ef941 mysql:5.7.22 "docker-entrypoint.s…" 5 hours ago Up 5 hours 3306/tcp 204553690-testrail-mysql_1 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 204553539-testrail-web_1 ed6b17d911a5 registry.gitlab.com/touchbit/image/testrail/fpm:latest "docker-php-entrypoi…" 5 hours ago Up 5 hours 9000/tcp 204553539-testrail-fpm_1 1a1eed057ea0 mysql:5.7.22 "docker-entrypoint.s…" 5 hours ago Up 5 hours 3306/tcp 204553539-testrail-mysql_1
      
      





すべてのタスクが正常に完了しました

タスクアーティファクトにはサービスとテストのログが含まれます













すべてが美しいように見えますが、ニュアンスがあります。 統合テストの実行中にパイプラインを強制的にキャンセルできます。その場合、実行中のコンテナーは停止しません。 時々、ランナーをきれいにする必要があります。 残念ながら、GitLab CEの改訂タスクはまだオープン状態です







しかし、スケジュールされたタスクの起動を追加しました。手動で起動することを禁止する人はいません。

プロジェクト-> CI / CD->スケジュールに移動し、 Clean runner



タスクを実行します













合計:









セットアップ時間は約2時間です。

実際、それがすべてです。 フィードバックをお待ちしております。







PS

freeseacher vvasilenok ivanychに感謝します。 あなたのコメントは、出版の文脈において非常に貴重でした。







コンテンツへ








All Articles