Skip to content
Draft
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
27 changes: 27 additions & 0 deletions 65_image_rebasing/Dockerfile.ping
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# syntax=docker/dockerfile:1.4
ARG IMAGE=ubuntu:latest
FROM $IMAGE as BASEIMAGE

ARG DEBIAN_FRONTEND=noninteractive

# NOTE: Escape the \$ otherwise they are rendered at buildtime
COPY --link=true --chmod=755 <<EOF /bin/ping.sh
#!/usr/bin/env bash
URL=\${1:-https://google.com}
if [ -z "\${URL}" ];then
URL=https://google.com
fi
echo "URL=\$URL"
#while true; do
curl -L --connect-timeout 5 --max-time 20 --retry 5 --retry-delay 0 --retry-max-time 40 -v \$URL
#sleep 5;
#done
EOF

RUN apt-get update \
&& apt-get install -fy -qq --no-install-recommends ca-certificates curl \
&& apt-get clean


ENTRYPOINT ["/bin/ping.sh"]
CMD [""]
114 changes: 114 additions & 0 deletions 65_image_rebasing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# README

Demonstrate building a simple nodejs app and changing the version without having to rebuild app.

## Reason

If we can rebase containers we can address CVEs without having to rebuild the full container.


TODO:

* It doesn't seem to work how I'd expect. I'd expect link=true to be recognised as a cached layer.

## Ubuntu Example

## Normal Build

NOTE: Would expect this to use the cache for `apt install`

```sh
# clean start
docker rmi $(docker images -aq) --force
docker builder prune --all -f

# build an initial image
docker buildx build -f Dockerfile.ping . -t $(basename $(pwd))_18_04 --build-arg IMAGE=ubuntu:18.04
docker run -it --rm $(basename $(pwd))_18_04

# switch ubuntu version (no caching)
docker buildx build -f Dockerfile.ping . -t $(basename $(pwd))_20_04 --build-arg IMAGE=ubuntu:20.04
docker run -it --rm $(basename $(pwd))_20_04

# switch ubuntu version (no caching)
docker buildx build -f Dockerfile.ping . -t $(basename $(pwd))_22_04 --build-arg IMAGE=ubuntu:22.04
docker run -it --rm $(basename $(pwd))_22_04
```

### First build

From a clean start both images should perform a full build

```sh
cd ./tool

docker rmi $(docker images -aq) --force
docker builder prune --all -f

export DOCKERFILE=Dockerfile

# no caching
docker buildx build -f $DOCKERFILE . -t $(basename $(pwd))_16_13_2 --build-arg BUILDIMAGE=node:16.13.2-bullseye --build-arg PRODUCTIONIMAGE=node:16.13.2-bullseye
docker run -it --rm $(basename $(pwd))_16_13_2

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd))_16_15 --build-arg BUILDIMAGE=node:16.15-bullseye --build-arg PRODUCTIONIMAGE=node:16.15-bullseye
docker run -it --rm $(basename $(pwd))_16_15
```

### Cached build

Once built rebuilding will use the cache for both.

```sh
docker buildx build -f $DOCKERFILE . -t $(basename $(pwd))_16_13_2 --build-arg BUILDIMAGE=node:16.13.2-bullseye --build-arg PRODUCTIONIMAGE=node:16.13.2-bullseye
docker run -it --rm $(basename $(pwd))_16_13_2

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd))_16_15 --build-arg BUILDIMAGE=node:16.15-bullseye --build-arg PRODUCTIONIMAGE=node:16.15-bullseye
docker run -it --rm $(basename $(pwd))_16_15

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd)) --build-arg BUILDIMAGE=node:16.13.2-bullseye --build-arg PRODUCTIONIMAGE=node:16.15-bullseye
docker run -it --rm $(basename $(pwd))

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd)) --build-arg BUILDIMAGE=node:16.15-bullseye --build-arg PRODUCTIONIMAGE=node:16.13.2-bullseye
docker run -it --rm $(basename $(pwd))
```

### Rebase Build

```sh
docker rmi $(docker images -aq) --force
docker builder prune --all -f

export DOCKERFILE=Dockerfile.rebase

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd))_16_13_2 --build-arg BUILDIMAGE=node:16.13.2-bullseye --build-arg PRODUCTIONIMAGE=node:16.13.2-bullseye
docker run -it --rm $(basename $(pwd))_16_13_2

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd))_16_15 --build-arg BUILDIMAGE=node:16.15-bullseye --build-arg PRODUCTIONIMAGE=node:16.15-bullseye
docker run -it --rm $(basename $(pwd))_16_15

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd)) --build-arg BUILDIMAGE=node:16.13.2-bullseye --build-arg PRODUCTIONIMAGE=node:16.15-bullseye
docker run -it --rm $(basename $(pwd))

docker buildx build -f $DOCKERFILE . -t $(basename $(pwd)) --build-arg BUILDIMAGE=node:16.15-bullseye --build-arg PRODUCTIONIMAGE=node:16.13.2-bullseye
docker run -it --rm $(basename $(pwd))
```

## Inspecting

```sh
docker image save -o ./$(basename $(pwd))_16_13_2.tar $(basename $(pwd))_16_13_2
mkdir -p ./out/$(basename $(pwd))_16_13_2 && tar -xvf ./$(basename $(pwd))_16_13_2.tar -C $_


docker image save -o ./$(basename $(pwd))_16_15.tar $(basename $(pwd))_16_15
mkdir -p ./out/$(basename $(pwd))_16_15 && tar -xvf ./$(basename $(pwd))_16_15.tar -C $_
```


## Resources

* Dockerfile frontend syntaxes [here](https://github.com/moby/buildkit/blob/dockerfile/1.4.0/frontend/dockerfile/docs/syntax.md#linked-copies-copy---link-add---link)
* Image rebase and improved remote cache support in new BuildKit [here](https://www.docker.com/blog/image-rebase-and-improved-remote-cache-support-in-new-buildkit/)
* Merge and Diff Ops [here](https://github.com/moby/buildkit/blob/v0.10.0/docs/merge%2Bdiff.md)
* Merge+Diff: Building DAGs More Efficiently and Elegantly [here](https://www.docker.com/blog/mergediff-building-dags-more-efficiently-and-elegantly/)
2 changes: 2 additions & 0 deletions 65_image_rebasing/tool/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
build
32 changes: 32 additions & 0 deletions 65_image_rebasing/tool/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"env": {
"browser": false,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2019,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"useTabs": false,
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120,
"tabWidth": 2
}]
}
}
5 changes: 5 additions & 0 deletions 65_image_rebasing/tool/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
out
build
docs
node_modules
*.tar
1 change: 1 addition & 0 deletions 65_image_rebasing/tool/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v16.13.2
8 changes: 8 additions & 0 deletions 65_image_rebasing/tool/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"useTabs": false,
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120,
"tabWidth": 2
}
43 changes: 43 additions & 0 deletions 65_image_rebasing/tool/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# syntax=docker/dockerfile:1.4
ARG BUILDIMAGE=node:latest
ARG PRODUCTIONIMAGE=node:latest

FROM $BUILDIMAGE AS BUILDER
LABEL dockerfile.baseimage="$IMAGE" dockerfile.description="tool" dockerfile.stage="BUILDER"

WORKDIR /scratch
COPY --link=false --chmod=755 <<EOF /usr/local/bin/node_capture_out.sh
#!/usr/bin/env bash
/usr/local/bin/node \$1 > \$2
EOF

COPY --link=false package.json package-lock.json ./
# https://docs.npmjs.com/cli/v7/commands/npm-ci
RUN npm ci

COPY tsconfig.json .prettierrc jest.config.js .eslintrc ./
COPY src ./src
COPY tests ./tests
#RUN npm run lint
RUN npm run test:coverage
RUN npm run build
RUN npm audit
RUN npm ci --only=production && npm cache clean --force
RUN /usr/local/bin/node_capture_out.sh ./build/src/index.js ./build/out.txt

FROM $PRODUCTIONIMAGE AS PRODUCTION
ARG DESCRIPTION="Test rebasing"
LABEL dockerfile.baseimage="$IMAGE" dockerfile.description="" dockerfile.stage="PRODUCTION"

COPY --link=false --chmod=755 <<EOF /usr/local/bin/node_cat.sh
#!/usr/bin/env bash
cat \$1
/usr/local/bin/node \$2
EOF

WORKDIR /work

COPY --from=BUILDER --link=false /scratch/node_modules ./node_modules
COPY --from=BUILDER --link=false /scratch/build ./

CMD ["/usr/local/bin/node_cat.sh", "/work/out.txt", "/work/src/index.js"]
43 changes: 43 additions & 0 deletions 65_image_rebasing/tool/Dockerfile.rebase
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# syntax=docker/dockerfile:1.4
ARG BUILDIMAGE=node:latest
ARG PRODUCTIONIMAGE=node:latest

FROM $BUILDIMAGE AS BUILDER
LABEL dockerfile.baseimage="$IMAGE" dockerfile.description="tool" dockerfile.stage="BUILDER"

WORKDIR /scratch
COPY --link=true --chmod=755 <<EOF /usr/local/bin/node_capture_out.sh
#!/usr/bin/env bash
/usr/local/bin/node \$1 > \$2
EOF

COPY --link=true package.json package-lock.json ./
# https://docs.npmjs.com/cli/v7/commands/npm-ci
RUN npm ci

COPY tsconfig.json .prettierrc jest.config.js .eslintrc ./
COPY src ./src
COPY tests ./tests
#RUN npm run lint
RUN npm run test:coverage
RUN npm run build
RUN npm audit
RUN npm ci --only=production && npm cache clean --force
RUN /usr/local/bin/node_capture_out.sh ./build/src/index.js ./build/out.txt

FROM $PRODUCTIONIMAGE AS PRODUCTION
ARG DESCRIPTION="Test rebasing"
LABEL dockerfile.baseimage="$IMAGE" dockerfile.description="" dockerfile.stage="PRODUCTION"

COPY --link=true --chmod=755 <<EOF /usr/local/bin/node_cat.sh
#!/usr/bin/env bash
cat \$1
/usr/local/bin/node \$2
EOF

WORKDIR /work

COPY --from=BUILDER --link=true /scratch/node_modules ./node_modules
COPY --from=BUILDER --link=true /scratch/build ./

CMD ["/usr/local/bin/node_cat.sh", "/work/out.txt", "/work/src/index.js"]
45 changes: 45 additions & 0 deletions 65_image_rebasing/tool/TEMPLATE_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# README

Demonstrates tool

## How to run

```sh
nvm use
npm install

# run targets
npm run start:dev
npm run test
npm run lint
```

## Debugging

Ensure that the sourcemap output is enabled.

```json
"sourceMap": true,
```

Open `vscode` in the correct directory.

```sh
# you must be in the code directory and not in the git root
cd ./xx_project_name
nvm install

# if the code is built it will use the version in here to debug
npm run clean
code .
```

1. Select `./src/index.ts` and put a breakpoint on the log line.
2. Click the debug icon. Click on create a `launch.json` and select `node.js` NOTE: If you select Run and Debug it will fail because the code is not built.
3. Click the debug icon again and then drop down the selection to select node.js and select a target of "start:dev"

The code should break on the breakpoint.

## Resources

* My basic typecript cmdline [01_basic_cmdline](https://github.com/chrisguest75/typescript_examples/tree/master/01_basic_cmdline)
8 changes: 8 additions & 0 deletions 65_image_rebasing/tool/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
transform: {
'^.+\\.ts?$': 'ts-jest',
},
testEnvironment: 'node',
testRegex: 'tests/.*\\.(test|spec)?\\.(ts|tsx|js)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
}
Loading