Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for cross repository blob mount #34

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
Expand Down
27 changes: 20 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ containerify --fromImage nginx:alpine --folder . --toImage frontend:latest --cus

This will take the `nginx:alpine` image, and copy the files from `./dist/` into `/usr/share/nginx/html`.

### Using with Github Container Registry (ghcr.io)

1. Create a token from https://github.com/settings/tokens/new?scopes=write:packages or use GITHUB_TOKEN from Github Actions
2. Example: `containerify --registry https://ghcr.io/v2/ --token "$GITHUB_TOKEN" --fromImage docker-mirror/node:alpine --toImage <some image name>:<some tag> --folder . `

### Using with AWS ECR

1. Create the repository in AWS from the console or through using the CLI
2. Create token using `aws ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken'`
3. Example: `containerify --toToken "Basic $TOKEN" --toRegistry https://<AWS ACCOUNT ID>.dkr.ecr.<AWS region for repository>.amazonaws.com/v2/ --fromImage node:alpine --toImage <name of repository>:<some tag> --folder .`

### Command line options

```
Expand All @@ -40,27 +51,29 @@ Options:
--toImage <name:tag> Required: Image name of target image - [path/]image:tag
--folder <full path> Required: Base folder of node application (contains package.json)
--file <path> Optional: Name of configuration file (defaults to containerify.json if found on path)
--doCrossMount <true/false> Cross mount image layers from the base image (only works if fromImage and toImage are in the same registry) (default: false)
--fromRegistry <registry url> Optional: URL of registry to pull base image from - Default: https://registry-1.docker.io/v2/
--fromToken <token> Optional: Authentication token for from registry
--toRegistry <registry url> Optional: URL of registry to push base image to - Default: https://registry-1.docker.io/v2/
--optimisticToRegistryCheck Optional: Treat redirects as layer existing in remote registry. Potentially unsafe, but could save bandwidth.
--optimisticToRegistryCheck Treat redirects as layer existing in remote registry. Potentially unsafe, but can save bandwidth.
--toToken <token> Optional: Authentication token for target registry
--toTar <path> Optional: Export to tar file
--toDocker Optional: Export to local docker registry
--registry <path> Optional: Convenience argument for setting both from and to registry
--platform <platform> Optional: Preferred platform, e.g. linux/amd64 or arm64
--token <path> Optional: Convenience argument for setting token for both from and to registry
--user <user> Optional: User account to run process in container - default: 1000
--workdir <directory> Optional: Workdir where node app will be added and run from - default: /app
--entrypoint <entrypoint> Optional: Entrypoint when starting container - default: npm start
--user <user> Optional: User account to run process in container - default: 1000 (empty for customContent)
--workdir <directory> Optional: Workdir where node app will be added and run from - default: /app (empty for customContent)
--entrypoint <entrypoint> Optional: Entrypoint when starting container - default: npm start (empty for customContent)
--labels <labels> Optional: Comma-separated list of key value pairs to use as labels
--label <label> Optional: Single label (name=value). This option can be used multiple times.
--envs <envs> Optional: Comma-separated list of key value pairs to use av environment variables.
--env <env> Optional: Single environment variable (name=value). This option can be used multiple times.
--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
--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
--verbose Verbose logging
--allowInsecureRegistries Allow insecure registries (with self-signed/untrusted cert)
--customContent <dirs/files> Optional: Skip normal node_modules and applayer and include specified root folder files/directories instead
--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
--extraContent <dirs/files> Optional: Add specific content. Specify as local-path:absolute-container-path,local-path2:absolute-container-path2 etc
--layerOwner <gid:uid> Optional: Set specific gid and uid on files in the added layers
--buildFolder <path> Optional: Use a specific build folder when creating the image
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"build": "tsc && chmod ugo+x lib/cli.js",
"lint": "eslint . --ext .ts --fix --ignore-path .gitignore",
"typecheck": "tsc --noEmit",
"watch": "tsc --watch",
"check": "npm run lint && npm run typecheck",
"dev": "tsc --watch",
"integrationTest": "cd tests/integration/ && ./test.sh",
Expand Down
12 changes: 10 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const possibleArgs = {
"--toImage <name:tag>": "Required: Image name of target image - [path/]image:tag",
"--folder <full path>": "Required: Base folder of node application (contains package.json)",
"--file <path>": "Optional: Name of configuration file (defaults to containerify.json if found on path)",
"--doCrossMount <true/false>":
"Cross mount image layers from the base image (only works if fromImage and toImage are in the same registry) (default: false)",
"--fromRegistry <registry url>":
"Optional: URL of registry to pull base image from - Default: https://registry-1.docker.io/v2/",
"--fromToken <token>": "Optional: Authentication token for from registry",
Expand Down Expand Up @@ -92,6 +94,7 @@ const defaultOptions = {
workdir: "/app",
user: "1000",
entrypoint: "npm start",
doCrossMount: false,
};

if (cliOptions.file && !fs.existsSync(cliOptions.file)) {
Expand Down Expand Up @@ -182,6 +185,11 @@ exitWithErrorIf(!!options.registry && !!options.toRegistry, "Do not set both --r
exitWithErrorIf(!!options.token && !!options.fromToken, "Do not set both --token and --fromToken");
exitWithErrorIf(!!options.token && !!options.toToken, "Do not set both --token and --toToken");

exitWithErrorIf(
!!options.doCrossMount && options.toRegistry != options.fromRegistry,
"Cross mounting only works if fromRegistry and toRegistry are the same",
);

if (options.setTimeStamp) {
try {
options.setTimeStamp = new Date(options.setTimeStamp).toISOString();
Expand Down Expand Up @@ -259,7 +267,7 @@ async function run(options: Options) {
const fromRegistry = options.fromRegistry
? createRegistry(options.fromRegistry, options.fromToken ?? "", allowInsecure)
: createDockerRegistry(allowInsecure, options.fromToken);
await fromRegistry.download(
const originalManifest = await fromRegistry.download(
options.fromImage,
fromdir,
getPreferredPlatform(options.platform),
Expand All @@ -286,7 +294,7 @@ async function run(options: Options) {
allowInsecure,
options.optimisticToRegistryCheck,
);
await toRegistry.upload(options.toImage, todir);
await toRegistry.upload(options.toImage, todir, options.doCrossMount, originalManifest, options.fromImage);
}
logger.debug("Deleting " + tmpdir + " ...");
await fse.remove(tmpdir);
Expand Down
Loading
Loading