Skip to content

Commit

Permalink
feat(service create/update): Add support of minScale/maxScale/concurr…
Browse files Browse the repository at this point in the history
…ency-target/concurrency-limit

Autoscaler concurrency annotations are added to the revision template if
--min-scale / --max-scale / --concurrency-target/--concurrency-limit
are provided to `kn service create` and `kn service update`

Fixes #151
  • Loading branch information
rhuss committed Jun 7, 2019
1 parent 8a1adf0 commit 143f363
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 23 deletions.
4 changes: 4 additions & 0 deletions docs/cmd/kn_service_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ kn service create NAME --image IMAGE [flags]
### Options

```
--concurrency-limit int Hard Limit of concurrent requests to be processed by a single replica.
--concurrency-target int Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given.
-e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables.
--force Create service forcefully, replaces existing service if any.
-h, --help help for create
--image string Image to run.
--limits-cpu string The limits on the requested CPU (e.g., 1000m).
--limits-memory string The limits on the requested CPU (e.g., 1024Mi).
--max-scale int Maximal number of replicas.
--min-scale int Minimal number of replicas.
-n, --namespace string List the requested object(s) in given namespace.
--requests-cpu string The requested CPU (e.g., 250m).
--requests-memory string The requested CPU (e.g., 64Mi).
Expand Down
4 changes: 4 additions & 0 deletions docs/cmd/kn_service_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ kn service update NAME [flags]
### Options

```
--concurrency-limit int Hard Limit of concurrent requests to be processed by a single replica.
--concurrency-target int Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given.
-e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables.
-h, --help help for update
--image string Image to run.
--limits-cpu string The limits on the requested CPU (e.g., 1000m).
--limits-memory string The limits on the requested CPU (e.g., 1024Mi).
--max-scale int Maximal number of replicas.
--min-scale int Minimal number of replicas.
-n, --namespace string List the requested object(s) in given namespace.
--requests-cpu string The requested CPU (e.g., 250m).
--requests-memory string The requested CPU (e.g., 64Mi).
Expand Down
11 changes: 11 additions & 0 deletions pkg/kn/commands/service/configuration_edit_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ type ConfigurationEditFlags struct {
Env []string
RequestsFlags, LimitsFlags ResourceFlags
ForceCreate bool
MinScale int
MaxScale int
ConcurrencyTarget int
ConcurrencyLimit int
}

type ResourceFlags struct {
Expand All @@ -46,6 +50,10 @@ func (p *ConfigurationEditFlags) AddUpdateFlags(command *cobra.Command) {
command.Flags().StringVar(&p.RequestsFlags.Memory, "requests-memory", "", "The requested CPU (e.g., 64Mi).")
command.Flags().StringVar(&p.LimitsFlags.CPU, "limits-cpu", "", "The limits on the requested CPU (e.g., 1000m).")
command.Flags().StringVar(&p.LimitsFlags.Memory, "limits-memory", "", "The limits on the requested CPU (e.g., 1024Mi).")
command.Flags().IntVar(&p.MinScale, "min-scale", 0, "Minimal number of replicas.")
command.Flags().IntVar(&p.MaxScale, "max-scale", 0, "Maximal number of replicas.")
command.Flags().IntVar(&p.ConcurrencyTarget, "concurrency-target", 0, "Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given.")
command.Flags().IntVar(&p.ConcurrencyLimit, "concurrency-limit", 0, "Hard Limit of concurrent requests to be processed by a single replica.")
}

func (p *ConfigurationEditFlags) AddCreateFlags(command *cobra.Command) {
Expand Down Expand Up @@ -93,6 +101,9 @@ func (p *ConfigurationEditFlags) Apply(service *servingv1alpha1.Service, cmd *co
if err != nil {
return err
}

servinglib.UpdateConcurrencyConfiguration(template, p.MinScale, p.MaxScale, p.ConcurrencyTarget, p.ConcurrencyLimit)

return nil
}

Expand Down
36 changes: 36 additions & 0 deletions pkg/kn/commands/service/service_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,42 @@ func TestServiceCreateRequestsLimitsMemory(t *testing.T) {
}
}

func TestServiceCreateMaxMinScale(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz",
"--min-scale", "1", "--max-scale", "5", "--concurrency-target", "10", "--concurrency-limit", "100"})

if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "services") {
t.Fatalf("Bad action %v", action)
}

template, err := servinglib.GetRevisionTemplate(created)
if err != nil {
t.Fatal(err)
}

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
"autoscaling.knative.dev/target", "10",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}

if template.Spec.ContainerConcurrency != 100 {
t.Fatalf("container concurrency not set to given value 1000")
}
}

func TestServiceCreateRequestsLimitsCPUMemory(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz",
Expand Down
85 changes: 64 additions & 21 deletions pkg/kn/commands/service/service_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,7 @@ func fakeServiceUpdate(original *v1alpha1.Service, args []string) (
}

func TestServiceUpdateImage(t *testing.T) {
orig := &v1alpha1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "knative.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
},
Spec: v1alpha1.ServiceSpec{
DeprecatedRunLatest: &v1alpha1.RunLatestType{
Configuration: v1alpha1.ConfigurationSpec{
DeprecatedRevisionTemplate: &v1alpha1.RevisionTemplateSpec{
Spec: v1alpha1.RevisionSpec{
DeprecatedContainer: &corev1.Container{},
},
},
},
},
},
}
orig := newEmptyService()

template, err := servinglib.GetRevisionTemplate(orig)
if err != nil {
Expand All @@ -110,6 +90,45 @@ func TestServiceUpdateImage(t *testing.T) {
}
}

func TestServiceUpdateMaxMinScale(t *testing.T) {
original := newEmptyService()

action, updated, _, err := fakeServiceUpdate(original, []string{
"service", "update", "foo",
"--min-scale", "1", "--max-scale", "5", "--concurrency-target", "10", "--concurrency-limit", "100"})

if err != nil {
t.Fatal(err)
} else if !action.Matches("update", "services") {
t.Fatalf("Bad action %v", action)
}

template, err := servinglib.GetRevisionTemplate(updated)
if err != nil {
t.Fatal(err)
}

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
"autoscaling.knative.dev/target", "10",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}

if template.Spec.ContainerConcurrency != 100 {
t.Fatalf("container concurrency not set to given value 1000")
}

}

func TestServiceUpdateEnv(t *testing.T) {
orig := &v1alpha1.Service{
TypeMeta: metav1.TypeMeta{
Expand Down Expand Up @@ -279,6 +298,30 @@ func TestServiceUpdateRequestsLimitsCPU_and_Memory(t *testing.T) {
}
}

func newEmptyService() *v1alpha1.Service {
return &v1alpha1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "knative.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
},
Spec: v1alpha1.ServiceSpec{
DeprecatedRunLatest: &v1alpha1.RunLatestType{
Configuration: v1alpha1.ConfigurationSpec{
DeprecatedRevisionTemplate: &v1alpha1.RevisionTemplateSpec{
Spec: v1alpha1.RevisionSpec{
DeprecatedContainer: &corev1.Container{},
},
},
},
},
},
}
}

func createMockServiceWithResources(t *testing.T, requestCPU, requestMemory, limitsCPU, limitsMemory string) *v1alpha1.Service {
service := &v1alpha1.Service{
TypeMeta: metav1.TypeMeta{
Expand Down
29 changes: 29 additions & 0 deletions pkg/serving/config_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ package serving

import (
"fmt"
"strconv"

servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
servingv1beta1 "github.com/knative/serving/pkg/apis/serving/v1beta1"
corev1 "k8s.io/api/core/v1"
)

Expand All @@ -33,6 +35,33 @@ func UpdateEnvVars(template *servingv1alpha1.RevisionTemplateSpec, vars map[stri
return nil
}

// Update min and max scale annotation if larger than 0
func UpdateConcurrencyConfiguration(template *servingv1alpha1.RevisionTemplateSpec, minScale int, maxScale int, target int, limit int) {
if minScale != 0 {
UpdateAnnotation(template, "autoscaling.knative.dev/minScale", strconv.Itoa(minScale))
}
if maxScale != 0 {
UpdateAnnotation(template, "autoscaling.knative.dev/maxScale", strconv.Itoa(maxScale))
}
if target != 0 {
UpdateAnnotation(template, "autoscaling.knative.dev/target", strconv.Itoa(target))
}

if limit != 0 {
template.Spec.ContainerConcurrency = servingv1beta1.RevisionContainerConcurrencyType(limit)
}
}

// Updater (or add) an annotation to the given service
func UpdateAnnotation(template *servingv1alpha1.RevisionTemplateSpec, annotation string, value string) {
annoMap := template.Annotations
if annoMap == nil {
annoMap = make(map[string]string)
template.Annotations = annoMap
}
annoMap[annotation] = value
}

// Utility function to translate between the API list form of env vars, and the
// more convenient map form.
func EnvToMap(vars []corev1.EnvVar) (map[string]string, error) {
Expand Down
18 changes: 18 additions & 0 deletions pkg/serving/config_changes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ import (
corev1 "k8s.io/api/core/v1"
)

func TestUpdateAutoscalingAnnotations(t *testing.T) {
template := &servingv1alpha1.RevisionTemplateSpec{}
UpdateConcurrencyConfiguration(template, 10, 100, 1000, 1000)
annos := template.Annotations
if annos["autoscaling.knative.dev/minScale"] != "10" {
t.Error("minScale failed")
}
if annos["autoscaling.knative.dev/maxScale"] != "100" {
t.Error("maxScale failed")
}
if annos["autoscaling.knative.dev/target"] != "1000" {
t.Error("target failed")
}
if template.Spec.ContainerConcurrency != 1000 {
t.Error("limit failed")
}
}

func TestUpdateEnvVarsNew(t *testing.T) {
template, container := getV1alpha1RevisionTemplateWithOldFields()
testUpdateEnvVarsNew(t, template, container)
Expand Down
4 changes: 2 additions & 2 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1
github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake
github.com/knative/serving/pkg/apis/serving
github.com/knative/serving/pkg/apis/serving/v1alpha1
github.com/knative/serving/pkg/apis/serving/v1beta1
github.com/knative/serving/pkg/client/clientset/versioned/scheme
github.com/knative/serving/pkg/apis/autoscaling
github.com/knative/serving/pkg/apis/networking
github.com/knative/serving/pkg/apis/networking/v1alpha1
github.com/knative/serving/pkg/apis/serving/v1beta1
github.com/knative/serving/pkg/apis/autoscaling/v1alpha1
github.com/knative/serving/pkg/apis/config
github.com/knative/serving/pkg/apis/autoscaling/v1alpha1
# github.com/knative/test-infra v0.0.0-20190531180034-a3c073a2fea1
github.com/knative/test-infra/scripts
# github.com/magiconair/properties v1.8.0
Expand Down

0 comments on commit 143f363

Please sign in to comment.