Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support additional docker flags and remove legacy docker build driver #1999

Merged
merged 5 commits into from
Apr 5, 2022
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
17 changes: 11 additions & 6 deletions cmd/porter/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ func buildBundleBuildCommand(p *porter.Porter) *cobra.Command {
cmd := &cobra.Command{
Use: "build",
Short: "Build a bundle",
Long: `Builds the bundle in the current directory by generating a Dockerfile and a CNAB bundle.json, and then building the invocation image.

Porter uses the docker driver as the default build driver, an alternate driver may be supplied via --driver or the PORTER_BUILD_DRIVER environment variable.
`,
Long: `Builds the bundle in the current directory by generating a Dockerfile and a CNAB bundle.json, and then building the invocation image.`,
Example: ` porter build
porter build --name newbuns
porter build --version 0.1.0
Expand All @@ -80,8 +77,16 @@ Porter uses the docker driver as the default build driver, an alternate driver m
f.StringVarP(&opts.Dir, "dir", "d", "",
"Path to the build context directory where all bundle assets are located.")
f.StringVar(&opts.Driver, "driver", porter.BuildDriverDefault,
fmt.Sprintf("Experimental. Driver for building the invocation image. Allowed values are: %s", strings.Join(porter.BuildDriverAllowedValues, ", ")))

fmt.Sprintf("Driver for building the invocation image. Allowed values are: %s", strings.Join(porter.BuildDriverAllowedValues, ", ")))
f.MarkHidden("driver") // Hide the driver flag since there aren't any choices to make right now
f.StringArrayVar(&opts.BuildArgs, "build-arg", nil,
"Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times.")
f.StringArrayVar(&opts.SSH, "ssh", nil,
"SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]). May be specified multiple times.")
f.StringArrayVar(&opts.Secrets, "secret", nil,
"Secret file to expose to the build (format: id=mysecret,src=/local/secret). May be specified multiple times.")
f.BoolVar(&opts.NoCache, "no-cache", false,
"Do not use the Docker cache when building the bundle's invocation image.")
// Allow configuring the --driver flag with build-driver, to avoid conflicts with other commands
cmd.Flag("driver").Annotations = map[string][]string{
"viper-key": {"build-driver"},
Expand Down
5 changes: 1 addition & 4 deletions cmd/porter/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"strings"
"testing"

"get.porter.sh/porter/pkg/experimental"
"get.porter.sh/porter/pkg/porter"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -135,8 +134,6 @@ func TestValidateInstallationListCommand(t *testing.T) {

func TestBuildValidate_Driver(t *testing.T) {
// Do not run in parallel
os.Setenv("PORTER_EXPERIMENTAL", experimental.BuildDrivers)
defer os.Unsetenv("PORTER_EXPERIMENTAL")

testcases := []struct {
name string
Expand All @@ -145,7 +142,7 @@ func TestBuildValidate_Driver(t *testing.T) {
wantDriver string
wantError string
}{
{name: "no flag", wantDriver: "docker"},
{name: "no flag", wantDriver: "buildkit"},
{name: "invalid flag", args: "--driver=missing-driver", wantError: "invalid --driver value missing-driver"},
{name: "valid flag", args: "--driver=buildkit", wantDriver: "buildkit"},
{name: "invalid config", args: "", configDriver: "invalid-driver", wantError: "invalid --driver value invalid-driver"},
Expand Down
10 changes: 5 additions & 5 deletions cmd/porter/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,22 @@ func TestExperimentalFlags(t *testing.T) {
cmd := buildRootCommandFrom(p.Porter)
cmd.SetArgs([]string{"install"})
cmd.Execute()
assert.False(t, p.Config.IsFeatureEnabled(experimental.FlagBuildDrivers))
assert.False(t, p.Config.IsFeatureEnabled(experimental.FlagStructuredLogs))
})

t.Run("flag set", func(t *testing.T) {
p := porter.NewTestPorter(t)
defer p.Teardown()

cmd := buildRootCommandFrom(p.Porter)
cmd.SetArgs([]string{"install", "--experimental", experimental.BuildDrivers})
cmd.SetArgs([]string{"install", "--experimental", experimental.StructuredLogs})
cmd.Execute()

assert.True(t, p.Config.IsFeatureEnabled(experimental.FlagBuildDrivers))
assert.True(t, p.Config.IsFeatureEnabled(experimental.FlagStructuredLogs))
})

t.Run("flag unset, env set", func(t *testing.T) {
os.Setenv(expEnvVar, experimental.BuildDrivers)
os.Setenv(expEnvVar, experimental.StructuredLogs)
defer os.Unsetenv(expEnvVar)

p := porter.NewTestPorter(t)
Expand All @@ -117,6 +117,6 @@ func TestExperimentalFlags(t *testing.T) {
cmd.SetArgs([]string{"install"})
cmd.Execute()

assert.True(t, p.Config.IsFeatureEnabled(experimental.FlagBuildDrivers))
assert.True(t, p.Config.IsFeatureEnabled(experimental.FlagStructuredLogs))
})
}
22 changes: 11 additions & 11 deletions docs/content/cli/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ Build a bundle

Builds the bundle in the current directory by generating a Dockerfile and a CNAB bundle.json, and then building the invocation image.

Porter uses the docker driver as the default build driver, an alternate driver may be supplied via --driver or the PORTER_BUILD_DRIVER environment variable.


```
porter build [flags]
```
Expand All @@ -32,14 +29,17 @@ porter build [flags]
### Options

```
-d, --dir string Path to the build context directory where all bundle assets are located.
--driver string Experimental. Driver for building the invocation image. Allowed values are: docker, buildkit (default "docker")
-f, --file porter.yaml Path to the Porter manifest. Defaults to porter.yaml in the current directory.
-h, --help help for build
--name string Override the bundle name
--no-lint Do not run the linter
-v, --verbose Enable verbose logging
--version string Override the bundle version
--build-arg stringArray Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times.
-d, --dir string Path to the build context directory where all bundle assets are located.
-f, --file porter.yaml Path to the Porter manifest. Defaults to porter.yaml in the current directory.
-h, --help help for build
--name string Override the bundle name
--no-cache Do not use cache when building the image.
--no-lint Do not run the linter
--secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). May be specified multiple times.
--ssh stringArray SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]). May be specified multiple times.
-v, --verbose Enable verbose logging
--version string Override the bundle version
```

### Options inherited from parent commands
Expand Down
22 changes: 11 additions & 11 deletions docs/content/cli/bundles_build.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ Build a bundle

Builds the bundle in the current directory by generating a Dockerfile and a CNAB bundle.json, and then building the invocation image.

Porter uses the docker driver as the default build driver, an alternate driver may be supplied via --driver or the PORTER_BUILD_DRIVER environment variable.


```
porter bundles build [flags]
```
Expand All @@ -32,14 +29,17 @@ porter bundles build [flags]
### Options

```
-d, --dir string Path to the build context directory where all bundle assets are located.
--driver string Experimental. Driver for building the invocation image. Allowed values are: docker, buildkit (default "docker")
-f, --file porter.yaml Path to the Porter manifest. Defaults to porter.yaml in the current directory.
-h, --help help for build
--name string Override the bundle name
--no-lint Do not run the linter
-v, --verbose Enable verbose logging
--version string Override the bundle version
--build-arg stringArray Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times.
-d, --dir string Path to the build context directory where all bundle assets are located.
-f, --file porter.yaml Path to the Porter manifest. Defaults to porter.yaml in the current directory.
-h, --help help for build
--name string Override the bundle name
--no-cache Do not use cache when building the image.
--no-lint Do not run the linter
--secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). May be specified multiple times.
--ssh stringArray SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]). May be specified multiple times.
-v, --verbose Enable verbose logging
--version string Override the bundle version
```

### Options inherited from parent commands
Expand Down
45 changes: 2 additions & 43 deletions docs/content/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,49 +185,8 @@ feature by:

### Build Drivers

The **build-drivers** experimental feature flag enables using a different
driver to build OCI images used by the bundle, such as the installer.

You can set your desired driver with either using `porter build --driver`,
PORTER_BUILD_DRIVER environment variable, or in the configuration file with
build-driver = "DRIVER".

The default driver is docker, and the full list of available drivers
is below:

* **Docker**: Build an OCI image using the [Docker library], without buildkit support.
This requires access to a Docker daemon, either locally or remote.
* **Buildkit**: Build an OCI image using [Docker with Buildkit].
With buildkit you can improve the performance of builds using caching, access
private resources during build, and more.
This requires access to a Docker daemon, either locally or remote.

Below are some examples of how to enable the build-drivers feature and specify an alternate
driver:

**Flags**
```
porter build --experimental build-drivers --driver buildkit
```

**Environment Variables**
```
export PORTER_EXPERIMENTAL=build-drivers
export PORTER_BUILD_DRIVER=buildkit
```

**Configuration File**
```toml
experimental = ["build-drivers"]
build-driver = "buildkit"
```

[install]: /cli/porter_install/
[upgrade]: /cli/porter_upgrade/
[invoke]: /cli/porter_invoke/
[uninstall]: /cli/porter_uninstall/
[Docker library]: https://github.com/moby/moby
[Docker with Buildkit]: https://docs.docker.com/develop/develop-images/build_enhancements/
The **build-drivers** experimental feature flag is no longer used.
Build drivers are enabled by default and the only available driver is buildkit.

### Structured Logs

Expand Down
50 changes: 11 additions & 39 deletions docs/content/custom-dockerfile.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Sometimes you may want to full control over your bundle's invocation image, for
When you run porter create, a template Dockerfile is created for you in the current directory named **template.Dockerfile**:

```Dockerfile
# syntax=docker/dockerfile-upstream:1.4.0
# This is a template Dockerfile for the bundle's invocation image
# You can customize it to use different base images, install tools and copy configuration files.
#
Expand All @@ -25,12 +26,14 @@ FROM debian:stretch-slim

