Container
The Container
type represents the state of an OCI-compatible container. This Container
object is not merely a string referencing an image on a remote registry. It is the actual state of a container, managed by the Dagger Engine, and passed to a Dagger Function's code as if it were just another variable.
Common operations
Some of the common operations used on the Container
type include:
Field | Description |
---|---|
from | Initializes the container from a specified base image |
asService | Turns the container into a Service |
asTarball | Returns a serialized tarball of the container as a File |
export / import | Writes / reads the container as an OCI tarball to / from a file path on the host |
publish | Publishes the container image to a registry |
stdout / stderr | Returns the output / error stream of the last executed command |
withDirectory / withMountedDirectory | Returns the container plus a directory copied / mounted at the given path |
withEntrypoint | Returns the container with a custom entrypoint command |
withExec | Returns the container after executing a command inside it |
withFile / withMountedFile | Returns the container plus a file copied / mounted at the given path |
withMountedCache | Returns the container plus a cache volume mounted at the given path |
withRegistryAuth | Returns the container with registry authentication configured |
withWorkdir | Returns the container configured with a specific working directory |
withServiceBinding | Returns the container with runtime dependency on another Service |
terminal | Opens an interactive terminal for this container |
Examples
Build image from Dockerfile
The following Dagger Function builds an image from a Dockerfile.
- Go
- Python
- TypeScript
- PHP
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Build and publish image from existing Dockerfile
func (m *MyModule) Build(
ctx context.Context,
// location of directory containing Dockerfile
src *dagger.Directory,
) (string, error) {
ref, err := src.
DockerBuild(). // build from Dockerfile
Publish(ctx, "ttl.sh/hello-dagger")
if err != nil {
return "", err
}
return ref, nil
}
from typing import Annotated
import dagger
from dagger import Doc, function, object_type
@object_type
class MyModule:
@function
async def build(
self,
src: Annotated[
dagger.Directory,
Doc("location of directory containing Dockerfile"),
],
) -> str:
"""Build and publish image from existing Dockerfile"""
ref = src.docker_build().publish("ttl.sh/hello-dagger") # build from Dockerfile
return await ref
import { dag, Directory, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Build and publish image from existing Dockerfile
* @param src location of directory containing Dockerfile
*/
@func()
async build(src: Directory): Promise<string> {
const ref = await src
.dockerBuild() // build from Dockerfile
.publish("ttl.sh/hello-dagger")
return ref
}
}
<?php
declare(strict_types=1);
namespace DaggerModule;
use Dagger\Attribute\DaggerFunction;
use Dagger\Attribute\DaggerObject;
use Dagger\Directory;
use function Dagger\dag;
#[DaggerObject]
class MyModule
{
// Build and publish image from existing Dockerfile
#[DaggerFunction]
public function build(
// location of directory containing Dockerfile
Directory $src,
): string {
$ref = $src
->dockerBuild() // build from Dockerfile
->publish('ttl.sh/hello-dagger');
return $ref;
}
}
Example
Build and publish an image from an existing Dockerfile
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'build https://github.com/dockersamples/python-flask-redis'
build https://github.com/dockersamples/python-flask-redis
dagger call build --src="https://github.com/dockersamples/python-flask-redis"
Build image from Dockerfile using different build context
The following function builds an image from a Dockerfile with a build context that is different than the current working directory.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Build and publish image from Dockerfile using a build context directory
// in a different location than the current working directory
func (m *MyModule) Build(
ctx context.Context,
// location of source directory
src *dagger.Directory,
// location of Dockerfile
dockerfile *dagger.File,
) (string, error) {
// get build context with dockerfile added
workspace := dag.Container().
WithDirectory("/src", src).
WithWorkdir("/src").
WithFile("/src/custom.Dockerfile", dockerfile).
Directory("/src")
// build using Dockerfile and publish to registry
ref, err := dag.Container().
Build(workspace, dagger.ContainerBuildOpts{
Dockerfile: "custom.Dockerfile",
}).
Publish(ctx, "ttl.sh/hello-dagger")
if err != nil {
return "", err
}
return ref, nil
}
from typing import Annotated
import dagger
from dagger import Doc, dag, function, object_type
@object_type
class MyModule:
@function
async def build(
self,
src: Annotated[
dagger.Directory,
Doc("location of source directory"),
],
dockerfile: Annotated[
dagger.File,
Doc("location of Dockerfile"),
],
) -> str:
"""
Build and publish image from Dockerfile
This example uses a build context directory in a different location
than the current working directory.
"""
# get build context with dockerfile added
workspace = (
dag.container()
.with_directory("/src", src)
.with_workdir("/src")
.with_file("/src/custom.Dockerfile", dockerfile)
.directory("/src")
)
# build using Dockerfile and publish to registry
ref = (
dag.container()
.build(context=workspace, dockerfile="custom.Dockerfile")
.publish("ttl.sh/hello-dagger")
)
return await ref
import { dag, Directory, File, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Build and publish image from existing Dockerfile. This example uses a
* build context directory in a different location than the current working
* directory.
* @param src location of source directory
* @param dockerfile location of dockerfile
*/
@func()
async build(src: Directory, dockerfile: File): Promise<string> {
// get build context with Dockerfile added
const workspace = await dag
.container()
.withDirectory("/src", src)
.withWorkdir("/src")
.withFile("/src/custom.Dockerfile", dockerfile)
.directory("/src")
// build using Dockerfile and publish to registry
const ref = await dag
.container()
.build(workspace, { dockerfile: "custom.Dockerfile" })
.publish("ttl.sh/hello-dagger")
return ref
}
}
Example
Build an image from the source code in https://github.com/dockersamples/python-flask-redis
using the Dockerfile from a different build context, at https://github.com/vimagick/dockerfiles#master:registry-cli/Dockerfile
:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'build https://github.com/dockersamples/python-flask-redis https://github.com/vimagick/dockerfiles#master:registry-cli/Dockerfile'
build https://github.com/dockersamples/python-flask-redis https://github.com/vimagick/dockerfiles#master:registry-cli/Dockerfile
dagger call \
build --src="https://github.com/dockersamples/python-flask-redis" \
--dockerfile=https://github.com/vimagick/dockerfiles#master:registry-cli/Dockerfile
Debug workflows with the interactive terminal
Dagger provides two features that can help greatly when trying to debug a workflow - opening an interactive terminal session at the failure point, or at explicit breakpoints throughout your workflow code. All context is available at the point of failure. Multiple terminals are supported in the same Dagger Function; they will open in sequence.
The following Dagger Function opens an interactive terminal session at different stages in a Dagger workflow to debug a container build.
- Go
- Python
- TypeScript
package main
import (
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
func (m *MyModule) Container() *dagger.Container {
return dag.Container().
From("alpine:latest").
Terminal().
WithExec([]string{"sh", "-c", "echo hello world > /foo && cat /foo"}).
Terminal()
}
import dagger
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
def container(self) -> dagger.Container:
return (
dag.container()
.from_("alpine:latest")
.terminal()
.with_exec(["sh", "-c", "echo hello world > /foo && cat /foo"])
.terminal()
)
import { dag, Container, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
@func()
container(): Container {
return dag
.container()
.from("alpine:latest")
.terminal()
.withExec(["sh", "-c", "echo hello world > /foo && cat /foo"])
.terminal()
}
}
Example
Execute a Dagger Function to build a container, and open an interactive terminal at two different points in the build process. The interactive terminal enables you to inspect the container filesystem and environment "live", during the build process.
- System shell
- Dagger Shell
- Dagger CLI
dagger -c container
container
dagger call container
Inspect directories and files
The following Dagger Function clones Dagger's GitHub repository and opens an interactive terminal session to inspect it. Under the hood, this creates a new container (defaults to alpine
) and starts a shell, mounting the repository directory inside.
- Go
- Python
- TypeScript
package main
import (
"context"
)
type MyModule struct{}
func (m *MyModule) SimpleDirectory(ctx context.Context) (string, error) {
return dag.
Git("https://github.com/dagger/dagger.git").
Head().
Tree().
Terminal().
File("README.md").
Contents(ctx)
}
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def simple_directory(self) -> str:
return await (
dag.git("https://github.com/dagger/dagger.git")
.head()
.tree()
.terminal()
.file("README.md")
.contents()
)
import { dag, Container, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
@func()
async simpleDirectory(): Promise<string> {
return await dag
.git("https://github.com/dagger/dagger.git")
.head()
.tree()
.terminal()
.file("README.md")
.contents()
}
}
The container created to mount the directory can be customized using additional options. The following Dagger Function revised the previous example to demonstrate this, using an ubuntu
container image and bash
shell instead of the defaults.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
func (m *MyModule) AdvancedDirectory(ctx context.Context) (string, error) {
return dag.
Git("https://github.com/dagger/dagger.git").
Head().
Tree().
Terminal(dagger.DirectoryTerminalOpts{
Container: dag.Container().From("ubuntu"),
Cmd: []string{"/bin/bash"},
}).
File("README.md").
Contents(ctx)
}
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def advanced_directory(self) -> str:
return await (
dag.git("https://github.com/dagger/dagger.git")
.head()
.tree()
.terminal(
container=dag.container().from_("ubuntu"),
cmd=["/bin/bash"],
)
.file("README.md")
.contents()
)
import { dag, Container, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
@func()
async advancedDirectory(): Promise<string> {
return await dag
.git("https://github.com/dagger/dagger.git")
.head()
.tree()
.terminal({
container: dag.container().from("ubuntu"),
cmd: ["/bin/bash"],
})
.file("README.md")
.contents()
}
}
Example
-
Execute a Dagger Function to clone Dagger's GitHub repository and open a terminal session in the repository directory:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c simple-directory
First type 'dagger' for interactive mode.simple-directory
dagger call simple-directory
-
Execute another Dagger Function that does the same as the previous one, except using an
ubuntu
container image as base and initializing the terminal with thebash
shell:- System shell
- Dagger Shell
- Dagger CLI
dagger -c advanced-directory
First type 'dagger' for interactive mode.advanced-directory
dagger call advanced-directory
Add OCI annotations to image
The following Dagger Function adds OpenContainer Initiative (OCI) annotations to an image.
- Go
- Python
- TypeScript
package main
import (
"context"
"fmt"
"math"
"math/rand/v2"
)
type MyModule struct{}
// Build and publish image with OCI annotations
func (m *MyModule) Build(ctx context.Context) (string, error) {
address, err := dag.Container().
From("alpine:latest").
WithExec([]string{"apk", "add", "git"}).
WithWorkdir("/src").
WithExec([]string{"git", "clone", "https://github.com/dagger/dagger", "."}).
WithAnnotation("org.opencontainers.image.authors", "John Doe").
WithAnnotation("org.opencontainers.image.title", "Dagger source image viewer").
Publish(ctx, fmt.Sprintf("ttl.sh/custom-image-%.0f", math.Floor(rand.Float64()*10000000))) //#nosec
if err != nil {
return "", err
}
return address, nil
}
import random
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def build(self) -> str:
"""Build and publish image with OCI annotations"""
address = await (
dag.container()
.from_("alpine:latest")
.with_exec(["apk", "add", "git"])
.with_workdir("/src")
.with_exec(["git", "clone", "https://github.com/dagger/dagger", "."])
.with_annotation("org.opencontainers.image.authors", "John Doe")
.with_annotation(
"org.opencontainers.image.title", "Dagger source image viewer"
)
.publish(f"ttl.sh/custom-image-{random.randrange(10 * 7)}")
)
return address
import { dag, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Build and publish image with OCI annotations
*/
@func()
async build(): Promise<string> {
const address = await dag
.container()
.from("alpine:latest")
.withExec(["apk", "add", "git"])
.withWorkdir("/src")
.withExec(["git", "clone", "https://github.com/dagger/dagger", "."])
.withAnnotation("org.opencontainers.image.authors", "John Doe")
.withAnnotation(
"org.opencontainers.image.title",
"Dagger source image viewer",
)
.publish(`ttl.sh/custom-image-${Math.floor(Math.random() * 10000000)}`)
return address
}
}
Example
Build and publish an image with OCI annotations:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c build
build
dagger call build
Add OCI labels to image
The following Dagger Function adds OpenContainer Initiative (OCI) labels to an image.
- Go
- Python
- TypeScript
package main
import (
"context"
"time"
)
type MyModule struct{}
// Build and publish image with OCI labels
func (m *MyModule) Build(
ctx context.Context,
) (string, error) {
ref, err := dag.Container().
From("alpine").
WithLabel("org.opencontainers.image.title", "my-alpine").
WithLabel("org.opencontainers.image.version", "1.0").
WithLabel("org.opencontainers.image.created", time.Now().String()).
WithLabel("org.opencontainers.image.source", "https://github.com/alpinelinux/docker-alpine").
WithLabel("org.opencontainers.image.licenses", "MIT").
Publish(ctx, "ttl.sh/my-alpine")
if err != nil {
return "", err
}
return ref, nil
}
from datetime import datetime, timezone
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def build(self) -> str:
"""Build and publish image with OCI labels"""
ref = (
dag.container()
.from_("alpine")
.with_label("org.opencontainers.image.title", "my-alpine")
.with_label("org.opencontainers.image.version", "1.0")
.with_label(
"org.opencontainers.image.created",
datetime.now(timezone.utc).isoformat(),
)
.with_label(
"org.opencontainers.image.source",
"https://github.com/alpinelinux/docker-alpine",
)
.with_label("org.opencontainers.image.licenses", "MIT")
.publish("ttl.sh/my-alpine")
)
return await ref
import { dag, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Build and publish image with OCI labels
*/
@func()
async build(): Promise<string> {
const ref = await dag
.container()
.from("alpine")
.withLabel("org.opencontainers.image.title", "my-alpine")
.withLabel("org.opencontainers.image.version", "1.0")
.withLabel("org.opencontainers.image.created", new Date())
.withLabel(
"org.opencontainers.image.source",
"https://github.com/alpinelinux/docker-alpine",
)
.withLabel("org.opencontainers.image.licenses", "MIT")
.publish("ttl.sh/hello-dagger")
return ref
}
}
Example
Build and publish an image with OCI labels:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c build
build
dagger call build