Terlepas dari kenyataan bahwa semua orang tahu betul bahwa pengujian perangkat lunak Anda penting dan perlu, dan banyak yang telah melakukannya secara otomatis sejak lama, di Habr yang luas, tidak ada satu resep pun untuk menyiapkan kombinasi produk populer seperti itu di ceruk ini sebagai (favorit kami) GitLab dan JUnit . Mari kita isi kesenjangan ini!
pengantar
Pertama, izinkan saya memberikan beberapa konteks:
Karena semua aplikasi kami berjalan di Kubernetes, kami akan mempertimbangkan untuk menjalankan pengujian pada infrastruktur yang sesuai.
Untuk perakitan dan penerapan kami menggunakan wer (dari segi komponen infrastruktur, otomatis Helm juga ikut terlibat).
Saya tidak akan membahas detail pembuatan pengujian yang sebenarnya: dalam kasus kami, klien menulis pengujian sendiri, dan kami hanya memastikan peluncurannya (dan adanya laporan terkait dalam permintaan penggabungan).
Seperti apa urutan tindakan secara umum?
Membangun aplikasi - kami akan menghilangkan deskripsi tahap ini.
Terapkan aplikasi ke namespace terpisah dari cluster Kubernetes dan mulai pengujian.
Mencari artefak dan menguraikan laporan JUnit dengan GitLab.
Menghapus namespace yang dibuat sebelumnya.
Sekarang - untuk implementasi!
pengaturan
GitLab CI
Mari kita mulai dengan sebuah fragmen .gitlab-ci.yaml, yang menjelaskan penerapan aplikasi dan menjalankan pengujian. Daftarnya ternyata cukup banyak, jadi dilengkapi dengan komentar:
variables:
# объявляем версию werf, которую собираемся использовать
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
script:
# создаем namespace в K8s, если его нет
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# загружаем werf и деплоим — подробнее об этом см. в документации
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#deploy-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf deploy --stages-storage :local
--namespace ${CI_ENVIRONMENT_SLUG}
--set "global.commit_ref_slug=${CI_COMMIT_REF_SLUG:-''}"
# передаем переменную `run_tests`
# она будет использоваться в рендере Helm-релиза
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# изменяем timeout (бывают долгие тесты) и передаем его в релиз
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
dependencies:
- Build
.test-base: &test-base
extends: .base_deploy
before_script:
# создаем директорию для будущего отчета, исходя из $CI_COMMIT_REF_SLUG
- mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# вынужденный костыль, т.к. GitLab хочет получить артефакты в своем build-dir’е
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
after_script:
# после окончания тестов удаляем релиз вместе с Job’ом
# (и, возможно, его инфраструктурой)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf dismiss --namespace ${CI_ENVIRONMENT_SLUG} --with-namespace
# мы разрешаем падения, но вы можете сделать иначе
allow_failure: true
variables:
RUN_TESTS: 'yes'
# задаем контекст в werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
tags:
# используем раннер с тегом `werf-runner`
- werf-runner
artifacts:
# требуется собрать артефакт для того, чтобы его можно было увидеть
# в пайплайне и скачать — например, для более вдумчивого изучения
paths:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# артефакты старше недели будут удалены
expire_in: 7 day
# важно: эти строки отвечают за парсинг отчета GitLab’ом
reports:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# для упрощения здесь показаны всего две стадии
# в реальности же у вас их будет больше — как минимум из-за деплоя
stages:
- build
- tests
build:
stage: build
script:
# сборка — снова по документации по werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#build-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf build-and-publish --stages-storage :local
tags:
- werf-runner
except:
- schedules
run tests:
<<: *test-base
environment:
# "сама соль" именования namespace’а
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
name: tests-${CI_COMMIT_REF_SLUG}
stage: tests
except:
- schedules
Kubernetes
Sekarang di direktori .helm/templates mari buat YAML dengan Job - tests-job.yaml — untuk menjalankan pengujian dan sumber daya Kubernetes yang diperlukan. Lihat penjelasan setelah daftar:
Sumber daya apa dijelaskan dalam konfigurasi ini? Saat menerapkan, kami membuat namespace unik untuk proyek tersebut (ini ditunjukkan dalam .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) dan luncurkan:
Peta Konfigurasi dengan skrip tes;
Pekerjaan dengan deskripsi pod dan arahan yang ditentukan command, yang baru saja menjalankan pengujian;
PV dan PVC, yang memungkinkan Anda menyimpan data pengujian.
Perhatikan kondisi pengantar dengan if di awal manifes - oleh karena itu, file YAML lain dari bagan Helm dengan aplikasi harus digabungkan balik desain sehingga mereka tidak dikerahkan selama pengujian. Itu adalah:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Namun jika tes memerlukan beberapa infrastruktur (misalnya, Redis, RabbitMQ, Mongo, PostgreSQL...) - YAML-nya dapat berupa tidak matikan. Terapkan juga ke dalam lingkungan pengujian... sesuaikan sesuai keinginan Anda, tentu saja.
Sentuhan terakhir
Karena perakitan dan penerapan menggunakan werf berfungsi untuk saat ini hanya di server build (dengan gitlab-runner), dan pod dengan pengujian diluncurkan di master, Anda perlu membuat direktori /mnt/tests pada tuannya dan memberikannya kepada pelari, misalnya melalui NFS. Contoh detail beserta penjelasannya dapat ditemukan di Dokumentasi K8.
Tidak ada yang melarang membuat share NFS langsung di gitlab-runner, lalu memasangnya di pod.
Catatan
Anda mungkin bertanya mengapa mempersulit segalanya dengan membuat Pekerjaan jika Anda bisa menjalankan skrip dengan tes langsung di shell runner? Jawabannya cukup sepele...
Beberapa pengujian memerlukan akses ke infrastruktur (MongoDB, RabbitMQ, PostgreSQL, dll.) untuk memverifikasi bahwa pengujian tersebut berfungsi dengan benar. Kami menjadikan pengujian terpadu - dengan pendekatan ini, memasukkan entitas tambahan tersebut menjadi mudah. Selain itu, kami mendapatkan standar pendekatan penerapan (bahkan jika menggunakan NFS, pemasangan direktori tambahan).
Hasil
Apa yang akan kita lihat ketika kita menerapkan konfigurasi yang telah disiapkan?
Permintaan penggabungan akan menampilkan statistik ringkasan untuk pengujian yang dijalankan di pipeline terbarunya:
Setiap kesalahan dapat diklik di sini untuk detailnya:
NB: Pembaca yang penuh perhatian akan melihat bahwa kami sedang menguji aplikasi NodeJS, dan di tangkapan layar - .NET... Jangan kaget: hanya saja saat menyiapkan artikel, tidak ditemukan kesalahan dalam pengujian aplikasi pertama, tetapi mereka ditemukan di tempat lain.
Kesimpulan
Seperti yang Anda lihat, tidak ada yang rumit!
Pada prinsipnya, jika Anda sudah memiliki shell collector dan berfungsi, tetapi Anda tidak memerlukan Kubernetes, melampirkan pengujian ke dalamnya akan menjadi tugas yang lebih sederhana daripada yang dijelaskan di sini. Dan masuk Dokumentasi GitLab CI Anda akan menemukan contoh untuk Ruby, Go, Gradle, Maven dan beberapa lainnya.