Skip to content

Commit

Permalink
Merge pull request #156 from kitianFresh/feature/support-cron-for-ehpa
Browse files Browse the repository at this point in the history
Cron-based autoscaling for EHPA
  • Loading branch information
qmhu authored Mar 8, 2022
2 parents ae7567f + 390805a commit f0b540f
Show file tree
Hide file tree
Showing 24 changed files with 1,677 additions and 310 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ COPY cmd cmd/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="${LDFLAGS}" -a -o ${PKGNAME} /go/src/github.com/gocrane/crane/cmd/${PKGNAME}/main.go

FROM alpine:3.13.5
RUN apk add --no-cache tzdata
WORKDIR /
ARG PKGNAME
COPY --from=builder /go/src/github.com/gocrane/crane/${PKGNAME} .
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ ifeq (, $(shell which mockgen))
go install github.com/golang/mock/mockgen ;\
rm -rf $$GO_MOCKGEN_TMP_DIR ;\
}
GO_IMPORTS=$(shell go env GOPATH)/bin/mockgen
GO_MOCKGEN=$(shell go env GOPATH)/bin/mockgen
else
GO_IMPORTS=$(shell which mockgen)
GO_MOCKGEN=$(shell which mockgen)
endif
5 changes: 3 additions & 2 deletions cmd/craned/app/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ func Run(ctx context.Context, opts *options.Options) error {
return err
}

initializationControllers(ctx, mgr, opts)
klog.Info("Starting crane manager")

if opts.WebhookConfig.Enabled {
initializationWebhooks(mgr)
}
initializationControllers(ctx, mgr, opts)
klog.Info("Starting crane manager")

// initialization custom collector metrics
initializationMetricCollector(mgr)
Expand Down
42 changes: 23 additions & 19 deletions cmd/metric-adapter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@ package main

import (
"flag"
"fmt"
"os"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/client-go/kubernetes"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
basecmd "sigs.k8s.io/custom-metrics-apiserver/pkg/cmd"
"sigs.k8s.io/custom-metrics-apiserver/pkg/provider"

Expand Down Expand Up @@ -50,19 +48,13 @@ type MetricAdapter struct {
Message string
}

func (a *MetricAdapter) makeProvider(remoteAdapter *metricprovider.RemoteAdapter, config *rest.Config, client client.Client) (provider.CustomMetricsProvider, error) {
kubeClient, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("unable to create kube client: %v", err)
}
func (a *MetricAdapter) makeCustomMetricProvider(remoteAdapter *metricprovider.RemoteAdapter, client client.Client, recorder record.EventRecorder) provider.CustomMetricsProvider {

broadcaster := record.NewBroadcaster()
broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{
Interface: kubeClient.CoreV1().Events(""),
})
recorder := broadcaster.NewRecorder(scheme, corev1.EventSource{Component: "crane-metric-adapter"})
return metricprovider.NewCustomMetricProvider(client, remoteAdapter, recorder)
}

return metricprovider.NewMetricProvider(client, remoteAdapter, recorder), nil
func (a *MetricAdapter) makeExternalMetricProvider(client client.Client, recorder record.EventRecorder) *metricprovider.ExternalMetricProvider {
return metricprovider.NewExternalMetricProvider(client, recorder)
}

func main() {
Expand Down Expand Up @@ -117,15 +109,27 @@ func main() {
}
}

metricProvider, err := cmd.makeProvider(remoteAdapter, config, client)
kubeClient, err := kubernetes.NewForConfig(config)
if err != nil {
klog.Error(err, "Failed to make provider")
os.Exit(1)
klog.Exitf("Failed to create kube client: %v", err)
}
cmd.WithCustomMetrics(metricProvider)

broadcaster := record.NewBroadcaster()
broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{
Interface: kubeClient.CoreV1().Events(""),
})
recorder := broadcaster.NewRecorder(scheme, corev1.EventSource{Component: "crane-metric-adapter"})

ctx := signals.SetupSignalHandler()

customMetricProvider := cmd.makeCustomMetricProvider(remoteAdapter, client, recorder)
externalMetricProvider := cmd.makeExternalMetricProvider(client, recorder)

cmd.WithCustomMetrics(customMetricProvider)
cmd.WithExternalMetrics(externalMetricProvider)

