Skip to content

Commit 6102243

Browse files
committed
Add --cpus support for docker update
This fix tries to address the issue raised in 31032 where it was not possible to specify `--cpus` for `docker update`. This fix adds `--cpus` support for `docker update`. In case both `--cpus` and `--cpu-period/--cpu-quota` have been specified, an error will be returned. Related docs has been updated. Integration tests have been added. This fix fixes 31032. This fix is related to 27921, 27958. Signed-off-by: Yong Tang <[email protected]>
1 parent 30cdabd commit 6102243

File tree

6 files changed

+74
-4
lines changed

6 files changed

+74
-4
lines changed

cli/command/container/update.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type updateOptions struct {
2828
memorySwap opts.MemSwapBytes
2929
kernelMemory opts.MemBytes
3030
restartPolicy string
31+
cpus opts.NanoCPUs
3132

3233
nFlag int
3334

@@ -66,6 +67,9 @@ func NewUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
6667
flags.Var(&opts.kernelMemory, "kernel-memory", "Kernel memory limit")
6768
flags.StringVar(&opts.restartPolicy, "restart", "", "Restart policy to apply when a container exits")
6869

70+
flags.Var(&opts.cpus, "cpus", "Number of CPUs")
71+
flags.SetAnnotation("cpus", "version", []string{"1.29"})
72+
6973
return cmd
7074
}
7175

@@ -97,6 +101,7 @@ func runUpdate(dockerCli *command.DockerCli, opts *updateOptions) error {
97101
CPUQuota: opts.cpuQuota,
98102
CPURealtimePeriod: opts.cpuRealtimePeriod,
99103
CPURealtimeRuntime: opts.cpuRealtimeRuntime,
104+
NanoCPUs: opts.cpus.Value(),
100105
}
101106

