From f7c1b017f30eee6c8030be2279fdea97961c230e Mon Sep 17 00:00:00 2001 From: Leno Hou Date: Fri, 14 Dec 2018 10:09:59 +0000 Subject: [PATCH] feature: update blkio device's read/write Bps/IOps fixes #2509 Signed-off-by: Leno Hou --- apis/types/resources.go | 2 +- cli/update.go | 24 ++++--- daemon/mgr/container.go | 12 ++++ test/cli_update_test.go | 148 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 176 insertions(+), 10 deletions(-) diff --git a/apis/types/resources.go b/apis/types/resources.go index 0397dc291a..261d9a5ab7 100644 --- a/apis/types/resources.go +++ b/apis/types/resources.go @@ -122,7 +122,7 @@ type Resources struct { // Total memory limit (memory + swap). Set as `-1` to enable unlimited swap. MemorySwap int64 `json:"MemorySwap"` - // Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. + // Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. -1 is also accepted, as a legacy alias of 0. // Maximum: 100 // Minimum: -1 MemorySwappiness *int64 `json:"MemorySwappiness"` diff --git a/cli/update.go b/cli/update.go index 6799a86d69..c93c22705f 100644 --- a/cli/update.go +++ b/cli/update.go @@ -51,6 +51,10 @@ func (uc *UpdateCommand) addFlags() { flagSet.StringSliceVarP(&uc.labels, "label", "l", nil, "Set label for container") flagSet.StringVar(&uc.restartPolicy, "restart", "", "Restart policy to apply when container exits") flagSet.StringSliceVar(&uc.diskQuota, "disk-quota", nil, "Update disk quota for container(/=10g)") + flagSet.Var(&uc.blkioDeviceReadBps, "device-read-bps", "Update read rate (bytes per second) from a device") + flagSet.Var(&uc.blkioDeviceWriteBps, "device-write-bps", "Update write rate (bytes per second) from a device") + flagSet.Var(&uc.blkioDeviceReadIOps, "device-read-iops", "Update read rate (io per second) from a device") + flagSet.Var(&uc.blkioDeviceWriteIOps, "device-write-iops", "Update write rate (io per second) from a device") } // updateRun is the entry of update command. @@ -69,14 +73,18 @@ func (uc *UpdateCommand) updateRun(args []string) error { } resource := types.Resources{ - CPUPeriod: uc.cpuperiod, - CPUShares: uc.cpushare, - CPUQuota: uc.cpuquota, - CpusetCpus: uc.cpusetcpus, - CpusetMems: uc.cpusetmems, - Memory: memory, - MemorySwap: memorySwap, - BlkioWeight: uc.blkioWeight, + CPUPeriod: uc.cpuperiod, + CPUShares: uc.cpushare, + CPUQuota: uc.cpuquota, + CpusetCpus: uc.cpusetcpus, + CpusetMems: uc.cpusetmems, + Memory: memory, + MemorySwap: memorySwap, + BlkioWeight: uc.blkioWeight, + BlkioDeviceReadBps: uc.blkioDeviceReadBps.Value(), + BlkioDeviceWriteBps: uc.blkioDeviceWriteBps.Value(), + BlkioDeviceReadIOps: uc.blkioDeviceReadIOps.Value(), + BlkioDeviceWriteIOps: uc.blkioDeviceWriteIOps.Value(), } restartPolicy, err := opts.ParseRestartPolicy(uc.restartPolicy) diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index 1051d59186..3b7c15a1e1 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -1284,6 +1284,18 @@ func (mgr *ContainerManager) updateContainerResources(c *Container, resources ty if resources.BlkioWeight != 0 { cResources.BlkioWeight = resources.BlkioWeight } + if resources.BlkioDeviceReadBps != nil { + cResources.BlkioDeviceReadBps = resources.BlkioDeviceReadBps + } + if resources.BlkioDeviceReadIOps != nil { + cResources.BlkioDeviceReadIOps = resources.BlkioDeviceReadIOps + } + if resources.BlkioDeviceWriteBps != nil { + cResources.BlkioDeviceWriteBps = resources.BlkioDeviceWriteBps + } + if resources.BlkioDeviceWriteIOps != nil { + cResources.BlkioDeviceWriteIOps = resources.BlkioDeviceWriteIOps + } if resources.CPUPeriod != 0 { cResources.CPUPeriod = resources.CPUPeriod } diff --git a/test/cli_update_test.go b/test/cli_update_test.go index f54396742d..b2ff848d43 100644 --- a/test/cli_update_test.go +++ b/test/cli_update_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "fmt" "os" "os/exec" "strings" @@ -10,6 +11,7 @@ import ( "github.com/alibaba/pouch/pkg/utils" "github.com/alibaba/pouch/test/command" "github.com/alibaba/pouch/test/environment" + "github.com/alibaba/pouch/test/util" "github.com/go-check/check" "github.com/gotestyourself/gotestyourself/icmd" @@ -353,7 +355,7 @@ func (suite *PouchUpdateSuite) TestUpdateContainerDeleteEnv(c *check.C) { } } -// TestUpdateContainerDiskQuota is to verify the correctness of delete env by update interface +// TestUpdateContainerDiskQuota is to verify the correctness of disk quota by update interface func (suite *PouchUpdateSuite) TestUpdateContainerDiskQuota(c *check.C) { if !environment.IsDiskQuota() { c.Skip("Host does not support disk quota") @@ -395,3 +397,147 @@ func (suite *PouchUpdateSuite) TestUpdateContainerDiskQuota(c *check.C) { } c.Assert(found, check.Equals, true) } + +// TestUpdateWriteBps is to verify the correctness of update write bps +func (suite *PouchUpdateSuite) TestUpdateWriteBps(c *check.C) { + cname := "TestUpdateWriteBps" + testDisk := "/dev/null" + + number, exist := util.GetMajMinNumOfDevice(testDisk) + if !exist { + c.Skip("fail to get major:minor device number") + } + + oldLimitSpeed := "100" + newLimitSpeed := "300" + blkioDeviceWriteBpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.write_bps_device" + oldThrottleDev := testDisk + ":" + oldLimitSpeed + newThrottleDev := testDisk + ":" + newLimitSpeed + expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed) + + res := command.PouchRun("run", "-d", "--name", cname, + "--device-write-bps ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success) + defer DelContainerForceMultyTime(c, cname) + + // update write bps + command.PouchRun("update", "--device-write-bps", newThrottleDev, cname).Assert(c, icmd.Success) + + // restart container to update the configuration since runc don't support + // update device write bps + command.PouchRun("restart", cname).Assert(c, icmd.Success) + + res = command.PouchRun("exec", cname, "cat", blkioDeviceWriteBpsFile) + res.Assert(c, icmd.Success) + + out := res.Stdout() + c.Assert(out, check.Equals, expected) + +} + +// TestUpdateReadBps is to verify the correctness of update read bps +func (suite *PouchUpdateSuite) TestUpdateReadBps(c *check.C) { + cname := "TestUpdateReadBps" + testDisk := "/dev/null" + + number, exist := util.GetMajMinNumOfDevice(testDisk) + if !exist { + c.Skip("fail to get major:minor device number") + } + + oldLimitSpeed := "100" + newLimitSpeed := "300" + blkioDeviceReadBpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device" + oldThrottleDev := testDisk + ":" + oldLimitSpeed + newThrottleDev := testDisk + ":" + newLimitSpeed + expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed) + + res := command.PouchRun("run", "-d", "--name", cname, + "--device-read-bps ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success) + defer DelContainerForceMultyTime(c, cname) + + // update write bps + command.PouchRun("update", "--device-read-bps", newThrottleDev, cname).Assert(c, icmd.Success) + + // restart container to update the configuration since runc don't support + // update device write bps + command.PouchRun("restart", cname).Assert(c, icmd.Success) + + res = command.PouchRun("exec", cname, "cat", blkioDeviceReadBpsFile) + res.Assert(c, icmd.Success) + + out := res.Stdout() + c.Assert(out, check.Equals, expected) + +} + +// TestUpdateWriteIOps is to verify the correctness of update write iops +func (suite *PouchUpdateSuite) TestUpdateWriteIOps(c *check.C) { + cname := "TestUpdateWriteIOps" + testDisk := "/dev/null" + + number, exist := util.GetMajMinNumOfDevice(testDisk) + if !exist { + c.Skip("fail to get major:minor device number") + } + + oldLimitSpeed := "100" + newLimitSpeed := "300" + blkioDeviceWriteIOpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.write_iops_device" + oldThrottleDev := testDisk + ":" + oldLimitSpeed + newThrottleDev := testDisk + ":" + newLimitSpeed + expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed) + + res := command.PouchRun("run", "-d", "--name", cname, + "--device-write-iops ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success) + defer DelContainerForceMultyTime(c, cname) + + // update write bps + command.PouchRun("update", "--device-write-iops", newThrottleDev, cname).Assert(c, icmd.Success) + + // restart container to update the configuration since runc don't support + // update device write bps + command.PouchRun("restart", cname).Assert(c, icmd.Success) + + res = command.PouchRun("exec", cname, "cat", blkioDeviceWriteIOpsFile) + res.Assert(c, icmd.Success) + + out := res.Stdout() + c.Assert(out, check.Equals, expected) + +} + +// TestUpdateReadIOps is to verify the correctness of update read iops +func (suite *PouchUpdateSuite) TestUpdateReadIOps(c *check.C) { + cname := "TestUpdateReadIOps" + testDisk := "/dev/null" + + number, exist := util.GetMajMinNumOfDevice(testDisk) + if !exist { + c.Skip("fail to get major:minor device number") + } + + oldLimitSpeed := "100" + newLimitSpeed := "300" + blkioDeviceReadIOpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device" + oldThrottleDev := testDisk + ":" + oldLimitSpeed + newThrottleDev := testDisk + ":" + newLimitSpeed + expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed) + + res := command.PouchRun("run", "-d", "--name", cname, + "--device-read-iops ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success) + defer DelContainerForceMultyTime(c, cname) + + // update write bps + command.PouchRun("update", "--device-read-iops", newThrottleDev, cname).Assert(c, icmd.Success) + + // restart container to update the configuration since runc don't support + // update device write bps + command.PouchRun("restart", cname).Assert(c, icmd.Success) + + res = command.PouchRun("exec", cname, "cat", blkioDeviceReadIOpsFile) + res.Assert(c, icmd.Success) + + out := res.Stdout() + c.Assert(out, check.Equals, expected) + +}