Container Images
Dagger allows you to build, publish, and export container images, also known as just-in-time artifacts, as part of your Dagger Functions. This section shows you how to work with container images using Dagger with practical examples.
Publish a container image to a private registry
The following Dagger Function publishes a just-in-time container image to a private registry.
- Go
- Python
- TypeScript
package main
import (
"context"
"fmt"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Publish a container image to a private registry
func (m *MyModule) Publish(
ctx context.Context,
// Registry address
registry string,
// Registry username
username string,
// Registry password
password *dagger.Secret,
) (string, error) {
return dag.Container().
From("nginx:1.23-alpine").
WithNewFile(
"/usr/share/nginx/html/index.html",
"Hello from Dagger!",
dagger.ContainerWithNewFileOpts{Permissions: 0o400},
).
WithRegistryAuth(registry, username, password).
Publish(ctx, fmt.Sprintf("%s/%s/my-nginx", registry, username))
}
from typing import Annotated
import dagger
from dagger import Doc, dag, function, object_type
@object_type
class MyModule:
@function
async def publish(
self,
registry: Annotated[str, Doc("Registry address")],
username: Annotated[str, Doc("Registry username")],
password: Annotated[dagger.Secret, Doc("Registry password")],
) -> str:
"""Publish a container image to a private registry"""
return await (
dag.container()
.from_("nginx:1.23-alpine")
.with_new_file(
"/usr/share/nginx/html/index.html",
"Hello from Dagger!",
permissions=0o400,
)
.with_registry_auth(registry, username, password)
.publish(f"{registry}/{username}/my-nginx")
)
import { dag, Secret, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Publish a container image to a private registry
*/
@func()
async publish(
/**
* Registry address
*/
registry: string,
/**
* Registry username
*/
username: string,
/**
* Registry password
*/
password: Secret,
): Promise<string> {
return await dag
.container()
.from("nginx:1.23-alpine")
.withNewFile("/usr/share/nginx/html/index.html", "Hello from Dagger!", {
permissions: 0o400,
})
.withRegistryAuth(registry, username, password)
.publish(`${registry}/${username}/my-nginx`)
}
}
Examples
Publish a just-in-time container image to Docker Hub, using the account username user
and the password set in the PASSWORD
environment variable:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'publish docker.io user env://PASSWORD'
publish docker.io user env://PASSWORD
dagger call publish --registry=docker.io --username=user --password=env://PASSWORD
Publish a just-in-time container image to GitHub Container Registry, using the account username user
and the GitHub personal access token set in the PASSWORD
environment variable:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'publish gchr.io user env://PASSWORD'
publish gchr.io user env://PASSWORD
dagger call publish --registry=gchr.io --username=user --password=env://PASSWORD
Publish a container image to a private registry with multiple tags
The following Dagger Function tags a just-in-time container image multiple times and publishes it to a private registry.
- Go
- Python
- TypeScript
package main
import (
"context"
"fmt"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Tag a container image multiple times and publish it to a private registry
func (m *MyModule) Publish(
ctx context.Context,
// Registry address
registry string,
// Registry username
username string,
// Registry password
password *dagger.Secret,
) ([]string, error) {
tags := [4]string{"latest", "1.0-alpine", "1.0", "1.0.0"}
addr := []string{}
ctr := dag.Container().
From("nginx:1.23-alpine").
WithNewFile(
"/usr/share/nginx/html/index.html",
"Hello from Dagger!",
dagger.ContainerWithNewFileOpts{Permissions: 0o400},
).
WithRegistryAuth(registry, username, password)
for _, tag := range tags {
a, err := ctr.Publish(ctx, fmt.Sprintf("%s/%s/my-nginx:%s", registry, username, tag))
if err != nil {
return addr, err
}
addr = append(addr, a)
}
return addr, nil
}
from typing import Annotated
import dagger
from dagger import Doc, dag, function, object_type
@object_type
class MyModule:
@function
async def publish(
self,
registry: Annotated[str, Doc("Registry address")],
username: Annotated[str, Doc("Registry username")],
password: Annotated[dagger.Secret, Doc("Registry password")],
) -> list[str]:
"""Tag a container image multiple times and publish it to a private registry"""
tags = ["latest", "1.0-alpine", "1.0", "1.0.0"]
addr = []
container = (
dag.container()
.from_("nginx:1.23-alpine")
.with_new_file(
"/usr/share/nginx/html/index.html",
"Hello from Dagger!",
permissions=0o400,
)
.with_registry_auth(registry, username, password)
)
for tag in tags:
a = await container.publish(f"{registry}/{username}/my-nginx:{tag}")
addr.append(a)
return addr
import { dag, Secret, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Tag a container image multiple times and publish it to a private registry
*/
@func()
async publish(
/**
* Registry address
*/
registry: string,
/**
* Registry username
*/
username: string,
/**
* Registry password
*/
password: Secret,
): Promise<string[]> {
const tags = ["latest", "1.0-alpine", "1.0", "1.0.0"]
const addr: string[] = []
const container = dag
.container()
.from("nginx:1.23-alpine")
.withNewFile("/usr/share/nginx/html/index.html", "Hello from Dagger!", {
permissions: 0o400,
})
.withRegistryAuth(registry, username, password)
for (const tag in tags) {
const a = await container.publish(
`${registry}/${username}/my-nginx:${tags[tag]}`,
)
addr.push(a)
}
return addr
}
}
Examples
Tag and publish a just-in-time container image to Docker Hub, using the account username user
and the password set in the PASSWORD
environment variable:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'publish docker.io user env://PASSWORD'
publish docker.io user env://PASSWORD
dagger call publish --registry=docker.io --username=user --password=env://PASSWORD
Tag and publish a just-in-time container image to GitHub Container Registry, using the account username user
and the GitHub personal access token set in the PASSWORD
environment variable:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'publish gchr.io user env://PASSWORD'
publish gchr.io user env://PASSWORD
dagger call publish --registry=gchr.io --username=user --password=env://PASSWORD
Build and load a container image into the host Docker Engine
The following Dagger Function builds a just-in-time container image and loads it into the Docker Engine running on the host.
- Go
- Python
- TypeScript
package main
import "dagger/my-module/internal/dagger"
type MyModule struct{}
// Return a container
func (m *MyModule) Base() *dagger.Container {
return dag.Container().
From("alpine:latest").
WithExec([]string{"mkdir", "/src"}).
WithExec([]string{"touch", "/src/foo", "/src/bar"})
}
import dagger
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
def base(self) -> dagger.Container:
"""Return a container"""
return (
dag.container()
.from_("alpine:latest")
.with_exec(["mkdir", "/src"])
.with_exec(["touch", "/src/foo", "/src/bar"])
)
import { dag, Container, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Return a container
*/
@func()
base(): Container {
return dag
.container()
.from("alpine:latest")
.withExec(["mkdir", "/src"])
.withExec(["touch", "/src/foo", "/src/bar"])
}
}
Example
Build and load a just-in-time container image into the Docker Engine running on the host:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'load /var/run/docker.sock myimage'
load /var/run/docker.sock myimage
dagger call load --docker=/var/run/docker.sock --tag=myimage
Export a container image to the host
The following Dagger Function returns a just-in-time container. This can be exported to the host as an OCI tarball.
- Go
- Python
- TypeScript
package main
import "dagger/my-module/internal/dagger"
type MyModule struct{}
// Return a container
func (m *MyModule) Base() *dagger.Container {
return dag.Container().
From("alpine:latest").
WithExec([]string{"mkdir", "/src"}).
WithExec([]string{"touch", "/src/foo", "/src/bar"})
}
import dagger
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
def base(self) -> dagger.Container:
"""Return a container"""
return (
dag.container()
.from_("alpine:latest")
.with_exec(["mkdir", "/src"])
.with_exec(["touch", "/src/foo", "/src/bar"])
)
import { dag, Container, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Return a container
*/
@func()
base(): Container {
return dag
.container()
.from("alpine:latest")
.withExec(["mkdir", "/src"])
.withExec(["touch", "/src/foo", "/src/bar"])
}
}
Examples
Load the container image returned by the Dagger Function into Docker:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'base | export-image myimage'
base | export-image myimage
dagger call base export-image --name myimage
Load the container image returned by the Dagger Function as a tarball to the host fileysystem:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'base | export /home/admin/mycontainer.tgz'
base | export /home/admin/mycontainer.tgz
dagger call base export --path=/home/admin/mycontainer.tgz
Set environment variables in a container
The following Dagger Function demonstrates how to set a single environment variable in a container.
- Go
- Python
- TypeScript
- PHP
package main
import "context"
type MyModule struct{}
// Set a single environment variable in a container
func (m *MyModule) SetEnvVar(ctx context.Context) (string, error) {
return dag.Container().
From("alpine").
WithEnvVariable("ENV_VAR", "VALUE").
WithExec([]string{"env"}).
Stdout(ctx)
}
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def set_env_var(self) -> str:
"""Set a single environment variable in a container"""
return await (
dag.container()
.from_("alpine")
.with_env_variable("ENV_VAR", "VALUE")
.with_exec(["env"])
.stdout()
)
import { dag, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Set a single environment variable in a container
*/
@func()
async setEnvVar(): Promise<string> {
return await dag
.container()
.from("alpine")
.withEnvVariable("ENV_VAR", "VALUE")
.withExec(["env"])
.stdout()
}
}
<?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
{
// Set a single environment variable in a container
#[DaggerFunction]
public function setEnvVar(): string
{
return dag()
->container()
->from('alpine')
->withEnvVariable('ENV_VAR', 'VALUE')
->withExec(['env'])
->stdout();
}
}
The following Dagger Function demonstrates how to set multiple environment variables in a container.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
type EnvVar struct {
Name string
Value string
}
// Set environment variables in a container
func (m *MyModule) SetEnvVars(ctx context.Context) (string, error) {
return dag.Container().
From("alpine").
With(EnvVariables([]*EnvVar{
{"ENV_VAR_1", "VALUE 1"},
{"ENV_VAR_2", "VALUE 2"},
{"ENV_VAR_3", "VALUE 3"},
})).
WithExec([]string{"env"}).
Stdout(ctx)
}
func EnvVariables(envs []*EnvVar) dagger.WithContainerFunc {
return func(c *dagger.Container) *dagger.Container {
for _, e := range envs {
c = c.WithEnvVariable(e.Name, e.Value)
}
return c
}
}
import dagger
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def set_env_vars(self) -> str:
"""Set environment variables in a container"""
return await (
dag.container()
.from_("alpine")
.with_(
self.env_variables(
[
("ENV_VAR_1", "VALUE 1"),
("ENV_VAR_2", "VALUE 2"),
("ENV_VAR_3", "VALUE 3"),
]
)
)
.with_exec(["env"])
.stdout()
)
def env_variables(self, envs: list[tuple[str, str]]):
def env_variables_inner(ctr: dagger.Container):
for key, value in envs:
ctr = ctr.with_env_variable(key, value)
return ctr
return env_variables_inner
import { dag, Container, Directory, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Set environment variables in a container
*/
@func()
async setEnvVars(): Promise<string> {
return await dag
.container()
.from("alpine")
.with(
envVariables([
["ENV_VAR_1", "VALUE 1"],
["ENV_VAR_2", "VALUE 2"],
["ENV_VAR_3", "VALUE_3"],
]),
)
.withExec(["env"])
.stdout()
}
}
function envVariables(envs: Array<[string, string]>) {
return (c: Container): Container => {
for (const [key, value] of envs) {
c = c.withEnvVariable(key, value)
}
return c
}
}
Example
Set a single environment variable in a container:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c set-env-var
set-env-var
dagger call set-env-var
Set multiple environment variables in a container:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c set-env-vars
set-env-vars
dagger call set-env-vars