Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ coverage.out
vendor
.vscode/
Dockerfile
buildkit/*.tar
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ Drone plugin uses Docker-in-Docker to build and publish Docker images to a conta

## Build

buildkit/version.json is the source of truth for the buildkit version to be used for self hosted. Please update this to use a newer buildkit version

Run the release script for buildkit

```console
sh buildkit/release.sh
```

Build the binaries with the following commands:

```console
Expand Down
70 changes: 38 additions & 32 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ func Run() {
Usage: "access token",
EnvVar: "ACCESS_TOKEN",
},
cli.BoolTFlag{
Name: "use-loaded-buildkit",
Usage: "Use preloaded buildkit image. Default is true.",
EnvVar: "PLUGIN_USE_LOADED_BUILDKIT",
},
}

if err := app.Run(os.Args); err != nil {
Expand Down Expand Up @@ -382,33 +387,33 @@ func run(c *cli.Context) error {
ArtifactFile: c.String("artifact-file"),
CacheMetricsFile: c.String("cache-metrics-file"),
Build: Build{
Remote: c.String("remote.url"),
Name: c.String("commit.sha"),
Dockerfile: c.String("dockerfile"),
Context: c.String("context"),
Tags: c.StringSlice("tags"),
Args: c.StringSlice("args"),
ArgsEnv: c.StringSlice("args-from-env"),
Target: c.String("target"),
Squash: c.Bool("squash"),
Pull: c.BoolT("pull-image"),
CacheFrom: c.Generic("cache-from").(*CustomStringSliceFlag).GetValue(),
CacheTo: c.Generic("cache-to").(*CustomStringSliceFlag).GetValue(),
Compress: c.Bool("compress"),
Repo: c.String("repo"),
Labels: c.StringSlice("custom-labels"),
LabelSchema: c.StringSlice("label-schema"),
AutoLabel: c.BoolT("auto-label"),
Link: c.String("link"),
NoCache: c.Bool("no-cache"),
Secret: c.String("secret"),
SecretEnvs: c.StringSlice("secrets-from-env"),
SecretFiles: c.StringSlice("secrets-from-file"),
AddHost: c.StringSlice("add-host"),
Quiet: c.Bool("quiet"),
Platform: c.String("platform"),
SSHAgentKey: c.String("ssh-agent-key"),
BuildxLoad: c.Bool("buildx-load"),
Remote: c.String("remote.url"),
Name: c.String("commit.sha"),
Dockerfile: c.String("dockerfile"),
Context: c.String("context"),
Tags: c.StringSlice("tags"),
Args: c.StringSlice("args"),
ArgsEnv: c.StringSlice("args-from-env"),
Target: c.String("target"),
Squash: c.Bool("squash"),
Pull: c.BoolT("pull-image"),
CacheFrom: c.Generic("cache-from").(*CustomStringSliceFlag).GetValue(),
CacheTo: c.Generic("cache-to").(*CustomStringSliceFlag).GetValue(),
Compress: c.Bool("compress"),
Repo: c.String("repo"),
Labels: c.StringSlice("custom-labels"),
LabelSchema: c.StringSlice("label-schema"),
AutoLabel: c.BoolT("auto-label"),
Link: c.String("link"),
NoCache: c.Bool("no-cache"),
Secret: c.String("secret"),
SecretEnvs: c.StringSlice("secrets-from-env"),
SecretFiles: c.StringSlice("secrets-from-file"),
AddHost: c.StringSlice("add-host"),
Quiet: c.Bool("quiet"),
Platform: c.String("platform"),
SSHAgentKey: c.String("ssh-agent-key"),
BuildxLoad: c.Bool("buildx-load"),
},
Daemon: Daemon{
Registry: c.String("docker.registry"),
Expand All @@ -427,11 +432,12 @@ func run(c *cli.Context) error {
ArtifactRegistry: c.String("artifact.registry"),
},
Builder: Builder{
Name: c.String("builder-name"),
Driver: c.String("builder-driver"),
DriverOpts: c.Generic("builder-driver-opts").(*CustomStringSliceFlag).GetValue(),
DriverOptsNew: c.Generic("builder-driver-opts-new").(*CustomStringSliceFlag).GetValue(),
RemoteConn: c.String("builder-remote-conn"),
Name: c.String("builder-name"),
Driver: c.String("builder-driver"),
DriverOpts: c.Generic("builder-driver-opts").(*CustomStringSliceFlag).GetValue(),
DriverOptsNew: c.Generic("builder-driver-opts-new").(*CustomStringSliceFlag).GetValue(),
RemoteConn: c.String("builder-remote-conn"),
UseLoadedBuildkit: c.BoolT("use-loaded-buildkit"),
},
BaseImageRegistry: c.String("docker.baseimageregistry"),
BaseImageUsername: c.String("docker.baseimageusername"),
Expand Down
8 changes: 8 additions & 0 deletions buildkit/release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

# Needs to be run before building Docker Image
buildkit_version=$(jq -r '.buildkit_version' buildkit/version.json)

docker pull ${buildkit_version}

docker save ${buildkit_version} > buildkit/buildkit.tar
3 changes: 3 additions & 0 deletions buildkit/version.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"buildkit_version": "harness/buildkit:1.0.6"
}
161 changes: 118 additions & 43 deletions docker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package docker

import (
"bytes"
"embed"
"encoding/json"
"fmt"
"os"
Expand Down Expand Up @@ -34,11 +36,12 @@ type (
}

Builder struct {
Name string // Buildx builder name
Driver string // Buildx driver type
DriverOpts []string // Buildx driver opts
DriverOptsNew []string // Buildx driver opts new
RemoteConn string // Buildx remote connection endpoint
Name string // Buildx builder name
Driver string // Buildx driver type
DriverOpts []string // Buildx driver opts
DriverOptsNew []string // Buildx driver opts new
RemoteConn string // Buildx remote connection endpoint
UseLoadedBuildkit bool
}

// Login defines Docker login parameters.
Expand All @@ -53,34 +56,34 @@ type (

// Build defines Docker build parameters.
Build struct {
Remote string // Git remote URL
Name string // Docker build using default named tag
Dockerfile string // Docker build Dockerfile
Context string // Docker build context
Tags []string // Docker build tags
Args []string // Docker build args
ArgsEnv []string // Docker build args from env
Target string // Docker build target
Squash bool // Docker build squash
Pull bool // Docker build pull
CacheFrom []string // Docker buildx cache-from
CacheTo []string // Docker buildx cache-to
Compress bool // Docker build compress
Repo string // Docker build repository
LabelSchema []string // label-schema Label map
AutoLabel bool // auto-label bool
Labels []string // Label map
Link string // Git repo link
NoCache bool // Docker build no-cache
Secret string // secret keypair
SecretEnvs []string // Docker build secrets with env var as source
SecretFiles []string // Docker build secrets with file as source
AddHost []string // Docker build add-host
Quiet bool // Docker build quiet
Platform string // Docker build platform
SSHAgentKey string // Docker build ssh agent key
SSHKeyPath string // Docker build ssh key path
BuildxLoad bool // Docker buildx --load
Remote string // Git remote URL
Name string // Docker build using default named tag
Dockerfile string // Docker build Dockerfile
Context string // Docker build context
Tags []string // Docker build tags
Args []string // Docker build args
ArgsEnv []string // Docker build args from env
Target string // Docker build target
Squash bool // Docker build squash
Pull bool // Docker build pull
CacheFrom []string // Docker buildx cache-from
CacheTo []string // Docker buildx cache-to
Compress bool // Docker build compress
Repo string // Docker build repository
LabelSchema []string // label-schema Label map
AutoLabel bool // auto-label bool
Labels []string // Label map
Link string // Git repo link
NoCache bool // Docker build no-cache
Secret string // secret keypair
SecretEnvs []string // Docker build secrets with env var as source
SecretFiles []string // Docker build secrets with file as source
AddHost []string // Docker build add-host
Quiet bool // Docker build quiet
Platform string // Docker build platform
SSHAgentKey string // Docker build ssh agent key
SSHKeyPath string // Docker build ssh key path
BuildxLoad bool // Docker buildx --load
}

// Plugin defines the Docker plugin parameters.
Expand Down Expand Up @@ -126,16 +129,25 @@ type (
TagStruct struct {
Tag string `json:"Tag"`
}

BuildKitConfig struct {
BuildkitVersion string `json:"buildkit_version"`
}
)

//go:embed buildkit/buildkit.tar
var buildkitTarball embed.FS

//go:embed buildkit/version.json
var buildKitVersionFile embed.FS

// Exec executes the plugin step
func (p Plugin) Exec() error {

// start the Docker daemon server
if !p.Daemon.Disabled {
p.startDaemon()
}

// poll the docker daemon until it is started. This ensures the daemon is
// ready to accept connections before we proceed.
for i := 0; ; i++ {
Expand Down Expand Up @@ -228,19 +240,78 @@ func (p Plugin) Exec() error {
p.Builder.Driver = dockerContainerDriver
}

loadedBuildkitVersion := true
loadedBuildkitTarball := true
var config BuildKitConfig

if p.Builder.UseLoadedBuildkit {
configData, err := buildKitVersionFile.ReadFile("buildkit/version.json")
if err != nil {
fmt.Printf("Failed to read embedded buildkit version.json: %v", err)
loadedBuildkitVersion = false
}

if err := json.Unmarshal(configData, &config); err != nil {
fmt.Printf("Failed to buildkit version.json: %v", err)
loadedBuildkitVersion = false
}

// Read the tarball from the embedded filesystem
data, err := buildkitTarball.ReadFile("buildkit/buildkit.tar")
if err != nil {
fmt.Printf("Failed to load buildkit tarball: %v", err)
loadedBuildkitTarball = false
}

loadCmd := commandLoad()
loadCmd.Stdin = bytes.NewReader(data)
if loadedBuildkitTarball {
if err := loadCmd.Run(); err != nil {
fmt.Printf("error while loading buildkit image: %s", err)
loadedBuildkitTarball = false
}
}
} else {
loadedBuildkitVersion = false
loadedBuildkitTarball = false
}

if p.Builder.Driver != "" && p.Builder.Driver != defaultDriver {
var (
raw []byte
err error
)

// Replace the image in driver opts with the buildkit version
if p.Builder.UseLoadedBuildkit && loadedBuildkitTarball && loadedBuildkitVersion {
fmt.Printf("Using BuildKit Version: %s\n", config.BuildkitVersion)
for i, opt := range p.Builder.DriverOpts {
if strings.HasPrefix(opt, "image=") {
// Replace the part after image= with config.BuildkitVersion
p.Builder.DriverOpts[i] = fmt.Sprintf("image=%s", config.BuildkitVersion)
}
}
}

shouldFallback := true
if len(p.Builder.DriverOptsNew) != 0 {
createCmd := cmdSetupBuildx(p.Builder, p.Builder.DriverOptsNew)
raw, err = createCmd.Output()
if err == nil {
shouldFallback = false
} else {
if err != nil {
fmt.Printf("Unable to setup buildx with new driver opts: %s\n", err)
// Mark that the fallback will be used
shouldFallback = true
} else {
p.Builder.Name = strings.TrimSuffix(string(raw), "\n")
// If builder creation is successful, inspect the builder
inspectCmd := cmdInspectBuildx(p.Builder.Name)
if err := inspectCmd.Run(); err != nil {
fmt.Printf("Error while inspecting buildx builder with new driver opts: %s\n", err)
// Mark that the fallback will be used
shouldFallback = true
} else {
shouldFallback = false
}
}
}
if shouldFallback {
Expand All @@ -249,12 +320,11 @@ func (p Plugin) Exec() error {
if err != nil {
return fmt.Errorf("error while creating buildx builder: %s and err: %s", string(raw), err)
}
}
p.Builder.Name = strings.TrimSuffix(string(raw), "\n")

inspectCmd := cmdInspectBuildx(p.Builder.Name)
if err := inspectCmd.Run(); err != nil {
return fmt.Errorf("error while bootstraping buildx builder: %s", err)
p.Builder.Name = strings.TrimSuffix(string(raw), "\n")
inspectCmd := cmdInspectBuildx(p.Builder.Name)
if err := inspectCmd.Run(); err != nil {
return fmt.Errorf("error while bootstraping buildx builder: %s", err)
}
}

removeCmd := cmdRemoveBuildx(p.Builder.Name)
Expand All @@ -267,6 +337,7 @@ func (p Plugin) Exec() error {
addProxyBuildArgs(&p.Build)

var cmds []*exec.Cmd

cmds = append(cmds, commandVersion()) // docker version
cmds = append(cmds, commandInfo()) // docker info

Expand Down Expand Up @@ -719,6 +790,10 @@ func commandRmi(tag string) *exec.Cmd {
return exec.Command(dockerExe, "rmi", tag)
}

func commandLoad() *exec.Cmd {
return exec.Command(dockerExe, "image", "load")
}

func writeSSHPrivateKey(key string) (path string, err error) {
home, err := os.UserHomeDir()
if err != nil {
Expand Down