Kubernetes para QA
Por Que Kubernetes?
- Isolamento – Cada ambiente isolado
- Reproducibilidade – Ambientes idênticos
- Escalabilidade – Teste com múltiplas réplicas
- Orquestração – Deploys atômicos
Recursos Kubernetes
Pod
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: api-test-pod
labels:
app: api
env: test
spec:
containers:
- name: api
image: api:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: api-secrets
key: database-url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: api:v1.0.0
ports:
- containerPort: 8080
env:
- name: ENV
value: "production"
livenessProbe:
httpGet:
path: /health
port: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
Service
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
type: ClusterIP
selector:
app: api
ports:
- port: 80
targetPort: 8080
name: http
Helm – Gerenciamento de Charts
Estrutura
myapp/
├── Chart.yaml
├── values.yaml
├── charts/
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl
│ └── tests/
│ └── test-connection.yaml
└── README.md
Chart.yaml
# Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for MyApp
type: application
version: 1.0.0
appVersion: "1.0.0"
keywords:
- web
- api
home: https://myapp.com
maintainers:
- name: DevOps Team
email: devops@myapp.com
dependencies:
- name: postgresql
version: "12.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
values.yaml
# values.yaml
replicaCount: 3
image:
repository: myapp/api
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: api.myapp.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: api-tls
hosts:
- api.myapp.com
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
postgresql:
enabled: true
auth:
database: myapp
username: myapp
password: changeme
tests:
enabled: true
image: curlimages/curl:latest
Test Template
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "myapp.fullname" . }}-test-connection"
labels:
helm.sh/hook: test
helm.sh/hook-delete-policy: before-hook-creation
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: "{{ .Values.tests.image }}"
command: ['sh', '-c']
args:
- |
echo "Testing API health endpoint..."
response=$(curl -f http://{{ include "myapp.fullname" . }}:{{ .Values.service.port }}/health || echo "FAILED")
echo "Response: $response"
if [ "$response" != "OK" ]; then
exit 1
fi
restartPolicy: Never
Testando no Kubernetes
Testes de Integração com Kind
# Criar cluster Kind
kind create cluster --name qa-tests
# Deploy app
kubectl apply -f deployment.yaml
# Run tests
kubectl run test-runner --image=myapp/test-runner -- curl http://api-service/health
# Ver resultado
kubectl logs test-runner
# Cleanup
kind delete cluster --name qa-tests
kubectl Testing Commands
# Verificar pods
kubectl get pods -l app=api
# Ver logs
kubectl logs -l app=api --tail=100
# Port-forward para teste local
kubectl port-forward svc/api-service 8080:80
# Executar testes
kubectl exec -it api-pod -- python -m pytest tests/
# Ver events
kubectl get events --sort-by='.lastTimestamp'
Teste com cURL
#!/bin/bash
# test-api.sh
API_URL="http://api-service"
echo "Testing API endpoints..."
# Health check
echo "1. Health check..."
response=$(curl -s -o /dev/null -w "{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}{http_code}" $API_URL/health)
if [ "$response" != "200" ]; then
echo "FAILED: Health check returned $response"
exit 1
fi
echo "OK"
# Teste de endpoint
echo "2. GET /users..."
response=$(curl -s $API_URL/users)
if echo "$response" | grep -q "users"; then
echo "OK"
else
echo "FAILED"
exit 1
fi
echo "All tests passed!"
CI/CD com Kubernetes
GitHub Actions
# .github/workflows/k8s-tests.yml
name: Kubernetes Tests
on:
push:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
- name: Deploy to test
run: |
helm upgrade --install myapp ./chart
--namespace test
--create-namespace
--values ./chart/values-test.yaml
--wait --timeout 5m
- name: Wait for pods
run: |
kubectl wait --for=condition=ready pod -l app=myapp
-n test --timeout=300s
- name: Run API tests
run: |
kubectl exec -n test deploy/myapp --
python -m pytest tests/ -v --junit-xml=/tmp/results.xml
- name: Run integration tests
run: |
kubectl run test-runner -n test
--image=myapp/test-runner
--rm -it --restart=Never
-- curl -f http://myapp/health
- name: Collect test results
uses: actions/upload-artifact@v4
with:
name: test-results
path: /tmp/results.xml
- name: Cleanup
if: always()
run: helm uninstall myapp -n test
Conclusão
Kubernetes facilita testes em ambientes controlados. As chaves são:
- Containerização – Ambientes reproduzíveis
- Helm charts – Deploys versionados
- Test hooks – Testes no ciclo de deploy
- CI/CD integration – Automação completa
- Monitoring – Observabilidade em testes