# PORTER_INIT

RUN apt-get update && apt-get install -y ca-certificates
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y ca-certificates

# PORTER_MIXINS

# Use the BUNDLE_DIR build argument to copy files into the bundle's working directory
COPY . ${BUNDLE_DIR}
COPY --link . ${BUNDLE_DIR}
```

Add the following line to your **porter.yaml** file to instruct porter to use the template, instead of generating one from scratch:
Expand All @@ -45,37 +48,14 @@ Mixins assume that apt is available to install packages.

# Buildkit

You can use [Buildkit] in your Dockerfile by enabling the [experimental] feature
for [build-drivers], and then specifying buildkit as the driver.

Below is the template for builds with Buildkit:

```Dockerfile
# syntax=docker/dockerfile-upstream:1.4.0-rc2
# This is a template Dockerfile for the bundle's invocation image
# You can customize it to use different base images, install tools and copy configuration files.
#
# Porter will use it as a template and append lines to it for the mixins
# and to set the CMD appropriately for the CNAB specification.
#
# Add the following line to porter.yaml to instruct Porter to use this template
# dockerfile: template.Dockerfile

# You can control where the mixin's Dockerfile lines are inserted into this file by moving the "# PORTER_*" tokens
# another location in this file. If you remove a token, its content is appended to the end of the Dockerfile.
FROM debian:stretch-slim
Porter automatically builds with Docker [buildkit] enabled.
The following docker flags are supported on the [porter build] command: \--ssh, \--secret, \--build-arg.
With these you can take advantage of Docker's support for using SSH connections, mounting secrets, and specifying custom build arguments.

