sqs-operator v0.1.6: SH02/SH03/SH04 fix + test_v2_suite + v2 test results
- v0.1.5: ensureHealthy checks all 4 resources (Deployment/Service/ConfigMap/Ingress) Service/ConfigMap/Ingress now auto-recreate in 2-4s when manually deleted - v0.1.6: revert MT03 configuration-snippet (nginx blocks risky annotations by default) Tenant isolation deferred to Keycloak JWT in production - test_v2_suite.sh: 8 phases, 52 tests, timing/resources/concurrent/30min marathon - Results: 40 PASS / 4 FAIL / 7 WARN (known: OOM restart under burst load) SH recovery: Deployment=48s Service=2s ConfigMap=4s Ingress=2s All3=2s Marathon: 11815 iter, 10830 sent, 2 pod restarts (OOM under load)
This commit is contained in:
@@ -202,21 +202,38 @@ func (r *QueueServiceReconciler) checkReady(ctx context.Context, qs *sqsv1alpha1
|
||||
}
|
||||
|
||||
// ensureHealthy мониторит состояние готового инстанса (фаза Ready).
|
||||
// Проверяет наличие всех критических ресурсов (Deployment, Service, ConfigMap, Ingress).
|
||||
// Если любой ресурс пропал — переход в Pending для пересоздания (OwnerReference не работает cross-namespace).
|
||||
// Если pod упал — переходим в Failed для последующего восстановления.
|
||||
func (r *QueueServiceReconciler) ensureHealthy(ctx context.Context, qs *sqsv1alpha1.QueueService, tenantNS string) (ctrl.Result, error) {
|
||||
deployName := "sqs-" + qs.Spec.TenantID
|
||||
tenantID := qs.Spec.TenantID
|
||||
|
||||
deploy := &appsv1.Deployment{}
|
||||
if err := r.Get(ctx, client.ObjectKey{Namespace: tenantNS, Name: deployName}, deploy); err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
qs.Status.Phase = sqsv1alpha1.QueueServicePhasePending
|
||||
qs.Status.Message = "deployment disappeared, reprovisioning"
|
||||
_ = r.Status().Update(ctx, qs)
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
// Проверяем критические ресурсы — если удалены вручную, пересоздаём через provision.
|
||||
checkResources := []struct {
|
||||
name string
|
||||
obj client.Object
|
||||
}{
|
||||
{"sqs-" + tenantID, &appsv1.Deployment{}},
|
||||
{"sqs-svc-" + tenantID, &corev1.Service{}},
|
||||
{"sqs-cfg-" + tenantID, &corev1.ConfigMap{}},
|
||||
{"sqs-ing-" + tenantID, &netv1.Ingress{}},
|
||||
}
|
||||
for _, res := range checkResources {
|
||||
if err := r.Get(ctx, client.ObjectKey{Namespace: tenantNS, Name: res.name}, res.obj); err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
log.FromContext(ctx).Info("resource disappeared, reprovisioning", "resource", res.name)
|
||||
qs.Status.Phase = sqsv1alpha1.QueueServicePhasePending
|
||||
qs.Status.Message = fmt.Sprintf("%s disappeared, reprovisioning", res.name)
|
||||
_ = r.Status().Update(ctx, qs)
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
return ctrl.Result{}, fmt.Errorf("health check get %s: %w", res.name, err)
|
||||
}
|
||||
return ctrl.Result{}, fmt.Errorf("health check get deployment: %w", err)
|
||||
}
|
||||
|
||||
// Deployment существует (проверен в цикле выше) — проверяем готовность pod
|
||||
deploy := &appsv1.Deployment{}
|
||||
_ = r.Get(ctx, client.ObjectKey{Namespace: tenantNS, Name: "sqs-" + tenantID}, deploy)
|
||||
if deploy.Status.AvailableReplicas < 1 {
|
||||
qs.Status.Phase = sqsv1alpha1.QueueServicePhaseFailed
|
||||
qs.Status.Message = "pod unavailable"
|
||||
@@ -224,8 +241,8 @@ func (r *QueueServiceReconciler) ensureHealthy(ctx context.Context, qs *sqsv1alp
|
||||
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
|
||||
}
|
||||
|
||||
// Всё хорошо — следующий check через 30 секунд
|
||||
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
|
||||
// Всё хорошо — следующий check через 15 секунд
|
||||
return ctrl.Result{RequeueAfter: 15 * time.Second}, nil
|
||||
}
|
||||
|
||||
// recoverFromFailed пробует восстановиться из Failed состояния.
|
||||
@@ -608,6 +625,9 @@ func (r *QueueServiceReconciler) ensureIngress(ctx context.Context, qs *sqsv1alp
|
||||
pathType := netv1.PathTypePrefix
|
||||
svcPort := int32(elasticMQPort)
|
||||
|
||||
// MT03 (auth/isolation): configuration-snippet НЕ используется — nginx Ingress Controller
|
||||
// блокирует его как "risky annotation" (CVE-2021-25742 mitigation, включён по умолчанию с v1.9+).
|
||||
// Изоляция тенантов будет обеспечена через Keycloak JWT в проде (не через SigV4/snippet).
|
||||
ing = &netv1.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
@@ -615,7 +635,6 @@ func (r *QueueServiceReconciler) ensureIngress(ctx context.Context, qs *sqsv1alp
|
||||
Labels: sqsLabels(qs.Spec.TenantID),
|
||||
Annotations: map[string]string{
|
||||
// Без rewrite-target: ElasticMQ JVM слушает по полному пути /sqs/{tenantId}/...
|
||||
// (context-path в конфиге определяет listen path у JVM образа, в отличие от native).
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout": "60",
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout": "60",
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size": "10m",
|
||||
|
||||
Reference in New Issue
Block a user