102107
updateConfig := containertypes.UpdateConfig{

container/container_unix.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,33 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
286286
// update resources of container
287287
resources := hostConfig.Resources
288288
cResources := &container.HostConfig.Resources
289+
290+
// validate NanoCPUs, CPUPeriod, and CPUQuota
291+
// Becuase NanoCPU effectively updates CPUPeriod/CPUQuota,
292+
// once NanoCPU is already set, updating CPUPeriod/CPUQuota will be blocked, and vice versa.
293+
// In the following we make sure the intended update (resources) does not conflict with the existing (cResource).
294+
if resources.NanoCPUs > 0 && cResources.CPUPeriod > 0 {
295+
return fmt.Errorf("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set")
296+
}
297+
if resources.NanoCPUs > 0 && cResources.CPUQuota > 0 {
298+
return fmt.Errorf("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set")
299+
}
300+
if resources.CPUPeriod > 0 && cResources.NanoCPUs > 0 {
301+
return fmt.Errorf("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set")
302+
}
303+
if resources.CPUQuota > 0 && cResources.NanoCPUs > 0 {
304+
return fmt.Errorf("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set")
305+
}
306+
289307
if resources.BlkioWeight != 0 {
290308
cResources.BlkioWeight = resources.BlkioWeight
291309
}
292310
if resources.CPUShares != 0 {
293311
cResources.CPUShares = resources.CPUShares
294312
}
313+
if resources.NanoCPUs != 0 {
314+
cResources.NanoCPUs = resources.NanoCPUs
315+
}
295316
if resources.CPUPeriod != 0 {
296317
cResources.CPUPeriod = resources.CPUPeriod
297318
}

daemon/update_linux.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
package daemon
44

55
import (
6+
"time"
7+
68
"github.com/docker/docker/api/types/container"
79
"github.com/docker/docker/libcontainerd"
810
)
@@ -11,8 +13,13 @@ func toContainerdResources(resources container.Resources) libcontainerd.Resource
1113
var r libcontainerd.Resources
1214
r.BlkioWeight = uint64(resources.BlkioWeight)
1315
r.CpuShares = uint64(resources.CPUShares)
14-
r.CpuPeriod = uint64(resources.CPUPeriod)
15-
r.CpuQuota = uint64(resources.CPUQuota)
16+
if resources.NanoCPUs != 0 {
17+
r.CpuPeriod = uint64(100 * time.Millisecond / time.Microsecond)
18+
r.CpuQuota = uint64(resources.NanoCPUs) * r.CpuPeriod / 1e9
19+
} else {
20+
r.CpuPeriod = uint64(resources.CPUPeriod)
21+
r.CpuQuota = uint64(resources.CPUQuota)
22+
}
1623
r.CpusetCpus = resources.CpusetCpus
1724
r.CpusetMems = resources.CpusetMems
1825
r.MemoryLimit = uint64(resources.Memory)

docs/api/version-history.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ keywords: "API, Docker, rcli, REST, documentation"
3939
* `POST /services/create` and `POST /services/(id or name)/update` now accept a `rollback` value for `FailureAction`.
4040
* `POST /services/create` and `POST /services/(id or name)/update` now accept an optional `RollbackConfig` object which specifies rollback options.
4141
* `GET /services` now supports a `mode` filter to filter services based on the service mode (either `global` or `replicated`).
42+
* `POST /containers/(name)/update` now supports updating `NanoCPUs` that represents CPU quota in units of 10<sup>-9</sup> CPUs.
4243

4344
## v1.27 API changes
4445

docs/reference/commandline/update.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
2121
Update configuration of one or more containers
2222

2323
Options:
24-
--blkio-weight value Block IO (relative weight), between 10 and 1000
24+
--blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
2525
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
2626
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
27-
-c, --cpu-shares int CPU shares (relative weight)
2827
--cpu-rt-period int Limit the CPU real-time period in microseconds
2928
--cpu-rt-runtime int Limit the CPU real-time runtime in microseconds
29+
-c, --cpu-shares int CPU shares (relative weight)
30+
--cpus decimal Number of CPUs (default 0.000)
3031
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
3132
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
3233
--help Print usage

integration-cli/docker_cli_update_unix_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,38 @@ func (s *DockerSuite) TestUpdateNotAffectMonitorRestartPolicy(c *check.C) {
282282
c.Assert(err, checker.IsNil)
283283
c.Assert(waitRun(id), checker.IsNil)
284284
}
285+
286+
func (s *DockerSuite) TestUpdateWithNanoCPUs(c *check.C) {
287+
testRequires(c, cpuCfsQuota, cpuCfsPeriod)
288+
289+
file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"
290+
file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
291+
292+
out, _ := dockerCmd(c, "run", "-d", "--cpus", "0.5", "--name", "top", "busybox", "top")
293+
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
294+
295+
out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2))
296+
c.Assert(strings.TrimSpace(out), checker.Equals, "50000\n100000")
297+
298+
out = inspectField(c, "top", "HostConfig.NanoCpus")
299+
c.Assert(out, checker.Equals, "5e+08", check.Commentf("setting the Nano CPUs failed"))
300+
out = inspectField(c, "top", "HostConfig.CpuQuota")
301+
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0"))
302+
out = inspectField(c, "top", "HostConfig.CpuPeriod")
303+
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0"))
304+
305+
out, _, err := dockerCmdWithError("update", "--cpu-quota", "80000", "top")
306+
c.Assert(err, checker.NotNil)
307+
c.Assert(out, checker.Contains, "Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set")
308+
309+
out, _ = dockerCmd(c, "update", "--cpus", "0.8", "top")
310+
out = inspectField(c, "top", "HostConfig.NanoCpus")
311+
c.Assert(out, checker.Equals, "8e+08", check.Commentf("updating the Nano CPUs failed"))
312+
out = inspectField(c, "top", "HostConfig.CpuQuota")
313+
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0"))
314+
out = inspectField(c, "top", "HostConfig.CpuPeriod")
315+
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0"))
316+
317+
out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2))
318+
c.Assert(strings.TrimSpace(out), checker.Equals, "80000\n100000")
319+
}

0 commit comments

Comments
 (0)