mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #110027 from zlabjp/fix-ipallocator-metrics
Fix cluster IP allocator metrics
This commit is contained in:
commit
68fc207cd9
@ -213,6 +213,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(apiResourceConfigSource
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, fmt.Errorf("cannot create cluster IP allocator: %v", err)
|
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, fmt.Errorf("cannot create cluster IP allocator: %v", err)
|
||||||
}
|
}
|
||||||
|
serviceClusterIPAllocator.EnableMetrics()
|
||||||
restStorage.ServiceClusterIPAllocator = serviceClusterIPRegistry
|
restStorage.ServiceClusterIPAllocator = serviceClusterIPRegistry
|
||||||
|
|
||||||
// allocator for secondary service ip range
|
// allocator for secondary service ip range
|
||||||
@ -233,6 +234,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(apiResourceConfigSource
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, fmt.Errorf("cannot create cluster secondary IP allocator: %v", err)
|
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, fmt.Errorf("cannot create cluster secondary IP allocator: %v", err)
|
||||||
}
|
}
|
||||||
|
secondaryServiceClusterIPAllocator.EnableMetrics()
|
||||||
restStorage.SecondaryServiceClusterIPAllocator = secondaryServiceClusterIPRegistry
|
restStorage.SecondaryServiceClusterIPAllocator = secondaryServiceClusterIPRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ type Interface interface {
|
|||||||
IPFamily() api.IPFamily
|
IPFamily() api.IPFamily
|
||||||
Has(ip net.IP) bool
|
Has(ip net.IP) bool
|
||||||
Destroy()
|
Destroy()
|
||||||
|
EnableMetrics()
|
||||||
|
|
||||||
// DryRun offers a way to try operations without persisting them.
|
// DryRun offers a way to try operations without persisting them.
|
||||||
DryRun() Interface
|
DryRun() Interface
|
||||||
@ -86,12 +87,12 @@ type Range struct {
|
|||||||
family api.IPFamily
|
family api.IPFamily
|
||||||
|
|
||||||
alloc allocator.Interface
|
alloc allocator.Interface
|
||||||
|
// metrics is a metrics recorder that can be disabled
|
||||||
|
metrics metricsRecorderInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Range over a net.IPNet, calling allocatorFactory to construct the backing store.
|
// New creates a Range over a net.IPNet, calling allocatorFactory to construct the backing store.
|
||||||
func New(cidr *net.IPNet, allocatorFactory allocator.AllocatorWithOffsetFactory) (*Range, error) {
|
func New(cidr *net.IPNet, allocatorFactory allocator.AllocatorWithOffsetFactory) (*Range, error) {
|
||||||
registerMetrics()
|
|
||||||
|
|
||||||
max := netutils.RangeSize(cidr)
|
max := netutils.RangeSize(cidr)
|
||||||
base := netutils.BigForIP(cidr.IP)
|
base := netutils.BigForIP(cidr.IP)
|
||||||
rangeSpec := cidr.String()
|
rangeSpec := cidr.String()
|
||||||
@ -116,10 +117,11 @@ func New(cidr *net.IPNet, allocatorFactory allocator.AllocatorWithOffsetFactory)
|
|||||||
max--
|
max--
|
||||||
|
|
||||||
r := Range{
|
r := Range{
|
||||||
net: cidr,
|
net: cidr,
|
||||||
base: base,
|
base: base,
|
||||||
max: maximum(0, int(max)),
|
max: maximum(0, int(max)),
|
||||||
family: family,
|
family: family,
|
||||||
|
metrics: &emptyMetricsRecorder{}, // disabled by default
|
||||||
}
|
}
|
||||||
|
|
||||||
offset := 0
|
offset := 0
|
||||||
@ -201,8 +203,10 @@ func (r *Range) allocate(ip net.IP, dryRun bool) error {
|
|||||||
label := r.CIDR()
|
label := r.CIDR()
|
||||||
ok, offset := r.contains(ip)
|
ok, offset := r.contains(ip)
|
||||||
if !ok {
|
if !ok {
|
||||||
// update metrics
|
if !dryRun {
|
||||||
clusterIPAllocationErrors.WithLabelValues(label.String(), "static").Inc()
|
// update metrics
|
||||||
|
r.metrics.incrementAllocationErrors(label.String(), "static")
|
||||||
|
}
|
||||||
return &ErrNotInRange{ip, r.net.String()}
|
return &ErrNotInRange{ip, r.net.String()}
|
||||||
}
|
}
|
||||||
if dryRun {
|
if dryRun {
|
||||||
@ -214,20 +218,20 @@ func (r *Range) allocate(ip net.IP, dryRun bool) error {
|
|||||||
allocated, err := r.alloc.Allocate(offset)
|
allocated, err := r.alloc.Allocate(offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// update metrics
|
// update metrics
|
||||||
clusterIPAllocationErrors.WithLabelValues(label.String(), "static").Inc()
|
r.metrics.incrementAllocationErrors(label.String(), "static")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !allocated {
|
if !allocated {
|
||||||
// update metrics
|
// update metrics
|
||||||
clusterIPAllocationErrors.WithLabelValues(label.String(), "static").Inc()
|
r.metrics.incrementAllocationErrors(label.String(), "static")
|
||||||
|
|
||||||
return ErrAllocated
|
return ErrAllocated
|
||||||
}
|
}
|
||||||
// update metrics
|
// update metrics
|
||||||
clusterIPAllocations.WithLabelValues(label.String(), "static").Inc()
|
r.metrics.incrementAllocations(label.String(), "static")
|
||||||
clusterIPAllocated.WithLabelValues(label.String()).Set(float64(r.Used()))
|
r.metrics.setAllocated(label.String(), r.Used())
|
||||||
clusterIPAvailable.WithLabelValues(label.String()).Set(float64(r.Free()))
|
r.metrics.setAvailable(label.String(), r.Free())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -249,20 +253,20 @@ func (r *Range) allocateNext(dryRun bool) (net.IP, error) {
|
|||||||
offset, ok, err := r.alloc.AllocateNext()
|
offset, ok, err := r.alloc.AllocateNext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// update metrics
|
// update metrics
|
||||||
clusterIPAllocationErrors.WithLabelValues(label.String(), "dynamic").Inc()
|
r.metrics.incrementAllocationErrors(label.String(), "dynamic")
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
// update metrics
|
// update metrics
|
||||||
clusterIPAllocationErrors.WithLabelValues(label.String(), "dynamic").Inc()
|
r.metrics.incrementAllocationErrors(label.String(), "dynamic")
|
||||||
|
|
||||||
return nil, ErrFull
|
return nil, ErrFull
|
||||||
}
|
}
|
||||||
// update metrics
|
// update metrics
|
||||||
clusterIPAllocations.WithLabelValues(label.String(), "dynamic").Inc()
|
r.metrics.incrementAllocations(label.String(), "dynamic")
|
||||||
clusterIPAllocated.WithLabelValues(label.String()).Set(float64(r.Used()))
|
r.metrics.setAllocated(label.String(), r.Used())
|
||||||
clusterIPAvailable.WithLabelValues(label.String()).Set(float64(r.Free()))
|
r.metrics.setAvailable(label.String(), r.Free())
|
||||||
|
|
||||||
return netutils.AddIPOffset(r.base, offset), nil
|
return netutils.AddIPOffset(r.base, offset), nil
|
||||||
}
|
}
|
||||||
@ -287,8 +291,8 @@ func (r *Range) release(ip net.IP, dryRun bool) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// update metrics
|
// update metrics
|
||||||
label := r.CIDR()
|
label := r.CIDR()
|
||||||
clusterIPAllocated.WithLabelValues(label.String()).Set(float64(r.Used()))
|
r.metrics.setAllocated(label.String(), r.Used())
|
||||||
clusterIPAvailable.WithLabelValues(label.String()).Set(float64(r.Free()))
|
r.metrics.setAvailable(label.String(), r.Free())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -364,6 +368,12 @@ func (r *Range) Destroy() {
|
|||||||
r.alloc.Destroy()
|
r.alloc.Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableMetrics enables metrics recording.
|
||||||
|
func (r *Range) EnableMetrics() {
|
||||||
|
registerMetrics()
|
||||||
|
r.metrics = &metricsRecorder{}
|
||||||
|
}
|
||||||
|
|
||||||
// calculateIPOffset calculates the integer offset of ip from base such that
|
// calculateIPOffset calculates the integer offset of ip from base such that
|
||||||
// base + offset = ip. It requires ip >= base.
|
// base + offset = ip. It requires ip >= base.
|
||||||
func calculateIPOffset(base *big.Int, ip net.IP) int {
|
func calculateIPOffset(base *big.Int, ip net.IP) int {
|
||||||
@ -436,3 +446,6 @@ func (dry dryRunRange) Has(ip net.IP) bool {
|
|||||||
|
|
||||||
func (dry dryRunRange) Destroy() {
|
func (dry dryRunRange) Destroy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dry dryRunRange) EnableMetrics() {
|
||||||
|
}
|
||||||
|
@ -434,10 +434,12 @@ func TestClusterIPMetrics(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
||||||
}
|
}
|
||||||
|
a.EnableMetrics()
|
||||||
// create IPv6 allocator
|
// create IPv6 allocator
|
||||||
cidrIPv6 := "2001:db8::/112"
|
cidrIPv6 := "2001:db8::/112"
|
||||||
_, clusterCIDRv6, _ := netutils.ParseCIDRSloppy(cidrIPv6)
|
_, clusterCIDRv6, _ := netutils.ParseCIDRSloppy(cidrIPv6)
|
||||||
b, err := NewInMemory(clusterCIDRv6)
|
b, err := NewInMemory(clusterCIDRv6)
|
||||||
|
b.EnableMetrics()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
||||||
}
|
}
|
||||||
@ -546,6 +548,7 @@ func TestClusterIPAllocatedMetrics(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
||||||
}
|
}
|
||||||
|
a.EnableMetrics()
|
||||||
|
|
||||||
em := testMetrics{
|
em := testMetrics{
|
||||||
free: 0,
|
free: 0,
|
||||||
@ -595,6 +598,58 @@ func TestClusterIPAllocatedMetrics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMetricsDisabled(t *testing.T) {
|
||||||
|
// create metrics enabled allocator
|
||||||
|
cidrIPv4 := "10.0.0.0/24"
|
||||||
|
_, clusterCIDRv4, _ := netutils.ParseCIDRSloppy(cidrIPv4)
|
||||||
|
a, err := NewInMemory(clusterCIDRv4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
||||||
|
}
|
||||||
|
a.EnableMetrics()
|
||||||
|
|
||||||
|
// create metrics disabled allocator with same CIDR
|
||||||
|
// this metrics should be ignored
|
||||||
|
b, err := NewInMemory(clusterCIDRv4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error creating CidrSet: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check initial state
|
||||||
|
em := testMetrics{
|
||||||
|
free: 0,
|
||||||
|
used: 0,
|
||||||
|
allocated: 0,
|
||||||
|
errors: 0,
|
||||||
|
}
|
||||||
|
expectMetrics(t, cidrIPv4, em)
|
||||||
|
|
||||||
|
// allocate in metrics enabled allocator
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
_, err := a.AllocateNext()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
em = testMetrics{
|
||||||
|
free: 154,
|
||||||
|
used: 100,
|
||||||
|
allocated: 100,
|
||||||
|
errors: 0,
|
||||||
|
}
|
||||||
|
expectMetrics(t, cidrIPv4, em)
|
||||||
|
|
||||||
|
// allocate in metrics disabled allocator
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
_, err := b.AllocateNext()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the metrics should not be changed
|
||||||
|
expectMetrics(t, cidrIPv4, em)
|
||||||
|
}
|
||||||
|
|
||||||
// Metrics helpers
|
// Metrics helpers
|
||||||
func clearMetrics() {
|
func clearMetrics() {
|
||||||
clusterIPAllocated.Reset()
|
clusterIPAllocated.Reset()
|
||||||
|
@ -85,3 +85,38 @@ func registerMetrics() {
|
|||||||
legacyregistry.MustRegister(clusterIPAllocationErrors)
|
legacyregistry.MustRegister(clusterIPAllocationErrors)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// metricsRecorderInterface is the interface to record metrics.
|
||||||
|
type metricsRecorderInterface interface {
|
||||||
|
setAllocated(cidr string, allocated int)
|
||||||
|
setAvailable(cidr string, available int)
|
||||||
|
incrementAllocations(cidr, scope string)
|
||||||
|
incrementAllocationErrors(cidr, scope string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// metricsRecorder implements metricsRecorderInterface.
|
||||||
|
type metricsRecorder struct{}
|
||||||
|
|
||||||
|
func (m *metricsRecorder) setAllocated(cidr string, allocated int) {
|
||||||
|
clusterIPAllocated.WithLabelValues(cidr).Set(float64(allocated))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricsRecorder) setAvailable(cidr string, available int) {
|
||||||
|
clusterIPAvailable.WithLabelValues(cidr).Set(float64(available))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricsRecorder) incrementAllocations(cidr, scope string) {
|
||||||
|
clusterIPAllocations.WithLabelValues(cidr, scope).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricsRecorder) incrementAllocationErrors(cidr, scope string) {
|
||||||
|
clusterIPAllocationErrors.WithLabelValues(cidr, scope).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// emptyMetricsRecorder is a null object implements metricsRecorderInterface.
|
||||||
|
type emptyMetricsRecorder struct{}
|
||||||
|
|
||||||
|
func (*emptyMetricsRecorder) setAllocated(cidr string, allocated int) {}
|
||||||
|
func (*emptyMetricsRecorder) setAvailable(cidr string, available int) {}
|
||||||
|
func (*emptyMetricsRecorder) incrementAllocations(cidr, scope string) {}
|
||||||
|
func (*emptyMetricsRecorder) incrementAllocationErrors(cidr, scope string) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user