Service
The Service
type represents a content-addressed service providing TCP connectivity.
Common operations​
Some of the common operations you can perform with a Service
include:
Field | Description |
---|---|
endpoint | Returns a URL or host:port pair to reach the service |
hostname | Returns a hostname to reach the service |
ports | Returns the list of ports provided by the service |
up | Creates a tunnel that forwards traffic from the caller's network to the service |
Examples​
Bind and use services in Dagger Functions​
The first Dagger Function below creates and returns an HTTP service. This service is bound and used from a different Dagger Function, via a service binding using an alias like www
.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Start and return an HTTP service
func (m *MyModule) HttpService() *dagger.Service {
return dag.Container().
From("python").
WithWorkdir("/srv").
WithNewFile("index.html", "Hello, world!").
WithExposedPort(8080).
AsService(dagger.ContainerAsServiceOpts{Args: []string{"python", "-m", "http.server", "8080"}})
}
// Send a request to an HTTP service and return the response
func (m *MyModule) Get(ctx context.Context) (string, error) {
return dag.Container().
From("alpine").
WithServiceBinding("www", m.HttpService()).
WithExec([]string{"wget", "-O-", "http://www:8080"}).
Stdout(ctx)
}
import dagger
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
def http_service(self) -> dagger.Service:
"""Start and return an HTTP service."""
return (
dag.container()
.from_("python")
.with_workdir("/srv")
.with_new_file("index.html", "Hello, world!")
.with_exposed_port(8080)
.as_service(args=["python", "-m", "http.server", "8080"])
)
@function
async def get(self) -> str:
"""Send a request to an HTTP service and return the response."""
return await (
dag.container()
.from_("alpine")
.with_service_binding("www", self.http_service())
.with_exec(["wget", "-O-", "http://www:8080"])
.stdout()
)
import { dag, object, func, Service } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Start and return an HTTP service
*/
@func()
httpService(): Service {
return dag
.container()
.from("python")
.withWorkdir("/srv")
.withNewFile("index.html", "Hello, world!")
.withExposedPort(8080)
.asService({ args: ["python", "-m", "http.server", "8080"] })
}
/**
* Send a request to an HTTP service and return the response
*/
@func()
async get(): Promise<string> {
return await dag
.container()
.from("alpine")
.withServiceBinding("www", this.httpService())
.withExec(["wget", "-O-", "http://www:8080"])
.stdout()
}
}
Example​
Send a request from one Dagger Function to a bound HTTP service instantiated by a different Dagger Function:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c get
get
dagger call get
Expose services in Dagger Functions to the host​
The Dagger Function below creates and returns an HTTP service. This service can be used from the host.
- Go
- Python
- TypeScript
package main
import (
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Start and return an HTTP service
func (m *MyModule) HttpService() *dagger.Service {
return dag.Container().
From("python").
WithWorkdir("/srv").
WithNewFile("index.html", "Hello, world!").
WithExposedPort(8080).
AsService(dagger.ContainerAsServiceOpts{Args: []string{"python", "-m", "http.server", "8080"}})
}
import dagger
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
def http_service(self) -> dagger.Service:
"""Start and return an HTTP service."""
return (
dag.container()
.from_("python")
.with_workdir("/srv")
.with_new_file("index.html", "Hello, world!")
.with_exposed_port(8080)
.as_service(args=["python", "-m", "http.server", "8080"])
)
import { dag, object, func, Service } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Start and return an HTTP service
*/
@func()
httpService(): Service {
return dag
.container()
.from("python")
.withWorkdir("/srv")
.withNewFile("index.html", "Hello, world!")
.withExposedPort(8080)
.asService({ args: ["python", "-m", "http.server", "8080"] })
}
}
Examples​
- Expose the HTTP service instantiated by a Dagger Function to the host on the default port:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'http-service | up'
http-service | up
dagger call http-service up
Access the service from the host:
curl localhost:8080
- Expose the HTTP service instantiated by a Dagger Function to the host on a different host port:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'http-service | up --ports 9000:8080'
http-service | up --ports 9000:8080
dagger call http-service up --ports 9000:8080
Access the service from the host:
curl localhost:9000
Expose host services to Dagger Functions​
The following Dagger Function accepts a Service
running on the host, binds it using an alias, and creates a client to access it via the service binding. This example uses a MariaDB database service running on host port 3306, aliased as db
in the Dagger Function.
This implies that a service is already listening on a port on the host, out-of-band of Dagger.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Send a query to a MariaDB service and return the response
func (m *MyModule) UserList(
ctx context.Context,
// Host service
svc *dagger.Service,
) (string, error) {
return dag.Container().
From("mariadb:10.11.2").
WithServiceBinding("db", svc).
WithExec([]string{"/usr/bin/mysql", "--user=root", "--password=secret", "--host=db", "-e", "SELECT Host, User FROM mysql.user"}).
Stdout(ctx)
}
from typing import Annotated
import dagger
from dagger import Doc, dag, function, object_type
@object_type
class MyModule:
@function
async def user_list(
self, svc: Annotated[dagger.Service, Doc("Host service")]
) -> str:
"""Send a query to a MariaDB service and return the response."""
return await (
dag.container()
.from_("mariadb:10.11.2")
.with_service_binding("db", svc)
.with_exec(
[
"/usr/bin/mysql",
"--user=root",
"--password=secret",
"--host=db",
"-e",
"SELECT Host, User FROM mysql.user",
]
)
.stdout()
)
import { dag, object, func, Service } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Send a query to a MariaDB service and return the response
*/
@func()
async userList(
/**
* Host service
*/
svc: Service,
): Promise<string> {
return await dag
.container()
.from("mariadb:10.11.2")
.withServiceBinding("db", svc)
.withExec([
"/usr/bin/mysql",
"--user=root",
"--password=secret",
"--host=db",
"-e",
"SELECT Host, User FROM mysql.user",
])
.stdout()
}
}
Example​
Send a query to the database service listening on host port 3306 and return the result as a string:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c 'user-list tcp://localhost:3306'
user-list tcp://localhost:3306
dagger call user-list --svc=tcp://localhost:3306
Use service endpoints​
The following Dagger Function starts a service manually, then retrieves its endpoint and sends a request. This example uses a NGINX HTTP service running on host port 80.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
func (m *MyModule) Get(ctx context.Context) (string, error) {
// Start NGINX service
service := dag.Container().From("nginx").WithExposedPort(80).AsService()
service, err := service.Start(ctx)
if err != nil {
return "", err
}
// Wait for service endpoint
endpoint, err := service.Endpoint(ctx, dagger.ServiceEndpointOpts{Scheme: "http", Port: 80})
if err != nil {
return "", err
}
// Send HTTP request to service endpoint
return dag.HTTP(endpoint).Contents(ctx)
}
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def get(self) -> str:
# start NGINX service
service = dag.container().from_("nginx").with_exposed_port(80).as_service()
await service.start()
# wait for service endpoint
endpoint = await service.endpoint(port=80, scheme="http")
# s end HTTP request to service endpoint
return await dag.http(endpoint).contents()
import { dag, object, func } from "@dagger.io/dagger"
@object()
export class MyModule {
@func()
async get(): Promise<string> {
// start NGINX service
let service = dag.container().from("nginx").withExposedPort(80).asService()
service = await service.start()
// wait for service to be ready
const endpoint = await service.endpoint({ port: 80, scheme: "http" })
// send HTTP request to service endpoint
return await dag.http(endpoint).contents()
}
}
Example​
Send a query to the HTTP service listening on host port 80 and return the result as a string:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c get
get
dagger call get
Create a transient service for unit tests​
The following Dagger Function creates a service and binds it to an application container for unit testing. In this example, the application being tested is Drupal. Drupal includes a large number of unit tests, including tests which depend on an active database service. This database service is created on-the-fly by the Dagger Function.
- Go
- Python
- TypeScript
package main
import (
"context"
"dagger/my-module/internal/dagger"
)
type MyModule struct{}
// Run unit tests against a database service
func (m *MyModule) Test(ctx context.Context) (string, error) {
mariadb := dag.Container().
From("mariadb:10.11.2").
WithEnvVariable("MARIADB_USER", "user").
WithEnvVariable("MARIADB_PASSWORD", "password").
WithEnvVariable("MARIADB_DATABASE", "drupal").
WithEnvVariable("MARIADB_ROOT_PASSWORD", "root").
WithExposedPort(3306).
AsService(dagger.ContainerAsServiceOpts{UseEntrypoint: true})
// get Drupal base image
// install additional dependencies
drupal := dag.Container().
From("drupal:10.0.7-php8.2-fpm").
WithExec([]string{"composer", "require", "drupal/core-dev", "--dev", "--update-with-all-dependencies"})
// add service binding for MariaDB
// run kernel tests using PHPUnit
return drupal.
WithServiceBinding("db", mariadb).
WithEnvVariable("SIMPLETEST_DB", "mysql://user:password@db/drupal").
WithEnvVariable("SYMFONY_DEPRECATIONS_HELPER", "disabled").
WithWorkdir("/opt/drupal/web/core").
WithExec([]string{"../../vendor/bin/phpunit", "-v", "--group", "KernelTests"}).
Stdout(ctx)
}
from dagger import dag, function, object_type
@object_type
class MyModule:
@function
async def test(self) -> str:
"""Run unit tests against a database service."""
# get MariaDB base image
mariadb = (
dag.container()
.from_("mariadb:10.11.2")
.with_env_variable("MARIADB_USER", "user")
.with_env_variable("MARIADB_PASSWORD", "password")
.with_env_variable("MARIADB_DATABASE", "drupal")
.with_env_variable("MARIADB_ROOT_PASSWORD", "root")
.with_exposed_port(3306)
.as_service(use_entrypoint=True)
)
# get Drupal base image
# install additional dependencies
drupal = (
dag.container()
.from_("drupal:10.0.7-php8.2-fpm")
.with_exec(
[
"composer",
"require",
"drupal/core-dev",
"--dev",
"--update-with-all-dependencies",
]
)
)
# add service binding for MariaDB
# run kernel tests using PHPUnit
return await (
drupal.with_service_binding("db", mariadb)
.with_env_variable("SIMPLETEST_DB", "mysql://user:password@db/drupal")
.with_env_variable("SYMFONY_DEPRECATIONS_HELPER", "disabled")
.with_workdir("/opt/drupal/web/core")
.with_exec(["../../vendor/bin/phpunit", "-v", "--group", "KernelTests"])
.stdout()
)
import { dag, object, func } from "@dagger.io/dagger"
@object()
class MyModule {
/**
* Run unit tests against a database service
*/
@func()
async test(): Promise<string> {
const mariadb = dag
.container()
.from("mariadb:10.11.2")
.withEnvVariable("MARIADB_USER", "user")
.withEnvVariable("MARIADB_PASSWORD", "password")
.withEnvVariable("MARIADB_DATABASE", "drupal")
.withEnvVariable("MARIADB_ROOT_PASSWORD", "root")
.withExposedPort(3306)
.asService({ useEntrypoint: true })
// get Drupal base image
// install additional dependencies
const drupal = dag
.container()
.from("drupal:10.0.7-php8.2-fpm")
.withExec([
"composer",
"require",
"drupal/core-dev",
"--dev",
"--update-with-all-dependencies",
])
// add service binding for MariaDB
// run kernel tests using PHPUnit
return await drupal
.withServiceBinding("db", mariadb)
.withEnvVariable("SIMPLETEST_DB", "mysql://user:password@db/drupal")
.withEnvVariable("SYMFONY_DEPRECATIONS_HELPER", "disabled")
.withWorkdir("/opt/drupal/web/core")
.withExec(["../../vendor/bin/phpunit", "-v", "--group", "KernelTests"])
.stdout()
}
}
Example​
Run Drupal's unit tests, instantiating a database service during the process:
- System shell
- Dagger Shell
- Dagger CLI
dagger -c test
test
dagger call test