# PORTER_INIT
By default, Porter uses the [1.4.0 dockerfile syntax](https://docs.docker.com/engine/reference/builder/#syntax), but you can modify this line to use new versions as they are released.

RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y ca-certificates

# PORTER_MIXINS

# Use the BUNDLE_DIR build argument to copy files into the bundle's working directory
COPY --link . ${BUNDLE_DIR}
```
[buildkit]: https://docs.docker.com/develop/develop-images/build_enhancements/
[porter build]: /cli/porter_build/

# Special Comments
Porter uses comments as placeholders to inject lines into your Dockerfile that all Porter bundles require.
Expand Down Expand Up @@ -129,14 +109,6 @@ The **BUNDLE_GID** argument declared in the [PORTER_INIT](#porter_init) section
Below is an example of how to copy a file into a directory outside [BUNDLE_DIR](#bundle_dir) and set the permissions so that the bundle can access them when it is run:

```Dockerfile
COPY myapp /myapp
RUN chgrp -R ${BUNDLE_GID} /myapp && chmod -R g=u /myapp
```

If you are using buildkit, you can use the following syntax to copy and set permissions in a single line:

```Dockerfile
# syntax=docker/dockerfile-upstream:1.4.0-rc2
COPY --chown=${BUNDLE_UID}:${BUNDLE_GID} --chmod=770 myapp /myapp
```

Expand Down
5 changes: 5 additions & 0 deletions examples/private-assets/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Put files here that you don't want copied into your bundle's invocation image
.gitignore
Dockerfile.tmpl
secrets/
1 change: 1 addition & 0 deletions examples/private-assets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.cnab/
33 changes: 33 additions & 0 deletions examples/private-assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Bundle with Private Assets

Sometimes you need to include assets from secured locations, such as a private repository in your bundle.
You can use the \--secret flag to pass secrets into the bundle when it is built.

## Try it out
1. Edit secrets/token and replace the contents with a [GitHub Personal Access Token](https://github.com/settings/tokens).
The permissions do not matter for this sample bundle.
There should not be a newline at the end of the file.

1. Build the bundle and pass the secret into the bundle with \--secret
```
porter build --secret id=token,src=secrets/token
```

1. Install the bundle to see the private assets embedded in the bundle
```
$ porter install example-private-assets --reference ghcr.io/getporter/examples/private-assets:v0.1.0
__________________________
< yarr, I'm a secret whale >
--------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
```
7 changes: 7 additions & 0 deletions examples/private-assets/check-secrets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ ! -f "/run/secrets/token" ]]; then
echo "You forgot to use --secret id=token,src=secrets/token"
exit 1
fi
17 changes: 17 additions & 0 deletions examples/private-assets/helpers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail

install() {
echo Hello World
}

upgrade() {
echo World 2.0
}

uninstall() {
echo Goodbye World
}

# Call the requested function and pass the arguments as-is
"$@"
28 changes: 28 additions & 0 deletions examples/private-assets/porter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
schemaVersion: 1.0.0-alpha.1

name: private-assets
version: 0.1.0
description: "Example bundle that contains private assets and prints it when run"
registry: ghcr.io/getporter/examples/
dockerfile: template.Dockerfile

mixins:
- exec

install:
- exec:
command: cat
arguments:
- /secret

upgrade:
- exec:
command: cat
arguments:
- /secret

uninstall:
- exec:
command: cat
arguments:
- /secret
Loading