Skip to content

Commit 9022292

Browse files
committed
feat: add depot build example with custom registry auth
Signed-off-by: Chris Goller <[email protected]>
1 parent a5a6754 commit 9022292

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed

examples/custom-auth/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FROM alpine:latest
2+
RUN echo howdy

examples/custom-auth/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Build with Depot using custom registry authentication
2+
3+
This extends the simple example to use custom authentication for the registry. This is useful when you want to push images to a private registry that requires authentication.

examples/custom-auth/main.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"time"
10+
11+
"github.com/depot/depot-go/build"
12+
"github.com/depot/depot-go/machine"
13+
cliv1 "github.com/depot/depot-go/proto/depot/cli/v1"
14+
"github.com/moby/buildkit/client"
15+
"github.com/moby/buildkit/session"
16+
"github.com/moby/buildkit/session/auth"
17+
"google.golang.org/grpc"
18+
"google.golang.org/grpc/codes"
19+
"google.golang.org/grpc/status"
20+
)
21+
22+
func main() {
23+
// You can use a context with timeout to cancel the build if you would like.
24+
ctx := context.Background()
25+
26+
// Set these environment variables...
27+
token := os.Getenv("DEPOT_TOKEN")
28+
project := os.Getenv("DEPOT_PROJECT_ID")
29+
30+
// ... and set these variables.
31+
dockerfilePath := "./Dockerfile"
32+
workingDir := "."
33+
imageTag := "AWS_ACCOUNT_ID_HERE.dkr.ecr.us-east-1.amazonaws.com/REPO_HERE:TAG_HERE"
34+
35+
// 1. Register a new build. This returns back an id and a temporary build token.
36+
req := &cliv1.CreateBuildRequest{
37+
ProjectId: project,
38+
}
39+
build, err := build.NewBuild(ctx, req, token)
40+
if err != nil {
41+
log.Fatal(err)
42+
}
43+
44+
// Set the buildErr to any error that represents the build failing.
45+
var buildErr error
46+
defer build.Finish(buildErr)
47+
48+
// 2. Acquire a buildkit machine.
49+
var buildkit *machine.Machine
50+
buildkit, buildErr = machine.Acquire(ctx, build.ID, build.Token, "arm64" /* or "amd64" */)
51+
if buildErr != nil {
52+
return
53+
}
54+
defer buildkit.Release()
55+
56+
connectCtx, cancelConnect := context.WithTimeout(ctx, 5*time.Minute)
57+
defer cancelConnect()
58+
59+
var buildkitClient *client.Client
60+
buildkitClient, buildErr = buildkit.Connect(connectCtx)
61+
if buildErr != nil {
62+
return
63+
}
64+
65+
solverOptions := client.SolveOpt{
66+
Frontend: "dockerfile.v0", // Interpret the build as a Dockerfile.
67+
FrontendAttrs: map[string]string{
68+
"filename": filepath.Base(dockerfilePath),
69+
"platform": "linux/arm64", // Build for arm64 architecture.
70+
},
71+
LocalDirs: map[string]string{
72+
"dockerfile": filepath.Dir(dockerfilePath),
73+
"context": workingDir,
74+
},
75+
Exports: []client.ExportEntry{
76+
{
77+
Type: "image",
78+
Attrs: map[string]string{
79+
"oci-mediatypes": "true",
80+
"push": "true", // Push the image to the registry...
81+
"name": imageTag, // ... with this tag.
82+
},
83+
},
84+
},
85+
Session: []session.Attachable{
86+
&EnvAuth{},
87+
},
88+
}
89+
90+
// 3. Print all build status updates as JSON to stdout.
91+
buildStatusCh := make(chan *client.SolveStatus, 10)
92+
go func() {
93+
enc := json.NewEncoder(os.Stdout)
94+
enc.SetIndent("", " ")
95+
for status := range buildStatusCh {
96+
_ = enc.Encode(status)
97+
}
98+
}()
99+
100+
// 4. Build and push the image.
101+
_, buildErr = buildkitClient.Solve(ctx, nil, solverOptions, buildStatusCh)
102+
if buildErr != nil {
103+
return
104+
}
105+
}
106+
107+
// EnvAuth is a custom auth provider that uses environment variables to provide registry credentials.
108+
// Uses REGISTRY_USERNAME and REGISTRY_TOKEN environment variables.
109+
type EnvAuth struct{}
110+
111+
// In BuildKit an Attachable is a client-side gRPC server that the build server can connect to.
112+
// BuildKit tunnels gRPC over gRPC, so the client-side can be dialed by the server-side.
113+
var _ session.Attachable = (*EnvAuth)(nil)
114+
115+
// Register hosts an AuthServer on the client-side for the build server.
116+
func (ap *EnvAuth) Register(server *grpc.Server) {
117+
auth.RegisterAuthServer(server, ap)
118+
}
119+
120+
// AuthServer is not documented in BuildKit, but these are functions called by the build server.
121+
var _ auth.AuthServer = (*EnvAuth)(nil)
122+
123+
// For AWS ECR username is `AWS` and for password run `aws ecr get-login-password --region YOUR_REGION`.
124+
func (ap *EnvAuth) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) {
125+
// If base image is at docker return empty creds to use public download.
126+
if req.Host == "registry-1.docker.io" {
127+
return &auth.CredentialsResponse{}, nil
128+
}
129+
130+
username := os.Getenv("REGISTRY_USERNAME")
131+
registryPassword := os.Getenv("REGISTRY_PASSWORD")
132+
133+
return &auth.CredentialsResponse{
134+
Username: username,
135+
Secret: registryPassword,
136+
}, nil
137+
}
138+
139+
// GetTokenAuthority needs to return an Unimplemented or a nil public key in order for the Credentials function to be called.
140+
func (ap *EnvAuth) GetTokenAuthority(ctx context.Context, req *auth.GetTokenAuthorityRequest) (*auth.GetTokenAuthorityResponse, error) {
141+
return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
142+
}
143+
144+
func (ap *EnvAuth) VerifyTokenAuthority(ctx context.Context, req *auth.VerifyTokenAuthorityRequest) (*auth.VerifyTokenAuthorityResponse, error) {
145+
return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
146+
}
147+
148+
func (ap *EnvAuth) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (rr *auth.FetchTokenResponse, err error) {
149+
return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
150+
}

examples/simple/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
## Simple Build with Depot
22

33
This example shows how to build and push an image with Depot.
4+
5+
See the [blog](https://depot.dev/blog/go-code-to-container-depot-api) for more details.

0 commit comments

Comments
 (0)