#buildpacks
1 messages ยท Page 1 of 1 (latest)
continuing in a thread ๐
so, the integration with buildpacks is possible but probably not in the way you think
could you share a link to the buildpack sdk please, so I can make sure?
Here's a quick example:
packClient, err := pack.NewClient(pack.WithLogger(NewLogger(io.Discard)))
if err != nil {
l.Errorf("Could not create pack client: %s", err.Error())
os.Exit(1)
}
opts := pack.BuildOptions{
Image: "registry.mydomain.app/" + accountID + "/" + appName + ":" + revision,
Builder: "heroku/buildpacks:20",
AppPath: appPath,
Publish: true,
ClearCache: false,
TrustBuilder: func(_ string) bool { return true },
}
// set context with timeout
err = packClient.Build(context.Background(), opts)
if err != nil {
l.Error(err.Error())
os.Exit(1)
}
Looks like it supports Docker client
https://github.com/buildpacks/pack/blob/main/pkg/client/client.go#L198
I'm not sure if it would be an addition of Dagger client in there or if pack can somehow directly connect to dagger engine via docker connection
Unfortunately not. These are both SDKs so you need to write code against their respective API to use them. For them to work together you would have to either 1) use a plugin/extension mechanism in one to integrate with the other, or 2) modify one to use the otherโs API
What do you recommend?
You can definitely implement buildpack support on top of the Dagger Go SDK. Possibly by modifying the pack tool to use Dagger, or just borrowing parts of its code into a new, simpler tool.
It all depends on what your goal is, and what is a reasonable effort to reach it.
What are you trying to achieve in the end?
I'd like to use Pack client to connect to dagger engine to build images
After that, I could use dagger SDK for rest of the operations
I see. How do you run the pack client today? From CI, a shell script, makefile, other?
It's just a binary which is invoked whenever someone does a git push on their repo
It does nothing other than build from git repo and push out the image but looking at dagger Go sdk, I felt it could do a lot more.
Feels intuitive to add dagger client to pack SDK. I'm not sure if that's something pack community will accept but that's okay.
Once pack is connected to dagger engine, I'm not sure how it can instruct for builds.
I'm aware of this project which integrates buildpack with buildkit https://github.com/tonistiigi/buildkit-pack
That would be option 2: modify pack to use the Dagger API. It's definitely possible, but it would probably be a lot of work. Not the kind of thing you'd do quickly this week to have a working project the next week.
Something like that might be another option: create a new tool from scratch (perhaps inspired by Tonis's prototype above) which supports buildpack from scratch on top of Dagger.
This might actually be more realistic, because buildpacks are really not that complicated...
But still not a trivial project, and you wouldn't have 100% compatibility right away
Sounds worth trying ๐
Another approach would be to configure pack to not orchestrate docker
or use another buildpack tool that does not require docker
then that tool can just be run inside a container, and orchestrated by Dagger
Would this be a plugin on dagger?
Let's see if Twitter can help ๐ https://twitter.com/solomonstre/status/1585127365164036096
Thinking about implementing buildpacks on top of @dagger_io as a side project. Is there a reference implementation of the spec that I could wrap for this purpose? Some sort of "libbuildpack"? I saw the pack CLI but that doesn't seem amenable to wrapping.
This is how I would do it personally ๐
It could be, eventually. We are working on a extension system (basically plugins). But you could also just use it as a regular tool that embeds Dagger
Cool
There are other options too, shortcuts for compatibility
If you're just looking to get compatibility with what you have, then build new features directly on Dagger, then you could simply run a Docker engine on the side, and run the pack CLI in Dagger, configured to send instructions to that external Docker engine.
In that case the integration would be less good with Dagger: the buildpack build itself would appear to Dagger as just the execution of the client. Dagger wouldn't know anything about the rest of the buildpack process. That stuff would not be magically cached for example.
It only makes sense if you just need to get that pack thing out of the way, to focus on a more interesting part.
If integrating pack is the main part of using Dagger for you, this option doesn't make sense.
Another option that is not yet available, but could be interesting in the future: in theory we could develop a Docker engine API proxy, backed by Dagger. So you could "fool" a regular docker client into thinking it's talking to a regular docker engine, when in fact it's talking to a facade to Dagger.
This proxy would never have 100% compatibility (an explicit non-goal), but it could support enough potentially to fool simple tools like pack that only use a fraction of the docker API
Yeah, integrating pack with dagger is important. Really want to avoid running the docker engine and just rely on dagger-buildkit
yet another option: maybe wrap podman inside a container? I keep hearing that podman is "daemonless". So I guess that means you can run a podman container inside a dagger container? In that scenario you would do dagger -> pack -> podman
Oh, docker engine proxy sounds nice.
yes but again: does not exist today ๐
Not really in a rush tbh.
honestly I bet someone with a little time on their hand, and equipped with a reference implementation of the buildpack spec, could reimplement pack on top of dagger in less than a week
with 10x less code too probably
kind of makes me want to try...
I am more than happy to contribute to make this happen
I dont know either side well enough to start though, haha
Ha ha let's try to figure that out ๐
So, here's what we have so far:
- Pack, complete CLI but wants to do everything, hard to wrap: https://github.com/buildpacks/pack
- Experimental buildkit implementation. Good inspiration, but old. Buildkit API is pretty complex too. https://github.com/tonistiigi/buildkit-pack
- Something promising: reference implementation? Could this be our starting point? https://github.com/buildpacks/lifecycle
CLI for building apps using Cloud Native Buildpacks - GitHub - buildpacks/pack: CLI for building apps using Cloud Native Buildpacks
buildkit frontend for buildpacks. Contribute to tonistiigi/buildkit-pack development by creating an account on GitHub.
Feels like the docker engine proxy could be beneficial to other such projects too. Whenever someone looks at Dagger and wants to substitute it with Docker engine, things would work out of the box(hopefully all of them)
It definitely would not be all of the things though.. The Docker engine API has a lot of compatibility bagage
But you could probably get the 10% of features used by 90% of people
we already support docker build out of the box ๐
as well as the core of docker run (not fancy stuff like volumes, network etc)
That's cool
my guess is several months before a docker engine proxy makes any sense to create or use
and even then it will be kind of a stopgap. Something you use when you don't have anything more native available
Yeah, that's true..
You can see parts of Tonis's thought process here: https://github.com/tonistiigi/buildkit-pack/blob/master/manifest.go#L11-L12
// These types are defined in code.cloudfoundry.org/cli/util/manifest but importing it
// means importing 8 packages so redefined for simplicity instead.
That buildpack stuff is a beast. Looks quite bloated and complex
Probably 80% of the work is just understanding all the complexity. Then the remaining 20% is using the parts of the code we actually need once identified, and writing the Dagger part
I don't connect how buildpacks/lifecycle and dagger can integrate...
here's the spec which pack implements: https://github.com/buildpacks/spec/blob/main/platform.md#cnb-terminology
buildpacks are just a complicated spec for running a bunch of scripts in sequence from application source code
it's initially very simple code that got wrapped in complicated words
Each of these scripts can run in a container - something which Dagger can do easily
Looking at the spec and the pack codebase.. It has turned into quite a beast of complexity
It's probably most realistic to modify pack directly to talk to Dagger, rather than start from scratch
As in have pack execute those scripts in Dagger, right?
Yes, replace all calls to the docker client to equivalent calls to the dagger client
(probably easier than a proxy)
how much easier, not sure
I'm looking at the source code now, my curiosity is piqued ๐
Haha, me too.
Would we have to implement this interface to use Dagger? https://github.com/buildpacks/imgutil/blob/6accc39f0cf9c026efe50ab137c805b5d1a9cecc/image.go#L36
No idea
Lot of the docker daemon interactions seem to boil down to this file. Just have to map equivalent Dagger calls wherever docker calls are made... Looks very promising, tbh. https://sourcegraph.com/github.com/buildpacks/imgutil@6accc39f0cf9c026efe50ab137c805b5d1a9cecc/-/blob/local/local.go
I'll have a closer look over the weekend
Huh, yes that seems like it could be if not 100% of the work, then a solid chunk of it at least
cc @tepid furnace @wild hawk @thin atlas this could be an interesting "stress test" of API features ๐ In addition to CUE SDK 0.3, and Bass
Thank you for having this chat and creating something amazing ๐
And thanks for being patient with us! Happy to chat about this any time, and of course work on the code too!
Check out the response I just got ๐ https://twitter.com/bmogilefsky/status/1585140800048226304?s=20&t=taX7vJCsgIieV72zu7O8RQ
@solomonstre @dagger_io That covers the whole process, at least from Paketo's perspective. If you're just looking for the library, it's here:
https://t.co/4wTGPByDnG
Hum, it appears that this ๐is for implementing a buildpack. But we want to implement a buildpack runner (like pack). So not as useful as I initially thought.
Oh, looks like the community is in fact interested in using buildkit. https://github.com/buildpacks/pack/issues/768
They were considering the buildkit frontend route. It's possible Buildkit frontend might offer a lot more but dagger client can be a drop-in replacement for Docker client
Just noticed in the end that there's a dagger issue linking this one. ๐
Kinda glad that there are other people in both communities that want this
This takes me back ๐ I was looking into this 1yr ago. It was the first thing I asked when I came here (#๐ญuniverse message) and it was my first conversation with @hasty glacier too ๐. It was also my first GitHub issue on the repo.
The problem was exporting the result of the build into the DAG so it can be reused in other steps (as with a Dockerfile, i.e., Container().Build(...)). I gave up on using a buildkit frontend because of performance reasons and not supporting all features from CNBP.
You can see in https://github.com/dagger/dagger/issues/1053#issuecomment-972770824 that my conclusion was to use the lifecycle directly:
Use lifecycle directly. Run inside a builder image (which includes everything you need), without having to bind the docker socket (unless you want to build to the local daemon). Also, since it's the lifecycle that does the exporting, we can explore how the output can be integrated with dagger's DAG.
Dagger would become the platform then.
In the next comment there's further explanation:
Another way of describing this is: the lifecycle is comparable to kaniko or other unprivileged image building tools. The pack CLI is glue code that makes it easy to use lifecycle with the Docker daemon. We could expand the functionality of the pack CLI so that it acts as glue code for other container runtimes, but that glue code is only necessary when containers are not natively accessible already. [...]
So Pack is the glue, but we can use Dagger as the glue instead.
So are you suggesting we make our own builder and run it with Dagger and ditch pack? If so, problem is that we'll have to add a lot of features to the builder image then. Currently, Pakteto and heroku builders have a lot of functionality for multiple languages built over the years which will be hard to port over.
No, I mean use the lifecycle instead of Pack. See here: https://blog.codecentric.de/gitlab-ci-paketo-buildpacks
Lifecycle: The lifecycle orchestrates buildpack execution, then assembles the resulting artifacts into a final app image.
Platform: A platform uses a lifecycle, buildpacks (packaged in a builder), and application source code to produce an OCI image.
Pack is a Platform. But Dagger can be a platform as well. You already have all the components.
If youโre looking to build images in CI (not locally), Iโd encourage you to use the lifecycle directly for that, so that you donโt need Docker. Hereโs an example: https://github.com/tektoncd/catalog/blob/main/task/buildpacks/0.3/buildpacks.yaml
Final Gitlab CI pipeline:
image: paketobuildpacks/builder
stages:
- build
# We somehow need to access GitLab Container Registry with the Paketo lifecycle
# So we simply create ~/.docker/config.json as stated in https://stackoverflow.com/a/41710291/4964553
before_script:
- mkdir ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_JOB_TOKEN\"}}}" >> ~/.docker/config.json
build-image:
stage: build
script:
- /cnb/lifecycle/creator -app=. $CI_REGISTRY_IMAGE:latest
The lifecycle is a binary that's available on the builder image.
Pack calls it.
Sure! I didn't attempt it but I'm interested in how this would work with Dagger ๐
Solomon mentioned earlier in the thread today that Dagger supports docker runbut doesn't support volumes
I think we can get away without mounting volumes though but looks like we'll really need exec. I am not sure if dagger supports that
Taking a look at the SDK now...
We can mount volumes but they're restricted to workdir which may not be an issue for you. Also, these volumes aren't bidirectional, they're mounted read-only so if you want to write to the host you need another call. Writing something to a mounted volume won't write it back to host automatically.
There's an Exec method but I'm not sure it'll work on running containers. In the example, it looks like it's running the Dockerfile cmomands
If you mean the Exec() in Container, it allows running any command inside said container.
Yeah, you're right. I'll try to port that gitlab example with dagger-go-sdk tomorrow
Before anyone grill me about using the "volume" terminology loosely here, you can say a volume is a bind mount. But you can still mount directories to the container in the way I described. ๐ผ
That's coming in https://github.com/dagger/dagger/pull/3123
I'm going to head out but here's what I tried.
I don't know if the qemu error is because I'm on a M1 Mac
EDIT: https://github.com/RealHarshThakur/dagger-builpack/blob/main/main.go
You need workarounds for now.
Oh, that's amazing. I did feel like debugging was going to be a huge pain point, it always was with Dockerfile. Glad to see it's already worked on
Yeah @thin atlas did an awesome demo where he attaches the terminal to a container in the middle of the pipeline and you can run around that container executing commands, like a breakpoint. Very powerful.
Yeah, I did expect it to fail as I didn't initalise the docker.json file but I don't think this is due to that. It looks something from qemu. Is there a way we can do equivalent of docker build -platform=linux/amd64 or something?
That's coming in https://github.com/dagger/dagger/pull/3119
Signed-off-by: Erik Sipsma erik@sipsma.dev
See docs/guides/avxpq-multiplatform-support.md for more details: https://github.com/sipsma/dagger/blob/platform-dagger/docs/guides/avxpq-multiplatform-sup...
I'm using the embedded engine and I think that's picking up the arch of my host machine, wonder if I can start my own
I think I've seen platform references around though, @wild hawk may give a straighter answer.
One thing, dagger.json is only needed when using extensions, which aren't released yet, so unless you want to explore the dev frontiers you can ignore that for now ๐
The current behavior is that your platform should default to using the platform where buildkit is running. So yeah, by default on macos m1 machines you'll end up running it inside the docker desktop linux VM, which is also ARM now I believe.
I think the reason you are picking up qemu is that the image you're using is x86 only: https://hub.docker.com/r/heroku/buildpacks/tags
So Buildkit sees that, pulls the x86 image and then tries to run it anyways using qemu. Unfortunately, it looks like docker is saying this is just a qemu issue, they aren't going to do anything about it, and instead you should try to use ARM images...: https://github.com/docker/for-mac/issues/5123
I don't love that we just have to repeat that unfortunate "solution" but it is indeed hard to fix without fixes from qemu or the buildpack image maintainers publishing arm images. I suppose one possibility would be to rebuild the buildpack image yourself as part of your pipeline instead of just pulling it, but after a brief glance that may be easier said than done: https://github.com/heroku/builder
I could actually host a buildkit daemon/dagger engine on a linux/amd64 machine
If you can point me to a doc/tell me at a high level how to host one, that would be great! ๐
Oh sure, though major forewarning that there's a good chance these details will change and this isn't really documented, tested or officially supported right now (it will be in the future though).
I suspect the easiest (though it's still not easy) way would be to setup a remote docker engine on the amd64 machine and then tell your local docker CLI to use that (via DOCKER_HOST, as documented here: https://docs.docker.com/engine/security/protect-access/). If you have the env var exported when you invoke dagger, dagger should use that remote docker host instead of the local one.
If that doesn't work, there's also undocumented support for connecting to buildkit running in a kubernetes pod or podman via a BUILDKIT_HOST env var. Can give pointers for that too.
Yeah, no worries if it's a thing in works. I know it's early days.
I was actually thinking if I can host the the dagger engine itself on a different machine and then connect my program via DAGGER_HOST but I'll need to know how to setup buildkit first and then start dagger engine on top of it.
Ok, so docs on how to host a buildkit daemon are pretty nice, lot of options. I'll figure out what's easier for me: https://github.com/moby/buildkit#expose-buildkit-as-a-tcp-service
How can I start Dagger engine on top of it once buildkit is deployed?
@azure sigil there's a short term answer and a longer term answer
short term: not supported right now, but we could quickly easily add a way for you to run a buildkit daemon yourself and configure the API router to connect to it. BUT that will not be supported long term, as the engine really bundles its own buildkit engine as a sub-component. We don't want to deal with the matrix from hell of supporting any variation of dagger/buildkit versions.
longer term: dagger engine is its own unit, with its own configuration and deployment options. It includes buildkit but you don't need to individually deploy that (nor can you). All the deployment features of buildkit are available for dagger engine
Oh, that makes sense. I am just looking at how the code for how dagger engine starts up
So I could just write a program which initialises a client to buildkit and then call the Start method here? https://github.com/dagger/dagger/blob/main/engine/engine.go#L43
the engine is really 2 distinct components right now:
- An API router that runs on the client machine
- A runner (buildkit engine + helpers) that runs in a container on a worker machine
You are welcome to hack away in the engine package (cc @thin atlas @wild hawk for more details on the internals), but just know that we don't guarantee that code's stability, we can and will move things around in that go package
Yeah, no issues with that...
I wonder if it's somehow already supported in dagger CLI. If I set the BUILDKIT_HOSTvariable and run the dagger dev command, it should start the engine on the remote buildkit I'll host and run the proxy locally. https://github.com/dagger/dagger/blob/main/cmd/dagger/dev.go#L31
Because when the engine.Start method initialises the buildkit client, it relies on the BUILDKIT_HOSTvariable.
Yeah the problem right now is that BUILDKIT_HOST assumes that buildkit is already running whereever you point it to. Dagger won't spin it up for you if it's not there. That's why I suspected that setting DOCKER_HOST might actually be the easiest route. By default, dagger spins up a buildkit for you in a docker container, but it does that just by shelling out to docker, so if you have DOCKER_HOST set then you can get our automatically setup buildkitd, but on whatever remote host you want.
Got it to work without having to run docker locally ๐
I did start up a buildkit daemon on a remote machine
Is there any plan to have dagger engine exposed via http? Happy to contribute to make it happen
Back to the buildpack integration, I'm not able to figure this one out. For some reason, writes to /src fails.
Logs:
#15 13.42 go: extracting github.com/gofrs/uuid v3.3.0+incompatible
#15 13.43 error writing go.mod: open /src/go.mod966711297.tmp: permission denied
#15 13.43 ERROR: failed to build: exit status 1
------
input:1: container.from.withMountedDirectory.withWorkdir.exec.directory process "/_shim /cnb/lifecycle/creator -app=. ttl.sh/random-new-image:latest" did not complete successfully: exit code: 145
I'll try copying the contents over rather than mounting
Oh, got it to work by using /tmp!! ๐
Thanks @gentle path @hasty glacier @wild hawk
You've all been a great help! ๐
@azure sigil FYI I have a working POC of a docker2dagger bridge ๐
Nice.
I wonder if I can still avoid using docker though
I remember the dagger-buildkit version matrix concern you had but I wonder if Dagger engine is only going to support one buildkit version at a time, then maybe we can have enforce it by not letting a dagger engine start if buildkit version doesn't match for the particular dagger release.
it may be more than version though
there are specific combinations of configuration flags that we may need to hardwire or manage
Oh, ok.
I really liked it when I could just connect a locally running stateless dagger engine to a remote buildkit where things are cached. It seemed like a much simpler version with host writes and everything just working out of the box.
I don't know how much of it was intended but I was wondering if I could have dagger engines connected to a single buildkit
Yes you will still be able to do this, we will release the dagger engine as a standalone docker image that you can run as a stateless, shared service. Just like builkitd today - but with a higher-level API
until thatโs ready weโll still allow swapping out buildkitd, but with the understanding that it will be deprecated eventually in favor of the above
by the way, even after that transition you will still be able to build your own engine, including the buildkit component, and deploy that, since itโs all open source and still powered by buildkit under the hood
Yeah, I just did this: https://github.com/dagger/dagger/pull/3938
I believe thereโs already another env variable that you can use. But things are moving fast so Iโll wait to see what the review says on that PR ๐
(thanks for taking the time to contribute this)
Oh, cool.
I'll fill in the description meanwhile for the setup I wanted . If it's already supported, that'd be amazing.