Skip to content

Commit d2d8cf2

Browse files
authored
simplify docker build, use testcontainers and build once, do not run Promtail in CI (#1401)
* simplify docker build, use testcontainers and build once, do not run promtail in CI * changeset
1 parent 24b9149 commit d2d8cf2

File tree

7 files changed

+40
-129
lines changed

7 files changed

+40
-129
lines changed

framework/.changeset/v0.2.13.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Simplify local Chainlink build
2+
- Remove dependency on "local-registry"
3+
- Skip Promtail to accelerate CI 🚀

framework/cmd/docker.go

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import (
66
"github.com/smartcontractkit/chainlink-testing-framework/framework"
77
"os"
88
"os/exec"
9-
"strings"
109
)
1110

12-
func rmTestContainers() error {
11+
func removeTestContainers() error {
1312
framework.L.Info().Str("label", "framework=ctf").Msg("Cleaning up docker containers")
1413
// Bash command for removing Docker containers and networks with "framework=ctf" label
1514
cmd := exec.Command("bash", "-c", `
@@ -45,48 +44,6 @@ func cleanUpDockerResources() error {
4544
return nil
4645
}
4746

48-
// BuildDocker runs Docker commands to set up a local registry, build an image, and push it.
49-
func BuildDocker(dockerfile string, buildContext string, imageName string) error {
50-
registryRunning := isContainerRunning("local-registry")
51-
if registryRunning {
52-
fmt.Println("Local registry container is already running.")
53-
} else {
54-
framework.L.Info().Msg("Starting local registry container...")
55-
err := runCommand("docker", "run", "-d", "-p", "5050:5000", "--name", "local-registry", "registry:2")
56-
if err != nil {
57-
return fmt.Errorf("failed to start local registry: %w", err)
58-
}
59-
framework.L.Info().Msg("Local registry started")
60-
}
61-
62-
img := fmt.Sprintf("localhost:5050/%s:latest", imageName)
63-
framework.L.Info().Str("DockerFile", dockerfile).Str("Context", buildContext).Msg("Building Docker image")
64-
err := runCommand("docker", "build", "-t", fmt.Sprintf("localhost:5050/%s:latest", imageName), "-f", dockerfile, buildContext)
65-
if err != nil {
66-
return fmt.Errorf("failed to build Docker image: %w", err)
67-
}
68-
framework.L.Info().Msg("Docker image built successfully")
69-
70-
framework.L.Info().Str("Image", img).Msg("Pushing Docker image to local registry")
71-
fmt.Println("Pushing Docker image to local registry...")
72-
err = runCommand("docker", "push", img)
73-
if err != nil {
74-
return fmt.Errorf("failed to push Docker image: %w", err)
75-
}
76-
framework.L.Info().Msg("Docker image pushed successfully")
77-
return nil
78-
}
79-
80-
// isContainerRunning checks if a Docker container with the given name is running.
81-
func isContainerRunning(containerName string) bool {
82-
cmd := exec.Command("docker", "ps", "--filter", fmt.Sprintf("name=%s", containerName), "--format", "{{.Names}}")
83-
output, err := cmd.Output()
84-
if err != nil {
85-
return false
86-
}
87-
return strings.Contains(string(output), containerName)
88-
}
89-
9047
// runCommand executes a command and prints the output.
9148
func runCommand(name string, args ...string) error {
9249
cmd := exec.Command(name, args...)

framework/cmd/interactive.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func createComponentsFromForm(form *nodeSetForm) error {
9494
func cleanup(form *nodeSetForm) error {
9595
var err error
9696
f := func() {
97-
err = rmTestContainers()
97+
err = removeTestContainers()
9898
}
9999
err = spinner.New().
100100
Title("Removing docker resources..").

framework/cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func main() {
8080
Aliases: []string{"rm"},
8181
Usage: "Remove Docker containers and networks with 'framework=ctf' label",
8282
Action: func(c *cli.Context) error {
83-
err := rmTestContainers()
83+
err := removeTestContainers()
8484
if err != nil {
8585
return fmt.Errorf("failed to clean Docker resources: %w", err)
8686
}

framework/components/clnode/clnode.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
const (
2222
DefaultHTTPPort = "6688"
2323
DefaultP2PPort = "6690"
24+
TmpImageName = "chainlink-tmp:latest"
2425
)
2526

2627
var (
@@ -257,8 +258,8 @@ func newNode(in *Input, pgOut *postgres.Output) (*NodeOut, error) {
257258
return nil, errors.New("you provided both 'image' and one of 'docker_file', 'docker_ctx' fields. Please provide either 'image' or params to build a local one")
258259
}
259260
if req.Image == "" {
260-
req.Image, err = framework.RebuildDockerImage(once, in.Node.DockerFilePath, in.Node.DockerContext, in.Node.DockerImageName)
261-
if err != nil {
261+
req.Image = TmpImageName
262+
if err := framework.BuildImageOnce(ctx, once, in.Node.DockerContext, in.Node.DockerFilePath, req.Image); err != nil {
262263
return nil, err
263264
}
264265
req.KeepImage = false

framework/config.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,10 @@ func Load[X any](t *testing.T) (*X, error) {
142142
//}
143143
err = DefaultNetwork(once)
144144
require.NoError(t, err)
145-
err = NewPromtail()
146-
require.NoError(t, err)
145+
if os.Getenv(EnvVarCI) != "true" {
146+
err = NewPromtail()
147+
require.NoError(t, err)
148+
}
147149
return input, nil
148150
}
149151

framework/docker.go

Lines changed: 27 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"golang.org/x/sync/errgroup"
1616
"io"
1717
"os"
18-
"os/exec"
1918
"path/filepath"
2019
"strings"
2120
"sync"
@@ -70,84 +69,6 @@ func DefaultTCName(name string) string {
7069
return fmt.Sprintf("%s-%s", name, uuid.NewString()[0:5])
7170
}
7271

73-
// BuildAndPublishLocalDockerImage runs Docker commands to set up a local registry, build an image, and push it.
74-
func BuildAndPublishLocalDockerImage(once *sync.Once, dockerfile string, buildContext string, imageName string) error {
75-
var retErr error
76-
once.Do(func() {
77-
L.Info().
78-
Str("Dockerfile", dockerfile).
79-
Str("Ctx", buildContext).
80-
Str("ImageName", imageName).
81-
Msg("Building local docker file")
82-
registryRunning := isContainerRunning("local-registry")
83-
if registryRunning {
84-
fmt.Println("Local registry container is already running.")
85-
} else {
86-
L.Info().Msg("Removing local registry")
87-
_ = runCommand("docker", "stop", "local-registry")
88-
_ = runCommand("docker", "rm", "local-registry")
89-
L.Info().Msg("Starting local registry container...")
90-
err := runCommand("docker", "run", "-d", "-p", "5050:5000", "--name", "local-registry", "registry:2")
91-
if err != nil {
92-
retErr = fmt.Errorf("failed to start local registry: %w", err)
93-
}
94-
L.Info().Msg("Local registry started")
95-
}
96-
97-
img := fmt.Sprintf("localhost:5050/%s:latest", imageName)
98-
err := runCommand("docker", "build", "-t", fmt.Sprintf("localhost:5050/%s:latest", imageName), "-f", dockerfile, buildContext)
99-
if err != nil {
100-
retErr = fmt.Errorf("failed to build Docker image: %w", err)
101-
}
102-
L.Info().Msg("Docker image built successfully")
103-
104-
L.Info().Str("Image", img).Msg("Pushing Docker image to local registry")
105-
fmt.Println("Pushing Docker image to local registry...")
106-
err = runCommand("docker", "push", img)
107-
if err != nil {
108-
retErr = fmt.Errorf("failed to push Docker image: %w", err)
109-
}
110-
L.Info().Msg("Docker image pushed successfully")
111-
})
112-
return retErr
113-
}
114-
115-
// isContainerRunning checks if a Docker container with the given name is running.
116-
func isContainerRunning(containerName string) bool {
117-
cmd := exec.Command("docker", "ps", "--filter", fmt.Sprintf("name=%s", containerName), "--format", "{{.Names}}")
118-
output, err := cmd.Output()
119-
if err != nil {
120-
return false
121-
}
122-
return strings.Contains(string(output), containerName)
123-
}
124-
125-
// runCommand executes a command and prints the output.
126-
func runCommand(name string, args ...string) error {
127-
cmd := exec.Command(name, args...)
128-
cmd.Stdout = os.Stdout
129-
cmd.Stderr = os.Stderr
130-
return cmd.Run()
131-
}
132-
133-
// TODO: use tc.NewDockerProvider().BuildImage() to skip managing the registry container
134-
// RebuildDockerImage rebuilds docker image if necessary
135-
func RebuildDockerImage(once *sync.Once, dockerfile string, buildContext string, imageName string) (string, error) {
136-
if dockerfile == "" {
137-
return "", errors.New("docker_file path must be provided")
138-
}
139-
if buildContext == "" {
140-
return "", errors.New("docker_ctx path must be provided")
141-
}
142-
if imageName == "" {
143-
imageName = "ctftmp"
144-
}
145-
if err := BuildAndPublishLocalDockerImage(once, dockerfile, buildContext, imageName); err != nil {
146-
return "", err
147-
}
148-
return fmt.Sprintf("localhost:5050/%s:latest", imageName), nil
149-
}
150-
15172
// DockerClient wraps a Docker API client and provides convenience methods
15273
type DockerClient struct {
15374
cli *client.Client
@@ -320,3 +241,30 @@ func WriteAllContainersLogs() error {
320241
}
321242
return eg.Wait()
322243
}
244+
245+
func BuildImageOnce(ctx context.Context, once *sync.Once, dctx, dfile, nameAndTag string) error {
246+
var (
247+
p *tc.DockerProvider
248+
dockerCtx string
249+
err error
250+
)
251+
once.Do(func() {
252+
nt := strings.Split(nameAndTag, ":")
253+
if len(nt) != 2 {
254+
err = errors.New("BuildImageOnce, tag must be in 'repo:tag' format")
255+
return
256+
}
257+
p, err = tc.NewDockerProvider()
258+
dockerCtx, err = filepath.Abs(dctx)
259+
_, err = p.BuildImage(ctx, &tc.ContainerRequest{
260+
FromDockerfile: tc.FromDockerfile{
261+
Repo: nt[0],
262+
Tag: nt[1],
263+
Context: dockerCtx,
264+
Dockerfile: dfile,
265+
PrintBuildLog: true,
266+
},
267+
})
268+
})
269+
return err
270+
}

0 commit comments

Comments
 (0)