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),
|
||||
memory: call.Memory,
|
||||
cpus: uint64(call.CPUs),
|
||||
fsSize: a.cfg.MaxFsSize,
|
||||
timeout: time.Duration(call.Timeout) * time.Second, // this is unnecessary, but in case removal fails...
|
||||
stdin: call.req.Body,
|
||||
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)
|
||||
defer state.UpdateState(ctx, ContainerStateDone, call.slots)
|
||||
|
||||
// if freezer is enabled, be consistent with freezer behavior and
|
||||
// block stdout and stderr between calls.
|
||||
isBlockIdleIO := MaxDisabledMsecs != a.cfg.FreezeIdle
|
||||
container, closer := NewHotContainer(call, isBlockIdleIO)
|
||||
container, closer := NewHotContainer(call, &a.cfg)
|
||||
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})
|
||||
@@ -795,6 +793,7 @@ type container struct {
|
||||
env map[string]string
|
||||
memory uint64
|
||||
cpus uint64
|
||||
fsSize uint64
|
||||
timeout time.Duration // cold only (superfluous, but in case)
|
||||
|
||||
stdin io.Reader
|
||||
@@ -806,7 +805,11 @@ type container struct {
|
||||
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()
|
||||
|
||||
@@ -834,6 +837,7 @@ func NewHotContainer(call *call, isBlockIdleIO bool) (*container, func()) {
|
||||
env: map[string]string(call.Config),
|
||||
memory: call.Memory,
|
||||
cpus: uint64(call.CPUs),
|
||||
fsSize: cfg.MaxFsSize,
|
||||
stdin: stdin,
|
||||
stdout: stdout,
|
||||
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) Memory() uint64 { return c.memory * 1024 * 1024 } // convert MB
|
||||
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
|
||||
func (c *container) WriteStat(ctx context.Context, stat drivers.Stat) {
|
||||
|
||||
@@ -19,6 +19,7 @@ type AgentConfig struct {
|
||||
MaxLogSize uint64 `json:"max_log_size_bytes"`
|
||||
MaxTotalCPU uint64 `json:"max_total_cpu_mcpus"`
|
||||
MaxTotalMemory uint64 `json:"max_total_memory_bytes"`
|
||||
MaxFsSize uint64 `json:"max_fs_size_mb"`
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -31,6 +32,7 @@ const (
|
||||
EnvMaxLogSize = "FN_MAX_LOG_SIZE_BYTES"
|
||||
EnvMaxTotalCPU = "FN_MAX_TOTAL_CPU_MCPUS"
|
||||
EnvMaxTotalMemory = "FN_MAX_TOTAL_MEMORY_BYTES"
|
||||
EnvMaxFsSize = "FN_MAX_FS_SIZE_MB"
|
||||
|
||||
MaxDisabledMsecs = time.Duration(math.MaxInt64)
|
||||
)
|
||||
@@ -53,6 +55,7 @@ func NewAgentConfig() (*AgentConfig, error) {
|
||||
err = setEnvUint(err, EnvMaxLogSize, &cfg.MaxLogSize)
|
||||
err = setEnvUint(err, EnvMaxTotalCPU, &cfg.MaxTotalCPU)
|
||||
err = setEnvUint(err, EnvMaxTotalMemory, &cfg.MaxTotalMemory)
|
||||
err = setEnvUint(err, EnvMaxFsSize, &cfg.MaxFsSize)
|
||||
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
|
||||
@@ -168,6 +168,13 @@ func (drv *DockerDriver) Prepare(ctx context.Context, task drivers.ContainerTask
|
||||
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()
|
||||
for _, mapping := range volumes {
|
||||
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) Memory() uint64 { return 256 * 1024 * 1024 }
|
||||
func (f *taskDockerTest) CPUs() uint64 { return 0 }
|
||||
func (f *taskDockerTest) FsSize() uint64 { return 0 }
|
||||
func (f *taskDockerTest) WorkDir() string { return "" }
|
||||
func (f *taskDockerTest) Close() {}
|
||||
func (f *taskDockerTest) Input() io.Reader { return f.input }
|
||||
|
||||
@@ -113,6 +113,9 @@ type ContainerTask interface {
|
||||
// CPUs in milli CPU units
|
||||
CPUs() uint64
|
||||
|
||||
// Filesystem size limit for the container, in megabytes.
|
||||
FsSize() uint64
|
||||
|
||||
// WorkDir returns the working directory to use for the task. Empty string
|
||||
// leaves it unset.
|
||||
WorkDir() string
|
||||
|
||||
Reference in New Issue
Block a user