mirror of
https://github.com/opencontainers/runc.git
synced 2025-09-26 19:41:35 +08:00
Merge pull request #4775 from kolyshkin/update-resources
runc update: support per-device weight and iops
This commit is contained in:
@@ -174,17 +174,40 @@ function setup() {
|
|||||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_dev_weight
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_dev_weight
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
# The loop device itself is no longer needed.
|
|
||||||
losetup -d "$dev"
|
|
||||||
|
|
||||||
if [ -v CGROUP_V2 ]; then
|
if [ -v CGROUP_V2 ]; then
|
||||||
file="io.bfq.weight"
|
file="io.bfq.weight"
|
||||||
else
|
else
|
||||||
file="blkio.bfq.weight_device"
|
file="blkio.bfq.weight_device"
|
||||||
fi
|
fi
|
||||||
weights=$(get_cgroup_value $file)
|
weights1=$(get_cgroup_value $file)
|
||||||
[[ "$weights" == *"default 333"* ]]
|
|
||||||
[[ "$weights" == *"$major:$minor 444"* ]]
|
# Check that runc update works.
|
||||||
|
runc update -r - test_dev_weight <<EOF
|
||||||
|
{
|
||||||
|
"blockIO": {
|
||||||
|
"weight": 111,
|
||||||
|
"weightDevice": [
|
||||||
|
{
|
||||||
|
"major": $major,
|
||||||
|
"minor": $minor,
|
||||||
|
"weight": 222
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
weights2=$(get_cgroup_value $file)
|
||||||
|
|
||||||
|
# The loop device itself is no longer needed.
|
||||||
|
losetup -d "$dev"
|
||||||
|
|
||||||
|
# Check original values.
|
||||||
|
grep '^default 333$' <<<"$weights1"
|
||||||
|
grep "^$major:$minor 444$" <<<"$weights1"
|
||||||
|
# Check updated values.
|
||||||
|
grep '^default 111$' <<<"$weights2"
|
||||||
|
grep "^$major:$minor 222$" <<<"$weights2"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "runc run (per-device multiple iops via unified)" {
|
@test "runc run (per-device multiple iops via unified)" {
|
||||||
|
@@ -379,6 +379,22 @@ function check_cpu_weight() {
|
|||||||
check_systemd_value "CPUWeight" "$weight"
|
check_systemd_value "CPUWeight" "$weight"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_cgroup_dev_iops() {
|
||||||
|
local dev=$1 rbps=$2 wbps=$3 riops=$4 wiops=$5
|
||||||
|
|
||||||
|
if [ -v CGROUP_V2 ]; then
|
||||||
|
iops=$(get_cgroup_value "io.max")
|
||||||
|
printf "== io.max ==\n%s\n" "$iops"
|
||||||
|
grep "^$dev rbps=$rbps wbps=$wbps riops=$riops wiops=$wiops$" <<<"$iops"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep "^$dev ${rbps}$" <<<"$(get_cgroup_value blkio.throttle.read_bps_device)"
|
||||||
|
grep "^$dev ${wbps}$" <<<"$(get_cgroup_value blkio.throttle.write_bps_device)"
|
||||||
|
grep "^$dev ${riops}$" <<<"$(get_cgroup_value blkio.throttle.read_iops_device)"
|
||||||
|
grep "^$dev ${wiops}$" <<<"$(get_cgroup_value blkio.throttle.write_iops_device)"
|
||||||
|
}
|
||||||
|
|
||||||
# Helper function to set a resources limit
|
# Helper function to set a resources limit
|
||||||
function set_resources_limit() {
|
function set_resources_limit() {
|
||||||
update_config '.linux.resources.pids.limit |= 100'
|
update_config '.linux.resources.pids.limit |= 100'
|
||||||
|
@@ -891,3 +891,65 @@ EOF
|
|||||||
runc update test_update --memory 1024
|
runc update test_update --memory 1024
|
||||||
wait_for_container 10 1 test_update stopped
|
wait_for_container 10 1 test_update stopped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "update per-device iops/bps values" {
|
||||||
|
[ $EUID -ne 0 ] && requires rootless_cgroup
|
||||||
|
|
||||||
|
# We need a major number of any disk device. Usually those are partitioned,
|
||||||
|
# with the device itself having minor of 0, and partitions are 1, 2...
|
||||||
|
major=$(awk '$2 == 0 {print $1; exit}' /proc/partitions)
|
||||||
|
if [ "$major" = "0" ] || [ "$major" = "" ]; then
|
||||||
|
echo "=== /proc/partitions ==="
|
||||||
|
cat /proc/partitions
|
||||||
|
echo "==="
|
||||||
|
skip "can't get device major number from /proc/partitions (got $major)"
|
||||||
|
fi
|
||||||
|
# Add an entry to check that
|
||||||
|
# - existing devices can be updated;
|
||||||
|
# - duplicates are handled properly;
|
||||||
|
# (see func upsert* in update.go).
|
||||||
|
update_config ' .linux.resources.blockIO.throttleReadBpsDevice |= [
|
||||||
|
{ major: '"$major"', minor: 0, rate: 485760 },
|
||||||
|
{ major: '"$major"', minor: 0, rate: 485760 }
|
||||||
|
]'
|
||||||
|
|
||||||
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_update
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
runc update -r - test_update <<EOF
|
||||||
|
{
|
||||||
|
"blockIO": {
|
||||||
|
"throttleReadBpsDevice": [
|
||||||
|
{
|
||||||
|
"major": $major,
|
||||||
|
"minor": 0,
|
||||||
|
"rate": 10485760
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"throttleWriteBpsDevice": [
|
||||||
|
{
|
||||||
|
"major": $major,
|
||||||
|
"minor": 0,
|
||||||
|
"rate": 9437184
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"throttleReadIOPSDevice": [
|
||||||
|
{
|
||||||
|
"major": $major,
|
||||||
|
"minor": 0,
|
||||||
|
"rate": 1000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"throttleWriteIOPSDevice": [
|
||||||
|
{
|
||||||
|
"major": $major,
|
||||||
|
"minor": 0,
|
||||||
|
"rate": 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
check_cgroup_dev_iops "$major:0" 10485760 9437184 1000 900
|
||||||
|
}
|
||||||
|
62
update.go
62
update.go
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/opencontainers/cgroups"
|
"github.com/opencontainers/cgroups"
|
||||||
@@ -273,6 +274,25 @@ other options are ignored.
|
|||||||
if r.BlockIO.Weight != nil {
|
if r.BlockIO.Weight != nil {
|
||||||
config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight
|
config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight
|
||||||
}
|
}
|
||||||
|
if r.BlockIO.LeafWeight != nil {
|
||||||
|
config.Cgroups.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight
|
||||||
|
}
|
||||||
|
// For devices, we either update an existing one, or insert a new one.
|
||||||
|
for _, wd := range r.BlockIO.WeightDevice {
|
||||||
|
config.Cgroups.Resources.BlkioWeightDevice = upsertWeightDevice(config.Cgroups.Resources.BlkioWeightDevice, wd)
|
||||||
|
}
|
||||||
|
for _, td := range r.BlockIO.ThrottleReadBpsDevice {
|
||||||
|
config.Cgroups.Resources.BlkioThrottleReadBpsDevice = upsertThrottleDevice(config.Cgroups.Resources.BlkioThrottleReadBpsDevice, td)
|
||||||
|
}
|
||||||
|
for _, td := range r.BlockIO.ThrottleWriteBpsDevice {
|
||||||
|
config.Cgroups.Resources.BlkioThrottleWriteBpsDevice = upsertThrottleDevice(config.Cgroups.Resources.BlkioThrottleWriteBpsDevice, td)
|
||||||
|
}
|
||||||
|
for _, td := range r.BlockIO.ThrottleReadIOPSDevice {
|
||||||
|
config.Cgroups.Resources.BlkioThrottleReadIOPSDevice = upsertThrottleDevice(config.Cgroups.Resources.BlkioThrottleReadIOPSDevice, td)
|
||||||
|
}
|
||||||
|
for _, td := range r.BlockIO.ThrottleWriteIOPSDevice {
|
||||||
|
config.Cgroups.Resources.BlkioThrottleWriteIOPSDevice = upsertThrottleDevice(config.Cgroups.Resources.BlkioThrottleWriteIOPSDevice, td)
|
||||||
|
}
|
||||||
|
|
||||||
// Setting CPU quota and period independently does not make much sense,
|
// Setting CPU quota and period independently does not make much sense,
|
||||||
// but historically runc allowed it and this needs to be supported
|
// but historically runc allowed it and this needs to be supported
|
||||||
@@ -381,3 +401,45 @@ other options are ignored.
|
|||||||
return container.Set(config)
|
return container.Set(config)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func upsertWeightDevice(devices []*cgroups.WeightDevice, wd specs.LinuxWeightDevice) []*cgroups.WeightDevice {
|
||||||
|
// Iterate backwards because in case of a duplicate
|
||||||
|
// the last one will be used.
|
||||||
|
for i, dev := range slices.Backward(devices) {
|
||||||
|
if dev.Major != wd.Major || dev.Minor != wd.Minor {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Update weights for existing device.
|
||||||
|
if wd.Weight != nil {
|
||||||
|
devices[i].Weight = *wd.Weight
|
||||||
|
}
|
||||||
|
if wd.LeafWeight != nil {
|
||||||
|
devices[i].LeafWeight = *wd.LeafWeight
|
||||||
|
}
|
||||||
|
return devices
|
||||||
|
}
|
||||||
|
|
||||||
|
// New device -- append it.
|
||||||
|
var weight, leafWeight uint16
|
||||||
|
if wd.Weight != nil {
|
||||||
|
weight = *wd.Weight
|
||||||
|
}
|
||||||
|
if wd.LeafWeight != nil {
|
||||||
|
leafWeight = *wd.LeafWeight
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(devices, cgroups.NewWeightDevice(wd.Major, wd.Minor, weight, leafWeight))
|
||||||
|
}
|
||||||
|
|
||||||
|
func upsertThrottleDevice(devices []*cgroups.ThrottleDevice, td specs.LinuxThrottleDevice) []*cgroups.ThrottleDevice {
|
||||||
|
// Iterate backwards because in case of a duplicate
|
||||||
|
// the last one will be used.
|
||||||
|
for i, dev := range slices.Backward(devices) {
|
||||||
|
if dev.Major == td.Major && dev.Minor == td.Minor {
|
||||||
|
devices[i].Rate = td.Rate
|
||||||
|
return devices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(devices, cgroups.NewThrottleDevice(td.Major, td.Minor, td.Rate))
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user