Skip to content

Commit

Permalink
Merge pull request kubernetes#53205 from kawych/master
Browse files Browse the repository at this point in the history
Automatic merge from submit-queue (batch tested with PRs 50223, 53205). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Create e2e tests for Custom Metrics - Stackdriver Adapter and HPA based on custom metrics from Stackdriver

**What this PR does / why we need it**:
- Add e2e test for Custom Metrics - Stackdriver Adapter
- Add 2e2 test for HPA based on custom metrics from Stackdriver
- Enable HorizontalPodAutoscalerUseRESTClients option

**Release note**:

```release-note
Horizontal pod autoscaler uses REST clients through the kube-aggregator instead of the legacy client through the API server proxy.
```
  • Loading branch information
Kubernetes Submit Queue authored Oct 11, 2017
2 parents 82869c5 + f3fddae commit 0564d52
Show file tree
Hide file tree
Showing 9 changed files with 570 additions and 10 deletions.
4 changes: 4 additions & 0 deletions cluster/gce/gci/configure-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,10 @@ function start-kube-controller-manager {
if [[ -n "${CLUSTER_SIGNING_DURATION:-}" ]]; then
params+=" --experimental-cluster-signing-duration=$CLUSTER_SIGNING_DURATION"
fi
# disable using HPA metrics REST clients if metrics-server isn't enabled
if [[ "${ENABLE_METRICS_SERVER:-}" != "true" ]]; then
params+=" --horizontal-pod-autoscaler-use-rest-clients=false"
fi

local -r kube_rc_docker_tag=$(cat /home/kubernetes/kube-docker-files/kube-controller-manager.docker_tag)
local container_env=""
Expand Down
2 changes: 1 addition & 1 deletion cmd/kube-controller-manager/app/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func NewCMServer() *CMServer {
ClusterSigningDuration: metav1.Duration{Duration: helpers.OneYear},
ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 60 * time.Second},
EnableTaintManager: true,
HorizontalPodAutoscalerUseRESTClients: false,
HorizontalPodAutoscalerUseRESTClients: true,
},
}
s.LeaderElection.LeaderElect = true
Expand Down
19 changes: 10 additions & 9 deletions cmd/kube-controller-manager/app/options/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,16 @@ func TestAddFlags(t *testing.T) {
{Group: "apiregistration.k8s.io", Resource: "apiservices"},
{Group: "apiextensions.k8s.io", Resource: "customresourcedefinitions"},
},
NodeEvictionRate: 0.2,
SecondaryNodeEvictionRate: 0.05,
LargeClusterSizeThreshold: 100,
UnhealthyZoneThreshold: 0.6,
DisableAttachDetachReconcilerSync: true,
ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 30 * time.Second},
Controllers: []string{"foo", "bar"},
EnableTaintManager: false,
UseServiceAccountCredentials: true,
NodeEvictionRate: 0.2,
SecondaryNodeEvictionRate: 0.05,
LargeClusterSizeThreshold: 100,
UnhealthyZoneThreshold: 0.6,
DisableAttachDetachReconcilerSync: true,
ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 30 * time.Second},
Controllers: []string{"foo", "bar"},
EnableTaintManager: false,
HorizontalPodAutoscalerUseRESTClients: true,
UseServiceAccountCredentials: true,
},
Kubeconfig: "/kubeconfig",
Master: "192.168.4.20",
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/autoscaling/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ go_library(
"autoscaling_timer.go",
"cluster_autoscaler_scalability.go",
"cluster_size_autoscaling.go",
"custom_metrics_autoscaling.go",
"dns_autoscaling.go",
"framework.go",
"horizontal_pod_autoscaling.go",
Expand All @@ -19,11 +20,15 @@ go_library(
"//pkg/api:go_default_library",
"//test/e2e/common:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/instrumentation/monitoring:go_default_library",
"//test/e2e/scheduling:go_default_library",
"//test/utils:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/golang.org/x/oauth2/google:go_default_library",
"//vendor/google.golang.org/api/monitoring/v3:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
Expand Down
210 changes: 210 additions & 0 deletions test/e2e/autoscaling/custom_metrics_autoscaling.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/*
Copyright 2017 The Kubernetes Authors.
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 autoscaling

import (
"context"
"time"

"golang.org/x/oauth2/google"
clientset "k8s.io/client-go/kubernetes"

. "github.com/onsi/ginkgo"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/test/e2e/framework"

gcm "google.golang.org/api/monitoring/v3"
as "k8s.io/api/autoscaling/v2beta1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/kubernetes/test/e2e/instrumentation/monitoring"
)

const (
stackdriverExporterDeployment = "stackdriver-exporter-deployment"
dummyDeploymentName = "dummy-deployment"
stackdriverExporterPod = "stackdriver-exporter-pod"
)

var _ = SIGDescribe("[HPA] Horizontal pod autoscaling (scale resource: Custom Metrics from Stackdriver)", func() {
BeforeEach(func() {
framework.SkipUnlessProviderIs("gce")
})

f := framework.NewDefaultFramework("horizontal-pod-autoscaling")
var kubeClient clientset.Interface

It("should autoscale with Custom Metrics from Stackdriver [Feature:CustomMetricsAutoscaling]", func() {
kubeClient = f.ClientSet
testHPA(f, kubeClient)
})
})

func testHPA(f *framework.Framework, kubeClient clientset.Interface) {
projectId := framework.TestContext.CloudConfig.ProjectID

ctx := context.Background()
client, err := google.DefaultClient(ctx, gcm.CloudPlatformScope)

// Hack for running tests locally, needed to authenticate in Stackdriver
// If this is your use case, create application default credentials:
// $ gcloud auth application-default login
// and uncomment following lines:
/*
ts, err := google.DefaultTokenSource(oauth2.NoContext)
framework.Logf("Couldn't get application default credentials, %v", err)
if err != nil {
framework.Failf("Error accessing application default credentials, %v", err)
}
client := oauth2.NewClient(oauth2.NoContext, ts)
*/

gcmService, err := gcm.New(client)
if err != nil {
framework.Failf("Failed to create gcm service, %v", err)
}

// Set up a cluster: create a custom metric and set up k8s-sd adapter
err = monitoring.CreateDescriptors(gcmService, projectId)
if err != nil {
framework.Failf("Failed to create metric descriptor: %v", err)
}
defer monitoring.CleanupDescriptors(gcmService, projectId)

err = monitoring.CreateAdapter()
if err != nil {
framework.Failf("Failed to set up: %v", err)
}
defer monitoring.CleanupAdapter()

// Run application that exports the metric
err = createDeploymentsToScale(f, kubeClient)
if err != nil {
framework.Failf("Failed to create stackdriver-exporter pod: %v", err)
}
defer cleanupDeploymentsToScale(f, kubeClient)

// Autoscale the deployments
err = createPodsHPA(f, kubeClient)
if err != nil {
framework.Failf("Failed to create 'Pods' HPA: %v", err)
}
err = createObjectHPA(f, kubeClient)
if err != nil {
framework.Failf("Failed to create 'Objects' HPA: %v", err)
}

waitForReplicas(stackdriverExporterDeployment, f.Namespace.ObjectMeta.Name, kubeClient, 15*time.Minute, 1)
waitForReplicas(dummyDeploymentName, f.Namespace.ObjectMeta.Name, kubeClient, 15*time.Minute, 1)
}

func createDeploymentsToScale(f *framework.Framework, cs clientset.Interface) error {
_, err := cs.Extensions().Deployments(f.Namespace.ObjectMeta.Name).Create(monitoring.StackdriverExporterDeployment(stackdriverExporterDeployment, f.Namespace.Name, 2, 100))
if err != nil {
return err
}
_, err = cs.Core().Pods(f.Namespace.ObjectMeta.Name).Create(monitoring.StackdriverExporterPod(stackdriverExporterPod, f.Namespace.Name, stackdriverExporterPod, monitoring.CustomMetricName, 100))
if err != nil {
return err
}
_, err = cs.Extensions().Deployments(f.Namespace.ObjectMeta.Name).Create(monitoring.StackdriverExporterDeployment(dummyDeploymentName, f.Namespace.Name, 2, 100))
return err
}

func cleanupDeploymentsToScale(f *framework.Framework, cs clientset.Interface) {
_ = cs.Extensions().Deployments(f.Namespace.ObjectMeta.Name).Delete(stackdriverExporterDeployment, &metav1.DeleteOptions{})
_ = cs.Core().Pods(f.Namespace.ObjectMeta.Name).Delete(stackdriverExporterPod, &metav1.DeleteOptions{})
_ = cs.Extensions().Deployments(f.Namespace.ObjectMeta.Name).Delete(dummyDeploymentName, &metav1.DeleteOptions{})
}

func createPodsHPA(f *framework.Framework, cs clientset.Interface) error {
var minReplicas int32 = 1
_, err := cs.AutoscalingV2beta1().HorizontalPodAutoscalers(f.Namespace.ObjectMeta.Name).Create(&as.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-metrics-pods-hpa",
Namespace: f.Namespace.ObjectMeta.Name,
},
Spec: as.HorizontalPodAutoscalerSpec{
Metrics: []as.MetricSpec{
{
Type: as.PodsMetricSourceType,
Pods: &as.PodsMetricSource{
MetricName: monitoring.CustomMetricName,
TargetAverageValue: *resource.NewQuantity(200, resource.DecimalSI),
},
},
},
MaxReplicas: 3,
MinReplicas: &minReplicas,
ScaleTargetRef: as.CrossVersionObjectReference{
APIVersion: "extensions/v1beta1",
Kind: "Deployment",
Name: stackdriverExporterDeployment,
},
},
})
return err
}

