Kevyet, tarpeen mukaan käyttöön otettavat KINDillä CI Worker Nodeille käyttöönotetut Kubernetes-klusterit
Michael Vittrup Larsen
Michael is a Consultant at our office in Aarhus. He has an MScEE from Aalborg University where he specialized in digital signal processing. Before joining us Michael was working on building and optimizing cloud infrastructure for the telecoms sector. In his spare time, he likes to explore the wilderness on his mountain bike.
Näin testaat Kubernetes-artifakteja, kuten Helm chartseja ja YAML-manifesteja, CI-putkissa kevyellä, tarpeen mukaan käyttöönotettavalla Kubernetes-klusterilla, joka on toteutettu KINDillä – Kubernetes in Dockerilla. Kontit ovat nousseet suosituiksi sovellusten paketointitavaksi, koska ne ratkaisevat riippuvuuksien hallinnan ongelman. Konttiin pakattu sovellus sisältää kaikki tarvittavat ajonaikaiset riippuvuudet, joten se on siirrettävissä eri suoritusympäristöjen välillä. Toisin sanoen: jos se toimii minun koneellani, se toimii todennäköisesti myös sinun koneellasi.
Automaattinen testaus on olennainen osa DevOpsia, ja testit kannattaa kontittaa samoista syistä kuin sovelluksetkin: jos tietty testi validoi luotettavasti minun koneellani, sen pitäisi toimia yhtä hyvin myös sinun koneellasi riippumatta siitä, mitä kirjastoja ja työkaluja olet asentanut paikallisesti.
Testaus konteilla
Seuraava kuva havainnollistaa pipelinea (tai mahdollisesti kahta pipelinea sen mukaan, miten ne on järjestetty), jossa yläosa rakentaa ja paketoi sovelluksen konttiin ja alaosa tekee saman sovelluksen validointiin käytettäville testeille. Sovellus etenee vain, jos konttipohjaiset testit menevät läpi.
Jos oletetaan, että sovellus on verkkoon liitetty palvelu, jota voidaan testata black-box-testauksella verkkoyhteyden kautta, edellä kuvattu toteutus on helppo tehdä seuraavasti:
Rakenna sovellus- ja testikontit esimerkiksi komennolla ‘docker build …’
Käynnistä sovelluskontin instanssi verkkoon liitettynä esimerkiksi komennolla ‘docker run …’
Käynnistä testikontin instanssi samaan verkkoon sovelluksen kanssa esimerkiksi komennolla ‘docker run …’
Testikontin poistumiskoodi määrittää sovellustestin tuloksen
Tämä on havainnollistettu alla olevassa kuvassa.
Edellä kuvatut vaiheet 2–4 voidaan määritellä myös docker-compose-määrityksessä, jossa on kaksi palvelua, esimerkiksi seuraavasti (testikontille määritetään sovelluksen verkkosijainti ympäristömuuttujalla):
version: '3.7' services: test: image: test-container:latest environment: APPLICATION_URL: http://application:8080 depends_on: - application application: image: application:latest ports: - 8080:8080Kahden kontin testi voidaan nyt suorittaa komennolla:
docker-compose up --exit-code-from test
Kubernetes-artifaktien testaus CI-pipelinessa
Edellä kuvattu prosessi toimii hyvin konttitasolla tehtävissä testeissä. Mutta entä jos CI-pipelinejen tuottamiin artifakteihin kuuluu Kubernetes-artifakteja, kuten YAML-manifesteja tai Helm chartseja, tai ne on otettava käyttöön Kubernetes-klusterissa validointia varten? Miten testaamme tällaisissa tilanteissa?
Yksi vaihtoehto on ottaa käyttöön Kubernetes-klusteri, johon CI-pipelinet voivat tehdä käyttöönottoja. Tällöin on kuitenkin otettava huomioon muutamia asioita:
Jaetusta klusterista, johon kaikki CI-pipelinet voivat tehdä käyttöönottoja, tulee käytännössä usean käyttäjän klusteri. Se voi edellyttää huolellista eristyksen, tietoturvan ja toimintavarmuuden suunnittelua.
Miten CI:n Kubernetes-klusteri mitoitetaan? Klusterin kapasiteetti on todennäköisesti erillään CI-työntekijöiden kapasiteetista, eli ne eivät voi jakaa laskentaresursseja. Tämä johtaa vähäiseen käyttöasteeseen. CI-klusteria ei myöskään voi mitoittaa liian pieneksi, koska emme halua testien epäonnistuvan muiden pipelinejen tilapäisen resurssinkulutuksen vuoksi.
Haluamme ehkä testata Kubernetes-artifaktejamme useilla Kubernetesin versioilla ja kokoonpanoilla, mikä tarkoittaa, että tarvitsemme käytännössä N CI-klusteria.
Voimme myös luoda Kubernetes-klusterin tarpeen mukaan jokaista CI-työtä varten. Tämä edellyttää:
Pääsyä pilven kaltaiseen alustaan, jossa Kubernetes-klustereita voidaan provisioida dynaamisesti.
CI-pipelineillamme on tarvittavat oikeudet infrastruktuurin luomiseen, mikä voi olla tietoturvan näkökulmasta epätoivottavaa.
Joissakin testiskenaarioissa tarvitsemme tuotantoa vastaavan klusterin, jolloin on harkittava jotakin edellä kuvatuista ratkaisuista, esimerkiksi ominaisuustestejä tai skaalautuvuustestejä varten. Monissa tilanteissa CI-pipelinejen tarvitsemat testit voidaan kuitenkin suorittaa yhden CI-työntekijäsolmun kapasiteetilla. Seuraavassa osiossa kuvataan, miten tarpeen mukaan luotavia klustereita rakennetaan kontteja tukevalla CI-työntekijäsolmulla.
Tarpeen mukaan luotava yksityinen Kubernetes-klusteri KINDillä
Kubernetes-in-Docker (KIND) on Docker-in-Docker (DIND) -teknologiaan perustuva Kubernetes-klusterin toteutus. Docker-in-Docker tarkoittaa, että voimme ajaa kontteja konttien sisällä, jolloin sisemmät kontit näkyvät vain ulomman kontin sisällä. KIND hyödyntää tätä toteuttamalla Kubernetes-klusterin solmut ulompina kontteina. Kun Kubernetes POD käynnistetään solmulla, se toteutetaan ulomman solmukontin sisällä olevilla konteilla.
KINDin avulla voimme luoda CI-työsolmumme konttiominaisuuksien päälle tarpeen mukaan yhden tai useamman solmun Kubernetes-klustereita.
KIND Kubernetes -klusteri:
Klusterin kapasiteettia rajoittaa luonnollisesti CI-työsolmun kapasiteetti, mutta muutoin Kubernetes-klusterilla on monia tuotantoklusterin ominaisuuksia, mukaan lukien HA-ominaisuudet.
Näytetään, miten Helmillä KIND-klusteriin käyttöönotetun sovelluksen testaaminen onnistuu. Sovellus on GitHubista löytyvä k8s-sentence-age -sovellus, johon kuuluu myös tässä blogissa kuvattua CI-pipelinea toteuttava GitHub Action. Sovellus on yksinkertainen palvelu, joka palauttaa satunnaisen numeron (”iän”) väliltä 0–100 ja tarjoaa myös asianmukaiset Prometheus-yhteensopivat metriikat.
KINDin asentaminen
KIND on yksittäinen kind-niminen suoritettava tiedosto, joka kommunikoi CI-työsolmun konttiajoympäristön kanssa. Se luo klusterin jokaista solmua varten (ulomman) kontin käyttäen Kubernetesin control-plane-komponentit sisältäviä kontti-imageja. Esimerkki kindin asentamisesta osana GitHub Actionia löytyy täältä.
Klusterin luominen
kind-työkalulla CI-pipelinemme voivat luoda yhden solmun Kubernetes-klusterin seuraavalla komennolla:
kind create cluster --wait 5m
Voimme tarvittaessa luoda testejämme varten myös usean solmun klustereita. Usean solmun klusterit vaativat konfiguraatiotiedoston, jossa solmujen roolit määritellään:
# config.yaml kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: workerYllä olevalla konfiguraatiotiedostolla voimme luoda kolmen solmun klusterin seuraavalla komennolla:
kind create cluster --config config.yaml
Voimme määrittää, mitä kontti-imagea KIND Kubernetes -solmujen tulee käyttää, ja siten hallita Kubernetesin versiota:
kind create cluster --image "kindest/node:v1.16.4"
Näin voimme testata helposti yhteensopivuuden useiden Kubernetes-versioiden kanssa osana CI-pipelineamme.
Sovellusimagejen rakentaminen ja niiden tuominen KINDin saataville
Esimerkin k8s-sentences-age-sovellus on pakattu age-nimiseen konttiin, ja sovelluksen testit on pakattu age-test-nimiseen konttiin. Nämä kontit rakennetaan tavalliseen tapaan seuraavasti:
docker build -t age:latest ../appdocker build -t age-test:latest .
Voimme tuoda näiden imagejen uuden version KIND Kubernetes -solmujemme saataville seuraavalla komennolla:
kind load docker-image age:latestkind load docker-image age-test:latest
Imagejen lataaminen KIND-klusterin solmuihin kopioi imagen klusterin jokaiselle solmulle.
Testin suorittaminen
Pipelinemme ottaa sovelluksen käyttöön sen Helm chartin avulla ja suorittaa testit tätä käyttöönotettua sovellusinstanssia vastaan.
Sovelluksen käyttöönotto sovelluksen Helm chartilla tarkoittaa, että emme testaa vain Kubernetesissa käyttöönotettavaa sovelluskonttia, vaan validoimme myös itse Helm chartin. Helm chart sisältää sovelluksen Kubernetes-piirustuksen määrittävät YAML-manifestit, joten sen validointi on erityisen tärkeää – ei vain eri Kubernetes-versioita vasten, vaan myös erilaisissa konfiguraatioissa, kuten Helm chartille annettavien arvojen eri yhdistelmillä.
Asennamme sovelluksen seuraavalla Helm-komennolla. Huomaa, että ohitamme Helm chartin image repositoryn, tagin ja pullPolicyn oletusasetukset, jotta paikallista imagea käytetään.
helm install --wait age ../helm/age \--set image.repository=age \--set image.tag=latest \--set image.pullPolicy=Never
Testikontti otetaan käyttöön Kubernetes Job -resurssina. Kubernetes Job -resurssit määrittävät työkuormia, jotka suoritetaan loppuun asti ja raportoivat valmistumistilansa. Työ käyttää aiemmin rakentamaamme paikallista ‘age-test‘-kontti-imagoa ja muodostaa yhteyden sovelluksen podeihin ympäristömuuttujissa annettujen URL-osoitteiden avulla. URL-osoitteet viittaavat Helm chartin luomaan Kubernetes-palveluun.
apiVersion: batch/v1 kind: Job metadata: name: component-test spec: template: metadata: labels: type: component-test spec: containers: - name: component-test image: age-test imagePullPolicy: Never env: - name: SERVICE_URL value: http://age:8080 - name: METRICS_URL value: http://age:8080/metrics restartPolicy: Never </code>Työ otetaan käyttöön tällä komennolla:
kubectl apply -f k8s-component-test-job.yaml
Testituloksen tarkistaminen
Komponenttitestityön on valmistuttava, ennen kuin voimme tarkistaa tuloksen. kubectl-työkalulla voidaan odottaa eri resurssien erilaisia tiloja, myös työn valmistumista. Putkemme odottaa siis testin valmistumista seuraavalla komennolla:
kubectl wait --for=condition=complete \--timeout=1m job/component-test
Komponenttitestityön testitulokset ovat osa sen lokeja. Jotta tulokset sisällytetään putken tulosteeseen, tulostamme työn lokit kubectlillä ja käytämme label selector -valitsinta työn podin valitsemiseen.
kubectl logs -l type=component-test
Komponenttitestin kokonaistila luetaan työn podin kentästä .status.succeeded ja tallennetaan SUCCESS-muuttujaan alla esitetyllä tavalla. Jos tila osoittaa epäonnistumista, putki päättyy virheeseen:
SUCCESS=$(kubectl get job component-test \-o jsonpath='{.status.succeeded}')if [ $SUCCESS != '1' ]; then exit 1; fiecho "Component test successful"
Koko putki löytyy GitHubin k8s-sentences-age-repositoriosta.
On hyvä huomata, että testityön käynnistäminen ja tuloksen tarkistaminen on juuri sitä, mitä helm test tekee. Helm test on tapa integroida testit virallisesti Helm chartiin siten, että chartin käyttäjät voivat suorittaa testit chartin asentamisen jälkeen. Siksi testit kannattaa sisällyttää Helm charteihisi ja testikontti kannattaa asettaa Helm chartin käyttäjien saataville. Jotta yllä oleva testityö voidaan sisällyttää Helm chartiin, meidän tarvitsee vain lisätä alla esitetty annotaatio ja sisällyttää YAML-tiedosto chartiin.
...metadata: name: component-test annotations: "helm.sh/hook": testKun KIND-klusteri ei riitä
Joissakin tilanteissa CI-työntekijän paikallinen Kubernetes-klusteri ei välttämättä sovellu testaukseesi. Näin voi olla esimerkiksi, kun:
Yksikkötestit kutsuvat funktioita eli käyttävät esimerkiksi sovelluksen luokkia. Tällöin sovellus ja testit ovat todennäköisesti yhdessä kontissa, joka voidaan suorittaa ilman Kubernetesia.
Komponenttitesteihin ei liity Kubernetes-artefakteja. Jos yllä esitetyssä esimerkissä ei olisi testattavaa Helm chartia, docker-compose-ratkaisu olisi riittänyt.
Testeihin sisältyy ominaisuustesti, esimerkiksi sovelluksesi suorituskyvyn ja skaalautuvuuden mittaaminen. Tällaisissa tilanteissa tarvitset kapasiteetiltaan vakaampaa infrastruktuuria.
Muista artefakteista riippuvia integraatiotestejä ei ole helppo ottaa käyttöön paikallisessa KIND-klusterissa, esimerkiksi suurta asiakasdataa sisältävää tietokantaa.
Toiminnalliset, integraatio- tai hyväksymistestit edellyttävät koko sovelluksen käyttöönottoa. Jotkin sovellukset eivät välttämättä mahdu KIND-klusterin rajalliseen kokoon.
Testeillä on ulkoisia riippuvuuksia, kuten pilvipalveluntarjoajakohtainen ingress/load balancing, tallennusratkaisut tai avaintenhallintapalvelut. Joissakin tapauksissa nämä voidaan simuloida ottamalla esimerkiksi tietokanta käyttöön KIND-klusterissa, mutta toisissa tapauksissa se ei onnistu.
KIND Kubernetes -klusterilla testaaminen on silti ihanteellinen vaihtoehto monissa tilanteissa, esimerkiksi kun testattavana on Kubernetes-artefakteja, kuten Helm chart tai YAML-manifesteja, ja kun ulkoinen CI-/staging-Kubernetes-klusteri aiheuttaa liikaa ylläpitotyötä tai käyttää resursseja tehottomasti.
- Cloud
- CI/CD
Subscribe to our newsletter
Related blogs