Skip to content

Commit 13cbc9e

Browse files
authored
Merge pull request #1402 from yuvipanda/docker-buildx
Shell out to `docker buildx build` to build images
2 parents 6d50085 + 709eb8e commit 13cbc9e

File tree

5 files changed

+90
-61
lines changed

5 files changed

+90
-61
lines changed

repo2docker/__main__.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ def get_argparser():
140140

141141
argparser.add_argument(
142142
"--build-memory-limit",
143-
help="Total Memory that can be used by the docker build process",
143+
# Removed argument, but we still want to support printing an error message if this is passed
144+
help=argparse.SUPPRESS,
144145
)
145146

146147
argparser.add_argument(
@@ -434,12 +435,13 @@ def make_r2d(argv=None):
434435
sys.exit(1)
435436

436437
if args.build_memory_limit:
437-
# if the string only contains numerals we assume it should be an int
438-
# and specifies a size in bytes
439-
if args.build_memory_limit.isnumeric():
440-
r2d.build_memory_limit = int(args.build_memory_limit)
441-
else:
442-
r2d.build_memory_limit = args.build_memory_limit
438+
# We no longer support build_memory_limit, it must be set in the builder instance
439+
print("--build-memory-limit is no longer supported", file=sys.stderr)
440+
print(
441+
"Check your build engine documentation to set memory limits. Use `docker buildx create` if using the default builder to create a custom builder with appropriate memory limits",
442+
file=sys.stderr,
443+
)
444+
sys.exit(-1)
443445

444446
if args.environment and not r2d.run:
445447
print("To specify environment variables, you also need to run " "the container")

repo2docker/app.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,23 @@ def _default_log_level(self):
165165
build_memory_limit = ByteSpecification(
166166
0,
167167
help="""
168-
Total memory that can be used by the docker image building process.
168+
Unsupported.
169169
170-
Set to 0 for no limits.
170+
When using docker, please use `docker buildx create` to create a new buildkit
171+
builder with appropriate limits instead.
171172
""",
172173
config=True,
173174
)
174175

176+
@observe("build_memory_limit")
177+
def build_memory_limit_changed(self, change):
178+
print("Setting build_memory_limit is not supported", file=sys.stderr)
179+
print(
180+
"Check your build engine documentation to set memory limits. Use `docker buildx create` if using the default builder to create a custom builder with appropriate memory limits",
181+
file=sys.stderr,
182+
)
183+
sys.exit(-1)
184+
175185
volumes = Dict(
176186
{},
177187
help="""
@@ -856,6 +866,7 @@ def build(self):
856866
for l in picked_buildpack.build(
857867
docker_client,
858868
self.output_image_spec,
869+
# This is deprecated, but passing it anyway to not break backwards compatibility
859870
self.build_memory_limit,
860871
build_args,
861872
self.cache_from,

repo2docker/docker.py

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22
Docker container engine for repo2docker
33
"""
44

5+
import shutil
6+
import tarfile
7+
import tempfile
8+
59
from iso8601 import parse_date
6-
from traitlets import Dict
10+
from traitlets import Dict, List, Unicode
711

812
import docker
913

1014
from .engine import Container, ContainerEngine, ContainerEngineException, Image
15+
from .utils import execute_cmd
1116

1217

1318
class DockerContainer(Container):
@@ -53,7 +58,7 @@ class DockerEngine(ContainerEngine):
5358
https://docker-py.readthedocs.io/en/4.2.0/api.html#module-docker.api.build
5459
"""
5560

56-
string_output = False
61+
string_output = True
5762

5863
extra_init_args = Dict(
5964
{},
@@ -69,6 +74,14 @@ class DockerEngine(ContainerEngine):
6974
config=True,
7075
)
7176

77+
extra_buildx_build_args = List(
78+
Unicode(),
79+
help="""
80+
Extra commandline arguments to pass to `docker buildx build` when building the image.
81+
""",
82+
config=True,
83+
)
84+
7285
def __init__(self, *, parent):
7386
super().__init__(parent=parent)
7487
try:
@@ -94,22 +107,46 @@ def build(
94107
platform=None,
95108
**kwargs,
96109
):
97-
return self._apiclient.build(
98-
buildargs=buildargs,
99-
cache_from=cache_from,
100-
container_limits=container_limits,
101-
forcerm=True,
102-
rm=True,
103-
tag=tag,
104-
custom_context=custom_context,
105-
decode=True,
106-
dockerfile=dockerfile,
107-
fileobj=fileobj,
108-
path=path,
109-
labels=labels,
110-
platform=platform,
111-
**kwargs,
112-
)
110+
if not shutil.which("docker"):
111+
raise RuntimeError("The docker commandline client must be installed")
112+
args = ["docker", "buildx", "build", "--progress", "plain", "--load"]
113+
if buildargs:
114+
for k, v in buildargs.items():
115+
args += ["--build-arg", f"{k}={v}"]
116+
117+
if cache_from:
118+
for cf in cache_from:
119+
args += ["--cache-from", cf]
120+
121+
if dockerfile:
122+
args += ["--file", dockerfile]
123+
124+
if tag:
125+
args += ["--tag", tag]
126+
127+
if labels:
128+
for k, v in labels.items():
129+
args += ["--label", f"{k}={v}"]
130+
131+
if platform:
132+
args += ["--platform", platform]
133+
134+
# place extra args right *before* the path
135+
args += self.extra_buildx_build_args
136+
137+
if fileobj:
138+
with tempfile.TemporaryDirectory() as d:
139+
tarf = tarfile.open(fileobj=fileobj)
140+
tarf.extractall(d)
141+
142+
args += [d]
143+
144+
yield from execute_cmd(args, True)
145+
else:
146+
# Assume 'path' is passed in
147+
args += [path]
148+
149+
yield from execute_cmd(args, True)
113150

114151
def images(self):
115152
images = self._apiclient.images()

tests/unit/test_app.py

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,18 @@ def test_local_dir_image_name(repo_with_content):
7878
)
7979

8080

81-
def test_build_kwargs(repo_with_content):
81+
def test_extra_buildx_build_args(repo_with_content):
8282
upstream, sha1 = repo_with_content
83-
argv = [upstream]
83+
argv = ["--DockerEngine.extra_buildx_build_args=--check", upstream]
8484
app = make_r2d(argv)
85-
app.extra_build_kwargs = {"somekey": "somevalue"}
86-
87-
with patch.object(docker.APIClient, "build") as builds:
88-
builds.return_value = []
85+
with patch("repo2docker.docker.execute_cmd") as execute_cmd:
8986
app.build()
90-
builds.assert_called_once()
91-
args, kwargs = builds.call_args
92-
assert "somekey" in kwargs
93-
assert kwargs["somekey"] == "somevalue"
87+
88+
args, kwargs = execute_cmd.call_args
89+
cmd = args[0]
90+
assert cmd[:3] == ["docker", "buildx", "build"]
91+
# make sure it's inserted before the end
92+
assert "--check" in cmd[:-1]
9493

9594

9695
def test_run_kwargs(repo_with_content):
@@ -107,26 +106,6 @@ def test_run_kwargs(repo_with_content):
107106
assert kwargs["somekey"] == "somevalue"
108107

109108

110-
def test_root_not_allowed():
111-
with TemporaryDirectory() as src, patch("os.geteuid") as geteuid:
112-
geteuid.return_value = 0
113-
argv = [src]
114-
with pytest.raises(SystemExit) as exc:
115-
app = make_r2d(argv)
116-
assert exc.code == 1
117-
118-
with pytest.raises(ValueError):
119-
app = Repo2Docker(repo=src, run=False)
120-
app.build()
121-
122-
app = Repo2Docker(repo=src, user_id=1000, user_name="jovyan", run=False)
123-
app.initialize()
124-
with patch.object(docker.APIClient, "build") as builds:
125-
builds.return_value = []
126-
app.build()
127-
builds.assert_called_once()
128-
129-
130109
def test_dryrun_works_without_docker(tmpdir, capsys):
131110
with chdir(tmpdir):
132111
with patch.object(docker, "APIClient") as client:

tests/unit/test_args.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ def test_mem_limit():
5050
"""
5151
Test various ways of passing --build-memory-limit
5252
"""
53-
r2d = make_r2d(["--build-memory-limit", "1024", "."])
54-
assert int(r2d.build_memory_limit) == 1024
53+
with pytest.raises(SystemExit):
54+
r2d = make_r2d(["--build-memory-limit", "1024", "."])
5555

56-
r2d = make_r2d(["--build-memory-limit", "3K", "."])
57-
assert int(r2d.build_memory_limit) == 1024 * 3
56+
with pytest.raises(SystemExit):
57+
r2d = make_r2d(["--Repo2Docker.build_memory_limit", "1024", "."])
5858

5959

6060
def test_run_required():

0 commit comments

Comments
 (0)