diff --git a/CHANGELOG.md b/CHANGELOG.md index 573849fe5..7d522fee0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [NEXT_RELEASE] +### Added +- Nginx default `requests` quota value for cpu and memory + ## [0.33.0] - 2020-06-23 ### Added - Verification to avoid ingress duplication when an unmanaged ingress exists diff --git a/pkg/server/k8s/converters.go b/pkg/server/k8s/converters.go index 2a4d79448..9addd666f 100644 --- a/pkg/server/k8s/converters.go +++ b/pkg/server/k8s/converters.go @@ -38,21 +38,20 @@ func containerSpecsToK8sContainers(containerSpecs []*spec.Container) ([]k8sv1.Co Image: cs.Image, } - if cs.ContainerLimits != nil { - cpu, err := resource.ParseQuantity(cs.ContainerLimits.CPU) + if cs.ContainerRequests != nil { + requests, err := containerQuotaToResourceList(cs.ContainerRequests) if err != nil { return nil, err } - memory, err := resource.ParseQuantity(cs.ContainerLimits.Memory) + c.Resources.Requests = requests + } + + if cs.ContainerLimits != nil { + limits, err := containerQuotaToResourceList(cs.ContainerLimits) if err != nil { return nil, err } - c.Resources = k8sv1.ResourceRequirements{ - Limits: k8sv1.ResourceList{ - k8sv1.ResourceCPU: cpu, - k8sv1.ResourceMemory: memory, - }, - } + c.Resources.Limits = limits } if len(cs.Command) > 0 { @@ -95,6 +94,22 @@ func containerSpecsToK8sContainers(containerSpecs []*spec.Container) ([]k8sv1.Co return containers, nil } +func containerQuotaToResourceList(quota *spec.ContainerLimits) (k8sv1.ResourceList, error) { + cpu, err := resource.ParseQuantity(quota.CPU) + if err != nil { + return nil, err + } + memory, err := resource.ParseQuantity(quota.Memory) + if err != nil { + return nil, err + } + + return k8sv1.ResourceList{ + k8sv1.ResourceCPU: cpu, + k8sv1.ResourceMemory: memory, + }, nil +} + func podSpecVolumesToK8sVolumes(vols []*spec.Volume) []k8sv1.Volume { volumes := make([]k8sv1.Volume, 0) for _, v := range vols { @@ -134,9 +149,9 @@ func podSpecToK8sPod(podSpec *spec.Pod) (*k8sv1.Pod, error) { } ps := k8sv1.PodSpec{ - RestartPolicy: k8sv1.RestartPolicyNever, - Containers: containers, - Volumes: volumes, + RestartPolicy: k8sv1.RestartPolicyNever, + Containers: containers, + Volumes: volumes, AutomountServiceAccountToken: &f, InitContainers: initContainers, } @@ -179,9 +194,9 @@ func deploySpecToK8sDeploy(deploySpec *spec.Deploy, replicas int32) (*v1beta2.De return nil, err } ps := k8sv1.PodSpec{ - RestartPolicy: k8sv1.RestartPolicyAlways, - Containers: containers, - Volumes: volumes, + RestartPolicy: k8sv1.RestartPolicyAlways, + Containers: containers, + Volumes: volumes, AutomountServiceAccountToken: &f, InitContainers: initContainers, DNSConfig: dnsConfigToK8sDNSConfig(deploySpec.DNSConfig), @@ -253,9 +268,9 @@ func cronJobSpecToK8sCronJob(cronJobSpec *spec.CronJob) (*k8sv1beta1.CronJob, er f := false ps := k8sv1.PodSpec{ - RestartPolicy: k8sv1.RestartPolicyNever, - Containers: containers, - Volumes: volumes, + RestartPolicy: k8sv1.RestartPolicyNever, + Containers: containers, + Volumes: volumes, AutomountServiceAccountToken: &f, InitContainers: initContainers, } diff --git a/pkg/server/k8s/converters_test.go b/pkg/server/k8s/converters_test.go index 4b8eddab5..625a4f2e4 100644 --- a/pkg/server/k8s/converters_test.go +++ b/pkg/server/k8s/converters_test.go @@ -28,6 +28,10 @@ func TestPodSpecToK8sContainers(t *testing.T) { CPU: "800m", Memory: "1Gi", }, + ContainerRequests: &spec.ContainerLimits{ + CPU: "100m", + Memory: "512Mi", + }, }}, } containers, err := podSpecToK8sContainers(ps) @@ -89,7 +93,30 @@ func TestPodSpecToK8sContainers(t *testing.T) { } } - expectedCPU, err := resource.ParseQuantity(ps.Containers[0].ContainerLimits.CPU) + expectedCPU, err := resource.ParseQuantity(ps.Containers[0].ContainerRequests.CPU) + if err != nil { + t.Fatal("error in default cpu limit:", err) + } + if c.Resources.Requests[k8sv1.ResourceCPU] != expectedCPU { + t.Errorf( + "expected %v, got %v", + expectedCPU, + c.Resources.Requests[k8sv1.ResourceCPU], + ) + } + expectedMemory, err := resource.ParseQuantity(ps.Containers[0].ContainerRequests.Memory) + if err != nil { + t.Fatal("error in default memory limit:", err) + } + if c.Resources.Requests[k8sv1.ResourceMemory] != expectedMemory { + t.Errorf( + "expected %v, got %v", + expectedMemory, + c.Resources.Requests[k8sv1.ResourceMemory], + ) + } + + expectedCPU, err = resource.ParseQuantity(ps.Containers[0].ContainerLimits.CPU) if err != nil { t.Fatal("error in default cpu limit:", err) } @@ -100,7 +127,7 @@ func TestPodSpecToK8sContainers(t *testing.T) { c.Resources.Limits[k8sv1.ResourceCPU], ) } - expectedMemory, err := resource.ParseQuantity(ps.Containers[0].ContainerLimits.Memory) + expectedMemory, err = resource.ParseQuantity(ps.Containers[0].ContainerLimits.Memory) if err != nil { t.Fatal("error in default memory limit:", err) } @@ -579,9 +606,9 @@ func TestK8sServiceToService(t *testing.T) { Namespace: namespace, }, Spec: k8sv1.ServiceSpec{ - Type: k8sv1.ServiceType(svcType), + Type: k8sv1.ServiceType(svcType), LoadBalancerSourceRanges: ranges, - Ports: []k8sv1.ServicePort{{}}, + Ports: []k8sv1.ServicePort{{}}, }, } svc := k8sServiceToService(k8sSvc) @@ -724,3 +751,30 @@ func TestDeploySpecPodTemplateAnnotations(t *testing.T) { t.Errorf("got %v; want %v", got, want) } } + +func TestContainerQuotaToResourceList(t *testing.T) { + quota := &spec.ContainerLimits{ + CPU: "100m", + Memory: "1Gi", + } + expectedCPU, err := resource.ParseQuantity(quota.CPU) + if err != nil { + t.Error("Error parsing default CPU value") + } + expectedMemory, err := resource.ParseQuantity(quota.Memory) + if err != nil { + t.Error("Error parsing default Memory value") + } + + rl, err := containerQuotaToResourceList(quota) + if err != nil { + t.Errorf("Got an unexpected error, %v", err) + } + + if rl[k8sv1.ResourceCPU] != expectedCPU { + t.Errorf("expected %v, got %v", expectedCPU, rl[k8sv1.ResourceCPU]) + } + if rl[k8sv1.ResourceMemory] != expectedMemory { + t.Errorf("expected %v, got %v", expectedMemory, rl[k8sv1.ResourceMemory]) + } +} diff --git a/pkg/server/spec/container.go b/pkg/server/spec/container.go index b1ee462ba..6b104aac1 100644 --- a/pkg/server/spec/container.go +++ b/pkg/server/spec/container.go @@ -18,15 +18,16 @@ type Port struct { } type Container struct { - Name string - Image string - ContainerLimits *ContainerLimits - Env map[string]string - VolumeMounts []*VolumeMounts - Command []string - Args []string - Ports []Port - Secrets []string + Name string + Image string + ContainerLimits *ContainerLimits + ContainerRequests *ContainerLimits + Env map[string]string + VolumeMounts []*VolumeMounts + Command []string + Args []string + Ports []Port + Secrets []string } type ContainerBuilder struct { @@ -63,6 +64,14 @@ func (b *ContainerBuilder) WithLimits(cpu, memory string) *ContainerBuilder { return b } +func (b *ContainerBuilder) WithRequests(cpu, memory string) *ContainerBuilder { + b.c.ContainerRequests = &ContainerLimits{ + CPU: cpu, + Memory: memory, + } + return b +} + func (b *ContainerBuilder) ExposePort(name string, port int) *ContainerBuilder { b.c.Ports = append(b.c.Ports, Port{Name: name, ContainerPort: int32(port)}) return b diff --git a/pkg/server/spec/container_test.go b/pkg/server/spec/container_test.go index 53f1b135f..f53f5a513 100644 --- a/pkg/server/spec/container_test.go +++ b/pkg/server/spec/container_test.go @@ -8,6 +8,7 @@ func TestContainerBuilder(t *testing.T) { expectedEnv := map[string]string{"Key": "Value"} expectedSecrets := []string{"SECRET", "VERY-SECRET"} expectedLimits := ContainerLimits{CPU: "200m", Memory: "256Mi"} + expectedRequests := ContainerLimits{CPU: "50m", Memory: "56Mi"} expectedCmd := []string{"echo", "hi"} expectedArgs := []string{"hello", "from", "test"} expectedPort := 5000 @@ -16,6 +17,7 @@ func TestContainerBuilder(t *testing.T) { WithEnv(expectedEnv). WithSecrets(expectedSecrets). WithLimits(expectedLimits.CPU, expectedLimits.Memory). + WithRequests(expectedRequests.CPU, expectedRequests.Memory). WithCommand(expectedCmd). WithArgs(expectedArgs). ExposePort("http", expectedPort). @@ -33,6 +35,12 @@ func TestContainerBuilder(t *testing.T) { if actual := c.ContainerLimits.Memory; actual != expectedLimits.Memory { t.Errorf("expected %s, got %s", expectedLimits.Memory, actual) } + if actual := c.ContainerRequests.CPU; actual != expectedRequests.CPU { + t.Errorf("expected %s, got %s", expectedRequests.CPU, actual) + } + if actual := c.ContainerRequests.Memory; actual != expectedRequests.Memory { + t.Errorf("expected %s, got %s", expectedRequests.Memory, actual) + } if actual := c.Ports[0].ContainerPort; actual != int32(expectedPort) { t.Errorf("expected %d, got %d", expectedPort, actual) } diff --git a/pkg/server/spec/nginx.go b/pkg/server/spec/nginx.go index c82036d15..a8ec9a91b 100644 --- a/pkg/server/spec/nginx.go +++ b/pkg/server/spec/nginx.go @@ -10,14 +10,16 @@ import ( ) const ( - NginxConfFile = "nginx.conf" - nginxConfTmplDir = "/etc/nginx/template/" - nginxConfDir = "/etc/nginx/" - nginxVolName = "nginx-conf" - nginxArgTmpl = "envsubst '%s' < %s%s > %s%s && nginx -g 'daemon off;'" - nginxBackendTmpl = "http://localhost:%d" - nginxDefaultCPULimit = "100m" - nginxDefaultMemoryLimit = "256Mi" + NginxConfFile = "nginx.conf" + nginxConfTmplDir = "/etc/nginx/template/" + nginxConfDir = "/etc/nginx/" + nginxVolName = "nginx-conf" + nginxArgTmpl = "envsubst '%s' < %s%s > %s%s && nginx -g 'daemon off;'" + nginxBackendTmpl = "http://localhost:%d" + nginxDefaultCPULimit = "100m" + nginxDefaultMemoryLimit = "256Mi" + nginxDefaultCPURequest = "25m" + nginxDefaultMemoryRequest = "56Mi" ) func newNginxContainerArgs(env map[string]string) string { @@ -54,6 +56,7 @@ func NewNginxContainer(image string, a *app.App) *Container { WithArgs([]string{"-c", args}). WithEnv(env). WithLimits(nginxDefaultCPULimit, nginxDefaultMemoryLimit). + WithRequests(nginxDefaultCPURequest, nginxDefaultMemoryRequest). ExposePort("nginx", secondaryPort). Build() } diff --git a/pkg/server/spec/nginx_test.go b/pkg/server/spec/nginx_test.go index 68112d08c..75fc05456 100644 --- a/pkg/server/spec/nginx_test.go +++ b/pkg/server/spec/nginx_test.go @@ -46,4 +46,7 @@ func TestNewNginxContainer(t *testing.T) { if actual := c.ContainerLimits.CPU; actual != nginxDefaultCPULimit { t.Errorf("expected %s, got %s", nginxDefaultCPULimit, actual) } + if actual := c.ContainerRequests.CPU; actual != nginxDefaultCPURequest { + t.Errorf("expected %s, got %s", nginxDefaultCPULimit, actual) + } }