Skip to content

Commit 4b3ad01

Browse files
authored
Merge pull request #223 from nitrictech/feature/container-builds
Container build refactor
2 parents 337a299 + 2973d11 commit 4b3ad01

File tree

5 files changed

+41
-61
lines changed

5 files changed

+41
-61
lines changed

packages/common/src/stack/container.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class StackContainer<ContainerExtensions = Record<string, any>> {
8989
);
9090
}
9191

92-
return origPath;
92+
return fullPath;
9393
}
9494

9595
/**

packages/common/src/stack/schema.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,10 @@ export const STACK_SCHEMA: JSONSchema7 = {
16121612
properties: {
16131613
dockerfile: { type: 'string' },
16141614
context: { type: 'string' },
1615+
args: {
1616+
type: 'object',
1617+
additionalProperties: { type: 'string' },
1618+
},
16151619
triggers: {
16161620
title: 'func triggers',
16171621
type: 'object',

packages/common/src/task/build-container.ts

Lines changed: 34 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
import { Task } from './task';
1616
import { ContainerImage } from '../types';
1717
import { StackContainer } from '../stack';
18-
import { dockerodeEvtToString } from '../index';
19-
// import rimraf from 'rimraf';
20-
21-
import tar from 'tar-fs';
22-
import Docker from 'dockerode';
18+
import { oneLine } from 'common-tags';
19+
import execa from 'execa';
2320

2421
interface BuildContainerTaskOptions {
2522
baseDir: string;
@@ -29,74 +26,52 @@ interface BuildContainerTaskOptions {
2926

3027
export class BuildContainerTask extends Task<ContainerImage> {
3128
private container: StackContainer;
32-
// private readonly stack: Stack;
3329
private readonly provider: string;
3430

3531
constructor({ container, provider = 'local' }: BuildContainerTaskOptions) {
3632
super(`${container.getName()}`);
3733
this.container = container;
38-
// this.stack = stack;
3934
this.provider = provider;
4035
}
4136

4237
async do(): Promise<ContainerImage> {
43-
const docker = new Docker();
44-
45-
// const ignoreFiles = await Template.getDockerIgnoreFiles(template);
46-
47-
const pack = tar.pack(this.container.getContext(), {
48-
// TODO: support ignore again
49-
// ignore: (name) =>
50-
// // Simple filter before more complex multimatch
51-
// ignoreFiles.filter((f) => name.includes(f)).length > 0 || match(name, ignoreFiles).length > 0,
52-
});
38+
const imageId = this.container.getImageTagName(this.provider);
39+
const { args = {} } = this.container.getDescriptor();
5340

54-
// FIXME: Currently dockerode does not support dockerfiles specified outside of build context
55-
const dockerfile = this.container.getDockerfile();
56-
57-
const options = {
58-
buildargs: {
59-
PROVIDER: this.provider,
60-
},
61-
t: this.container.getImageTagName(this.provider),
62-
dockerfile,
63-
};
41+
const cmd = oneLine`
42+
docker build ${this.container.getContext()}
43+
-f ${this.container.getDockerfile()}
44+
-t ${imageId}
45+
--progress plain
46+
--build-arg PROVIDER=${this.provider}
47+
${Object.keys(args)
48+
.map((k) => `--build-arg ${k}=${args[k]}`)
49+
.join(' ')}
50+
`;
6451

65-
let stream: NodeJS.ReadableStream;
6652
try {
67-
stream = await docker.buildImage(pack, options);
68-
} catch (error) {
69-
if (error.errno && error.errno === -61) {
70-
throw new Error('Unable to connect to docker, is it running locally?');
71-
}
72-
throw error;
73-
}
74-
75-
// Get build updates
76-
const buildResults = await new Promise<any[]>((resolve, reject) => {
77-
docker.modem.followProgress(
78-
stream,
79-
(errorInner: Error, resolveInner: Record<string, any>[]) =>
80-
errorInner ? reject(errorInner) : resolve(resolveInner),
81-
(event: any) => {
82-
try {
83-
this.update(dockerodeEvtToString(event));
84-
} catch (error) {
85-
reject(new Error(error.message.replace(/\n/g, '')));
86-
}
53+
const dockerProcess = execa.command(cmd, {
54+
// Enable buildkit for out of context dockerfile
55+
env: {
56+
DOCKER_BUILDKIT: '1',
8757
},
88-
);
89-
});
58+
});
59+
60+
// Only outputs on stderr
61+
dockerProcess.stderr.on('data', (data) => {
62+
// fs.writeFileSync('debug.txt', data);
63+
this.update(data.toString());
64+
});
9065

91-
const filteredResults = buildResults.filter((obj) => 'aux' in obj && 'ID' in obj['aux']);
92-
if (filteredResults.length > 0) {
93-
const imageId = filteredResults[filteredResults.length - 1]['aux'].ID.split(':').pop() as string;
94-
return { id: imageId, name: this.container.getName() } as ContainerImage;
95-
} else {
96-
const {
97-
errorDetail: { message },
98-
} = buildResults.pop() as any;
99-
throw new Error(message);
66+
// wait for the process to finalize
67+
await dockerProcess;
68+
} catch (e) {
69+
throw new Error(e.message);
10070
}
71+
72+
return {
73+
id: imageId,
74+
name: this.container.getName(),
75+
};
10176
}
10277
}

packages/common/src/types/compute/container.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ export interface NitricContainer<Ext> extends NitricComputeUnit<Ext> {
1818
// The path to the Dockerfile to use to build this source
1919
// relative to context
2020
dockerfile: string;
21+
args?: Record<string, string>;
2122
}

packages/plugins/azure/src/tasks/deploy/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export class Deploy extends Task<void> {
243243

244244
// DEPLOY SERVICES
245245
let deployedAzureApps: NitricComputeAzureAppService[] = [];
246-
if (stack.getFunctions().length > 0) {
246+
if (stack.getFunctions().length > 0 || stack.getContainers().length > 0) {
247247
// deploy a registry for deploying this stacks containers
248248
// TODO: We will want to prefer a pre-existing registry, supplied by the user
249249
const registry = new containerregistry.Registry(`${stack.getName()}-registry`, {

0 commit comments

Comments
 (0)