containerify 2.5.1 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/lib/appLayerCreator.js +37 -11
- package/lib/cli.js +18 -12
- package/lib/types.d.ts +6 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,19 @@ This will pull the `node:13-slim` image from Docker hub, build the image by addi
|
|
|
18
18
|
containerify --fromImage node:13-slim --folder src/ --toImage myapp:latest --toRegistry https://registry.example.com/v2/ --setTimeStamp=$(git show -s --format="%aI" HEAD)
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
### customContent - Adding compiled code to non-node container
|
|
22
|
+
|
|
23
|
+
If you want to build a non-node container (e.g. add compiled frontend code to an nginx container), you can use `--customContent`. When doing this
|
|
24
|
+
the normal `node_modules` etc layers will not be added, and workdir, user and entrypoint will not be overridden (allthough they can be explicitely modified
|
|
25
|
+
if needed).
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
npm run build
|
|
29
|
+
containerify --fromImage nginx:alpine --folder . --toImage frontend:latest --customContent dist:/var/www/html --toRegistry https://registry.example.com/v2/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This will take nginx:alpine and copy the files in `./dist/` into `/var/www/html`.
|
|
33
|
+
|
|
21
34
|
### Command line options
|
|
22
35
|
|
|
23
36
|
```
|
package/lib/appLayerCreator.js
CHANGED
|
@@ -166,19 +166,26 @@ function parseCommandLineToParts(entrypoint) {
|
|
|
166
166
|
}
|
|
167
167
|
function addAppLayers(options, config, todir, manifest, tmpdir) {
|
|
168
168
|
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
yield
|
|
169
|
+
if (Object.entries(options.customContent).length > 0) {
|
|
170
|
+
// We only add these layers if they have been explicitely set for customContent. This allows customContent
|
|
171
|
+
// to be used to add compiled frontend code to an nginx container without also modifying the entrypoint, user,
|
|
172
|
+
// and workdir.
|
|
173
|
+
if (options.nonDefaults.workdir)
|
|
174
|
+
yield addWorkdirLayer(options, config, options.nonDefaults.workdir);
|
|
175
|
+
if (options.nonDefaults.entrypoint)
|
|
176
|
+
yield addEntrypointLayer(options, config, options.nonDefaults.entrypoint);
|
|
177
|
+
if (options.nonDefaults.user)
|
|
178
|
+
yield addUserLayer(options, config, options.nonDefaults.user);
|
|
179
|
+
yield addEnvsLayer(options, config);
|
|
180
|
+
yield addLabelsLayer(options, config);
|
|
181
|
+
yield addDataLayer(tmpdir, todir, options, config, manifest, Object.entries(options.customContent), "custom");
|
|
180
182
|
}
|
|
181
183
|
else {
|
|
184
|
+
yield addWorkdirLayer(options, config, options.workdir);
|
|
185
|
+
yield addEntrypointLayer(options, config, options.entrypoint);
|
|
186
|
+
yield addUserLayer(options, config, options.user);
|
|
187
|
+
yield addEnvsLayer(options, config);
|
|
188
|
+
yield addLabelsLayer(options, config);
|
|
182
189
|
const appFiles = (yield fs_1.promises.readdir(options.folder)).filter((l) => !ignore.includes(l));
|
|
183
190
|
const depLayerContent = appFiles.filter((l) => depLayerPossibles.includes(l));
|
|
184
191
|
const appLayerContent = appFiles.filter((l) => !depLayerPossibles.includes(l));
|
|
@@ -190,6 +197,25 @@ function addAppLayers(options, config, todir, manifest, tmpdir) {
|
|
|
190
197
|
}
|
|
191
198
|
});
|
|
192
199
|
}
|
|
200
|
+
function addWorkdirLayer(options, config, workdir) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
addEmptyLayer(config, options, `WORKDIR ${workdir}`, (config) => (config.config.WorkingDir = workdir));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function addEntrypointLayer(options, config, entrypoint) {
|
|
206
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
207
|
+
const entrypointParts = parseCommandLineToParts(entrypoint);
|
|
208
|
+
addEmptyLayer(config, options, `ENTRYPOINT ${JSON.stringify(entrypoint)}`, (config) => (config.config.Entrypoint = entrypointParts));
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function addUserLayer(options, config, user) {
|
|
212
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
213
|
+
addEmptyLayer(config, options, `USER ${user}`, (config) => {
|
|
214
|
+
config.config.User = user;
|
|
215
|
+
config.container_config.User = user;
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
}
|
|
193
219
|
function addLabelsLayer(options, config) {
|
|
194
220
|
return __awaiter(this, void 0, void 0, function* () {
|
|
195
221
|
if (Object.keys(options.labels).length > 0) {
|
package/lib/cli.js
CHANGED
|
@@ -38,9 +38,9 @@ const possibleArgs = {
|
|
|
38
38
|
"--registry <path>": "Optional: Convenience argument for setting both from and to registry",
|
|
39
39
|
"--platform <platform>": "Optional: Preferred platform, e.g. linux/amd64 or arm64",
|
|
40
40
|
"--token <path>": "Optional: Convenience argument for setting token for both from and to registry",
|
|
41
|
-
"--user <user>": "Optional: User account to run process in container - default: 1000",
|
|
42
|
-
"--workdir <directory>": "Optional: Workdir where node app will be added and run from - default: /app",
|
|
43
|
-
"--entrypoint <entrypoint>": "Optional: Entrypoint when starting container - default: npm start",
|
|
41
|
+
"--user <user>": "Optional: User account to run process in container - default: 1000 (empty for customContent)",
|
|
42
|
+
"--workdir <directory>": "Optional: Workdir where node app will be added and run from - default: /app (empty for customContent)",
|
|
43
|
+
"--entrypoint <entrypoint>": "Optional: Entrypoint when starting container - default: npm start (empty for customContent)",
|
|
44
44
|
"--labels <labels>": "Optional: Comma-separated list of key value pairs to use as labels",
|
|
45
45
|
"--label <label>": "Optional: Single label (name=value). This option can be used multiple times.",
|
|
46
46
|
"--envs <envs>": "Optional: Comma-separated list of key value pairs to use av environment variables.",
|
|
@@ -48,16 +48,17 @@ const possibleArgs = {
|
|
|
48
48
|
"--setTimeStamp <timestamp>": "Optional: Set a specific ISO 8601 timestamp on all entries (e.g. git commit hash). Default: 1970 in tar files, and current time on manifest/config",
|
|
49
49
|
"--verbose": "Verbose logging",
|
|
50
50
|
"--allowInsecureRegistries": "Allow insecure registries (with self-signed/untrusted cert)",
|
|
51
|
-
"--customContent <dirs/files>": "Optional: Skip normal node_modules and applayer and include specified root folder files/directories instead",
|
|
51
|
+
"--customContent <dirs/files>": "Optional: Skip normal node_modules and applayer and include specified root folder files/directories instead. You can specify as local-path:absolute-container-path if you want to place it in a specific location",
|
|
52
52
|
"--extraContent <dirs/files>": "Optional: Add specific content. Specify as local-path:absolute-container-path,local-path2:absolute-container-path2 etc",
|
|
53
53
|
"--layerOwner <gid:uid>": "Optional: Set specific gid and uid on files in the added layers",
|
|
54
54
|
"--buildFolder <path>": "Optional: Use a specific build folder when creating the image",
|
|
55
55
|
"--layerCacheFolder <path>": "Optional: Folder to cache base layers between builds",
|
|
56
56
|
"--version": "Get containerify version",
|
|
57
57
|
};
|
|
58
|
-
function setKeyValue(target, keyValue, separator = "=") {
|
|
58
|
+
function setKeyValue(target, keyValue, separator = "=", defaultValue) {
|
|
59
|
+
var _a;
|
|
59
60
|
const [k, v] = keyValue.split(separator, 2);
|
|
60
|
-
target[k.trim()] = v.trim();
|
|
61
|
+
target[k.trim()] = (_a = v === null || v === void 0 ? void 0 : v.trim()) !== null && _a !== void 0 ? _a : defaultValue;
|
|
61
62
|
}
|
|
62
63
|
const cliLabels = {};
|
|
63
64
|
commander_1.program.on("option:label", (ops) => {
|
|
@@ -114,9 +115,9 @@ Object.keys(envOpt)
|
|
|
114
115
|
exitWithErrorIf(true, `Env ${l} specified both with --envs and --env`);
|
|
115
116
|
});
|
|
116
117
|
const envs = Object.assign(Object.assign(Object.assign({}, configFromFile.envs), envOpt), cliEnv); //Let cli arguments override file
|
|
117
|
-
const customContent =
|
|
118
|
-
(_e = configFromFile.customContent) === null || _e === void 0 ? void 0 : _e.forEach((c) => customContent
|
|
119
|
-
(_f = cliOptions.customContent) === null || _f === void 0 ? void 0 : _f.split(",").forEach((c) => customContent
|
|
118
|
+
const customContent = {};
|
|
119
|
+
(_e = configFromFile.customContent) === null || _e === void 0 ? void 0 : _e.forEach((c) => setKeyValue(customContent, c, ":", c));
|
|
120
|
+
(_f = cliOptions.customContent) === null || _f === void 0 ? void 0 : _f.split(",").forEach((c) => setKeyValue(customContent, c, ":", c));
|
|
120
121
|
const cliExtraContent = {};
|
|
121
122
|
(_g = cliOptions.extraContent) === null || _g === void 0 ? void 0 : _g.split(",").forEach((x) => setKeyValue(cliExtraContent, x, ":"));
|
|
122
123
|
const extraContent = Object.assign(Object.assign({}, configFromFile.extraContent), cliExtraContent);
|
|
@@ -128,9 +129,14 @@ const cliParams = (0, utils_1.omit)(cliOptions, [
|
|
|
128
129
|
"customContent",
|
|
129
130
|
"extraContent",
|
|
130
131
|
]);
|
|
131
|
-
const
|
|
132
|
+
const setOptions = Object.assign(Object.assign(Object.assign({}, configFromFile), cliParams), { customContent,
|
|
132
133
|
extraContent,
|
|
133
134
|
labels, envs: Object.entries(envs).map(([k, v]) => `${k}=${v}`) });
|
|
135
|
+
const options = Object.assign(Object.assign(Object.assign({}, defaultOptions), setOptions), { nonDefaults: {
|
|
136
|
+
user: setOptions.user,
|
|
137
|
+
workdir: setOptions.workdir,
|
|
138
|
+
entrypoint: setOptions.entrypoint,
|
|
139
|
+
} });
|
|
134
140
|
function exitWithErrorIf(check, error) {
|
|
135
141
|
if (check) {
|
|
136
142
|
logger_1.default.error("ERROR: " + error);
|
|
@@ -179,7 +185,7 @@ if (options.fromRegistry && !options.fromRegistry.endsWith("/"))
|
|
|
179
185
|
if (!options.fromRegistry && !((_k = (_j = (_h = options.fromImage) === null || _h === void 0 ? void 0 : _h.split(":")) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.includes("/"))) {
|
|
180
186
|
options.fromImage = "library/" + options.fromImage;
|
|
181
187
|
}
|
|
182
|
-
options.customContent.forEach((p) => {
|
|
188
|
+
Object.keys(options.customContent).forEach((p) => {
|
|
183
189
|
exitWithErrorIf(!fs.existsSync(p), "Could not find " + p + " in the base folder " + options.folder);
|
|
184
190
|
});
|
|
185
191
|
if (options.layerCacheFolder) {
|
|
@@ -196,7 +202,7 @@ if (options.layerCacheFolder) {
|
|
|
196
202
|
options.layerCacheFolder += "/";
|
|
197
203
|
}
|
|
198
204
|
}
|
|
199
|
-
Object.keys(options.extraContent).forEach(k => {
|
|
205
|
+
Object.keys(options.extraContent).forEach((k) => {
|
|
200
206
|
exitWithErrorIf(!fs.existsSync(options.folder + k), "Could not find `" + k + "` in the folder " + options.folder);
|
|
201
207
|
});
|
|
202
208
|
function run(options) {
|
package/lib/types.d.ts
CHANGED
|
@@ -75,10 +75,15 @@ export type Options = {
|
|
|
75
75
|
setTimeStamp?: string;
|
|
76
76
|
verbose?: boolean;
|
|
77
77
|
allowInsecureRegistries?: boolean;
|
|
78
|
-
customContent: string
|
|
78
|
+
customContent: Record<string, string>;
|
|
79
79
|
extraContent: Record<string, string>;
|
|
80
80
|
layerOwner?: string;
|
|
81
81
|
buildFolder?: string;
|
|
82
82
|
layerCacheFolder?: string;
|
|
83
|
+
nonDefaults: {
|
|
84
|
+
user?: string;
|
|
85
|
+
workdir?: string;
|
|
86
|
+
entrypoint?: string;
|
|
87
|
+
};
|
|
83
88
|
};
|
|
84
89
|
export {};
|
package/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "2.
|
|
1
|
+
export declare const VERSION = "2.6.0";
|
package/lib/version.js
CHANGED