Skip to content

Commit ff5af9a

Browse files
Add buildkit support (testcontainers#955)
1 parent 0220ff4 commit ff5af9a

File tree

11 files changed

+284
-59
lines changed

11 files changed

+284
-59
lines changed

docs/features/images.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ const container = await GenericContainer
2424
.build("my-custom-image", { deleteOnExit: false });
2525
```
2626

27+
### With buildkit
28+
29+
```javascript
30+
const { GenericContainer } = require("testcontainers");
31+
32+
const container = await GenericContainer
33+
.fromDockerfile("/path/to/build-context")
34+
.withBuildkit()
35+
.build();
36+
```
37+
2738
### With a pull policy
2839

2940
Testcontainers will automatically pull an image if it doesn't exist. This is configurable:

package-lock.json

Lines changed: 62 additions & 57 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM node:10-alpine
2+
3+
MAINTAINER Cristian Greco
4+
5+
EXPOSE 8080
6+
7+
RUN --mount=type=tmpfs,target=/buildkit-test \
8+
echo "BuildKit tmpfs mount is working" > /buildkit-test/success.txt && \
9+
cat /buildkit-test/success.txt
10+
11+
RUN apk add --no-cache curl dumb-init libcap openssl
12+
13+
RUN openssl req -x509 -nodes -days 36500 \
14+
-subj "/C=CA/ST=QC/O=Company Inc/CN=localhost" \
15+
-newkey rsa:2048 -keyout /etc/ssl/private/cert.key \
16+
-out /etc/ssl/certs/cert.crt \
17+
&& chmod 666 /etc/ssl/private/cert.key
18+
19+
RUN npm init -y && \
20+
npm install [email protected]
21+
22+
COPY index.js .
23+
24+
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
25+
CMD ["node", "index.js"]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
services:
2+
container:
3+
build:
4+
context: .
5+
dockerfile: Dockerfile
6+
ports:
7+
- 8080
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const fs = require("fs");
2+
const http = require("http");
3+
const https = require("https");
4+
const express = require("express");
5+
6+
const app = express();
7+
8+
app.get("/hello-world", (req, res) => {
9+
res.status(200).send("hello-world");
10+
});
11+
12+
app.get("/hello-world-delay", (req, res) => {
13+
setTimeout(() => {
14+
res.status(200).send("hello-world");
15+
}, 3000);
16+
});
17+
18+
app.post("/hello-world-post", (req, res) => {
19+
res.status(200).send("hello-world");
20+
});
21+
22+
app.get("/env", (req, res) => {
23+
res.status(200).json(process.env);
24+
});
25+
26+
app.get("/cmd", (req, res) => {
27+
res.status(200).json(process.argv);
28+
});
29+
30+
app.get("/auth", (req, res) => {
31+
const auth = req.headers.authorization;
32+
const [, base64Encoded] = auth.split(" ");
33+
const credentials = Buffer.from(base64Encoded, "base64").toString("ascii");
34+
const [username, password] = credentials.split(":");
35+
if (username === "user" && password === "pass") {
36+
res.status(200).end();
37+
} else {
38+
res.status(401).end();
39+
}
40+
});
41+
42+
app.get("/header-or-400/:headerName", (req, res) => {
43+
if (req.headers[req.params["headerName"]] !== undefined) {
44+
res.status(200).end();
45+
} else {
46+
res.status(400).end();
47+
}
48+
});
49+
50+
const PORT = 8080;
51+
const TLS_PORT = 8443;
52+
53+
http.createServer(app).listen(PORT, () => console.log(`Listening on port ${PORT}`));
54+
https
55+
.createServer(
56+
{
57+
key: fs.readFileSync("/etc/ssl/private/cert.key", "utf8"),
58+
cert: fs.readFileSync("/etc/ssl/certs/cert.crt", "utf8"),
59+
},
60+
app
61+
)
62+
.listen(TLS_PORT, () => console.log(`Listening on secure port ${TLS_PORT}`));
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM node:10-alpine
2+
3+
MAINTAINER Cristian Greco
4+
5+
EXPOSE 8080
6+
7+
RUN --mount=type=tmpfs,target=/buildkit-test \
8+
echo "BuildKit tmpfs mount is working" > /buildkit-test/success.txt && \
9+
cat /buildkit-test/success.txt
10+
11+
RUN apk add --no-cache curl dumb-init libcap openssl
12+
13+
RUN openssl req -x509 -nodes -days 36500 \
14+
-subj "/C=CA/ST=QC/O=Company Inc/CN=localhost" \
15+
-newkey rsa:2048 -keyout /etc/ssl/private/cert.key \
16+
-out /etc/ssl/certs/cert.crt \
17+
&& chmod 666 /etc/ssl/private/cert.key
18+
19+
RUN npm init -y && \
20+
npm install [email protected]
21+
22+
COPY index.js .
23+
24+
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
25+
CMD ["node", "index.js"]
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const fs = require("fs");
2+
const http = require("http");
3+
const https = require("https");
4+
const express = require("express");
5+
6+
const app = express();
7+
8+
app.get("/hello-world", (req, res) => {
9+
res.status(200).send("hello-world");
10+
});
11+
12+
app.get("/hello-world-delay", (req, res) => {
13+
setTimeout(() => {
14+
res.status(200).send("hello-world");
15+
}, 3000);
16+
});
17+
18+
app.post("/hello-world-post", (req, res) => {
19+
res.status(200).send("hello-world");
20+
});
21+
22+
app.get("/env", (req, res) => {
23+
res.status(200).json(process.env);
24+
});
25+
26+
app.get("/cmd", (req, res) => {
27+
res.status(200).json(process.argv);
28+
});
29+
30+
app.get("/auth", (req, res) => {
31+
const auth = req.headers.authorization;
32+
const [, base64Encoded] = auth.split(" ");
33+
const credentials = Buffer.from(base64Encoded, "base64").toString("ascii");
34+
const [username, password] = credentials.split(":");
35+
if (username === "user" && password === "pass") {
36+
res.status(200).end();
37+
} else {
38+
res.status(401).end();
39+
}
40+
});
41+
42+
app.get("/header-or-400/:headerName", (req, res) => {
43+
if (req.headers[req.params["headerName"]] !== undefined) {
44+
res.status(200).end();
45+
} else {
46+
res.status(400).end();
47+
}
48+
});
49+
50+
const PORT = 8080;
51+
const TLS_PORT = 8443;
52+
53+
http.createServer(app).listen(PORT, () => console.log(`Listening on port ${PORT}`));
54+
https
55+
.createServer(
56+
{
57+
key: fs.readFileSync("/etc/ssl/private/cert.key", "utf8"),
58+
cert: fs.readFileSync("/etc/ssl/certs/cert.crt", "utf8"),
59+
},
60+
app
61+
)
62+
.listen(TLS_PORT, () => console.log(`Listening on secure port ${TLS_PORT}`));

packages/testcontainers/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@
3131
},
3232
"dependencies": {
3333
"@balena/dockerignore": "^1.0.2",
34-
"@types/dockerode": "^3.3.29",
34+
"@types/dockerode": "^3.3.35",
3535
"archiver": "^7.0.1",
3636
"async-lock": "^1.4.1",
3737
"byline": "^5.0.0",
3838
"debug": "^4.3.5",
3939
"docker-compose": "^0.24.8",
40-
"dockerode": "^3.3.5",
40+
"dockerode": "^4.0.4",
4141
"get-port": "^7.1.0",
4242
"proper-lockfile": "^4.1.2",
4343
"properties-reader": "^2.3.0",

packages/testcontainers/src/docker-compose-environment/docker-compose-environment.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
4343
await startedEnvironment.down();
4444
});
4545

46+
if (!process.env.CI_PODMAN) {
47+
it("should work with buildkit", async () => {
48+
const buildkitFixtures = path.resolve(fixtures, "docker-compose-with-buildkit");
49+
const startedEnvironment = await new DockerComposeEnvironment(buildkitFixtures, "docker-compose.yml").up();
50+
await checkEnvironmentContainerIsHealthy(startedEnvironment, await composeContainerName("container"));
51+
await startedEnvironment.down();
52+
});
53+
}
54+
4655
it("should use pull policy", async () => {
4756
const env = new DockerComposeEnvironment(fixtures, "docker-compose-with-many-services.yml");
4857

packages/testcontainers/src/generic-container/generic-container-builder.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class GenericContainerBuilder {
1717
private buildArgs: BuildArgs = {};
1818
private pullPolicy: ImagePullPolicy = PullPolicy.defaultPolicy();
1919
private cache = true;
20+
private buildkit = false;
2021
private target?: string;
2122
private platform?: string;
2223

@@ -41,6 +42,11 @@ export class GenericContainerBuilder {
4142
return this;
4243
}
4344

45+
public withBuildkit(): this {
46+
this.buildkit = true;
47+
return this;
48+
}
49+
4450
public withPlatform(platform: string): this {
4551
this.platform = platform;
4652
return this;
@@ -79,6 +85,7 @@ export class GenericContainerBuilder {
7985
labels,
8086
target: this.target,
8187
platform: this.platform,
88+
version: this.buildkit ? "2" : "1",
8289
};
8390

8491
if (this.pullPolicy.shouldPull()) {

0 commit comments

Comments
 (0)