Skip to content

Dagger & Dockerfile

We build packages, use Dagger commands, but why reinvent the wheel?
We are used to Dockerfiles, and all our projects already utilize them. So, let’s reuse this code with Dagger!

Let’s try to build our Dockerfile and publish it to a private registry like Scaleway.

Dockerfile

For now, I’ll start with a very simple Dockerfile. (Yes, it’s not using a Node.js user, but it’s just for the demo.)

Here it is:

FROM node:lts
WORKDIR /app
COPY . /app
EXPOSE 8080
CMD [ "npm", "run", "start" ]

Daggerization

Initialization

To daggerize our project, we’ll start by initializing Dagger with the TypeScript SDK:

Fenêtre de terminal
dagger init --sdk=typescript --source=./dagger

Then, in dagger.json, I’ll exclude node_modules to avoid copying them during development.
This can cause issues between different OS and Node.js versions.

"exclude": [
"**/node_modules"
]

Build

We’ll first create a function to install dependencies.

@func()
dev(source: Directory): Directory {
const nodeCache = dag.cacheVolume("node")
const npmInstall = dag
.container()
// start from a base Node.js container
.from("node:lts")
// add the source code at /src
.withDirectory("/app", source)
// mount the cache volume at /root/.npm
.withMountedCache("/root/.npm", nodeCache)
// change the working directory to /src
.withWorkdir("/app")
// run npm install to install dependencies
.withExec(["npm", "install"])
// Return directory
return npmInstall.directory("/app")
}

This function allows us to return the directory with the installed dependencies for later use.

Let’s test it:

dagger call dev --source=.

Dagger build

Great! Now let’s build the Dockerfile.

Building the Dockerfile

Before trying to publish, let’s test the container live from Dagger.
Is that possible?

Yes! You can create services and expose them on your host. If you don’t expose them, you can use the service as an HTTP endpoint for your other functions.

@func()
build(source: Directory): Service {
const devDirectory = this.dev(source)
return dag
.container()
.withDirectory("/app", devDirectory)
.build(devDirectory, {dockerfile: "Dockerfile"})
.asService()
}

I want to expose this as a service to verify that it works and the Dockerfile is properly applied.

If we simply run the following command, the service will start but won’t be accessible on our host:

Fenêtre de terminal
dagger call build --source=.

Let’s expose the service using --ports:

Fenêtre de terminal
dagger call build --source=. up --ports 9002:8080

Dagger services

Our container is responding properly!

*[main][~/Documents/dev-aidalinfo/tmp/node-api-demo]$ curl http://localhost:9002
Ready !!! 🔥🔥🔥

Perfect! Now, let’s revert it to container mode:

@func()
build(source: Directory): Container {
const devDirectory = this.dev(source)
return dag
.container()
.withDirectory("/app", devDirectory)
.build(devDirectory, {dockerfile: "Dockerfile"})
}

And let’s test exposing it on our host in container mode:

Exposed container

It works! 😲

Conclusion

We now have a function that builds using the Dockerfile. For publishing to a private registry, check out the next page!
I prefer to separate topics to keep the information digestible and well-structured.

Full Dagger Code

Here’s the complete index.ts for Dagger:

import { dag, Container, Directory, object, func } from "@dagger.io/dagger"
@object()
export class NodeApiDemo {
@func()
build(source: Directory): Container {
const devDirectory = this.dev(source)
return dag
.container()
.withDirectory("/app", devDirectory)
.build(devDirectory, {dockerfile: "Dockerfile"})
}
@func()
dev(source: Directory): Directory {
const nodeCache = dag.cacheVolume("node")
const npmInstall = dag
.container()
// start from a base Node.js container
.from("node:lts")
// add the source code at /src
.withDirectory("/app", source)
// mount the cache volume at /root/.npm
.withMountedCache("/root/.npm", nodeCache)
// change the working directory to /src
.withWorkdir("/app")
// run npm install to install dependencies
.withExec(["npm", "install"])
// Return directory
return npmInstall.directory("/app")
}
}

GitHub Repository

https://github.com/Killian-Aidalinfo/node-api-demo-dockerfile