From 2ab416e4d04fed0dcd159d3a379703a24e065bc1 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Fri, 2 Feb 2024 15:05:25 +1100 Subject: [PATCH 1/2] Add device-level IO limit options The Docker run options `--device-read-bps`, `--device-read-iops`, `--device-write-bps`, `--device-write-iops` can now be set. --- README.md | 24 ++++++++++++++++++++++++ commands/run.sh | 28 ++++++++++++++++++++++++++++ plugin.yml | 8 ++++++++ 3 files changed, 60 insertions(+) diff --git a/README.md b/README.md index 3476f8a..30f93c4 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,30 @@ Enables debug mode, which outputs the full Docker commands that will be run on t Default: `false` +### `device-read-bps` (optional, array) + +Limit read rate from a device (format: `:[]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`. + +Example: `["/dev/sda1:200mb"]` + +### `device-read-iops` (optional, array) + +Limit read rate (IO per second) from a device (format: `:`). Number is a positive integer. + +Example: `["/dev/sda1:400"]` + +### `device-write-bps` (optional, array) + +Limit write rate to a device (format: `:[]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`. + +Example: `["/dev/sda1:200mb"]` + +### `device-write-iops` (optional, array) + +Limit write rate (IO per second) to a device (format: `:`). Number is a positive integer. + +Example: `["/dev/sda1:400"]` + ### `entrypoint` (optional, string) Override the image’s default entrypoint, and defaults the `shell` option to `false`. See the [docker run --entrypoint documentation](https://docs.docker.com/engine/reference/run/#entrypoint-default-command-to-execute-at-runtime) for more details. Set it to `""` (empty string) to disable the default entrypoint for the image, but note that you may need to use this plugin's `command` option instead of the top-level `command` option or set a `shell` instead (depending on the command you want/need to run - see [Issue 138](https://github.com/buildkite-plugins/docker-buildkite-plugin/issues/138) for more information). diff --git a/commands/run.sh b/commands/run.sh index cde573b..d962d5a 100644 --- a/commands/run.sh +++ b/commands/run.sh @@ -407,6 +407,34 @@ if [[ -n "${BUILDKITE_PLUGIN_DOCKER_MEMORY_SWAPPINESS:-}" ]]; then args+=("--memory-swappiness=${BUILDKITE_PLUGIN_DOCKER_MEMORY_SWAPPINESS}") fi +# Handle setting device read throughput if provided +if plugin_read_list_into_result BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_BPS; then + for arg in "${result[@]}"; do + args+=("--device-read-bps" "$arg") + done +fi + +# Handle setting device write throughput if provided +if plugin_read_list_into_result BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_BPS; then + for arg in "${result[@]}"; do + args+=("--device-write-bps" "$arg") + done +fi + +# Handle setting device read IOPS if provided +if plugin_read_list_into_result BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_IOPS; then + for arg in "${result[@]}"; do + args+=("--device-read-iops" "$arg") + done +fi + +# Handle setting device write IOPS if provided +if plugin_read_list_into_result BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_IOPS; then + for arg in "${result[@]}"; do + args+=("--device-write-iops" "$arg") + done +fi + # Handle entrypoint if set, and default shell to disabled if [[ -n ${BUILDKITE_PLUGIN_DOCKER_ENTRYPOINT+x} ]]; then args+=("--entrypoint" "${BUILDKITE_PLUGIN_DOCKER_ENTRYPOINT}") diff --git a/plugin.yml b/plugin.yml index 852a964..68afe12 100644 --- a/plugin.yml +++ b/plugin.yml @@ -17,6 +17,14 @@ configuration: type: string debug: type: boolean + device-read-bps: + type: array + device-read-iops: + type: array + device-write-bps: + type: array + device-write-iops: + type: array entrypoint: type: string environment: From 216a54ccbbb21b5e0010cdc4c559262df574902e Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 5 Feb 2024 13:47:56 +1100 Subject: [PATCH 2/2] Add tests for device io limits --- tests/command.bats | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/command.bats b/tests/command.bats index 1ea94b2..3190142 100644 --- a/tests/command.bats +++ b/tests/command.bats @@ -1028,6 +1028,74 @@ EOF unstub docker } +@test "Runs BUILDKITE_COMMAND with multiple added device read bps" { + export BUILDKITE_COMMAND="echo hello world" + export BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_BPS_0='bps-0' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_BPS_1='bps-1' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_BPS_2='bps-2' + + stub docker \ + "run -t -i --rm --init --volume $PWD:/workdir --workdir /workdir --device-read-bps bps-0 --device-read-bps bps-1 --device-read-bps bps-2 --label com.buildkite.job-id=1-2-3-4 image:tag /bin/sh -e -c 'echo hello world' : echo ran command in docker" + + run "$PWD"/hooks/command + + assert_success + assert_output --partial "ran command in docker" + + unstub docker +} + +@test "Runs BUILDKITE_COMMAND with multiple added device write bps" { + export BUILDKITE_COMMAND="echo hello world" + export BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_BPS_0='bps-0' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_BPS_1='bps-1' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_BPS_2='bps-2' + + stub docker \ + "run -t -i --rm --init --volume $PWD:/workdir --workdir /workdir --device-write-bps bps-0 --device-write-bps bps-1 --device-write-bps bps-2 --label com.buildkite.job-id=1-2-3-4 image:tag /bin/sh -e -c 'echo hello world' : echo ran command in docker" + + run "$PWD"/hooks/command + + assert_success + assert_output --partial "ran command in docker" + + unstub docker +} + +@test "Runs BUILDKITE_COMMAND with multiple added device read iops" { + export BUILDKITE_COMMAND="echo hello world" + export BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_IOPS_0='iops-0' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_IOPS_1='iops-1' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_READ_IOPS_2='iops-2' + + stub docker \ + "run -t -i --rm --init --volume $PWD:/workdir --workdir /workdir --device-read-iops iops-0 --device-read-iops iops-1 --device-read-iops iops-2 --label com.buildkite.job-id=1-2-3-4 image:tag /bin/sh -e -c 'echo hello world' : echo ran command in docker" + + run "$PWD"/hooks/command + + assert_success + assert_output --partial "ran command in docker" + + unstub docker +} + +@test "Runs BUILDKITE_COMMAND with multiple added device write iops" { + export BUILDKITE_COMMAND="echo hello world" + export BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_IOPS_0='iops-0' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_IOPS_1='iops-1' + export BUILDKITE_PLUGIN_DOCKER_DEVICE_WRITE_IOPS_2='iops-2' + + stub docker \ + "run -t -i --rm --init --volume $PWD:/workdir --workdir /workdir --device-write-iops iops-0 --device-write-iops iops-1 --device-write-iops iops-2 --label com.buildkite.job-id=1-2-3-4 image:tag /bin/sh -e -c 'echo hello world' : echo ran command in docker" + + run "$PWD"/hooks/command + + assert_success + assert_output --partial "ran command in docker" + + unstub docker +} + @test "Runs BUILDKITE_COMMAND with one added capability" { export BUILDKITE_COMMAND="echo hello world" export BUILDKITE_PLUGIN_DOCKER_ADD_CAPS_0='cap-0'