func createObjectHPA(f *framework.Framework, cs clientset.Interface) error {
var minReplicas int32 = 1
_, err := cs.AutoscalingV2beta1().HorizontalPodAutoscalers(f.Namespace.ObjectMeta.Name).Create(&as.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-metrics-objects-hpa",
Namespace: f.Namespace.ObjectMeta.Name,
},
Spec: as.HorizontalPodAutoscalerSpec{
Metrics: []as.MetricSpec{
{
Type: as.ObjectMetricSourceType,
Object: &as.ObjectMetricSource{
MetricName: monitoring.CustomMetricName,
Target: as.CrossVersionObjectReference{
Kind: "Pod",
Name: stackdriverExporterPod,
},
TargetValue: *resource.NewQuantity(200, resource.DecimalSI),
},
},
},
MaxReplicas: 3,
MinReplicas: &minReplicas,
ScaleTargetRef: as.CrossVersionObjectReference{
APIVersion: "extensions/v1beta1",
Kind: "Deployment",
Name: dummyDeploymentName,
},
},
})
return err
}

func waitForReplicas(deploymentName, namespace string, cs clientset.Interface, timeout time.Duration, desiredReplicas int) {
interval := 20 * time.Second
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
deployment, err := cs.Extensions().Deployments(namespace).Get(deploymentName, metav1.GetOptions{})
if err != nil {
framework.Failf("Failed to get replication controller %s: %v", deployment, err)
}
replicas := int(deployment.Status.ReadyReplicas)
framework.Logf("waiting for %d replicas (current: %d)", desiredReplicas, replicas)
return replicas == desiredReplicas, nil // Expected number of replicas found. Exit.
})
if err != nil {
framework.Failf("Timeout waiting %v for %v replicas", timeout, desiredReplicas)
}
}
9 changes: 9 additions & 0 deletions test/e2e/instrumentation/monitoring/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ go_library(
name = "go_default_library",
srcs = [
"cadvisor.go",
"custom_metrics_deployments.go",
"custom_metrics_stackdriver.go",
"influxdb.go",
"metrics_grabber.go",
"stackdriver.go",
Expand All @@ -23,10 +25,17 @@ go_library(
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/golang.org/x/oauth2/google:go_default_library",
"//vendor/google.golang.org/api/monitoring/v3:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/selection:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/custom_metrics:go_default_library",
],
)

Expand Down
Loading

0 comments on commit 0564d52

Please sign in to comment.