Commit c1cd8372 authored by Jay Linski's avatar Jay Linski

Add possibility to specify memory in Docker containers

The memory of Docker containers created by runners can now be limited:
* Memory
* MemorySwap
* MemoryReservation

See https://docs.docker.com/engine/reference/run/#runtime-constraints-on-resources.

Implements #1582.
parent d5d0b1e6
......@@ -577,7 +577,7 @@ v 1.6.0
- Pass all configured CA certificates to builds !299
- Use git-init templates (clone) and git config without --global (fetch) to disable recurseSubmodules !314
- Improve docker machine logging !234
- Add posibility to specify a list of volumes to inherit from another container !236
- Add possibility to specify a list of volumes to inherit from another container !236
- Fix range mismatch handling error while patch tracing !319
- Add docker+machine and kubernetes executors to "I'm not sure" part of executors README.md !320
- Remove ./git/index.lock before fetching !316
......@@ -649,7 +649,7 @@ v 1.3.1
v 1.3.0
- Add incremental build trace update
- Add posibility to specify CpusetCpus, Dns and DnsSearch for docker containers created by runners
- Add possibility to specify CpusetCpus, Dns and DnsSearch for docker containers created by runners
- Add a custom `User-Agent` header with version number and runtime information (go version, platform, os)
- Add artifacts expiration handling
- Add artifacts handling for failed builds
......
......@@ -13,6 +13,7 @@ import (
"path/filepath"
"github.com/BurntSushi/toml"
units "github.com/docker/go-units"
log "github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitlab-runner/helpers"
......@@ -53,6 +54,9 @@ type DockerConfig struct {
Hostname string `toml:"hostname,omitempty" json:"hostname" long:"hostname" env:"DOCKER_HOSTNAME" description:"Custom container hostname"`
Image string `toml:"image" json:"image" long:"image" env:"DOCKER_IMAGE" description:"Docker image to be used"`
Runtime string `toml:"runtime,omitempty" json:"runtime" long:"runtime" env:"DOCKER_RUNTIME" description:"Docker runtime to be used"`
Memory string `toml:"memory,omitempty" json:"memory" long:"memory" env:"DOCKER_MEMORY" description:"Memory limit (format: <number>[<unit>]). Unit can be one of b, k, m, or g. Minimum is 4M."`
MemorySwap string `toml:"memory_swap,omitempty" json:"memory_swap" long:"memory-swap" env:"DOCKER_MEMORY_SWAP" description:"Total memory limit (memory + swap, format: <number>[<unit>]). Unit can be one of b, k, m, or g."`
MemoryReservation string `toml:"memory_reservation,omitempty" json:"memory_reservation" long:"memory-reservation" env:"DOCKER_MEMORY_RESERVATION" description:"Memory soft limit (format: <number>[<unit>]). Unit can be one of b, k, m, or g."`
CPUSetCPUs string `toml:"cpuset_cpus,omitempty" json:"cpuset_cpus" long:"cpuset-cpus" env:"DOCKER_CPUSET_CPUS" description:"String value containing the cgroups CpusetCpus to use"`
CPUS string `toml:"cpus,omitempty" json:"cpus" long:"cpus" env:"DOCKER_CPUS" description:"Number of CPUs"`
DNS []string `toml:"dns,omitempty" json:"dns" long:"dns" env:"DOCKER_DNS" description:"A list of DNS servers for the container to use"`
......@@ -286,6 +290,31 @@ func (c *DockerConfig) GetNanoCPUs() (int64, error) {
return int64(nano), nil
}
func (c *DockerConfig) getMemoryBytes(size string, fieldName string) int64 {
if size == "" {
return 0
}
bytes, err := units.RAMInBytes(size)
if err != nil {
log.Fatalf("Error parsing docker %s: %s", fieldName, err)
}
return bytes
}
func (c *DockerConfig) GetMemory() int64 {
return c.getMemoryBytes(c.Memory, "memory")
}
func (c *DockerConfig) GetMemorySwap() int64 {
return c.getMemoryBytes(c.MemorySwap, "memory_swap")
}
func (c *DockerConfig) GetMemoryReservation() int64 {
return c.getMemoryBytes(c.MemoryReservation, "memory_reservation")
}
func (c *KubernetesConfig) GetHelperImage() string {
if len(c.HelperImage) > 0 {
return c.HelperImage
......
......@@ -118,6 +118,9 @@ This defines the Docker Container parameters.
| `runtime` | Specify a runtime for Docker container |
| `tls_cert_path` | When set it will use `ca.pem`, `cert.pem` and `key.pem` from that folder to make secure TLS connection to Docker (useful in boot2docker) |
| `image` | Use this image to run builds |
| `memory` | String value containing the memory limit |
| `memory_swap` | String value containing the total memory limit |
| `memory_reservation` | String value containing the memory soft limit |
| `cpuset_cpus` | String value containing the cgroups CpusetCpus to use |
| `cpus` | Number of CPUs (available in docker 1.13 or later) |
| `dns` | A list of DNS servers for the container to use |
......@@ -153,6 +156,9 @@ Example:
hostname = ""
tls_cert_path = "/Users/ayufan/.boot2docker/certs"
image = "ruby:2.1"
memory = "128m"
memory_swap = "256m"
memory_reservation = "64m"
cpuset_cpus = "0,1"
dns = ["8.8.8.8"]
dns_search = [""]
......
......@@ -841,9 +841,12 @@ func (s *executor) createContainer(containerType string, imageDefinition common.
hostConfig := &container.HostConfig{
Resources: container.Resources{
CpusetCpus: s.Config.Docker.CPUSetCPUs,
NanoCPUs: nanoCPUs,
Devices: s.devices,
Memory: s.Config.Docker.GetMemory(),
MemorySwap: s.Config.Docker.GetMemorySwap(),
MemoryReservation: s.Config.Docker.GetMemoryReservation(),
CpusetCpus: s.Config.Docker.CPUSetCPUs,
NanoCPUs: nanoCPUs,
Devices: s.devices,
},
DNS: s.Config.Docker.DNS,
DNSSearch: s.Config.Docker.DNSSearch,
......
......@@ -941,6 +941,42 @@ func testDockerConfigurationWithServiceContainer(t *testing.T, dockerConfig *com
assert.NoError(t, err, "Should create service container without errors")
}
func TestDockerMemorySetting(t *testing.T) {
dockerConfig := &common.DockerConfig{
Memory: "42m",
}
cce := func(t *testing.T, config *container.Config, hostConfig *container.HostConfig) {
assert.Equal(t, int64(44040192), hostConfig.Memory)
}
testDockerConfigurationWithJobContainer(t, dockerConfig, cce)
}
func TestDockerMemorySwapSetting(t *testing.T) {
dockerConfig := &common.DockerConfig{
MemorySwap: "2g",
}
cce := func(t *testing.T, config *container.Config, hostConfig *container.HostConfig) {
assert.Equal(t, int64(2147483648), hostConfig.MemorySwap)
}
testDockerConfigurationWithJobContainer(t, dockerConfig, cce)
}
func TestDockerMemoryReservationSetting(t *testing.T) {
dockerConfig := &common.DockerConfig{
MemoryReservation: "64m",
}
cce := func(t *testing.T, config *container.Config, hostConfig *container.HostConfig) {
assert.Equal(t, int64(67108864), hostConfig.MemoryReservation)
}
testDockerConfigurationWithJobContainer(t, dockerConfig, cce)
}
func TestDockerCPUSSetting(t *testing.T) {
examples := []struct {
cpus string
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment