From 666bbfdbd5c5ab3a0a5e96f738d5d70321190ad2 Mon Sep 17 00:00:00 2001 From: Mikhail Malyshev Date: Thu, 12 Mar 2026 10:48:19 +0000 Subject: [PATCH] pkg build: add env var support for mirror, org, builder image and config Introduce environment variables for key CI/CD flags so that self-hosted runners (e.g. GitHub Actions) can configure registry mirrors and push targets without modifying calling Makefiles: - LINUXKIT_MIRROR - equivalent to --mirror (space/comma-separated); CLI flags take precedence (last SetProxy wins) - LINUXKIT_PKG_ORG - equivalent to --org for all pkg subcommands - LINUXKIT_BUILDER_IMAGE - equivalent to --builder-image - LINUXKIT_BUILDER_CONFIG - equivalent to --builder-config All env var constants are consolidated in pkg_build.go alongside the existing LINUXKIT_CACHE, LINUXKIT_BUILDER_NAME, LINUXKIT_BUILDERS. Priority for all: CLI flag > env var > built-in default Adds a new Environment Variables section to docs/packages.md with a reference table covering all LINUXKIT_* vars and a note explaining the two-layer mirror configuration required in CI (linuxkit pulls vs buildkit Dockerfile pulls). Signed-off-by: Roman Shaposhnik Signed-off-by: Mikhail Malyshev --- docs/packages.md | 32 ++++++++++++++++++++++++++++++++ src/cmd/linuxkit/cmd.go | 8 +++++++- src/cmd/linuxkit/pkg.go | 6 +++++- src/cmd/linuxkit/pkg_build.go | 22 +++++++++++++--------- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/docs/packages.md b/docs/packages.md index 79ab56cff..a8419e219 100644 --- a/docs/packages.md +++ b/docs/packages.md @@ -382,6 +382,38 @@ ARG all_proxy LinuxKit does not judge between lower-cased or upper-cased variants of these options, e.g. `http_proxy` vs `HTTP_PROXY`, as `docker build` does not either. It just passes them through "as-is". +### Environment Variables + +The following environment variables can be used to configure `linuxkit` without +modifying command-line invocations — useful for CI/CD runners and shared build +scripts. CLI flags always take precedence over env vars, which take precedence +over built-in defaults. + +| Variable | Equivalent flag | Scope | Description | +|---|---|---|---| +| `LINUXKIT_MIRROR` | `--mirror` | All commands | Space- or comma-separated list of mirror specs, each in `[=]` format (same as `--mirror`). E.g. `LINUXKIT_MIRROR=docker.io=http://mymirror.local` | +| `LINUXKIT_PKG_ORG` | `--org` | `pkg` subcommands | Override the registry organisation used when tagging and pushing packages. E.g. `LINUXKIT_PKG_ORG=myorg/lfedge` | +| `LINUXKIT_BUILDER_IMAGE` | `--builder-image` | `pkg build` | buildkit container image to use. Useful when the builder image must come from an internal mirror. | +| `LINUXKIT_BUILDER_CONFIG` | `--builder-config` | `pkg build` | Path to a buildkit `config.toml` file. The primary way to configure buildkit's own registry mirrors for `FROM` pulls inside Dockerfiles. | +| `LINUXKIT_BUILDER_NAME` | `--builder-name` | `pkg build` | Name of the buildkit builder container. | +| `LINUXKIT_BUILDERS` | `--builders` | `pkg build` | Platform-to-builder-context mapping; see [Providing native builder nodes](#providing-native-builder-nodes). | +| `LINUXKIT_CACHE` | `--cache` | All commands | Path to the linuxkit OCI image cache directory (default `~/.linuxkit/cache`). | + +#### Registry mirrors in CI + +There are two layers of registry access in `linuxkit pkg build`, each requiring +its own mirror configuration: + +1. **linuxkit's own pulls** (cache lookups, `show-tag`, `cache pull`, etc.) — + configure via `LINUXKIT_MIRROR` or `--mirror`. + +2. **buildkit's pulls** (`FROM` and `COPY --from` inside Dockerfiles) — + buildkit has its own registry client. Configure its mirrors via a + `config.toml` file passed through `LINUXKIT_BUILDER_CONFIG` or + `--builder-config`. See the + [buildkit registry configuration docs](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md) + for the file format. + ## Build Args `linuxkit` does not support passing random CLI flags for build arguments when building packages. diff --git a/src/cmd/linuxkit/cmd.go b/src/cmd/linuxkit/cmd.go index fdff24387..e60f1640d 100644 --- a/src/cmd/linuxkit/cmd.go +++ b/src/cmd/linuxkit/cmd.go @@ -58,6 +58,12 @@ func newCmd() *cobra.Command { PersistentPreRunE: func(cmd *cobra.Command, args []string) error { readConfig() + // prepend mirrors from env var so CLI flags take precedence (last SetProxy call wins) + if envMirrors := os.Getenv(envVarMirror); envMirrors != "" { + envList := strings.FieldsFunc(envMirrors, func(r rune) bool { return r == ',' || r == ' ' }) + mirrorsRaw = append(envList, mirrorsRaw...) + } + // convert the provided mirrors to a map for _, m := range mirrorsRaw { if m == "" { @@ -115,7 +121,7 @@ func newCmd() *cobra.Command { cmd.AddCommand(versionCmd()) cmd.PersistentFlags().StringVar(&cacheDir, "cache", defaultLinuxkitCache(), fmt.Sprintf("Directory for caching and finding cached image, overrides env var %s", envVarCacheDir)) - cmd.PersistentFlags().StringArrayVar(&mirrorsRaw, "mirror", nil, "Mirror to use for pulling images, format is =, e.g. docker.io=http://mymirror.io, or just http://mymirror.io for all not otherwise specified; must include protocol. Can be provided multiple times.") + cmd.PersistentFlags().StringArrayVar(&mirrorsRaw, "mirror", nil, fmt.Sprintf("Mirror to use for pulling images, format is =, e.g. docker.io=http://mymirror.io, or just http://mymirror.io for all not otherwise specified; must include protocol. Can be provided multiple times. Also read from env var %s (space/comma-separated list); CLI flags take precedence.", envVarMirror)) cmd.PersistentFlags().StringArrayVar(&certFiles, "cert-file", nil, "Path to certificate files to use for pulling images, can be provided multiple times. Will augment system-provided certs.") cmd.PersistentFlags().BoolVarP(&flagQuiet, "quiet", "q", false, "Quiet execution") cmd.PersistentFlags().IntVarP(&flagVerbose, flagVerboseName, "v", 1, "Verbosity of logging: 0 = quiet, 1 = info, 2 = debug, 3 = trace. Default is info. Setting it explicitly will create structured logging lines.") diff --git a/src/cmd/linuxkit/pkg.go b/src/cmd/linuxkit/pkg.go index e79a62cf5..52b9b9faa 100644 --- a/src/cmd/linuxkit/pkg.go +++ b/src/cmd/linuxkit/pkg.go @@ -2,6 +2,8 @@ package main import ( "errors" + "fmt" + "os" "github.com/linuxkit/linuxkit/src/cmd/linuxkit/pkglib" "github.com/spf13/cobra" @@ -74,6 +76,8 @@ func pkgCmd() *cobra.Command { } if cmd.Flags().Changed("org") { pkglibConfig.Org = &argOrg + } else if org := os.Getenv(envVarPkgOrg); org != "" { + pkglibConfig.Org = &org } if cmd.Flags().Changed("tag") { pkglibConfig.Tag = tag @@ -100,7 +104,7 @@ func pkgCmd() *cobra.Command { cmd.PersistentFlags().BoolVar(&argNoNetwork, "nonetwork", !piBase.Network, "Disallow network use during build") cmd.PersistentFlags().BoolVar(&argNetwork, "network", piBase.Network, "Allow network use during build") - cmd.PersistentFlags().StringVar(&argOrg, "org", piBase.Org, "Override the hub org") + cmd.PersistentFlags().StringVar(&argOrg, "org", piBase.Org, fmt.Sprintf("Override the hub org. Also read from env var %s; CLI flag takes precedence.", envVarPkgOrg)) cmd.PersistentFlags().StringVar(&buildYML, "build-yml", defaultPkgBuildYML, "Override the name of the yml file") cmd.PersistentFlags().StringVar(&hash, "hash", "", "Override the image hash (default is to query git for the package's tree-sh)") cmd.PersistentFlags().StringVar(&tag, "tag", piBase.Tag, "Override the tag using fixed strings and/or text templates. Acceptable are .Hash for the hash") diff --git a/src/cmd/linuxkit/pkg_build.go b/src/cmd/linuxkit/pkg_build.go index 43c9b57ce..79ff1ce54 100644 --- a/src/cmd/linuxkit/pkg_build.go +++ b/src/cmd/linuxkit/pkg_build.go @@ -17,6 +17,10 @@ const ( buildersEnvVar = "LINUXKIT_BUILDERS" envVarCacheDir = "LINUXKIT_CACHE" envVarBuilderName = "LINUXKIT_BUILDER_NAME" + envVarBuilderImage = "LINUXKIT_BUILDER_IMAGE" + envVarBuilderConfig = "LINUXKIT_BUILDER_CONFIG" + envVarMirror = "LINUXKIT_MIRROR" + envVarPkgOrg = "LINUXKIT_PKG_ORG" defaultBuilderImage = "moby/buildkit:v0.26.3" ) @@ -42,8 +46,8 @@ func pkgBuildCmd() *cobra.Command { skipPlatforms string builders string builderName = flagOverEnvVarOverDefaultString{def: pkglib.DefaultBuilderName(), envVar: envVarBuilderName} - builderImage string - builderConfig string + builderImage = flagOverEnvVarOverDefaultString{def: defaultBuilderImage, envVar: envVarBuilderImage} + builderConfig = flagOverEnvVarOverDefaultString{def: "", envVar: envVarBuilderConfig} builderRestart bool preCacheImages bool release string @@ -193,17 +197,17 @@ func pkgBuildCmd() *cobra.Command { if err != nil { return fmt.Errorf("error in --builders flag: %w", err) } - if builderConfig != "" { - if _, err := os.Stat(builderConfig); err != nil { - return fmt.Errorf("error reading builder config file %s: %w", builderConfig, err) + if builderConfig.String() != "" { + if _, err := os.Stat(builderConfig.String()); err != nil { + return fmt.Errorf("error reading builder config file %s: %w", builderConfig.String(), err) } } opts = append(opts, pkglib.WithBuildBuilders(buildersMap)) opts = append(opts, pkglib.WithBuildBuilderConfig(pkglib.BuilderConfig{ Name: builderName.String(), - Image: builderImage, - ConfigPath: builderConfig, + Image: builderImage.String(), + ConfigPath: builderConfig.String(), Restart: builderRestart, })) opts = append(opts, pkglib.WithProgress(progress)) @@ -309,8 +313,8 @@ func pkgBuildCmd() *cobra.Command { cmd.Flags().StringVar(&skipPlatforms, "skip-platforms", "", "Platforms that should be skipped, even if present in build.yml") cmd.Flags().StringVar(&builders, "builders", "", "Which builders to use for which platforms, e.g. linux/arm64=docker-context-arm64, overrides defaults and environment variables, see https://github.com/linuxkit/linuxkit/blob/master/docs/packages.md#Providing-native-builder-nodes") cmd.Flags().Var(&builderName, "builder-name", fmt.Sprintf("Name of the buildkit builder container, default: %s, overrides env var %s", pkglib.DefaultBuilderName(), envVarBuilderName)) - cmd.Flags().StringVar(&builderImage, "builder-image", defaultBuilderImage, "buildkit builder container image to use") - cmd.Flags().StringVar(&builderConfig, "builder-config", "", "path to buildkit builder config.toml file to use, overrides the default config.toml in the builder image. When provided, copied over into builder, along with all certs. Use paths for certificates relative to your local host, they will be adjusted on copying into the container. USE WITH CAUTION") + cmd.Flags().Var(&builderImage, "builder-image", fmt.Sprintf("buildkit builder container image to use, overrides env var %s", envVarBuilderImage)) + cmd.Flags().Var(&builderConfig, "builder-config", fmt.Sprintf("path to buildkit builder config.toml file to use, overrides the default config.toml in the builder image. When provided, copied over into builder, along with all certs. Use paths for certificates relative to your local host, they will be adjusted on copying into the container. USE WITH CAUTION. Overrides env var %s", envVarBuilderConfig)) cmd.Flags().BoolVar(&builderRestart, "builder-restart", false, "force restarting builder, even if container with correct name and image exists") cmd.Flags().BoolVar(&preCacheImages, "precache-images", false, "download all referenced images in the Dockerfile to the linuxkit cache before building, thus referencing the local cache instead of pulling from the registry; this is useful for handling mirrors and special connections") cmd.Flags().Var(&cacheDir, "cache", fmt.Sprintf("Directory for caching and finding cached image, overrides env var %s", envVarCacheDir))