fix(buildkitd): Start the daemon if it is not active
Add a method that will retrieve the version, the running state and the network host existence of the buildkitd container. If the version is outdated or there is no host network, we delete the container and install a proper one. If the container is correctly configured but is not active, we start it, which saves some time. Signed-off-by: Lucas Perreau <lucas.perreau@ext.adeo.com>
This commit is contained in:
parent
fd27d3d980
commit
4107f9a875
62
util/buildkitd/buildkit_information.go
Normal file
62
util/buildkitd/buildkit_information.go
Normal file
@ -0,0 +1,62 @@
|
||||
package buildkitd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
func getBuildkitInformation(ctx context.Context) (*BuilkitInformation, error) {
|
||||
formatString := "{{.Config.Image}};{{.State.Running}};{{ if index .NetworkSettings.Networks \"host\" }}{{ \"true\" }}{{else}}{{\"false\"}}{{end}}"
|
||||
cmd := exec.CommandContext(ctx,
|
||||
"docker",
|
||||
"inspect",
|
||||
"--format",
|
||||
formatString,
|
||||
containerName,
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := strings.Split(string(output), ";")
|
||||
|
||||
// Retrieve the tag
|
||||
ref, err := reference.ParseNormalizedNamed(strings.TrimSpace(s[0]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tag, ok := ref.(reference.Tagged)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to parse image: %s", output)
|
||||
}
|
||||
|
||||
// Retrieve the state
|
||||
isActive, err := strconv.ParseBool(strings.TrimSpace(s[1]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Retrieve the check on if the host network is configured
|
||||
haveHostNetwork, err := strconv.ParseBool(strings.TrimSpace(s[2]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BuilkitInformation{
|
||||
Version: tag.Tag(),
|
||||
IsActive: isActive,
|
||||
HaveHostNetwork: haveHostNetwork,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type BuilkitInformation struct {
|
||||
Version string
|
||||
IsActive bool
|
||||
HaveHostNetwork bool
|
||||
}
|
@ -9,7 +9,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
bk "github.com/moby/buildkit/client"
|
||||
_ "github.com/moby/buildkit/client/connhelper/dockercontainer" // import the container connection driver
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -41,48 +40,73 @@ func init() {
|
||||
}
|
||||
|
||||
func Start(ctx context.Context) (string, error) {
|
||||
lg := log.Ctx(ctx)
|
||||
|
||||
if vendoredVersion == "" {
|
||||
return "", fmt.Errorf("vendored version is empty")
|
||||
}
|
||||
|
||||
// Attempt to detect the current buildkit version
|
||||
currentVersion, err := getBuildkitVersion(ctx)
|
||||
if err != nil {
|
||||
// If that failed, it might either be because buildkitd is not running
|
||||
// or because the docker CLI is out of service.
|
||||
if err := checkDocker(ctx); err != nil {
|
||||
if err := checkBuildkit(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
currentVersion = ""
|
||||
lg.Debug().Msg("no buildkit daemon detected")
|
||||
} else {
|
||||
lg.Debug().Str("version", currentVersion).Msg("detected buildkit version")
|
||||
return fmt.Sprintf("docker-container://%s", containerName), nil
|
||||
}
|
||||
|
||||
// ensure the buildkit is active and properly set up (e.g. connected to host and last version with moby/buildkit)
|
||||
func checkBuildkit(ctx context.Context) error {
|
||||
lg := log.Ctx(ctx)
|
||||
|
||||
config, err := getBuildkitInformation(ctx)
|
||||
if err != nil {
|
||||
// If that failed, it might be because the docker CLI is out of service.
|
||||
if err := checkDocker(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if currentVersion != vendoredVersion {
|
||||
if currentVersion != "" {
|
||||
lg.Debug().Msg("no buildkit daemon detected")
|
||||
|
||||
if err := removeBuildkit(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := installBuildkit(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
lg.
|
||||
Debug().
|
||||
Str("version", config.Version).
|
||||
Bool("isActive", config.IsActive).
|
||||
Bool("haveHostNetwork", config.HaveHostNetwork).
|
||||
Msg("detected buildkit config")
|
||||
|
||||
if config.Version != vendoredVersion || !config.HaveHostNetwork {
|
||||
lg.
|
||||
Info().
|
||||
Str("version", vendoredVersion).
|
||||
Bool("have host network", config.HaveHostNetwork).
|
||||
Msg("upgrading buildkit")
|
||||
|
||||
if err := removeBuildkit(ctx); err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := installBuildkit(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !config.IsActive {
|
||||
lg.
|
||||
Info().
|
||||
Str("version", vendoredVersion).
|
||||
Msg("starting buildkit")
|
||||
}
|
||||
|
||||
if err := startBuildkit(ctx); err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("docker-container://%s", containerName), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensure the docker CLI is available and properly set up (e.g. permissions to
|
||||
@ -103,6 +127,7 @@ func checkDocker(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start the buildkit daemon
|
||||
func startBuildkit(ctx context.Context) error {
|
||||
lg := log.
|
||||
Ctx(ctx).
|
||||
@ -110,6 +135,35 @@ func startBuildkit(ctx context.Context) error {
|
||||
Str("version", vendoredVersion).
|
||||
Logger()
|
||||
|
||||
lg.Debug().Msg("starting buildkit image")
|
||||
|
||||
cmd := exec.CommandContext(ctx,
|
||||
"docker",
|
||||
"start",
|
||||
containerName,
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
lg.
|
||||
Error().
|
||||
Err(err).
|
||||
Bytes("output", output).
|
||||
Msg("failed to start buildkit container")
|
||||
return err
|
||||
}
|
||||
|
||||
return waitBuildkit(ctx)
|
||||
}
|
||||
|
||||
// Pull and run the buildkit daemon with a proper configuration
|
||||
// If the buildkit daemon is already configured, use startBuildkit
|
||||
func installBuildkit(ctx context.Context) error {
|
||||
lg := log.
|
||||
Ctx(ctx).
|
||||
With().
|
||||
Str("version", vendoredVersion).
|
||||
Logger()
|
||||
|
||||
lg.Debug().Msg("pulling buildkit image")
|
||||
// #nosec
|
||||
cmd := exec.CommandContext(ctx,
|
||||
@ -167,6 +221,8 @@ func waitBuildkit(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME Does output "failed to wait: signal: broken pipe"
|
||||
defer c.Close()
|
||||
|
||||
// Try to connect every 100ms up to 100 times (10 seconds total)
|
||||
@ -207,26 +263,3 @@ func removeBuildkit(ctx context.Context) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBuildkitVersion(ctx context.Context) (string, error) {
|
||||
cmd := exec.CommandContext(ctx,
|
||||
"docker",
|
||||
"inspect",
|
||||
"--format",
|
||||
"{{.Config.Image}}",
|
||||
containerName,
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ref, err := reference.ParseNormalizedNamed(strings.TrimSpace(string(output)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tag, ok := ref.(reference.Tagged)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("failed to parse image: %s", output)
|
||||
}
|
||||
return tag.Tag(), nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user