Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 37 additions & 56 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ NAME
{{rootCmdUse}} run - Run a function locally

SYNOPSIS
{{rootCmdUse}} run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
{{rootCmdUse}} run [-r|--registry] [-i|--image] [-e|--env] [--build]
[-b|--builder] [--builder-image] [-c|--confirm]
[--address] [--json] [-v|--verbose]

DESCRIPTION
Expand All @@ -37,38 +37,32 @@ DESCRIPTION
Values provided for flags are not persisted to the function's metadata.

Containerized Runs
The --container flag indicates that the function's container should be
run rather than running the source code directly. This may require that
the function's container first be rebuilt. Building the container on or
off can be altered using the --build flag. The value --build=auto
can be used to indicate the function should be run in a container, with
the container automatically built if necessary.

The --container flag defaults to true if the builder defined for the
function is a containerized builder such as Pack or S2I, and in the case
where the function's runtime requires containerized builds (is not yet
supported by the Host builder.
You can build your function in a container using the Pack or S2i builders.
On the contrary, non-containerized run is achieved via Host builder which
will use your host OS' environment to build the function. This builder is
currently enabled for Go and Python. Building defaults to using the Host
builder when available. You can alter this by using the --builder flag
eg: --builder=s2i.

Process Scaffolding
This is an Experimental Feature currently available only to Go projects.
When running a function with --container=false (host-based runs), the
function is first wrapped code which presents it as a process.
This "scaffolding" is transient, written for each build or run, and should
in most cases be transparent to a function author. However, to customize,
or even completely replace this scafolding code, see the 'scaffold'
subcommand.
This is an Experimental Feature currently available only to Go and Python
projects. When running a function with --builder=host, the function is
first wrapped with code which presents it as a process. This "scaffolding"
is transient, written for each build or run, and should in most cases be
transparent to a function author.

EXAMPLES

o Run the function locally from within its container.
$ {{rootCmdUse}} run

o Run the function locally from within its container, forcing a rebuild
of the container even if no filesysem changes are detected
$ {{rootCmdUse}} run --build
of the container even if no filesystem changes are detected. There are 2
builders available for containerized build - 'pack' and 's2i'.
$ {{rootCmdUse}} run --build=<builder>

o Run the function locally on the host with no containerization (Go only).
$ {{rootCmdUse}} run --container=false
o Run the function locally on the host with no containerization (Go/Python only).
$ {{rootCmdUse}} run --builder=host

o Run the function locally on a specific address.
$ {{rootCmdUse}} run --address='[::]:8081'
Expand All @@ -78,7 +72,7 @@ EXAMPLES
`,
SuggestFor: []string{"rnu"},
PreRunE: bindEnv("build", "builder", "builder-image", "base-image",
"confirm", "container", "env", "image", "path", "registry",
"confirm", "env", "image", "path", "registry",
"start-timeout", "verbose", "address", "json"),
RunE: func(cmd *cobra.Command, _ []string) error {
return runRun(cmd, newClient)
Expand Down Expand Up @@ -120,8 +114,6 @@ EXAMPLES
"You may provide this flag multiple times for setting multiple environment variables. "+
"To unset, specify the environment variable name followed by a \"-\" (e.g., NAME-).")
cmd.Flags().Duration("start-timeout", f.Run.StartTimeout, fmt.Sprintf("time this function needs in order to start. If not provided, the client default %v will be in effect. ($FUNC_START_TIMEOUT)", fn.DefaultStartTimeout))
cmd.Flags().BoolP("container", "t", runContainerizedByDefault(f),
"Run the function in a container. ($FUNC_CONTAINER)")

// TODO: Without the "Host" builder enabled, this code-path is unreachable,
// so remove hidden flag when either the Host builder path is available,
Expand Down Expand Up @@ -156,10 +148,6 @@ EXAMPLES
return cmd
}

func runContainerizedByDefault(f fn.Function) bool {
return f.Build.Builder == "pack" || f.Build.Builder == "s2i" || !oci.IsSupported(f.Runtime)
}

func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
var (
cfg runConfig
Expand All @@ -170,16 +158,20 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
if f, err = fn.NewFunction(cfg.Path); err != nil {
return
}
if err = cfg.Validate(cmd, f); err != nil {
return
}
if !f.Initialized() {
return fn.NewErrNotInitialized(f.Root)
}

if err = cfg.Validate(cmd, f); err != nil {
return
}

if f, err = cfg.Configure(f); err != nil { // Updates f with deploy cfg
return
}

container := f.Build.Builder != "host"

// Ignore the verbose flag if JSON output
if cfg.JSON {
cfg.Verbose = false
Expand All @@ -190,7 +182,7 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
if err != nil {
return
}
if cfg.Container {
if container {
clientOptions = append(clientOptions, fn.WithRunner(docker.NewRunner(cfg.Verbose, os.Stdout, os.Stderr)))
}
if cfg.StartTimeout != 0 {
Expand All @@ -204,7 +196,7 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
//
// If requesting to run via the container, build the container if it is
// either out-of-date or a build was explicitly requested.
if cfg.Container {
if container {
var digested bool

buildOptions, err := cfg.buildOptions()
Expand All @@ -218,31 +210,25 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
if err != nil {
return err
}
if !digested {
// assign valid undigested image
f.Build.Image = cfg.Image
}
}

if digested {
// run cmd takes f.Build.Image - see newContainerConfig in docker/runner.go
// it doesnt get saved, just runtime image
// image was parsed and both digested AND undigested imgs are valid
f.Build.Image = cfg.Image
} else {
}

// actual build step
if !digested {
if f, _, err = build(cmd, cfg.Build, f, client, buildOptions); err != nil {
return err
}
}
} else {
} else { // if !container
// dont run digested image without a container
if cfg.Image != "" {
digested, err := isDigested(cfg.Image)
if err != nil {
return err
}
if digested {
return fmt.Errorf("cannot use digested image with --container=false")
return fmt.Errorf("cannot use digested image with non-containerized builds (--builder=host)")
}
}
}
Expand Down Expand Up @@ -314,10 +300,6 @@ type runConfig struct {
// Can be 'auto' or a truthy value.
Build string

// Container indicates the function should be run in a container.
// Requires the container be built.
Container bool

// Env variables. may include removals using a "-"
Env []string

Expand All @@ -337,7 +319,6 @@ func newRunConfig(cmd *cobra.Command) (c runConfig) {
buildConfig: newBuildConfig(),
Build: viper.GetString("build"),
Env: viper.GetStringSlice("env"),
Container: viper.GetBool("container"),
StartTimeout: viper.GetDuration("start-timeout"),
Address: viper.GetString("address"),
JSON: viper.GetBool("json"),
Expand All @@ -363,7 +344,7 @@ func (c runConfig) Configure(f fn.Function) (fn.Function, error) {

f.Run.Envs, err = applyEnvs(f.Run.Envs, c.Env)

// The other members; build, path, and container; are not part of function
// The other members; build and path; are not part of function
// state, so are not mentioned here in Configure.
return f, err
}
Expand Down Expand Up @@ -396,13 +377,13 @@ func (c runConfig) Validate(cmd *cobra.Command, f fn.Function) (err error) {
}
}

if !c.Container && !oci.IsSupported(f.Runtime) {
if f.Build.Builder == "host" && !oci.IsSupported(f.Runtime) {
return fmt.Errorf("the %q runtime currently requires being run in a container", f.Runtime)
}

// When the docker runner respects the StartTimeout, this validation check
// can be removed
if c.StartTimeout != 0 && c.Container {
if c.StartTimeout != 0 && f.Build.Builder != "host" {
return errors.New("the ability to specify the startup timeout for containerized runs is coming soon")
}

Expand Down
43 changes: 18 additions & 25 deletions docs/reference/func_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ NAME
func run - Run a function locally

SYNOPSIS
func run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
func run [-r|--registry] [-i|--image] [-e|--env] [--build]
[-b|--builder] [--builder-image] [-c|--confirm]
[--address] [--json] [-v|--verbose]

DESCRIPTION
Expand All @@ -19,38 +19,32 @@ DESCRIPTION
Values provided for flags are not persisted to the function's metadata.

Containerized Runs
The --container flag indicates that the function's container should be
run rather than running the source code directly. This may require that
the function's container first be rebuilt. Building the container on or
off can be altered using the --build flag. The value --build=auto
can be used to indicate the function should be run in a container, with
the container automatically built if necessary.

The --container flag defaults to true if the builder defined for the
function is a containerized builder such as Pack or S2I, and in the case
where the function's runtime requires containerized builds (is not yet
supported by the Host builder.
You can build your function in a container using the Pack or S2i builders.
On the contrary, non-containerized run is achieved via Host builder which
will use your host OS' environment to build the function. This builder is
currently enabled for Go and Python. Building defaults to using the Host
builder when available. You can alter this by using the --builder flag
eg: --builder=s2i.

Process Scaffolding
This is an Experimental Feature currently available only to Go projects.
When running a function with --container=false (host-based runs), the
function is first wrapped code which presents it as a process.
This "scaffolding" is transient, written for each build or run, and should
in most cases be transparent to a function author. However, to customize,
or even completely replace this scafolding code, see the 'scaffold'
subcommand.
This is an Experimental Feature currently available only to Go and Python
projects. When running a function with --builder=host, the function is
first wrapped with code which presents it as a process. This "scaffolding"
is transient, written for each build or run, and should in most cases be
transparent to a function author.

EXAMPLES

o Run the function locally from within its container.
$ func run

o Run the function locally from within its container, forcing a rebuild
of the container even if no filesysem changes are detected
$ func run --build
of the container even if no filesystem changes are detected. There are 2
builders available for containerized build - 'pack' and 's2i'.
$ func run --build=<builder>

o Run the function locally on the host with no containerization (Go only).
$ func run --container=false
o Run the function locally on the host with no containerization (Go/Python only).
$ func run --builder=host

o Run the function locally on a specific address.
$ func run --address='[::]:8081'
Expand All @@ -72,7 +66,6 @@ func run
-b, --builder string Builder to use when creating the function's container. Currently supported builders are "host", "pack" and "s2i". (default "pack")
--builder-image string Specify a custom builder image for use by the builder other than its default. ($FUNC_BUILDER_IMAGE)
-c, --confirm Prompt to confirm options interactively ($FUNC_CONFIRM)
-t, --container Run the function in a container. ($FUNC_CONTAINER) (default true)
-e, --env stringArray Environment variable to set in the form NAME=VALUE. You may provide this flag multiple times for setting multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).
-h, --help help for run
-i, --image string Full image name in the form [registry]/[namespace]/[name]:[tag]. This option takes precedence over --registry. Specifying tag is optional. ($FUNC_IMAGE)
Expand Down
59 changes: 50 additions & 9 deletions hack/allocate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,54 @@ dapr_runtime() {
# to only start a single instance rather than four.
# helm repo add bitnami https://charts.bitnami.com/bitnami
echo "${blue}- Redis ${reset}"
$HELM repo add bitnami https://charts.bitnami.com/bitnami
$HELM install redis bitnami/redis --set image.tag=6.2
$HELM repo update
# Deploy Redis using simple manifest with official Redis image
# (Bitnami images have migration issues as of Sept 2025)
$KUBECTL apply -f - << EOF
apiVersion: v1
kind: Service
metadata:
name: redis-master
namespace: default
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-master
namespace: default
spec:
serviceName: redis-master
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: redis-storage
mountPath: /data
volumeClaimTemplates:
- metadata:
name: redis-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
EOF

# 2) Expose a Redis-backed Dapr State Storage component
echo "${blue}- State Storage Component${reset}"
Expand All @@ -370,9 +415,7 @@ spec:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
value: ""
EOF

# 3) Expose A Redis-backed Dapr Pub/Sub Component
Expand All @@ -390,9 +433,7 @@ spec:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
value: ""
EOF

echo "${green}✅ Dapr Runtime${reset}"
Expand Down
2 changes: 1 addition & 1 deletion hack/install-binaries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ install_binaries() {

local kubectl_version=1.33.1
local kind_version=0.29.0
local dapr_version=1.14.1
local dapr_version=1.16.0
local helm_version=3.18.0
local stern_version=1.32.0
local kn_version=1.18.0
Expand Down
11 changes: 10 additions & 1 deletion pkg/builders/buildpacks/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,16 @@ func (b *Builder) Build(ctx context.Context, f fn.Function, platforms []fn.Platf
}

if f.Runtime == "python" {
cli = pyScaffoldInjector{cli}
if fi, _ := os.Lstat(filepath.Join(f.Root, "Procfile")); fi == nil {
// HACK (of a hack): need to get the right invocation signature
// the standard scaffolding does this in toSignature() func.
// we know we have python here.
invoke := f.Invoke
if invoke == "" {
invoke = "http"
}
cli = pyScaffoldInjector{cli, invoke}
}
}

// Client with a logger which is enabled if in Verbose mode and a dockerClient that supports SSH docker daemon connection.
Expand Down
Loading
Loading