Parcourir la source

Merge pull request #748 from docker/aci_resource_req

Aci resource reservation & limits
Guillaume Tardif il y a 5 ans
Parent
commit
7fb976732f

+ 1 - 1
aci/convert/container.go

@@ -54,7 +54,7 @@ func ContainerToComposeProject(r containers.ContainerConfig) (types.Project, err
 				Environment: toComposeEnvs(r.Environment),
 				Deploy: &types.DeployConfig{
 					Resources: types.Resources{
-						Limits: &types.Resource{
+						Reservations: &types.Resource{
 							NanoCPUs:    fmt.Sprintf("%f", r.CPULimit),
 							MemoryBytes: types.UnitBytes(r.MemLimit.Value()),
 						},

+ 102 - 54
aci/convert/convert.go

@@ -175,10 +175,6 @@ func getDNSSidecar(containers []containerinstance.Container) containerinstance.C
 			Image:   to.StringPtr(dnsSidecarImage),
 			Command: &alpineCmd,
 			Resources: &containerinstance.ResourceRequirements{
-				Limits: &containerinstance.ResourceLimits{
-					MemoryInGB: to.Float64Ptr(0.1),  // "The memory requirement should be in incrememts of 0.1 GB."
-					CPU:        to.Float64Ptr(0.01), //  "The CPU requirement should be in incrememts of 0.01."
-				},
 				Requests: &containerinstance.ResourceRequests{
 					MemoryInGB: to.Float64Ptr(0.1),
 					CPU:        to.Float64Ptr(0.01),
@@ -357,38 +353,73 @@ func (s serviceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (c
 		volumes = &allVolumes
 	}
 
-	memLimit := 1. // Default 1 Gb
-	var cpuLimit float64 = 1
+	resource, err := s.getResourceRequestsLimits()
+	if err != nil {
+		return containerinstance.Container{}, err
+	}
+
+	return containerinstance.Container{
+		Name: to.StringPtr(s.Name),
+		ContainerProperties: &containerinstance.ContainerProperties{
+			Image:                to.StringPtr(s.Image),
+			Command:              to.StringSlicePtr(s.Command),
+			EnvironmentVariables: getEnvVariables(s.Environment),
+			Resources:            resource,
+			VolumeMounts:         volumes,
+		},
+	}, nil
+}
+
+func (s serviceConfigAciHelper) getResourceRequestsLimits() (*containerinstance.ResourceRequirements, error) {
+	memRequest := 1. // Default 1 Gb
+	var cpuRequest float64 = 1
+	var err error
+	hasMemoryRequest := func() bool {
+		return s.Deploy != nil && s.Deploy.Resources.Reservations != nil && s.Deploy.Resources.Reservations.MemoryBytes != 0
+	}
+	hasCPURequest := func() bool {
+		return s.Deploy != nil && s.Deploy.Resources.Reservations != nil && s.Deploy.Resources.Reservations.NanoCPUs != ""
+	}
+	if hasMemoryRequest() {
+		memRequest = bytesToGb(s.Deploy.Resources.Reservations.MemoryBytes)
+	}
+
+	if hasCPURequest() {
+		cpuRequest, err = strconv.ParseFloat(s.Deploy.Resources.Reservations.NanoCPUs, 0)
+		if err != nil {
+			return nil, err
+		}
+	}
+	memLimit := memRequest
+	cpuLimit := cpuRequest
 	if s.Deploy != nil && s.Deploy.Resources.Limits != nil {
 		if s.Deploy.Resources.Limits.MemoryBytes != 0 {
 			memLimit = bytesToGb(s.Deploy.Resources.Limits.MemoryBytes)
+			if !hasMemoryRequest() {
+				memRequest = memLimit
+			}
 		}
 		if s.Deploy.Resources.Limits.NanoCPUs != "" {
 			cpuLimit, err = strconv.ParseFloat(s.Deploy.Resources.Limits.NanoCPUs, 0)
 			if err != nil {
-				return containerinstance.Container{}, err
+				return nil, err
+			}
+			if !hasCPURequest() {
+				cpuRequest = cpuLimit
 			}
 		}
 	}
-	return containerinstance.Container{
-		Name: to.StringPtr(s.Name),
-		ContainerProperties: &containerinstance.ContainerProperties{
-			Image:                to.StringPtr(s.Image),
-			Command:              to.StringSlicePtr(s.Command),
-			EnvironmentVariables: getEnvVariables(s.Environment),
-			Resources: &containerinstance.ResourceRequirements{
-				Limits: &containerinstance.ResourceLimits{
-					MemoryInGB: to.Float64Ptr(memLimit),
-					CPU:        to.Float64Ptr(cpuLimit),
-				},
-				Requests: &containerinstance.ResourceRequests{
-					MemoryInGB: to.Float64Ptr(memLimit), // TODO: use the memory requests here and not limits
-					CPU:        to.Float64Ptr(cpuLimit), // TODO: use the cpu requests here and not limits
-				},
-			},
-			VolumeMounts: volumes,
+	resources := containerinstance.ResourceRequirements{
+		Requests: &containerinstance.ResourceRequests{
+			MemoryInGB: to.Float64Ptr(memRequest),
+			CPU:        to.Float64Ptr(cpuRequest),
 		},
-	}, nil
+		Limits: &containerinstance.ResourceLimits{
+			MemoryInGB: to.Float64Ptr(memLimit),
+			CPU:        to.Float64Ptr(cpuLimit),
+		},
+	}
+	return &resources, nil
 }
 
 func getEnvVariables(composeEnv types.MappingWithEquals) *[]containerinstance.EnvironmentVariable {
@@ -413,6 +444,10 @@ func bytesToGb(b types.UnitBytes) float64 {
 	return math.Round(f*100) / 100
 }
 
+func gbToBytes(memInBytes float64) uint64 {
+	return uint64(memInBytes * 1024 * 1024 * 1024)
+}
+
 // ContainerGroupToServiceStatus convert from an ACI container definition to service status
 func ContainerGroupToServiceStatus(containerID string, group containerinstance.ContainerGroup, container containerinstance.Container, region string) compose.ServiceStatus {
 	var replicas = 1
@@ -438,18 +473,27 @@ func fqdn(group containerinstance.ContainerGroup, region string) string {
 
 // ContainerGroupToContainer composes a Container from an ACI container definition
 func ContainerGroupToContainer(containerID string, cg containerinstance.ContainerGroup, cc containerinstance.Container, region string) containers.Container {
-	memLimits := 0.
-	if cc.Resources != nil &&
-		cc.Resources.Limits != nil &&
-		cc.Resources.Limits.MemoryInGB != nil {
-		memLimits = *cc.Resources.Limits.MemoryInGB * 1024 * 1024 * 1024
-	}
-
+	memLimits := uint64(0)
+	memRequest := uint64(0)
 	cpuLimit := 0.
-	if cc.Resources != nil &&
-		cc.Resources.Limits != nil &&
-		cc.Resources.Limits.CPU != nil {
-		cpuLimit = *cc.Resources.Limits.CPU
+	cpuReservation := 0.
+	if cc.Resources != nil {
+		if cc.Resources.Limits != nil {
+			if cc.Resources.Limits.MemoryInGB != nil {
+				memLimits = gbToBytes(*cc.Resources.Limits.MemoryInGB)
+			}
+			if cc.Resources.Limits.CPU != nil {
+				cpuLimit = *cc.Resources.Limits.CPU
+			}
+		}
+		if cc.Resources.Requests != nil {
+			if cc.Resources.Requests.MemoryInGB != nil {
+				memRequest = gbToBytes(*cc.Resources.Requests.MemoryInGB)
+			}
+			if cc.Resources.Requests.CPU != nil {
+				cpuReservation = *cc.Resources.Requests.CPU
+			}
+		}
 	}
 
 	command := ""
@@ -468,26 +512,30 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
 		}
 	}
 
-	var config *containers.RuntimeConfig = &containers.RuntimeConfig{FQDN: fqdn(cg, region)}
-	if envVars != nil {
-		config.Env = envVars
+	config := &containers.RuntimeConfig{
+		FQDN: fqdn(cg, region),
+		Env:  envVars,
+	}
+	hostConfig := &containers.HostConfig{
+		CPULimit:          cpuLimit,
+		CPUReservation:    cpuReservation,
+		MemoryLimit:       memLimits,
+		MemoryReservation: memRequest,
+		RestartPolicy:     toContainerRestartPolicy(cg.RestartPolicy),
 	}
 	c := containers.Container{
-		ID:                     containerID,
-		Status:                 status,
-		Image:                  to.String(cc.Image),
-		Command:                command,
-		CPUTime:                0,
-		CPULimit:               cpuLimit,
-		MemoryUsage:            0,
-		MemoryLimit:            uint64(memLimits),
-		PidsCurrent:            0,
-		PidsLimit:              0,
-		Labels:                 nil,
-		Ports:                  ToPorts(cg.IPAddress, *cc.Ports),
-		Platform:               platform,
-		RestartPolicyCondition: toContainerRestartPolicy(cg.RestartPolicy),
-		Config:                 config,
+		ID:          containerID,
+		Status:      status,
+		Image:       to.String(cc.Image),
+		Command:     command,
+		CPUTime:     0,
+		MemoryUsage: 0,
+		PidsCurrent: 0,
+		PidsLimit:   0,
+		Ports:       ToPorts(cg.IPAddress, *cc.Ports),
+		Platform:    platform,
+		Config:      config,
+		HostConfig:  hostConfig,
 	}
 
 	return c

+ 89 - 15
aci/convert/convert_test.go

@@ -83,6 +83,10 @@ func TestContainerGroupToContainer(t *testing.T) {
 			Resources: &containerinstance.ResourceRequirements{
 				Limits: &containerinstance.ResourceLimits{
 					CPU:        to.Float64Ptr(3),
+					MemoryInGB: to.Float64Ptr(0.2),
+				},
+				Requests: &containerinstance.ResourceRequests{
+					CPU:        to.Float64Ptr(2),
 					MemoryInGB: to.Float64Ptr(0.1),
 				},
 			},
@@ -90,13 +94,11 @@ func TestContainerGroupToContainer(t *testing.T) {
 	}
 
 	var expectedContainer = containers.Container{
-		ID:          "myContainerID",
-		Status:      "Running",
-		Image:       "sha256:666",
-		Command:     "mycommand",
-		CPULimit:    3,
-		MemoryLimit: 107374182,
-		Platform:    "Linux",
+		ID:       "myContainerID",
+		Status:   "Running",
+		Image:    "sha256:666",
+		Command:  "mycommand",
+		Platform: "Linux",
 		Ports: []containers.Port{{
 			HostPort:      uint32(80),
 			ContainerPort: uint32(80),
@@ -106,7 +108,13 @@ func TestContainerGroupToContainer(t *testing.T) {
 		Config: &containers.RuntimeConfig{
 			FQDN: "myapp.eastus.azurecontainer.io",
 		},
-		RestartPolicyCondition: "any",
+		HostConfig: &containers.HostConfig{
+			CPULimit:          3,
+			CPUReservation:    2,
+			MemoryLimit:       gbToBytes(0.2),
+			MemoryReservation: gbToBytes(0.1),
+			RestartPolicy:     "any",
+		},
 	}
 
 	container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer, "eastus")
@@ -536,8 +544,9 @@ func TestComposeContainerGroupToContainerIgnoreDomainNameWithoutPorts(t *testing
 	assert.Assert(t, group.IPAddress == nil)
 }
 
-func TestComposeContainerGroupToContainerResourceLimits(t *testing.T) {
-	_0_1Gb := 0.1 * 1024 * 1024 * 1024
+var _0_1Gb = gbToBytes(0.1)
+
+func TestComposeContainerGroupToContainerResourceRequests(t *testing.T) {
 	project := types.Project{
 		Services: []types.ServiceConfig{
 			{
@@ -545,7 +554,7 @@ func TestComposeContainerGroupToContainerResourceLimits(t *testing.T) {
 				Image: "image1",
 				Deploy: &types.DeployConfig{
 					Resources: types.Resources{
-						Limits: &types.Resource{
+						Reservations: &types.Resource{
 							NanoCPUs:    "0.1",
 							MemoryBytes: types.UnitBytes(_0_1Gb),
 						},
@@ -558,12 +567,48 @@ func TestComposeContainerGroupToContainerResourceLimits(t *testing.T) {
 	group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
 	assert.NilError(t, err)
 
+	request := *((*group.Containers)[0]).Resources.Requests
+	assert.Equal(t, *request.CPU, float64(0.1))
+	assert.Equal(t, *request.MemoryInGB, float64(0.1))
 	limits := *((*group.Containers)[0]).Resources.Limits
 	assert.Equal(t, *limits.CPU, float64(0.1))
 	assert.Equal(t, *limits.MemoryInGB, float64(0.1))
 }
 
-func TestComposeContainerGroupToContainerResourceLimitsDefaults(t *testing.T) {
+func TestComposeContainerGroupToContainerResourceRequestsAndLimits(t *testing.T) {
+	project := types.Project{
+		Services: []types.ServiceConfig{
+			{
+				Name:  "service1",
+				Image: "image1",
+				Deploy: &types.DeployConfig{
+					Resources: types.Resources{
+						Reservations: &types.Resource{
+							NanoCPUs:    "0.1",
+							MemoryBytes: types.UnitBytes(_0_1Gb),
+						},
+						Limits: &types.Resource{
+							NanoCPUs:    "0.3",
+							MemoryBytes: types.UnitBytes(2 * _0_1Gb),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
+	assert.NilError(t, err)
+
+	request := *((*group.Containers)[0]).Resources.Requests
+	assert.Equal(t, *request.CPU, float64(0.1))
+	assert.Equal(t, *request.MemoryInGB, float64(0.1))
+	limits := *((*group.Containers)[0]).Resources.Limits
+	assert.Equal(t, *limits.CPU, float64(0.3))
+	assert.Equal(t, *limits.MemoryInGB, float64(0.2))
+}
+
+func TestComposeContainerGroupToContainerResourceLimitsOnly(t *testing.T) {
 	project := types.Project{
 		Services: []types.ServiceConfig{
 			{
@@ -572,6 +617,35 @@ func TestComposeContainerGroupToContainerResourceLimitsDefaults(t *testing.T) {
 				Deploy: &types.DeployConfig{
 					Resources: types.Resources{
 						Limits: &types.Resource{
+							NanoCPUs:    "0.3",
+							MemoryBytes: types.UnitBytes(2 * _0_1Gb),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
+	assert.NilError(t, err)
+
+	request := *((*group.Containers)[0]).Resources.Requests
+	assert.Equal(t, *request.CPU, float64(0.3))
+	assert.Equal(t, *request.MemoryInGB, float64(0.2))
+	limits := *((*group.Containers)[0]).Resources.Limits
+	assert.Equal(t, *limits.CPU, float64(0.3))
+	assert.Equal(t, *limits.MemoryInGB, float64(0.2))
+}
+
+func TestComposeContainerGroupToContainerResourceRequestsDefaults(t *testing.T) {
+	project := types.Project{
+		Services: []types.ServiceConfig{
+			{
+				Name:  "service1",
+				Image: "image1",
+				Deploy: &types.DeployConfig{
+					Resources: types.Resources{
+						Reservations: &types.Resource{
 							NanoCPUs:    "",
 							MemoryBytes: 0,
 						},
@@ -584,9 +658,9 @@ func TestComposeContainerGroupToContainerResourceLimitsDefaults(t *testing.T) {
 	group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
 	assert.NilError(t, err)
 
-	limits := *((*group.Containers)[0]).Resources.Limits
-	assert.Equal(t, *limits.CPU, float64(1))
-	assert.Equal(t, *limits.MemoryInGB, float64(1))
+	request := *((*group.Containers)[0]).Resources.Requests
+	assert.Equal(t, *request.CPU, float64(1))
+	assert.Equal(t, *request.MemoryInGB, float64(1))
 }
 
 func TestComposeContainerGroupToContainerenvVar(t *testing.T) {

+ 23 - 16
api/containers/api.go

@@ -37,30 +37,37 @@ var RestartPolicyList = []string{RestartPolicyNone, RestartPolicyAny, RestartPol
 
 // Container represents a created container
 type Container struct {
-	ID                     string
-	Status                 string
-	Image                  string
-	Command                string
-	CPUTime                uint64
-	CPULimit               float64
-	MemoryUsage            uint64
-	MemoryLimit            uint64
-	PidsCurrent            uint64
-	PidsLimit              uint64
-	Config                 *RuntimeConfig `json:",omitempty"`
-	Labels                 []string       `json:",omitempty"`
-	Ports                  []Port         `json:",omitempty"`
-	Platform               string
-	RestartPolicyCondition string
+	ID          string
+	Status      string
+	Image       string
+	Command     string
+	CPUTime     uint64
+	MemoryUsage uint64
+	PidsCurrent uint64
+	PidsLimit   uint64
+	Config      *RuntimeConfig `json:",omitempty"`
+	HostConfig  *HostConfig    `json:",omitempty"`
+	Ports       []Port         `json:",omitempty"`
+	Platform    string
 }
 
 // RuntimeConfig config of a created container
 type RuntimeConfig struct {
-	Env map[string]string `json:",omitempty"`
+	Labels []string          `json:",omitempty"`
+	Env    map[string]string `json:",omitempty"`
 	// FQDN is the fqdn to use
 	FQDN string `json:"fqdn,omitempty"`
 }
 
+// HostConfig config of the container host
+type HostConfig struct {
+	RestartPolicy     string
+	CPUReservation    float64
+	CPULimit          float64
+	MemoryReservation uint64
+	MemoryLimit       uint64
+}
+
 // Port represents a published port of a container
 type Port struct {
 	// HostPort is the port number on the host

+ 8 - 4
cli/cmd/testdata/inspect-out-id.golden

@@ -4,11 +4,15 @@
     "Image": "nginx",
     "Command": "",
     "CPUTime": 0,
-    "CPULimit": 0,
     "MemoryUsage": 0,
-    "MemoryLimit": 0,
     "PidsCurrent": 0,
     "PidsLimit": 0,
-    "Platform": "Linux",
-    "RestartPolicyCondition": "none"
+    "HostConfig": {
+        "RestartPolicy": "none",
+        "CPUReservation": 0,
+        "CPULimit": 0,
+        "MemoryReservation": 0,
+        "MemoryLimit": 0
+    },
+    "Platform": "Linux"
 }

+ 3 - 1
example/backend.go

@@ -71,7 +71,9 @@ func (cs *containerService) Inspect(ctx context.Context, id string) (containers.
 		ID:                     "id",
 		Image:                  "nginx",
 		Platform:               "Linux",
-		RestartPolicyCondition: "none",
+		HostConfig: &containers.HostConfig{
+			RestartPolicy: "none",
+		},
 	}, nil
 }
 

Fichier diff supprimé car celui-ci est trop grand
+ 362 - 287
protos/containers/v1/containers.pb.go


+ 14 - 8
protos/containers/v1/containers.proto

@@ -45,14 +45,20 @@ message Container {
 	string command = 4;
 	uint64 cpu_time = 5;
 	uint64 memory_usage = 6;
-	uint64 memory_limit = 7;
-	uint64 pids_current = 8;
-	uint64 pids_limit = 9;
-	repeated string labels = 10;
-	repeated Port ports = 11;
-	uint64 cpu_limit = 12;
-	string platform = 13;
-	string restart_policy_condition = 14;
+	uint64 pids_current = 7;
+	uint64 pids_limit = 8;
+	repeated string labels = 9;
+	repeated Port ports = 10;
+	string platform = 11;
+	HostConfig host_config = 12;
+}
+
+message HostConfig {
+	uint64 memory_reservation = 1;
+	uint64 memory_limit = 2;
+	uint64 cpu_reservation = 3;
+	uint64 cpu_limit = 4;
+	string restart_policy = 5;
 }
 
 message InspectRequest {

+ 18 - 14
server/proxy/containers.go

@@ -122,20 +122,24 @@ func (p *proxy) Logs(request *containersv1.LogsRequest, stream containersv1.Cont
 
 func toGrpcContainer(c containers.Container) *containersv1.Container {
 	return &containersv1.Container{
-		Id:                     c.ID,
-		Image:                  c.Image,
-		Status:                 c.Status,
-		Command:                c.Command,
-		CpuTime:                c.CPUTime,
-		MemoryUsage:            c.MemoryUsage,
-		MemoryLimit:            c.MemoryLimit,
-		Platform:               c.Platform,
-		PidsCurrent:            c.PidsCurrent,
-		PidsLimit:              c.PidsLimit,
-		Labels:                 c.Labels,
-		Ports:                  portsToGrpc(c.Ports),
-		CpuLimit:               uint64(c.CPULimit),
-		RestartPolicyCondition: c.RestartPolicyCondition,
+		Id:          c.ID,
+		Image:       c.Image,
+		Status:      c.Status,
+		Command:     c.Command,
+		CpuTime:     c.CPUTime,
+		MemoryUsage: c.MemoryUsage,
+		Platform:    c.Platform,
+		PidsCurrent: c.PidsCurrent,
+		PidsLimit:   c.PidsLimit,
+		Labels:      c.Config.Labels,
+		Ports:       portsToGrpc(c.Ports),
+		HostConfig: &containersv1.HostConfig{
+			MemoryReservation: c.HostConfig.MemoryReservation,
+			MemoryLimit:       c.HostConfig.MemoryLimit,
+			CpuReservation:    uint64(c.HostConfig.CPUReservation),
+			CpuLimit:          uint64(c.HostConfig.CPULimit),
+			RestartPolicy:     c.HostConfig.RestartPolicy,
+		},
 	}
 }
 

+ 42 - 6
tests/aci-e2e/e2e-aci_test.go

@@ -249,8 +249,9 @@ func TestRunVolume(t *testing.T) {
 		containerInspect, err := ParseContainerInspect(res.Stdout())
 		assert.NilError(t, err)
 		assert.Equal(t, containerInspect.Platform, "Linux")
-		assert.Equal(t, containerInspect.CPULimit, 1.0)
-		assert.Equal(t, containerInspect.RestartPolicyCondition, containers.RestartPolicyNone)
+		assert.Equal(t, containerInspect.HostConfig.CPULimit, 1.0)
+		assert.Equal(t, containerInspect.HostConfig.CPUReservation, 1.0)
+		assert.Equal(t, containerInspect.HostConfig.RestartPolicy, containers.RestartPolicyNone)
 
 		assert.Assert(t, is.Len(containerInspect.Ports, 1))
 		hostIP = containerInspect.Ports[0].HostIP
@@ -388,16 +389,18 @@ func TestContainerRunAttached(t *testing.T) {
 			}
 			return poll.Continue("waiting for container to be running, current inspect result: \n%s", res.Combined())
 		}
-		poll.WaitOn(t, checkRunning, poll.WithDelay(5*time.Second), poll.WithTimeout(60*time.Second))
+		poll.WaitOn(t, checkRunning, poll.WithDelay(5*time.Second), poll.WithTimeout(90*time.Second))
 
 		inspectRes := c.RunDockerCmd("inspect", container)
 
 		containerInspect, err := ParseContainerInspect(inspectRes.Stdout())
 		assert.NilError(t, err)
 		assert.Equal(t, containerInspect.Platform, "Linux")
-		assert.Equal(t, containerInspect.CPULimit, 0.1)
-		assert.Equal(t, containerInspect.MemoryLimit, uint64(107374182))
-		assert.Equal(t, containerInspect.RestartPolicyCondition, containers.RestartPolicyOnFailure)
+		assert.Equal(t, containerInspect.HostConfig.CPULimit, 0.1)
+		assert.Equal(t, containerInspect.HostConfig.MemoryLimit, uint64(107374182))
+		assert.Equal(t, containerInspect.HostConfig.CPUReservation, 0.1)
+		assert.Equal(t, containerInspect.HostConfig.MemoryReservation, uint64(107374182))
+		assert.Equal(t, containerInspect.HostConfig.RestartPolicy, containers.RestartPolicyOnFailure)
 
 		assert.Assert(t, is.Len(containerInspect.Ports, 1))
 		port := containerInspect.Ports[0]
@@ -480,6 +483,39 @@ func overwriteFileStorageAccount(t *testing.T, absComposefileName string, storag
 	assert.NilError(t, err)
 }
 
+func TestUpResources(t *testing.T) {
+	const (
+		composeProjectName = "testresources"
+		serverContainer    = composeProjectName + "_web"
+		wordsContainer     = composeProjectName + "_words"
+	)
+
+	c := NewParallelE2eCLI(t, binDir)
+	setupTestResourceGroup(t, c)
+
+	t.Run("compose up", func(t *testing.T) {
+		c.RunDockerCmd("compose", "up", "-f", "../composefiles/aci-demo/aci_demo_port_resources.yaml", "--project-name", composeProjectName)
+
+		res := c.RunDockerCmd("inspect", serverContainer)
+
+		webInspect, err := ParseContainerInspect(res.Stdout())
+		assert.NilError(t, err)
+		assert.Equal(t, webInspect.HostConfig.CPULimit, 0.7)
+		assert.Equal(t, webInspect.HostConfig.MemoryLimit, uint64(1073741824))
+		assert.Equal(t, webInspect.HostConfig.CPUReservation, 0.5)
+		assert.Equal(t, webInspect.HostConfig.MemoryReservation, uint64(536870912))
+
+		res = c.RunDockerCmd("inspect", wordsContainer)
+
+		wordsInspect, err := ParseContainerInspect(res.Stdout())
+		assert.NilError(t, err)
+		assert.Equal(t, wordsInspect.HostConfig.CPULimit, 0.5)
+		assert.Equal(t, wordsInspect.HostConfig.MemoryLimit, uint64(751619276))
+		assert.Equal(t, wordsInspect.HostConfig.CPUReservation, 0.5)
+		assert.Equal(t, wordsInspect.HostConfig.MemoryReservation, uint64(751619276))
+	})
+}
+
 func TestUpUpdate(t *testing.T) {
 	const (
 		composeProjectName = "acidemo"

+ 0 - 14
tests/composefiles/aci-demo/aci_demo_port.yaml

@@ -1,14 +0,0 @@
-services:
-  db:
-    build: db
-    image: gtardif/sentences-db
-
-  words:
-    build: words
-    image: gtardif/sentences-api
-
-  web:
-    build: web
-    image: gtardif/sentences-web
-    ports:
-      - "80:80"

+ 24 - 0
tests/composefiles/aci-demo/aci_demo_port_resources.yaml

@@ -0,0 +1,24 @@
+services:
+  db:
+    image: gtardif/sentences-db
+
+  words:
+    image: gtardif/sentences-api
+    deploy:
+      resources:
+        reservations:
+          cpus: '0.5'
+          memory: 0.7G
+
+  web:
+    image: gtardif/sentences-web
+    ports:
+      - "80:80"
+    deploy:
+      resources:
+        limits:
+          cpus: '0.7'
+          memory: 1G
+        reservations:
+          cpus: '0.5'
+          memory: 0.5G

+ 8 - 4
tests/e2e/testdata/inspect-id.golden

@@ -4,11 +4,15 @@
     "Image": "nginx",
     "Command": "",
     "CPUTime": 0,
-    "CPULimit": 0,
     "MemoryUsage": 0,
-    "MemoryLimit": 0,
     "PidsCurrent": 0,
     "PidsLimit": 0,
-    "Platform": "Linux",
-    "RestartPolicyCondition": "none"
+    "HostConfig": {
+        "RestartPolicy": "none",
+        "CPUReservation": 0,
+        "CPULimit": 0,
+        "MemoryReservation": 0,
+        "MemoryLimit": 0
+    },
+    "Platform": "Linux"
 }

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff