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

Dockerfiles POC #802

Closed
wants to merge 34 commits into from
Closed

Dockerfiles POC #802

wants to merge 34 commits into from

Conversation

natalieparellano
Copy link
Member

@natalieparellano natalieparellano commented Feb 15, 2022

This PR updates #786 and integrates the work done in #797. It also pulls in code from https://github.com/redhat-buildpacks/poc/tree/main/kaniko/code.

In theory, using this branch it is possible to perform a build that uses extensions to extend the build and/or run image and get an app image that is based off the extended run image.

To see it in action, run test-extender.sh (use REGISTRY_HOST to configure the registry where the extended images should be saved).

Changes of note:

  • extender/spec.md for proposed platform <-> extender interface
  • new cmd/extender package
  • new extender package
    • the DockerfileApplier interface (this could allow platforms to supply their own implementation, using extender as a library to provide CNB logic)
  • changes to detector.go and builder.go
  • changes to buildpack package:
    • buildpack/build.go
    • buildpack/detect.go
    • buildpack/dockerfile.go
    • buildpack/extension.go

Significant work still to be done:

  • kaniko implementation:
    • Enable and verify caching
    • Enable "ignore paths" provided by the end user
    • When extending the build image, don't push and pull the image between Dockerfile builds (we can just parse the commands in the Dockerfile)
    • Decide if we need an in-process registry
  • Decide what build.Dockerfiles should be considered "valid" (e.g., they must start with ARG #{base_image})
  • Set the correct value of io.buildpacks.rebasable
  • Run genpkgs
  • Exclude genpkgs from the final image
  • ...much more

natalieparellano and others added 26 commits December 13, 2021 16:53
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
…pply to both

build and run will be repeated in the list.

Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Anthony Emengo <aemengo@vmware.com>
Signed-off-by: Anthony Emengo <aemengo@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Jesse Brown <jabrown85@gmail.com>
…t a final image

Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Add argument for target image

Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
@natalieparellano natalieparellano changed the title Extender lib Dockerfiles POC Feb 15, 2022
Copy link
Contributor

@jabrown85 jabrown85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a great start to me!

extender/testdata/layers/group.toml
extender/testdata/layers/plan.toml
extender/testdata/layers/report.toml
extender/testdata/layers/samples_*/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: newline

Suggested change
extender/testdata/layers/samples_*/*
extender/testdata/layers/samples_*/*

if err != nil {
return cmd.FailErrCode(err, ba.platform.CodeFor(platform.BuildError), "build")
}

builder := &lifecycle.Builder{
AppDir: ba.appDir,
LayersDir: ba.layersDir,
LayersDir: ba.layersDir, // TODO: when there are extensions, this should default to something other than /layers - maybe /layers/config/ext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that up to the platform? I guess having a different default is probably good for documentation kind of reason.

da.buildpacksDir,
da.platform,
)
detector, err := lifecycle.NewDetector(buildpack.DetectConfig{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the old formatting was better IMO

if err != nil {
return cmd.FailErr(err, fmt.Sprintf("lookup buildpack.toml for buildpack '%s'", groupBp.String()))
var buildable buildpack.Buildable
if groupBp.Extension {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future note: This feels like a place we could improve the API. If we had an api like multistore.Lookup(groupBp) could we remove the branching here and anywhere else we need to lookup?

@@ -284,6 +291,67 @@ func (e *Exporter) addAppLayers(opts ExportOptions, slices []layers.Slice, meta
return nil
}

func (e *Exporter) addExtenderLayers(opts ExportOptions, meta *platform.LayersMetadata) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this entirely if we say that extensions produce images in registries, at least. If we intend on supporting non-registry flows, then we would want to be able to capture and use these layers as the run-image during exporter.

I don't know if we've made that decision. I'm fine leaving this here as POC idea until we do, though it is incorrect in implementation.

name = "Buildpack using curl"

[[stacks]]
id = "*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:newline

Suggested change
id = "*"
id = "*"

FROM \${base_image}

# TODO: why wasn't this needed before?
USER root
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this was not needed before because we were executing the instructions on the builder which was running as root.

This raises a good question/concern. If, for run extensions, we apply Dockerfile after Dockerfile and the last Dockerfile leaves the USER root as the last instruction...is that ok? That feels wrong as one of the pillars of CNB is that the resulting image should not be root IMO. It gets a bit muddier when you think about full run image replacements as well. Does the final image need to be using the same CNB_USER_ID as the original run image reference to make things happy/correct?

I'm sure @sclevine has some thoughts on this...

Signed-off-by: Natalie Arellano <narellano@vmware.com>
@BarDweller
Copy link
Contributor

Ran into an issue where if the Dockerfile being processed attempts to pull any new images, the pull failed because kaniko had a null/empty default platform, resulting in errors like..

time="2022-02-17T18:34:55Z" level=info msg="Retrieving image manifest redhat/ubi8-minimal:latest"
time="2022-02-17T18:34:55Z" level=info msg="Retrieving image redhat/ubi8-minimal:latest from registry index.docker.io"
time="2022-02-17T18:34:55Z" level=error msg="Error parsing the serverURL" error="docker-credential-ecr-login can only be used with Amazon Elastic Container Registry." serverURL=index.docker.io
ERROR: no child with platform  in index redhat/ubi8-minimal:latest

(Note the empty platform name in the final ERROR output)

Did some digging, found kaniko treats the CustomPlatform option differently to all it's others, and essentially requires it to be set to the default platform if the value is not set by a user.

Have created a quick PR for the branch of this PR to fix that.. #804

Signed-off-by: Ozzy Osborne <bardweller@gmail.com>
Kaniko will now push cache layerse into the registry at `$REGISTRY_HOST/extended/buildimage/cache` and `$REGISTRY_HOST/extended/runimage/cache` - allowing for faster builds when the layer can be re-used.

Signed-off-by: Jesse Brown <jabrown85@gmail.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
Signed-off-by: Natalie Arellano <narellano@vmware.com>
See buildpacks/spec#286 - this was patched in a newer lifecycle, but is missing in the POC

Signed-off-by: Natalie Arellano <narellano@vmware.com>
@natalieparellano
Copy link
Member Author

Some thoughts on next steps...

While the POC seems to work, there are a number of features missing. Some are procedural / cosmetic, but there are a few harder problems to solve:

  • isolating registry credentials from Dockerfiles
  • running syft on the extended image (see related comment)
  • validations on the extended image (is it rebasable, did the user change, etc.)

For isolating registry credentials, the platform would need to pull all the base images from the registry before starting the extender container. The base images could be provided to kaniko in either a local registry, or in a cache directory - but the latter seems not performant as kaniko expects to find the layers in a single tar, which would make it difficult to re-use layers across images. We could see about PR'ing kaniko the ability to lookup layers from a blob store.

Another problem is outputs - kaniko can output to either a registry or to an oci layout directory. The former might be more convenient as it is readily chain-able as an input to the next Dockerfile. But there are other headaches associated with creating a local registry (such as networking) that would need to be thought through.

The following diagram illustrates how this might work. It assumes we are using a local registry but the idea is the same if we try to go the other route (changing how --cache-dir behaves in kaniko, making in chain-able). The other discussions currently underway in the project (1, 2) might influence which route we decide to take. cc @jjbustamante @jromero @samj1912

Screen Shot 2022-04-14 at 12 12 41 PM

@natalieparellano
Copy link
Member Author

Also just to add - buildpacks/spec#298 (comment) proposes a phased implementation that would let us get something out that would deliver value while we work out some of these thornier issues.

…uilder (#845)

Signed-off-by: Natalie Arellano <narellano@vmware.com>
…deps (#844)

Signed-off-by: Natalie Arellano <narellano@vmware.com>
@natalieparellano
Copy link
Member Author

Closing as I think this POC has served its purpose. For further details on the "real" implementation please follow buildpacks/rfcs#224

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants