Skip to content

Commit

Permalink
Merge pull request #2 from drone-plugins/buildx_support
Browse files Browse the repository at this point in the history
Add buildx support
  • Loading branch information
shubham149 authored Apr 17, 2023
2 parents f6d94e4 + 33c79cb commit 78fd2a5
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 59 deletions.
35 changes: 35 additions & 0 deletions buildx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package docker

import (
"os/exec"
)

const (
defaultDriver = "docker"
dockerContainerDriver = "docker-container"
remoteDriver = "remote"
)

func cmdSetupBuildx(builder Builder) *exec.Cmd {
args := []string{"buildx", "create", "--use", "--driver", builder.Driver}
if builder.Name != "" {
args = append(args, "--name", builder.Name)
}
if builder.DriverOpts != "" {
args = append(args, "--driver-opt", builder.DriverOpts)
}
if builder.RemoteConn != "" && builder.Driver == remoteDriver {
args = append(args, builder.RemoteConn)
}
return exec.Command(dockerExe, args...)
}

func cmdInspectBuildx(name string) *exec.Cmd {
args := []string{"buildx", "inspect", "--bootstrap", "--builder", name}
return exec.Command(dockerExe, args...)
}

func cmdRemoveBuildx(name string) *exec.Cmd {
args := []string{"buildx", "rm", name}
return exec.Command(dockerExe, args...)
}
47 changes: 38 additions & 9 deletions cmd/drone-docker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,6 @@ func main() {
Usage: "docker daemon IPv6 networking",
EnvVar: "PLUGIN_IPV6",
},
cli.BoolFlag{
Name: "daemon.experimental",
Usage: "docker daemon Experimental mode",
EnvVar: "PLUGIN_EXPERIMENTAL",
},
cli.BoolFlag{
Name: "daemon.debug",
Usage: "docker daemon executes in debug mode",
Expand Down Expand Up @@ -158,10 +153,17 @@ func main() {
Usage: "build target",
EnvVar: "PLUGIN_TARGET",
},
cli.StringSliceFlag{
cli.GenericFlag{
Name: "cache-from",
Usage: "images to consider as cache sources",
Usage: "cache import location",
EnvVar: "PLUGIN_CACHE_FROM",
Value: new(docker.CustomStringSliceFlag),
},
cli.GenericFlag{
Name: "cache-to",
Usage: "cache export location",
EnvVar: "PLUGIN_CACHE_TO",
Value: new(docker.CustomStringSliceFlag),
},
cli.BoolFlag{
Name: "squash",
Expand Down Expand Up @@ -279,6 +281,26 @@ func main() {
Usage: "ssh agent key to use",
EnvVar: "PLUGIN_SSH_AGENT_KEY",
},
cli.StringFlag{
Name: "builder-name",
EnvVar: "PLUGIN_BUILDER_NAME",
},
cli.StringFlag{
Name: "builder-driver",
EnvVar: "PLUGIN_BUILDER_DRIVER",
},
cli.StringFlag{
Name: "builder-driver-opts",
EnvVar: "PLUGIN_BUILDER_DRIVER_OPTS",
},
cli.StringFlag{
Name: "builder-remote-conn",
EnvVar: "PLUGIN_BUILDER_REMOTE_CONN",
},
cli.BoolFlag{
Name: "buildx-load",
EnvVar: "PLUGIN_BUILDX_LOAD",
},
}

if err := app.Run(os.Args); err != nil {
Expand Down Expand Up @@ -309,7 +331,8 @@ func run(c *cli.Context) error {
Target: c.String("target"),
Squash: c.Bool("squash"),
Pull: c.BoolT("pull-image"),
CacheFrom: c.StringSlice("cache-from"),
CacheFrom: c.Generic("cache-from").(*docker.CustomStringSliceFlag).GetValue(),
CacheTo: c.Generic("cache-to").(*docker.CustomStringSliceFlag).GetValue(),
Compress: c.Bool("compress"),
Repo: c.String("repo"),
Labels: c.StringSlice("custom-labels"),
Expand All @@ -324,6 +347,7 @@ func run(c *cli.Context) error {
Quiet: c.Bool("quiet"),
Platform: c.String("platform"),
SSHAgentKey: c.String("ssh-agent-key"),
BuildxLoad: c.Bool("buildx-load"),
},
Daemon: docker.Daemon{
Registry: c.String("docker.registry"),
Expand All @@ -338,7 +362,12 @@ func run(c *cli.Context) error {
DNS: c.StringSlice("daemon.dns"),
DNSSearch: c.StringSlice("daemon.dns-search"),
MTU: c.String("daemon.mtu"),
Experimental: c.Bool("daemon.experimental"),
},
Builder: docker.Builder{
Name: c.String("builder-name"),
Driver: c.String("builder-driver"),
DriverOpts: c.String("builder-driver-opts"),
RemoteConn: c.String("builder-remote-conn"),
},
}

Expand Down
33 changes: 33 additions & 0 deletions custom_string_slice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package docker

import (
"strings"
)

// CustomStringSliceFlag is like a regular StringSlice flag but with
// semicolon as a delimiter
type CustomStringSliceFlag struct {
Value []string
}

func (f *CustomStringSliceFlag) GetValue() []string {
if f.Value == nil {
return make([]string, 0)
}
return f.Value
}

func (f *CustomStringSliceFlag) String() string {
if f.Value == nil {
return ""
}
return strings.Join(f.Value, ";")
}

func (f *CustomStringSliceFlag) Set(v string) error {
for _, s := range strings.Split(v, ";") {
s = strings.TrimSpace(s)
f.Value = append(f.Value, s)
}
return nil
}
4 changes: 2 additions & 2 deletions daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
"os"
)

const dockerExe = "/usr/local/bin/docker"
const dockerdExe = "/usr/local/bin/dockerd"
const dockerExe = "/usr/bin/docker"
const dockerdExe = "/usr/bin/dockerd"
const dockerHome = "/root/.docker/"

func (p Plugin) startDaemon() {
Expand Down
109 changes: 61 additions & 48 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ type (
DNSSearch []string // Docker daemon dns search domain
MTU string // Docker daemon mtu setting
IPv6 bool // Docker daemon IPv6 networking
Experimental bool // Docker daemon enable experimental mode
}

Builder struct {
Name string // Buildx builder name
Driver string // Buildx driver type
DriverOpts string // Buildx driver opts
RemoteConn string // Buildx remote connection endpoint
}

// Login defines Docker login parameters.
Expand All @@ -49,7 +55,8 @@ type (
Target string // Docker build target
Squash bool // Docker build squash
Pull bool // Docker build pull
CacheFrom []string // Docker build cache-from
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
Expand All @@ -65,16 +72,18 @@ type (
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.
Plugin struct {
Login Login // Docker login configuration
Build Build // Docker build configuration
Daemon Daemon // Docker daemon configuration
Dryrun bool // Docker push is skipped
Cleanup bool // Docker purge is enabled
CardPath string // Card path to write file to
Login Login // Docker login configuration
Build Build // Docker build configuration
Builder Builder // Docker Buildx builder configuration
Daemon Daemon // Docker daemon configuration
Dryrun bool // Docker push is skipped
Cleanup bool // Docker purge is enabled
CardPath string // Card path to write file to
}

Card []struct {
Expand Down Expand Up @@ -164,9 +173,28 @@ func (p Plugin) Exec() error {
}
}

if p.Build.Squash && !p.Daemon.Experimental {
fmt.Println("Squash build flag is only available when Docker deamon is started with experimental flag. Ignoring...")
p.Build.Squash = false
// cache export feature is currently not supported for docker driver hence we have to create docker-container driver
if len(p.Build.CacheTo) > 0 && (p.Builder.Driver == "" || p.Builder.Driver == defaultDriver) {
p.Builder.Driver = dockerContainerDriver
}

if p.Builder.Driver != "" && p.Builder.Driver != defaultDriver {
createCmd := cmdSetupBuildx(p.Builder)
raw, err := createCmd.Output()
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)
}

removeCmd := cmdRemoveBuildx(p.Builder.Name)
defer func() {
removeCmd.Run()
}()
}

// add proxy build args
Expand All @@ -176,29 +204,8 @@ func (p Plugin) Exec() error {
cmds = append(cmds, commandVersion()) // docker version
cmds = append(cmds, commandInfo()) // docker info

// pre-pull cache images
for _, img := range p.Build.CacheFrom {
cmds = append(cmds, commandPull(img))
}

// setup for using ssh agent (https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds)
if p.Build.SSHAgentKey != "" {
var sshErr error
p.Build.SSHKeyPath, sshErr = writeSSHPrivateKey(p.Build.SSHAgentKey)
if sshErr != nil {
return sshErr
}
}

cmds = append(cmds, commandBuild(p.Build)) // docker build

for _, tag := range p.Build.Tags {
cmds = append(cmds, commandTag(p.Build, tag)) // docker tag

if !p.Dryrun {
cmds = append(cmds, commandPush(p.Build, tag)) // docker push
}
}
// Command to build, tag and push
cmds = append(cmds, commandBuildx(p.Build, p.Builder, p.Dryrun)) // docker build

// execute all commands in batch mode.
for _, cmd := range cmds {
Expand All @@ -207,9 +214,7 @@ func (p Plugin) Exec() error {
trace(cmd)

err := cmd.Run()
if err != nil && isCommandPull(cmd.Args) {
fmt.Printf("Could not pull cache-from image %s. Ignoring...\n", cmd.Args[2])
} else if err != nil && isCommandPrune(cmd.Args) {
if err != nil && isCommandPrune(cmd.Args) {
fmt.Printf("Could not prune system containers. Ignoring...\n")
} else if err != nil && isCommandRmi(cmd.Args) {
fmt.Printf("Could not remove image %s. Ignoring...\n", cmd.Args[2])
Expand Down Expand Up @@ -283,15 +288,28 @@ func commandInfo() *exec.Cmd {
return exec.Command(dockerExe, "info")
}

// helper function to create the docker build command.
func commandBuild(build Build) *exec.Cmd {
// helper function to create the docker buildx command.
func commandBuildx(build Build, builder Builder, dryrun bool) *exec.Cmd {
args := []string{
"buildx",
"build",
"--rm=true",
"-f", build.Dockerfile,
"-t", build.Name,
}

if builder.Name != "" {
args = append(args, "--builder", builder.Name)
}
for _, t := range build.Tags {
args = append(args, "-t", fmt.Sprintf("%s:%s", build.Repo, t))
}
if dryrun {
if build.BuildxLoad {
args = append(args, "--load")
}
} else {
args = append(args, "--push")
}
args = append(args, build.Context)
if build.Squash {
args = append(args, "--squash")
Expand All @@ -308,6 +326,9 @@ func commandBuild(build Build) *exec.Cmd {
for _, arg := range build.CacheFrom {
args = append(args, "--cache-from", arg)
}
for _, arg := range build.CacheTo {
args = append(args, "--cache-to", arg)
}
for _, arg := range build.ArgsEnv {
addProxyValue(&build, arg)
}
Expand Down Expand Up @@ -366,11 +387,6 @@ func commandBuild(build Build) *exec.Cmd {
args = append(args, "--label", label)
}
}

// we need to enable buildkit, for secret support and ssh agent support
if build.Secret != "" || len(build.SecretEnvs) > 0 || len(build.SecretFiles) > 0 || build.SSHAgentKey != "" {
os.Setenv("DOCKER_BUILDKIT", "1")
}
return exec.Command(dockerExe, args...)
}

Expand Down Expand Up @@ -497,9 +513,6 @@ func commandDaemon(daemon Daemon) *exec.Cmd {
if len(daemon.MTU) != 0 {
args = append(args, "--mtu", daemon.MTU)
}
if daemon.Experimental {
args = append(args, "--experimental")
}
return exec.Command(dockerdExe, args...)
}

Expand Down

0 comments on commit 78fd2a5

Please sign in to comment.