Skip to content

Commit f29584e

Browse files
committed
Merge branch 'gitlab-runner-docker-ulimit-docker-ulimit'
2 parents 49546cc + a00f10e commit f29584e

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

common/config.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"path/filepath"
1212
"reflect"
13+
"strconv"
1314
"strings"
1415
"time"
1516

@@ -222,6 +223,7 @@ type DockerConfig struct {
222223
HelperImageFlavor string `toml:"helper_image_flavor,omitempty" json:"helper_image_flavor" long:"helper-image-flavor" env:"DOCKER_HELPER_IMAGE_FLAVOR" description:"Set helper image flavor (alpine, ubuntu), defaults to alpine"`
223224
ContainerLabels map[string]string `toml:"container_labels,omitempty" json:"container_labels,omitempty" long:"container-labels" description:"A toml table/json object of key-value. Value is expected to be a string. When set, this will create containers with the given container labels. Environment variables will be substituted for values here."`
224225
EnableIPv6 bool `toml:"enable_ipv6,omitempty" json:"enable_ipv6" long:"enable-ipv6" description:"Enable IPv6 for automatically created networks. This is only takes affect when the feature flag FF_NETWORK_PER_BUILD is enabled."`
226+
Ulimit map[string]string `toml:"ulimit,omitempty" json:"ulimit" long:"ulimit" env:"DOCKER_ULIMIT" description:"Ulimit options for container"`
225227
}
226228

227229
type InstanceConfig struct {
@@ -432,6 +434,35 @@ func (c KubernetesConfig) ConvertFromDockerPullPolicy(dockerPullPolicies []Docke
432434
return policies, nil
433435
}
434436

437+
func (c *DockerConfig) GetUlimits() ([]*units.Ulimit, error) {
438+
ulimits := make([]*units.Ulimit, 0, len(c.Ulimit))
439+
440+
for tp, limits := range c.Ulimit {
441+
ulimit := units.Ulimit{
442+
Name: tp,
443+
}
444+
445+
before, after, ok := strings.Cut(limits, ":")
446+
447+
var err error
448+
ulimit.Soft, err = strconv.ParseInt(before, 10, 64)
449+
if err != nil {
450+
return nil, fmt.Errorf("invalid soft limit value: %w", err)
451+
}
452+
453+
ulimit.Hard = ulimit.Soft
454+
if ok {
455+
ulimit.Hard, err = strconv.ParseInt(after, 10, 64)
456+
if err != nil {
457+
return nil, fmt.Errorf("invalid soft limit value: %w", err)
458+
}
459+
}
460+
461+
ulimits = append(ulimits, &ulimit)
462+
}
463+
return ulimits, nil
464+
}
465+
435466
type KubernetesDNSPolicy string
436467

437468
// Get returns one of the predefined values in kubernetes notation or an error if the value is not matched.

docs/configuration/advanced-configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ The following settings define the Docker container parameters.
324324
| `tls_verify` | Enable or disable TLS verification of connections to Docker daemon. Disabled by default. |
325325
| `user` | Run all commands in the container as the specified user. |
326326
| `userns_mode` | The user namespace mode for the container and Docker services when user namespace remapping option is enabled. Available in Docker 1.10 or later. |
327+
| `ulimit` | Ulimit values that are passed to the container. Uses the same syntax as the Docker `--ulimit` flag. |
327328
| `volumes` | Additional volumes that should be mounted. Same syntax as the Docker `-v` flag. |
328329
| `volumes_from` | A list of volumes to inherit from another container in the form ``<container name>[:<ro|rw>]``. Access level defaults to read-write, but can be manually set to `ro` (read-only) or `rw` (read-write). |
329330
| `volume_driver` | The volume driver to use for the container. |
@@ -375,6 +376,8 @@ Example:
375376
links = ["mysql_container:mysql"]
376377
allowed_images = ["ruby:*", "python:*", "php:*"]
377378
allowed_services = ["postgres:9", "redis:*", "mysql:*"]
379+
[runners.docker.ulimit]
380+
"rtprio" = "99"
378381
[[runners.docker.services]]
379382
name = "registry.example.com/svc1"
380383
alias = "svc1"

executors/docker/docker.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,11 @@ func (e *executor) createHostConfig() (*container.HostConfig, error) {
624624
"the valid values are: 'process', 'hyperv', 'default' and an empty string", isolation)
625625
}
626626

627+
ulimits, err := e.Config.Docker.GetUlimits()
628+
if err != nil {
629+
return nil, err
630+
}
631+
627632
return &container.HostConfig{
628633
Resources: container.Resources{
629634
Memory: e.Config.Docker.GetMemory(),
@@ -636,6 +641,7 @@ func (e *executor) createHostConfig() (*container.HostConfig, error) {
636641
DeviceRequests: e.deviceRequests,
637642
OomKillDisable: e.Config.Docker.GetOomKillDisable(),
638643
DeviceCgroupRules: e.Config.Docker.DeviceCgroupRules,
644+
Ulimits: ulimits,
639645
},
640646
DNS: e.Config.Docker.DNS,
641647
DNSSearch: e.Config.Docker.DNSSearch,

executors/docker/docker_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/docker/docker/api/types"
1818
"github.com/docker/docker/api/types/container"
1919
"github.com/docker/docker/api/types/network"
20+
"github.com/docker/go-units"
2021
logrustest "github.com/sirupsen/logrus/hooks/test"
2122
"github.com/stretchr/testify/assert"
2223
"github.com/stretchr/testify/mock"
@@ -1120,6 +1121,63 @@ func TestDockerSysctlsSetting(t *testing.T) {
11201121
testDockerConfigurationWithJobContainer(t, dockerConfig, cce)
11211122
}
11221123

1124+
func TestDockerUlimitSetting(t *testing.T) {
1125+
dockerConfig := &common.DockerConfig{}
1126+
1127+
tests := map[string]struct {
1128+
ulimit map[string]string
1129+
expectedUlimit []*units.Ulimit
1130+
expectedError bool
1131+
}{
1132+
"soft and hard values": {
1133+
ulimit: map[string]string{
1134+
"nofile": "1024:2048",
1135+
},
1136+
expectedUlimit: []*units.Ulimit{
1137+
{
1138+
Name: "nofile",
1139+
Soft: 1024,
1140+
Hard: 2048,
1141+
},
1142+
},
1143+
expectedError: false,
1144+
},
1145+
"single limit value": {
1146+
ulimit: map[string]string{
1147+
"nofile": "1024",
1148+
},
1149+
expectedUlimit: []*units.Ulimit{
1150+
{
1151+
Name: "nofile",
1152+
Soft: 1024,
1153+
Hard: 1024,
1154+
},
1155+
},
1156+
expectedError: false,
1157+
},
1158+
"invalid limit value": {
1159+
ulimit: map[string]string{
1160+
"nofile": "a",
1161+
},
1162+
expectedError: true,
1163+
},
1164+
}
1165+
1166+
for name, test := range tests {
1167+
t.Run(name, func(t *testing.T) {
1168+
dockerConfig.Ulimit = test.ulimit
1169+
1170+
ulimits, err := dockerConfig.GetUlimits()
1171+
if test.expectedError {
1172+
assert.Error(t, err)
1173+
return
1174+
}
1175+
1176+
assert.Equal(t, ulimits, test.expectedUlimit)
1177+
})
1178+
}
1179+
}
1180+
11231181
type testAllowedPrivilegedJobDescription struct {
11241182
expectedPrivileged bool
11251183
privileged bool

0 commit comments

Comments
 (0)