Лабораторная 6.4: Добавление наблюдаемости
Связанный урок: Урок 6.4: Отладка и наблюдаемость
Навигация: ← Предыдущая лабораторная: Интеграционное тестирование | Обзор модуля
Цели
- Разобраться в существующем структурированном логировании
- Добавить пользовательские метрики Prometheus
- Добавить генерацию событий Kubernetes
- Настроить отладку с Delve
- Проверить, что все возможности наблюдаемости работают
Предварительные требования
- Завершение Лабораторной 6.3
- Оператор Database, развёрнутый в кластере
- Понимание концепций наблюдаемости
Упражнение 1: проверка структурированного логирования
Kubebuilder уже настраивает структурированное логирование с zap. Проверим, что оно работает.
Задача 1.1: проверьте существующую конфигурацию логирования
В вашем cmd/main.go логирование уже настроено:
opts := zap.Options{
Development: true,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
Задача 1.2: проверьте логирование в контроллере
Ваш контроллер уже использует структурированное логирование. Проверьте internal/controller/database_controller.go:
func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
// ... later in the code:
logger.Info("Reconciling Database", "name", db.Name)
logger.Info("STATE TRANSITION: Pending -> Provisioning", "database", db.Name)
}
Задача 1.3: протестируйте логирование
# Deploy the operator (if not already deployed)
cd ~/postgres-operator
make deploy IMG=postgres-operator:latest
# Watch logs in real-time
kubectl logs -n postgres-operator-system -l control-plane=controller-manager -f
# In another terminal, create a Database to trigger reconciliation
kubectl apply -f - <<EOF
apiVersion: database.example.com/v1
kind: Database
metadata:
name: test-logging
namespace: default
spec:
image: postgres:14
databaseName: testdb
username: testuser
storage:
size: 1Gi
EOF
Ожидаемый вывод (в терминале с логами):
INFO Reconciling Database {"controller": "database", "name": "test-logging"}
INFO STATE TRANSITION: Pending -> Provisioning {"database": "test-logging"}
INFO Creating Secret {"name": "test-logging-credentials"}
INFO Creating StatefulSet {"name": "test-logging"}
Задача 1.4: очистка
kubectl delete database test-logging
Упражнение 2: добавление метрик Prometheus
Задача 2.1: добавьте RBAC-привязку для метрик
Каркас Kubebuilder создаёт ClusterRole metrics-reader, но не привязывает его ни к кому. Нужно создать привязку, чтобы ServiceAccount мог обращаться к своим метрикам.
Создайте config/rbac/metrics_reader_role_binding.yaml:
cat > ~/postgres-operator/config/rbac/metrics_reader_role_binding.yaml << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: postgres-operator
app.kubernetes.io/managed-by: kustomize
name: metrics-reader-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metrics-reader
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
EOF
Обновите config/rbac/kustomization.yaml, чтобы включить новый файл:
cat > ~/postgres-operator/config/rbac/kustomization.yaml << 'EOF'
resources:
# All RBAC will be applied under this service account in
# the deployment namespace. You may comment out this resource
# if your manager will use a service account that exists at
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
# subjects if changing service account names.
- service_account.yaml
- role.yaml
- role_binding.yaml
- leader_election_role.yaml
- leader_election_role_binding.yaml
# The following RBAC configurations are used to protect
# the metrics endpoint with authn/authz. These configurations
# ensure that only authorized users and service accounts
# can access the metrics endpoint. Comment the following
# permissions if you want to disable this protection.
# More info: https://book.kubebuilder.io/reference/metrics.html
- metrics_auth_role.yaml
- metrics_auth_role_binding.yaml
- metrics_reader_role.yaml
- metrics_reader_role_binding.yaml
# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by
# default, aiding admins in cluster management. Those roles are
# not used by the postgres-operator itself. You can comment the following lines
# if you do not want those helpers be installed with your Project.
- database_admin_role.yaml
- database_editor_role.yaml
- database_viewer_role.yaml
EOF
Задача 2.2: создайте файл метрик
Создайте internal/controller/metrics.go:
cat > ~/postgres-operator/internal/controller/metrics.go << 'EOF'
/*
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"github.com/prometheus/client_golang/prometheus"
"sigs.k8s.io/controller-runtime/pkg/metrics"
)
var (
// ReconcileTotal counts the total number of reconciliations
ReconcileTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "database_reconcile_total",
Help: "Total number of reconciliations per controller",
},
[]string{"result"}, // success, error, requeue
)
// ReconcileDuration measures the duration of reconciliations
ReconcileDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "database_reconcile_duration_seconds",
Help: "Duration of reconciliations in seconds",
Buckets: prometheus.DefBuckets,
},
[]string{"result"},
)
// DatabasesTotal tracks the current number of Database resources
DatabasesTotal = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "database_resources_total",
Help: "Current number of Database resources by phase",
},
[]string{"phase"},
)
// DatabaseInfo provides information about each database
DatabaseInfo = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "database_info",
Help: "Information about Database resources",
},
[]string{"name", "namespace", "image", "phase"},
)
)
func init() {
// Register custom metrics with the global registry
metrics.Registry.MustRegister(
ReconcileTotal,
ReconcileDuration,
DatabasesTotal,
DatabaseInfo,
)
}
EOF
Задача 2.3: обновите контроллер для использования метрик
Добавьте инструментирование метриками в вашу функцию Reconcile. Обновите internal/controller/database_controller.go:
Добавьте импорт:
import (
// ... existing imports ...
"time"
)
Обновите функцию Reconcile — добавьте в самом начале:
func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
start := time.Now()
reconcileResult := "success"
// Defer metrics recording
defer func() {
duration := time.Since(start).Seconds()
ReconcileDuration.WithLabelValues(reconcileResult).Observe(duration)
ReconcileTotal.WithLabelValues(reconcileResult).Inc()
}()
logger := log.FromContext(ctx)
// ... rest of existing code ...
Обновите обработку ошибок — при возврате ошибок задавайте результат:
// Example: in error returns, set reconcileResult before returning
if err := r.Get(ctx, req.NamespacedName, db); err != nil {
if errors.IsNotFound(err) {
return ctrl.Result{}, nil
}
reconcileResult = "error" // Add this line
return ctrl.Result{}, err
}
Добавьте метрику информации о базе данных — в функции reconcile после получения базы данных:
// Record database info metric
DatabaseInfo.WithLabelValues(
db.Name,
db.Namespace,
db.Spec.Image,
db.Status.Phase,
).Set(1)
Задача 2.4: пересоберите и разверните
cd ~/postgres-operator
# Rebuild the operator (for docker)
make docker-build IMG=postgres-operator:latest
# Build with podman (note: image will be localhost/postgres-operator:latest)
make docker-build IMG=postgres-operator:latest CONTAINER_TOOL=podman
# Load into kind (for docker)
kind load docker-image postgres-operator:latest
# For podman: Load image into kind (save to tarball, then load)
podman save localhost/postgres-operator:latest -o /tmp/postgres-operator.tar
kind load image-archive /tmp/postgres-operator.tar --name k8s-operators-course
rm /tmp/postgres-operator.tar
# For docker: Deploy operator
make deploy IMG=postgres-operator:latest
# For podman: Deploy operator - use localhost/ prefix to match the loaded image
make deploy IMG=localhost/postgres-operator:latest
# Redeploy
kubectl rollout restart deployment -n postgres-operator-system postgres-operator-controller-manager
# Wait for it to be ready
kubectl wait --for=condition=ready pod -l control-plane=controller-manager -n postgres-operator-system --timeout=60s
Задача 2.5: протестируйте метрики
Эндпоинт метрик по умолчанию использует HTTPS с аутентификацией.
Примечание: RBAC оператора включает metrics-reader-rolebinding, который предоставляет ServiceAccount контроллера разрешение на чтение метрик. Это было добавлено в config/rbac/metrics_reader_role_binding.yaml.
# Create a test database first
kubectl apply -f - <<EOF
apiVersion: database.example.com/v1
kind: Database
metadata:
name: test-metrics
namespace: default
spec:
image: postgres:14
databaseName: metricsdb
username: metricsuser
storage:
size: 1Gi
EOF
# Wait for it to be reconciled
sleep 30
# Get a token for the ServiceAccount
TOKEN=$(kubectl create token -n postgres-operator-system postgres-operator-controller-manager)
# Port forward to the metrics service
kubectl port-forward -n postgres-operator-system svc/postgres-operator-controller-manager-metrics-service 8443:8443 &
sleep 2
# Query metrics with the token
curl -k -H "Authorization: Bearer $TOKEN" https://localhost:8443/metrics 2>/dev/null | grep database_
# Stop port-forward
pkill -f "port-forward.*8443"
Альтернатива: отключить защищённые метрики для локальной разработки
Если вы предпочитаете более простой доступ во время разработки:
# Patch the deployment to disable secure metrics
kubectl patch deployment -n postgres-operator-system postgres-operator-controller-manager \
--type='json' -p='[
{"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": [
"--metrics-bind-address=:8080",
"--leader-elect",
"--health-probe-bind-address=:8081",
"--metrics-secure=false"
]}
]'
# Wait for rollout
kubectl rollout status deployment -n postgres-operator-system postgres-operator-controller-manager
# Port forward and query metrics (no auth needed)
kubectl port-forward -n postgres-operator-system deployment/postgres-operator-controller-manager 8080:8080 &
sleep 2
curl http://localhost:8080/metrics 2>/dev/null | grep database_
# Stop port-forward
pkill -f "port-forward.*8080"
Ожидаемый вывод:
# HELP database_reconcile_total Total number of reconciliations per controller
# TYPE database_reconcile_total counter
database_reconcile_total{result="success"} 5
# HELP database_reconcile_duration_seconds Duration of reconciliations in seconds
# TYPE database_reconcile_duration_seconds histogram
database_reconcile_duration_seconds_bucket{result="success",le="0.005"} 2
...
# HELP database_info Information about Database resources
# TYPE database_info gauge
database_info{image="postgres:14",name="test-metrics",namespace="default",phase="Provisioning"} 1
Задача 2.6: очистка
# Stop port-forward
pkill -f "port-forward.*8443"
# Delete test database
kubectl delete database test-metrics
Упражнение 3: добавление событий Kubernetes
Задача 3.1: добавьте разрешение RBAC для событий
Контроллеру нужно разрешение на создание событий. Добавьте маркер RBAC kubebuilder в internal/controller/database_controller.go.
Найдите существующие маркеры RBAC (в начале файла, перед функцией Reconcile) и добавьте разрешение на события:
// +kubebuilder:rbac:groups=database.example.com,resources=databases,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=database.example.com,resources=databases/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=database.example.com,resources=databases/finalizers,verbs=update
// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch // <-- ADD THIS LINE
Затем перегенерируйте манифесты RBAC:
cd ~/postgres-operator
make manifests
Это обновит config/rbac/role.yaml, добавив разрешение на события.
Задача 3.2: добавьте регистратор событий (Event Recorder) в контроллер
Обновите internal/controller/database_controller.go:
Добавьте импорт:
import (
// ... existing imports ...
"k8s.io/client-go/tools/record"
)
Обновите структуру:
// DatabaseReconciler reconciles a Database object
type DatabaseReconciler struct {
client.Client
Scheme *runtime.Scheme
Recorder record.EventRecorder
}
Задача 3.3: обновите main.go, чтобы предоставить регистратор событий
Обновите cmd/main.go:
if err := (&controller.DatabaseReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("database-controller"),
}).SetupWithManager(mgr); err != nil {
Задача 3.4: генерируйте события в контроллере
Добавьте события в ключевых точках вашего контроллера. Обновите internal/controller/database_controller.go:
В handleProvisioning после создания StatefulSet:
func (r *DatabaseReconciler) handleProvisioning(ctx context.Context, db *databasev1.Database) (ctrl.Result, error) {
// ... existing code ...
if errors.IsNotFound(err) {
logger.Info("Creating StatefulSet", "database", db.Name)
if err := r.reconcileStatefulSet(ctx, db); err != nil {
r.Recorder.Event(db, "Warning", "CreateFailed", "Failed to create StatefulSet: "+err.Error())
return ctrl.Result{}, err
}
r.Recorder.Event(db, "Normal", "Created", "StatefulSet created successfully")
return ctrl.Result{Requeue: true}, nil
}
// ... rest of existing code ...
}
В handleVerifying, когда база данных становится готова:
func (r *DatabaseReconciler) handleVerifying(ctx context.Context, db *databasev1.Database) (ctrl.Result, error) {
// ... existing code ...
logger.Info("Database is now READY!", "database", db.Name, "endpoint", db.Status.Endpoint)
r.Recorder.Event(db, "Normal", "Ready", "Database is ready at "+db.Status.Endpoint)
return ctrl.Result{}, r.Status().Update(ctx, db)
}
В handleDeletion:
func (r *DatabaseReconciler) handleDeletion(ctx context.Context, db *databasev1.Database) (ctrl.Result, error) {
// ... at the beginning ...
r.Recorder.Event(db, "Normal", "Deleting", "Starting cleanup of database resources")
// ... at the end before removing finalizer ...
r.Recorder.Event(db, "Normal", "Deleted", "Cleanup completed successfully")
// ... rest of code ...
}
Задача 3.5: обновите тестовые файлы (важно!)
Поскольку мы добавили Recorder в структуру, обновите internal/controller/database_controller_test.go:
// In each test where you create DatabaseReconciler, add the Recorder field:
controllerReconciler := &DatabaseReconciler{
Client: k8sClient,
Scheme: k8sClient.Scheme(),
Recorder: record.NewFakeRecorder(100), // Add this line
}
Добавьте импорт:
import (
// ... existing imports ...
"k8s.io/client-go/tools/record"
)
Задача 3.6: пересоберите и разверните
cd ~/postgres-operator
# Run tests first to make sure they pass
make test
# Rebuild the operator (for docker)
make docker-build IMG=postgres-operator:latest
# Build with podman (note: image will be localhost/postgres-operator:latest)
make docker-build IMG=postgres-operator:latest CONTAINER_TOOL=podman
# Load into kind (for docker)
kind load docker-image postgres-operator:latest
# For podman: Load image into kind (save to tarball, then load)
podman save localhost/postgres-operator:latest -o /tmp/postgres-operator.tar
kind load image-archive /tmp/postgres-operator.tar --name k8s-operators-course
rm /tmp/postgres-operator.tar
# For docker: Deploy operator
make deploy IMG=postgres-operator:latest
# For podman: Deploy operator - use localhost/ prefix to match the loaded image
make deploy IMG=localhost/postgres-operator:latest
# Redeploy
kubectl rollout restart deployment -n postgres-operator-system postgres-operator-controller-manager
# Wait for it to be ready
kubectl wait --for=condition=ready pod -l control-plane=controller-manager -n postgres-operator-system --timeout=60s
Задача 3.7: протестируйте события
# Create a test database
kubectl apply -f - <<EOF
apiVersion: database.example.com/v1
kind: Database
metadata:
name: test-events
namespace: default
spec:
image: postgres:14
databaseName: eventsdb
username: eventsuser
storage:
size: 1Gi
EOF
# Wait for reconciliation
sleep 30
# View events for the database
kubectl get events --field-selector involvedObject.name=test-events --sort-by='.lastTimestamp'
# Or view all recent events
kubectl get events -n default --sort-by='.lastTimestamp' | head -20
Ожидаемый вывод:
LAST SEEN TYPE REASON OBJECT MESSAGE
30s Normal Created database/test-events StatefulSet created successfully
15s Normal Ready database/test-events Database is ready at test-events.default.svc.cluster.local:5432
Задача 3.8: очистка
kubectl delete database test-events
Упражнение 4: настройка отладчика Delve
Примечание: для этого упражнения вы запустите оператор локально (вне кластера) для отладки. Сначала уменьшите масштаб развёрнутого оператора, чтобы он не конфликтовал.
Задача 4.1: установите Delve
go install github.com/go-delve/delve/cmd/dlv@latest
# Verify installation
dlv version
Задача 4.2: подготовьтесь к локальной отладке
cd ~/postgres-operator
# Undeploy the operator (removes deployment, webhooks, and RBAC)
make undeploy
# Verify it's gone
kubectl get pods -n postgres-operator-system
# Reinstall CRDs (undeploy removes them)
make install
Задача 4.3: отладка с Delve
При локальном запуске оператора для отладки:
- Вебхуки должны быть отключены — им нужны TLS-сертификаты, которых локально нет
- CRD должны быть установлены — уже сделано в предыдущих упражнениях
- Kubeconfig должен быть валиден — используется ваш локальный контекст kubectl
cd ~/postgres-operator
# IMPORTANT: Disable webhooks (they require TLS certs that don't exist locally)
export ENABLE_WEBHOOKS=false
# Start the operator with Delve
dlv debug ./cmd/main.go -- \
--metrics-bind-address=:8080 \
--health-probe-bind-address=:8081 \
--metrics-secure=false
Теперь в консоли Delve:
# Set a breakpoint in the Reconcile function
(dlv) break internal/controller/database_controller.go:81
Breakpoint 1 set at ...
# Start the operator
(dlv) continue
Оператор теперь запущен. В другом терминале создайте Database, чтобы запустить согласование:
kubectl apply -f - <<EOF
apiVersion: database.example.com/v1
kind: Database
metadata:
name: debug-test
namespace: default
spec:
image: postgres:14
databaseName: debugdb
username: debuguser
storage:
size: 1Gi
EOF
Вернувшись в Delve, точка останова должна сработать:
# Inspect variables
(dlv) print req
(dlv) print req.NamespacedName
# Step through code
(dlv) next
(dlv) next
# After the db variable is populated:
(dlv) print db.Name
(dlv) print db.Spec
# Continue execution
(dlv) continue
# Exit when done
(dlv) quit
Задача 4.4: очистка сессии отладки
cd ~/postgres-operator
# For docker: Deploy operator
make deploy IMG=postgres-operator:latest
# For podman: Deploy operator - use localhost/ prefix to match the loaded image
make deploy IMG=localhost/postgres-operator:latest
# Wait for it to be ready
kubectl wait --for=condition=ready pod -l control-plane=controller-manager -n postgres-operator-system --timeout=60s
# Delete the test database
kubectl delete database debug-test
Задача 4.5: отладка в VS Code (альтернатива)
Для более удобной отладки создайте .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Operator",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/main.go",
"args": [
"--metrics-bind-address=:8080",
"--health-probe-bind-address=:8081",
"--metrics-secure=false"
],
"env": {
"ENABLE_WEBHOOKS": "false"
}
}
]
}
Затем:
- Сначала уменьшите масштаб развёрнутого оператора
- Установите точки останова, кликнув на полосе слева
- Нажмите F5, чтобы начать отладку
- В терминале создайте Database, чтобы сработала точка останова
- VS Code остановится на вашей точке останова
Задача 4.6: полезные команды Delve
break <file>:<line> - Set breakpoint
continue (c) - Continue execution
next (n) - Step over (next line)
step (s) - Step into function
print (p) <var> - Print variable value
locals - Show all local variables
stack - Show call stack
goroutines - List all goroutines
quit (q) - Exit debugger
Распространённые проблемы:
no such file or directory: tls.crt→ установитеENABLE_WEBHOOKS=falseTimeout: failed waiting for Informer to sync→ проверьте kubeconfig и связь с кластером- Точка останова не срабатывает → создайте ресурс Database, чтобы запустить согласование
Упражнение 5: полная проверка наблюдаемости
Задача 5.1: разверните и создайте тестовый ресурс
cd ~/postgres-operator
# For Docker: Make sure latest version is deployed
make docker-build IMG=postgres-operator:latest
kind load docker-image postgres-operator:latest
make deploy IMG=postgres-operator:latest
# For Podman
# Build with podman (note: image will be localhost/postgres-operator:latest)
make docker-build IMG=postgres-operator:latest CONTAINER_TOOL=podman
# For podman: Load image into kind (save to tarball, then load)
podman save localhost/postgres-operator:latest -o /tmp/postgres-operator.tar
kind load image-archive /tmp/postgres-operator.tar --name k8s-operators-course
rm /tmp/postgres-operator.tar
# For podman: Deploy operator - use localhost/ prefix to match the loaded image
make deploy IMG=localhost/postgres-operator:latest
# Redeploy
kubectl rollout restart deployment -n postgres-operator-system postgres-operator-controller-manager
# Wait for deployment
kubectl wait --for=condition=ready pod -l control-plane=controller-manager -n postgres-operator-system --timeout=120s
# Create test database
kubectl apply -f - <<EOF
apiVersion: database.example.com/v1
kind: Database
metadata:
name: observability-test
namespace: default
spec:
image: postgres:14
databaseName: obsdb
username: obsuser
storage:
size: 1Gi
EOF
Задача 5.2: проверьте все возможности наблюдаемости
echo "=== 1. Checking Logs ==="
kubectl logs -n postgres-operator-system -l control-plane=controller-manager --tail=50 | grep -E "(Reconciling|STATE TRANSITION|Creating|Ready)"
echo ""
echo "=== 2. Checking Events ==="
kubectl get events --field-selector involvedObject.name=observability-test --sort-by='.lastTimestamp'
echo ""
echo "=== 3. Checking Database Status ==="
kubectl get database observability-test -o jsonpath='{.status}' | jq .
echo ""
echo "=== 4. Checking Metrics ==="
# Note: This assumes you've disabled secure metrics (Option A from Exercise 2)
# If secure metrics are enabled, you'll need to use a token
kubectl port-forward -n postgres-operator-system deployment/postgres-operator-controller-manager 8080:8080 &
sleep 2
curl -s http://localhost:8080/metrics 2>/dev/null | grep -E "^database_" | head -20 || echo "Metrics not available (secure metrics may be enabled)"
pkill -f "port-forward.*8080" 2>/dev/null
# If secure metrics are enabled, use below
# Get a token for the ServiceAccount
TOKEN=$(kubectl create token -n postgres-operator-system postgres-operator-controller-manager)
# Port forward to the metrics service
kubectl port-forward -n postgres-operator-system svc/postgres-operator-controller-manager-metrics-service 8443:8443 &
sleep 2
# Query metrics with the token
curl -k -H "Authorization: Bearer $TOKEN" https://localhost:8443/metrics 2>/dev/null | grep database_
# Stop port-forward
pkill -f "port-forward.*8443"
Задача 5.3: очистка
kubectl delete database observability-test
Итоги лабораторной
В этой лабораторной вы:
- Проверили, что существующее структурированное логирование работает
- Добавили пользовательские метрики Prometheus для отслеживания согласования
- Добавили генерацию событий Kubernetes для видимости пользователю
- Научились использовать отладчик Delve для устранения неполадок
- Проверили, что все возможности наблюдаемости работают вместе
Ключевые уроки
- Структурированное логирование — уже настроено Kubebuilder; используйте
log.FromContext(ctx)с парами «ключ-значение» - Пользовательские метрики — регистрируйте через
metrics.Registry.MustRegister()в функцииinit() - Event Recorder — добавьте в структуру реконсайлера, получайте от менеджера через
mgr.GetEventRecorderFor() - События видны пользователю — используйте
Normalдля успеха,Warningдля ошибок - Обновляйте тесты — при добавлении полей в структуру реконсайлера обновляйте и тестовые файлы
- Отладка Delve — используйте
ENABLE_WEBHOOKS=falseдля локальной отладки - Защищённые метрики — современный Kubebuilder использует HTTPS с аутентификацией на порту 8443; используйте токен ServiceAccount для доступа
- Отключайте защищённые метрики для разработки — добавьте флаг
--metrics-secure=falseдля более простого локального тестирования
Решения
Полные рабочие решения для этой лабораторной доступны в каталоге решений:
- Metrics RBAC Binding — ClusterRoleBinding для доступа к метрикам
- RBAC Kustomization — обновлённый kustomization с привязкой метрик
- Metrics Implementation — пользовательские метрики Prometheus
- Observability Examples — паттерны логирования и событий
Поздравляем!
Вы завершили Модуль 6! Теперь вы понимаете:
- Основы и стратегии тестирования
- Модульное тестирование с envtest
- Интеграционное тестирование с реальными кластерами
- Отладку и наблюдаемость
В Модуле 7 вы изучите развёртывание в продакшене и лучшие практики!