klog.Infof(cmd.Message)
if err := cmd.Run(wait.NeverStop); err != nil {
if err := cmd.Run(ctx.Done()); err != nil {
klog.Error(err, "Failed to run metrics adapter")
os.Exit(1)
}
Expand Down
3 changes: 3 additions & 0 deletions deploy/craned/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ spec:
- name: craned
image: docker.io/gocrane/craned:v0.2.0
imagePullPolicy: IfNotPresent
env:
- name: TZ
value: Asia/Shanghai
command:
- /craned
- --prometheus-address=PROMETHEUS_ADDRESS
Expand Down
294 changes: 168 additions & 126 deletions deploy/craned/webhooks.yaml

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion deploy/metric-adapter/apiservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,19 @@ spec:
version: v1beta2
insecureSkipTLSVerify: true
groupPriorityMinimum: 100
versionPriority: 200
versionPriority: 200

---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1beta1.external.metrics.k8s.io
spec:
service:
name: metric-adapter
namespace: crane-system
group: external.metrics.k8s.io
version: v1beta1
insecureSkipTLSVerify: true
groupPriorityMinimum: 100
versionPriority: 100
3 changes: 3 additions & 0 deletions deploy/metric-adapter/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ spec:
- name: metric-adapter
image: docker.io/gocrane/metric-adapter:v0.2.0
imagePullPolicy: IfNotPresent
env:
- name: TZ
value: Asia/Shanghai
args:
- /metric-adapter
- --secure-port=6443
Expand Down
63 changes: 63 additions & 0 deletions examples/autoscaling/effective-hpa-cron-local.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
metadata:
name: php-apache-local
spec:
# ScaleTargetRef is the reference to the workload that should be scaled.
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1 # MinReplicas is the lower limit replicas to the scale target which the autoscaler can scale down to.
maxReplicas: 10 # MaxReplicas is the upper limit replicas to the scale target which the autoscaler can scale up to.
scaleStrategy: Auto # ScaleStrategy indicate the strategy to scaling target, value can be "Auto" and "Manual".
# Better to setting cron to fill the one complete time period such as one day, one week
# Below is one day cron scheduling, it
#100 -------- --------- ----------
# | | | | | |
#1 ------------ ----- -------- ----------
#(time) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# Local timezone means you use the server's(or maybe is a container's) timezone which the craned running in. for example, if your craned started as utc timezone, then it is utc. if it started as Asia/Shanghai, then it is Asia/Shanghai.
crons:
- name: "cron1"
timezone: "Local"
description: "keep normal"
start: "0 0 ? * *"
end: "0 6 ? * *"
targetReplicas: 1
- name: "cron2"
timezone: "Local"
description: "scale up"
start: "0 6 ? * *"
end: "0 9 ? * *"
targetReplicas: 100
- name: "cron3"
timezone: "Local"
description: "scale down"
start: "00 9 ? * *"
end: "00 11 ? * *"
targetReplicas: 1
- name: "cron4"
timezone: "Local"
description: "scale up"
start: "00 11 ? * *"
end: "00 14 ? * *"
targetReplicas: 100
- name: "cron5"
timezone: "Local"
description: "scale down"
start: "00 14 ? * *"
end: "00 17 ? * *"
targetReplicas: 1
- name: "cron6"
timezone: "Local"
description: "scale up"
start: "00 17 ? * *"
end: "00 20 ? * *"
targetReplicas: 100
- name: "cron7"
timezone: "Local"
description: "keep normal"
start: "00 20 ? * *"
end: "00 00 ? * *"
targetReplicas: 1
62 changes: 62 additions & 0 deletions examples/autoscaling/effective-hpa-cron-shanghai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
metadata:
name: php-apache-shanghai
spec:
# ScaleTargetRef is the reference to the workload that should be scaled.
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1 # MinReplicas is the lower limit replicas to the scale target which the autoscaler can scale down to.
maxReplicas: 10 # MaxReplicas is the upper limit replicas to the scale target which the autoscaler can scale up to.
scaleStrategy: Auto # ScaleStrategy indicate the strategy to scaling target, value can be "Auto" and "Manual".
# Better to setting cron to fill the one complete time period such as one day, one week
# Below is one day cron scheduling, it
#100 -------- --------- ----------
# | | | | | |
#1 ------------ ----- -------- ----------
#(time) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
crons:
- name: "cron1"
timezone: "Asia/Shanghai"
description: "keep normal"
start: "0 0 ? * *"
end: "0 6 ? * *"
targetReplicas: 1
- name: "cron2"
timezone: "Asia/Shanghai"
description: "scale up"
start: "0 6 ? * *"
end: "0 9 ? * *"
targetReplicas: 100
- name: "cron3"
timezone: "Asia/Shanghai"
description: "scale down"
start: "00 9 ? * *"
end: "00 11 ? * *"
targetReplicas: 1
- name: "cron4"
timezone: "Asia/Shanghai"
description: "scale up"
start: "00 11 ? * *"
end: "00 14 ? * *"
targetReplicas: 100
- name: "cron5"
timezone: "Asia/Shanghai"
description: "scale down"
start: "00 14 ? * *"
end: "00 17 ? * *"
targetReplicas: 1
- name: "cron6"
timezone: "Asia/Shanghai"
description: "scale up"
start: "00 17 ? * *"
end: "00 20 ? * *"
targetReplicas: 100
- name: "cron7"
timezone: "Asia/Shanghai"
description: "keep normal"
start: "00 20 ? * *"
end: "00 00 ? * *"
targetReplicas: 1
55 changes: 55 additions & 0 deletions examples/autoscaling/effective-hpa-cron.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
metadata:
name: php-apache
spec:
# ScaleTargetRef is the reference to the workload that should be scaled.
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1 # MinReplicas is the lower limit replicas to the scale target which the autoscaler can scale down to.
maxReplicas: 10 # MaxReplicas is the upper limit replicas to the scale target which the autoscaler can scale up to.
scaleStrategy: Auto # ScaleStrategy indicate the strategy to scaling target, value can be "Auto" and "Manual".
# Better to setting cron to fill the one complete time period such as one day, one week
# Below is one day cron scheduling, it
#100 -------- --------- ----------
# | | | | | |
#1 ------------ ----- -------- ----------
#(time) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
crons:
- name: "cron1"
description: "keep normal"
start: "0 0 ? * *"
end: "0 6 ? * *"
targetReplicas: 1
- name: "cron2"
description: "scale up"
start: "0 6 ? * *"
end: "0 9 ? * *"
targetReplicas: 100
- name: "cron3"
description: "scale down"
start: "00 9 ? * *"
end: "00 11 ? * *"
targetReplicas: 1
- name: "cron4"
description: "scale up"
start: "00 11 ? * *"
end: "00 14 ? * *"
targetReplicas: 100
- name: "cron5"
description: "scale down"
start: "00 14 ? * *"
end: "00 17 ? * *"
targetReplicas: 1
- name: "cron6"
description: "scale up"
start: "00 17 ? * *"
end: "00 20 ? * *"
targetReplicas: 100
- name: "cron7"
description: "keep normal"
start: "00 20 ? * *"
end: "00 00 ? * *"
targetReplicas: 1
Loading

0 comments on commit f0b540f

Please sign in to comment.