Last active
March 9, 2023 18:04
-
-
Save vito/c9374b3452262fdb38baf85764ede9fe to your computer and use it in GitHub Desktop.
2023-03-09 Dagger community call Services demos
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"log" | |
"os" | |
"dagger.io/dagger" | |
) | |
func main() { | |
ctx := context.Background() | |
c, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr)) | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer c.Close() | |
web, worker := concourse(c.Pipeline("concourse")) | |
tests := c.Pipeline("smoke tests") | |
concSrc := tests.Git("https://github.com/concourse/concourse"). | |
Branch("master"). | |
Tree() | |
smoke := tests. | |
Container(). | |
From("concourse/unit"). | |
WithMountedDirectory("/src", concSrc). | |
WithWorkdir("/src"). | |
WithExec([]string{"go", "install", "./fly"}). | |
WithWorkdir("/src/web/wats"). | |
WithServiceBinding("web", web). | |
WithServiceBinding("worker", worker). | |
WithEnvVariable("ATC_URL", "http://web:8080"). | |
WithExec([]string{"yarn", "install"}). | |
WithExec([]string{"yarn", "test", "-v", "--color", "test/smoke.js"}) | |
_, err = smoke.ExitCode(ctx) | |
if err != nil { | |
log.Fatal(err) | |
} | |
} | |
func concourse(c *dagger.Client) (web *dagger.Container, worker *dagger.Container) { | |
db := c.Pipeline("db"). | |
Container(). | |
From("postgres"). | |
WithEnvVariable("POSTGRES_DB", "concourse"). | |
WithEnvVariable("POSTGRES_USER", "dev"). | |
WithEnvVariable("POSTGRES_PASSWORD", "dev"). | |
WithExposedPort(5432). | |
WithExec(nil) | |
conc := c.Container(). | |
From("concourse/concourse") | |
keys := conc.Pipeline("keygen"). | |
WithWorkdir("/keys"). | |
WithExec([]string{"generate-key", "-t", "rsa", "-f", "./session_signing_key"}). | |
WithExec([]string{"generate-key", "-t", "ssh", "-f", "./tsa_host_key"}). | |
WithExec([]string{"generate-key", "-t", "ssh", "-f", "./worker_key"}). | |
Directory(".") | |
web = conc.Pipeline("web"). | |
WithMountedFile("/concourse-keys/session_signing_key", keys.File("session_signing_key")). | |
WithMountedFile("/concourse-keys/authorized_worker_keys", keys.File("worker_key.pub")). | |
WithMountedFile("/concourse-keys/tsa_host_key", keys.File("tsa_host_key")). | |
WithEnvVariable("CONCOURSE_SESSION_SIGNING_KEY", "/concourse-keys/session_signing_key"). | |
WithEnvVariable("CONCOURSE_TSA_AUTHORIZED_KEYS", "/concourse-keys/authorized_worker_keys"). | |
WithEnvVariable("CONCOURSE_TSA_HOST_KEY", "/concourse-keys/tsa_host_key"). | |
WithEnvVariable("CONCOURSE_POSTGRES_HOST", "db"). | |
WithEnvVariable("CONCOURSE_POSTGRES_USER", "dev"). | |
WithEnvVariable("CONCOURSE_POSTGRES_PASSWORD", "dev"). | |
WithEnvVariable("CONCOURSE_POSTGRES_DATABASE", "concourse"). | |
WithEnvVariable("CONCOURSE_EXTERNAL_URL", "http://web:8080"). | |
WithEnvVariable("CONCOURSE_ADD_LOCAL_USER", "test:test,guest:guest"). | |
WithEnvVariable("CONCOURSE_MAIN_TEAM_LOCAL_USER", "test"). | |
WithEnvVariable("CONCOURSE_CLUSTER_NAME", "dev"). | |
WithServiceBinding("db", db). | |
WithExposedPort(8080). | |
WithExec([]string{"web"}) | |
worker = conc.Pipeline("worker"). | |
WithMountedFile("/concourse-keys/worker_key", keys.File("worker_key")). | |
WithMountedFile("/concourse-keys/tsa_host_key.pub", keys.File("tsa_host_key.pub")). | |
WithEnvVariable("CONCOURSE_RUNTIME", "containerd"). | |
WithEnvVariable("CONCOURSE_TSA_PUBLIC_KEY", "/concourse-keys/tsa_host_key.pub"). | |
WithEnvVariable("CONCOURSE_TSA_WORKER_PRIVATE_KEY", "/concourse-keys/worker_key"). | |
WithEnvVariable("CONCOURSE_TSA_HOST", "web:2222"). | |
WithEnvVariable("CONCOURSE_BIND_IP", "0.0.0.0"). | |
WithEnvVariable("CONCOURSE_BAGGAGECLAIM_BIND_IP", "0.0.0.0"). | |
WithEnvVariable("CONCOURSE_BAGGAGECLAIM_DRIVER", "overlay"). | |
WithEnvVariable("CONCOURSE_CONTAINERD_DNS_SERVER", "1.1.1.1,8.8.8.8"). | |
WithServiceBinding("web", web). | |
WithExposedPort(7777). | |
WithExposedPort(7788). | |
WithMountedCache("/worker-state", c.CacheVolume("concourse-worker")). | |
WithExec([]string{"worker"}, dagger.ContainerWithExecOpts{ | |
InsecureRootCapabilities: true, | |
}) | |
return | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"os" | |
"sort" | |
"strconv" | |
"dagger.io/dagger" | |
"github.com/compose-spec/compose-go/cli" | |
"github.com/compose-spec/compose-go/types" | |
"golang.org/x/sync/errgroup" | |
) | |
func main() { | |
ctx := context.Background() | |
opts, err := cli.NewProjectOptions(os.Args[1:], | |
cli.WithWorkingDirectory("."), | |
cli.WithDefaultConfigPath, | |
cli.WithOsEnv, | |
cli.WithConfigFileEnv, | |
) | |
if err != nil { | |
panic(err) | |
} | |
project, err := cli.ProjectFromOptions(opts) | |
if err != nil { | |
panic(err) | |
} | |
c, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr)) | |
if err != nil { | |
panic(err) | |
} | |
defer c.Close() | |
eg, ctx := errgroup.WithContext(ctx) | |
for _, svc := range project.Services { | |
ctr, err := serviceContainer(c, project, svc) | |
if err != nil { | |
panic(err) | |
} | |
eg.Go(func() error { | |
return ctr.Run(ctx) | |
}) | |
} | |
err = eg.Wait() | |
if err != nil { | |
panic(err) | |
} | |
} | |
func serviceContainer(c *dagger.Client, project *types.Project, svc types.ServiceConfig) (*dagger.Container, error) { | |
ctr := c.Pipeline(svc.Name).Container() | |
if svc.Image != "" { | |
ctr = ctr.From(svc.Image) | |
} else if svc.Build != nil { | |
args := []dagger.BuildArg{} | |
for name, val := range svc.Build.Args { | |
if val != nil { | |
args = append(args, dagger.BuildArg{ | |
Name: name, | |
Value: *val, | |
}) | |
} | |
} | |
ctr = ctr.Build(c.Host().Directory(svc.Build.Context), dagger.ContainerBuildOpts{ | |
Dockerfile: svc.Build.Dockerfile, | |
BuildArgs: args, | |
Target: svc.Build.Target, | |
}) | |
} | |
// sort env to ensure same container | |
type env struct{ name, value string } | |
envs := []env{} | |
for name, val := range svc.Environment { | |
if val != nil { | |
envs = append(envs, env{name, *val}) | |
} | |
} | |
sort.Slice(envs, func(i, j int) bool { | |
return envs[i].name < envs[j].name | |
}) | |
for _, env := range envs { | |
ctr = ctr.WithEnvVariable(env.name, env.value) | |
} | |
for _, port := range svc.Ports { | |
switch port.Mode { | |
case "ingress": | |
publishedPort, err := strconv.Atoi(port.Published) | |
if err != nil { | |
return nil, err | |
} | |
ctr = ctr.WithExposedPort(int(port.Target), dagger.ContainerWithExposedPortOpts{ | |
// NB: totally made up non-final API, proof-of-concept only | |
Publish: publishedPort, | |
}) | |
default: | |
return nil, fmt.Errorf("port mode %s not supported", port.Mode) | |
} | |
} | |
for _, expose := range svc.Expose { | |
port, err := strconv.Atoi(expose) | |
if err != nil { | |
return nil, err | |
} | |
ctr = ctr.WithExposedPort(port) | |
} | |
for _, vol := range svc.Volumes { | |
switch vol.Type { | |
case types.VolumeTypeBind: | |
ctr = ctr.WithMountedDirectory(vol.Target, c.Host().Directory(vol.Source)) | |
case types.VolumeTypeVolume: | |
ctr = ctr.WithMountedCache(vol.Target, c.CacheVolume(vol.Source)) | |
default: | |
return nil, fmt.Errorf("volume type %s not supported", vol.Type) | |
} | |
} | |
for depName := range svc.DependsOn { | |
cfg, err := project.GetService(depName) | |
if err != nil { | |
return nil, err | |
} | |
svcCtr, err := serviceContainer(c, project, cfg) | |
if err != nil { | |
return nil, err | |
} | |
ctr = ctr.WithServiceBinding(depName, svcCtr) | |
} | |
var opts dagger.ContainerWithExecOpts | |
if svc.Privileged { | |
opts.InsecureRootCapabilities = true | |
} | |
ctr = ctr.WithExec(svc.Command, opts) | |
return ctr, nil | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"os" | |
"time" | |
"dagger.io/dagger" | |
) | |
func main() { | |
ctx := context.Background() | |
if len(os.Args) < 3 { | |
fatal(fmt.Errorf("usage: %s <dbname> <command ...>", os.Args[0])) | |
return | |
} | |
dbName := os.Args[1] | |
cmd := os.Args[2:] | |
client, err := dagger.Connect(ctx) | |
if err != nil { | |
fatal(err) | |
return | |
} | |
defer client.Close() | |
redis := client.Container().From("redis") | |
// a redis service with a persistent cache | |
redisSrv := redis. | |
WithExposedPort(6379). | |
WithMountedCache("/data", client.CacheVolume(dbName)). | |
WithWorkdir("/data"). | |
WithExec(nil) | |
// a redis-cli container that runs against the service | |
redisCLI := redis. | |
WithServiceBinding("redis", redisSrv). | |
WithEntrypoint([]string{"redis-cli", "-h", "redis"}) | |
// the user's command, which we avoid caching via an env var | |
redisCmd := redisCLI. | |
WithEnvVariable("AT", time.Now().String()). | |
WithExec(cmd) | |
// first run the command and immediately save | |
_, err = redisCmd.WithExec([]string{"save"}).ExitCode(ctx) | |
if err != nil { | |
fatal(err) | |
return | |
} | |
// then print the output of the (cached) command | |
out, err := redisCmd.Stdout(ctx) | |
if err != nil { | |
fatal(err) | |
return | |
} | |
fmt.Print(out) | |
} | |
func fatal(err error) { | |
fmt.Fprintf(os.Stderr, "error: %s\n", err) | |
os.Exit(1) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment