mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
fn: add storage opt size support (#860)
Added env FN_MAX_FS_SIZE_MB, which if defined and non-zero is passed to docker as storage opt size. We do not validate if this option is supported by docker currently. This is because it's difficult to actually validate this since it not only depends on storage driver and its backing filesystem, but also the mount options used to mount that fs.
This commit is contained in:
@@ -597,6 +597,7 @@ func (a *agent) prepCold(ctx context.Context, call *call, tok ResourceToken, ch
|
|||||||
env: map[string]string(call.Config),
|
env: map[string]string(call.Config),
|
||||||
memory: call.Memory,
|
memory: call.Memory,
|
||||||
cpus: uint64(call.CPUs),
|
cpus: uint64(call.CPUs),
|
||||||
|
fsSize: a.cfg.MaxFsSize,
|
||||||
timeout: time.Duration(call.Timeout) * time.Second, // this is unnecessary, but in case removal fails...
|
timeout: time.Duration(call.Timeout) * time.Second, // this is unnecessary, but in case removal fails...
|
||||||
stdin: call.req.Body,
|
stdin: call.req.Body,
|
||||||
stdout: common.NewClampWriter(call.w, a.cfg.MaxResponseSize, models.ErrFunctionResponseTooBig),
|
stdout: common.NewClampWriter(call.w, a.cfg.MaxResponseSize, models.ErrFunctionResponseTooBig),
|
||||||
@@ -629,10 +630,7 @@ func (a *agent) runHot(ctx context.Context, call *call, tok ResourceToken, state
|
|||||||
state.UpdateState(ctx, ContainerStateStart, call.slots)
|
state.UpdateState(ctx, ContainerStateStart, call.slots)
|
||||||
defer state.UpdateState(ctx, ContainerStateDone, call.slots)
|
defer state.UpdateState(ctx, ContainerStateDone, call.slots)
|
||||||
|
|
||||||
// if freezer is enabled, be consistent with freezer behavior and
|
container, closer := NewHotContainer(call, &a.cfg)
|
||||||
// block stdout and stderr between calls.
|
|
||||||
isBlockIdleIO := MaxDisabledMsecs != a.cfg.FreezeIdle
|
|
||||||
container, closer := NewHotContainer(call, isBlockIdleIO)
|
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
logger := logrus.WithFields(logrus.Fields{"id": container.id, "app": call.AppName, "route": call.Path, "image": call.Image, "memory": call.Memory, "cpus": call.CPUs, "format": call.Format, "idle_timeout": call.IdleTimeout})
|
logger := logrus.WithFields(logrus.Fields{"id": container.id, "app": call.AppName, "route": call.Path, "image": call.Image, "memory": call.Memory, "cpus": call.CPUs, "format": call.Format, "idle_timeout": call.IdleTimeout})
|
||||||
@@ -795,6 +793,7 @@ type container struct {
|
|||||||
env map[string]string
|
env map[string]string
|
||||||
memory uint64
|
memory uint64
|
||||||
cpus uint64
|
cpus uint64
|
||||||
|
fsSize uint64
|
||||||
timeout time.Duration // cold only (superfluous, but in case)
|
timeout time.Duration // cold only (superfluous, but in case)
|
||||||
|
|
||||||
stdin io.Reader
|
stdin io.Reader
|
||||||
@@ -806,7 +805,11 @@ type container struct {
|
|||||||
stats *drivers.Stats
|
stats *drivers.Stats
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHotContainer(call *call, isBlockIdleIO bool) (*container, func()) {
|
func NewHotContainer(call *call, cfg *AgentConfig) (*container, func()) {
|
||||||
|
|
||||||
|
// if freezer is enabled, be consistent with freezer behavior and
|
||||||
|
// block stdout and stderr between calls.
|
||||||
|
isBlockIdleIO := MaxDisabledMsecs != cfg.FreezeIdle
|
||||||
|
|
||||||
id := id.New().String()
|
id := id.New().String()
|
||||||
|
|
||||||
@@ -834,6 +837,7 @@ func NewHotContainer(call *call, isBlockIdleIO bool) (*container, func()) {
|
|||||||
env: map[string]string(call.Config),
|
env: map[string]string(call.Config),
|
||||||
memory: call.Memory,
|
memory: call.Memory,
|
||||||
cpus: uint64(call.CPUs),
|
cpus: uint64(call.CPUs),
|
||||||
|
fsSize: cfg.MaxFsSize,
|
||||||
stdin: stdin,
|
stdin: stdin,
|
||||||
stdout: stdout,
|
stdout: stdout,
|
||||||
stderr: stderr,
|
stderr: stderr,
|
||||||
@@ -877,6 +881,7 @@ func (c *container) Timeout() time.Duration { return c.timeout }
|
|||||||
func (c *container) EnvVars() map[string]string { return c.env }
|
func (c *container) EnvVars() map[string]string { return c.env }
|
||||||
func (c *container) Memory() uint64 { return c.memory * 1024 * 1024 } // convert MB
|
func (c *container) Memory() uint64 { return c.memory * 1024 * 1024 } // convert MB
|
||||||
func (c *container) CPUs() uint64 { return c.cpus }
|
func (c *container) CPUs() uint64 { return c.cpus }
|
||||||
|
func (c *container) FsSize() uint64 { return c.fsSize }
|
||||||
|
|
||||||
// WriteStat publishes each metric in the specified Stats structure as a histogram metric
|
// WriteStat publishes each metric in the specified Stats structure as a histogram metric
|
||||||
func (c *container) WriteStat(ctx context.Context, stat drivers.Stat) {
|
func (c *container) WriteStat(ctx context.Context, stat drivers.Stat) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type AgentConfig struct {
|
|||||||
MaxLogSize uint64 `json:"max_log_size_bytes"`
|
MaxLogSize uint64 `json:"max_log_size_bytes"`
|
||||||
MaxTotalCPU uint64 `json:"max_total_cpu_mcpus"`
|
MaxTotalCPU uint64 `json:"max_total_cpu_mcpus"`
|
||||||
MaxTotalMemory uint64 `json:"max_total_memory_bytes"`
|
MaxTotalMemory uint64 `json:"max_total_memory_bytes"`
|
||||||
|
MaxFsSize uint64 `json:"max_fs_size_mb"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -31,6 +32,7 @@ const (
|
|||||||
EnvMaxLogSize = "FN_MAX_LOG_SIZE_BYTES"
|
EnvMaxLogSize = "FN_MAX_LOG_SIZE_BYTES"
|
||||||
EnvMaxTotalCPU = "FN_MAX_TOTAL_CPU_MCPUS"
|
EnvMaxTotalCPU = "FN_MAX_TOTAL_CPU_MCPUS"
|
||||||
EnvMaxTotalMemory = "FN_MAX_TOTAL_MEMORY_BYTES"
|
EnvMaxTotalMemory = "FN_MAX_TOTAL_MEMORY_BYTES"
|
||||||
|
EnvMaxFsSize = "FN_MAX_FS_SIZE_MB"
|
||||||
|
|
||||||
MaxDisabledMsecs = time.Duration(math.MaxInt64)
|
MaxDisabledMsecs = time.Duration(math.MaxInt64)
|
||||||
)
|
)
|
||||||
@@ -53,6 +55,7 @@ func NewAgentConfig() (*AgentConfig, error) {
|
|||||||
err = setEnvUint(err, EnvMaxLogSize, &cfg.MaxLogSize)
|
err = setEnvUint(err, EnvMaxLogSize, &cfg.MaxLogSize)
|
||||||
err = setEnvUint(err, EnvMaxTotalCPU, &cfg.MaxTotalCPU)
|
err = setEnvUint(err, EnvMaxTotalCPU, &cfg.MaxTotalCPU)
|
||||||
err = setEnvUint(err, EnvMaxTotalMemory, &cfg.MaxTotalMemory)
|
err = setEnvUint(err, EnvMaxTotalMemory, &cfg.MaxTotalMemory)
|
||||||
|
err = setEnvUint(err, EnvMaxFsSize, &cfg.MaxFsSize)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cfg, err
|
return cfg, err
|
||||||
|
|||||||
@@ -168,6 +168,13 @@ func (drv *DockerDriver) Prepare(ctx context.Context, task drivers.ContainerTask
|
|||||||
container.HostConfig.CPUPeriod = 100000
|
container.HostConfig.CPUPeriod = 100000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If defined, impose file system size limit. In MB units.
|
||||||
|
if task.FsSize() != 0 {
|
||||||
|
container.HostConfig.StorageOpt = make(map[string]string)
|
||||||
|
sizeOption := fmt.Sprintf("%vM", task.FsSize())
|
||||||
|
container.HostConfig.StorageOpt["size"] = sizeOption
|
||||||
|
}
|
||||||
|
|
||||||
volumes := task.Volumes()
|
volumes := task.Volumes()
|
||||||
for _, mapping := range volumes {
|
for _, mapping := range volumes {
|
||||||
hostDir := mapping[0]
|
hostDir := mapping[0]
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ func (f *taskDockerTest) WriteStat(context.Context, drivers.Stat) { /* TODO */ }
|
|||||||
func (f *taskDockerTest) Volumes() [][2]string { return [][2]string{} }
|
func (f *taskDockerTest) Volumes() [][2]string { return [][2]string{} }
|
||||||
func (f *taskDockerTest) Memory() uint64 { return 256 * 1024 * 1024 }
|
func (f *taskDockerTest) Memory() uint64 { return 256 * 1024 * 1024 }
|
||||||
func (f *taskDockerTest) CPUs() uint64 { return 0 }
|
func (f *taskDockerTest) CPUs() uint64 { return 0 }
|
||||||
|
func (f *taskDockerTest) FsSize() uint64 { return 0 }
|
||||||
func (f *taskDockerTest) WorkDir() string { return "" }
|
func (f *taskDockerTest) WorkDir() string { return "" }
|
||||||
func (f *taskDockerTest) Close() {}
|
func (f *taskDockerTest) Close() {}
|
||||||
func (f *taskDockerTest) Input() io.Reader { return f.input }
|
func (f *taskDockerTest) Input() io.Reader { return f.input }
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ type ContainerTask interface {
|
|||||||
// CPUs in milli CPU units
|
// CPUs in milli CPU units
|
||||||
CPUs() uint64
|
CPUs() uint64
|
||||||
|
|
||||||
|
// Filesystem size limit for the container, in megabytes.
|
||||||
|
FsSize() uint64
|
||||||
|
|
||||||
// WorkDir returns the working directory to use for the task. Empty string
|
// WorkDir returns the working directory to use for the task. Empty string
|
||||||
// leaves it unset.
|
// leaves it unset.
|
||||||
WorkDir() string
|
WorkDir() string
|
||||||
|
|||||||
Reference in New Issue
Block a user