Skip to content

Commit

Permalink
Added support for BuildX (#528)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanhartkopf authored Apr 7, 2022
1 parent c8af4b2 commit 64c9e45
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 7 deletions.
14 changes: 13 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@
version: 2.1
jobs:
build:
machine: { docker_layer_caching: true }
machine:
docker_layer_caching: true
image: ubuntu-2004:202104-01
environment:
CIRCLE_TEST_REPORTS: /home/circleci/junit
CIRCLE_ARTIFACTS: /home/circleci/artifacts
_JAVA_OPTIONS: -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Xmx8192m
DOCKER_BUILDKIT: 1
BUILDX_PLATFORMS: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6
steps:
- checkout
- run:
name: Install buildx
command: |
export DOCKER_BUILDKIT=1
docker build --platform=local -o . "https://github.com/docker/buildx.git"
mkdir -p ~/.docker/cli-plugins
mv buildx ~/.docker/cli-plugins/docker-buildx
docker buildx create --name mybuilder --use
- run:
name: delete_unrelated_tags
command: |
Expand Down
6 changes: 6 additions & 0 deletions changelog/@unreleased/pr-528.v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type: improvement
improvement:
description: Add ability to do multi platform docker builds using buildx
links:
- https://github.com/palantir/gradle-docker/pull/528
- https://github.com/palantir/gradle-docker/issues/353
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ build/
a newer version of the base image before building; defaults to `false`
- `noCache` (optional) a boolean argument which defines whether Docker build should add the option --no-cache,
so that it rebuilds the whole image from scratch; defaults to `false`
- `buildx` (optional) a boolean argument which defines whether Docker build should use buildx for cross platform builds; defaults to `false`
- `platform` (optional) a list of strings argument which defines which platforms buildx should target; defaults to empty
- `builder` (optional) a string argument which defines which builder buildx should use; defaults to `null`
- `load` (optional) a boolean argument which defines whether Docker buildx builder should add --load flag,
loading the image into the local repository; defaults to `false`

To build a docker container, run the `docker` task. To push that container to a
docker repository, run the `dockerPush` task.
Expand Down
36 changes: 36 additions & 0 deletions src/main/groovy/com/palantir/gradle/docker/DockerExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class DockerExtension {
private boolean pull = false
private boolean noCache = false
private String network = null
private boolean buildx = false
private Set<String> platform = ImmutableSet.of()
private boolean load = false
private String builder = null

private File resolvedDockerfile = null
private File resolvedDockerComposeTemplate = null
Expand Down Expand Up @@ -175,4 +179,36 @@ class DockerExtension {
public void noCache(boolean noCache) {
this.noCache = noCache
}

public boolean getLoad() {
return pull
}

public void load(boolean pull) {
this.pull = pull
}

boolean getBuildx() {
return buildx
}

public void buildx(boolean buildx) {
this.buildx = buildx
}

public Set<String> getPlatform() {
return platform
}

public void platform(String... args) {
this.platform = ImmutableSet.copyOf(args)
}

String getBuilder() {
return builder
}

public void builder(String builder) {
this.builder = builder
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,21 @@ class PalantirDockerPlugin implements Plugin<Project> {
}

private List<String> buildCommandLine(DockerExtension ext) {
List<String> buildCommandLine = ['docker', 'build']
List<String> buildCommandLine = ['docker']
if (ext.buildx) {
buildCommandLine.addAll(['buildx', 'build'])
if (!ext.platform.isEmpty()) {
buildCommandLine.addAll('--platform', String.join(',', ext.platform))
}
if (ext.load) {
buildCommandLine.add '--load'
}
if (ext.builder != null) {
buildCommandLine.addAll('--builder', ext.builder)
}
} else {
buildCommandLine.add 'build'
}
if (ext.noCache) {
buildCommandLine.add '--no-cache'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ class DockerComposePluginTests extends AbstractPluginTest {
with('dockerComposeUp').build()
then:
file("foobarbaz").exists()
execCond("docker stop helloworld")
execCond("docker rm helloworld")
}

def 'docker-compose successfully creates docker image from custom file'() {
Expand Down Expand Up @@ -200,6 +202,8 @@ class DockerComposePluginTests extends AbstractPluginTest {
with('dockerComposeUp').build()
then:
file("qux").exists()
execCond("docker stop helloworld2")
execCond("docker rm helloworld2")
}

def 'can set custom properties on generateDockerCompose.ext'() {
Expand Down Expand Up @@ -236,10 +240,9 @@ class DockerComposePluginTests extends AbstractPluginTest {
id 'com.palantir.docker-compose'
}
'''.stripIndent()
with('dockerComposeUp').build()
when:
with('dockerComposeDown').build()
BuildResult buildResult = with('dockerComposeUp', 'dockerComposeDown').build()
then:
processCount() == 0
buildResult.task(':dockerComposeDown').outcome == TaskOutcome.SUCCESS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class DockerRunPluginTests extends AbstractPluginTest {
buildResult.output =~ /(?m)\/test/

buildResult.task(':dockerRunStatus').outcome == TaskOutcome.SUCCESS
buildResult.output =~ /(?m):dockerRunStatus\nDocker container 'foo' is STOPPED./
buildResult.output =~ /(?m):dockerRunStatus\s+Docker container 'foo' is STOPPED./
}

def 'can mount volumes'() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,37 @@ class PalantirDockerPluginTests extends AbstractPluginTest {
execCond("docker rmi -f ${id}")
}

def 'check multiarch'() {
given:
String id = 'id4'
String filename = "foo.txt"
file('Dockerfile') << """
FROM alpine
MAINTAINER ${id}
ADD ${filename} /tmp/
""".stripIndent()
buildFile << """
plugins {
id 'com.palantir.docker'
}
docker {
name '${id}'
files "${filename}"
buildx true
load true
platform 'linux/arm64'
}
""".stripIndent()
new File(projectDir, filename).createNewFile()
when:
BuildResult buildResult = with('docker').build()
then:
buildResult.task(':dockerPrepare').outcome == TaskOutcome.SUCCESS
buildResult.task(':docker').outcome == TaskOutcome.SUCCESS
exec("docker inspect --format '{{.Architecture}}' ${id}") == "'arm64'\n"
execCond("docker rmi -f ${id}")
}

// Gradle explicitly disallows the test case, fails with the following:
//Could not determine the dependencies of task ':publishDockerPublicationPublicationToMavenLocal'.
//> Publishing is not able to resolve a dependency on a project with multiple publications that have different coordinates.
Expand Down Expand Up @@ -457,7 +488,7 @@ class PalantirDockerPluginTests extends AbstractPluginTest {

then:
buildResult.task(':docker').outcome == TaskOutcome.SUCCESS
buildResult.output.contains 'Pulling from library/alpine'
buildResult.output.contains 'load metadata for docker.io/library/alpine'
execCond("docker rmi -f ${id}")
}

Expand Down Expand Up @@ -488,6 +519,8 @@ class PalantirDockerPluginTests extends AbstractPluginTest {
buildResult.task(':docker').outcome == TaskOutcome.FAILED
buildResult.output.contains('network foobar not found') or(
buildResult.output.contains('No such network: foobar')
) or(
buildResult.output.contains('network mode "foobar" not supported by buildkit')
)
execCond("docker rmi -f ${id}")
}
Expand Down

0 comments on commit 64c9e45

Please sign in to comment.