diff --git a/.github/workflows/images.yaml b/.github/workflows/images.yaml new file mode 100644 index 0000000..83ff135 --- /dev/null +++ b/.github/workflows/images.yaml @@ -0,0 +1,1043 @@ +name: images + +on: + push: + branches: + - main + pull_request: + types: [labeled, synchronize, opened] + workflow_dispatch: + inputs: + force_rebuild: + description: 'Force rebuild all images' + required: false + default: false + type: boolean + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'push')) + permissions: + packages: write + contents: read + attestations: write + id-token: write + steps: + - + name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - + name: Login to GitHub Container Registry + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: 1.22 + - + uses: imjasonh/setup-crane@6da1ae018866400525525ce74ff892880c099987 # v0.5 + - + run: | + set -x + TAG_KKV=7fa31f42731fc20a77988b478a3896732cc3dc88 + TAG_HOOK=92363d7d1771abc780e7559c778215be61f934d4 + TAG_KAFKA=2.5.1-kafka-server-start + TAG_ZOOKEEPER=2.5.1-zookeeper-server-start + TAG_INITUTILS=initutils-nonroot@sha256:8988aca5b34feabe8d7d4e368f74b2ede398f692c7e99a38b262a938d475812c + TAG_CURL=8.18.0 + TAG_BUSYBOX=1.37.0-glibc + TAG_TINYGO=0.32.0 + TAG_KAFKACAT=1.7.0@sha256:8658c1fa53632764bfcc3f9fad3dbf8b1d1a74f05244cd3a0ce9825e3344dc98 + crane cp docker.io/yolean/kafka-keyvalue:$TAG_KKV ghcr.io/yolean/kafka-keyvalue:$TAG_KKV + crane digest docker.io/yolean/kafka-hook:$TAG_HOOK + crane cp docker.io/yolean/kafka-hook:$TAG_HOOK ghcr.io/yolean/kafka-hook:$TAG_HOOK + crane cp solsson/kafka:$TAG_KAFKA ghcr.io/yolean/kafka:$TAG_KAFKA + crane cp solsson/kafka:$TAG_ZOOKEEPER ghcr.io/yolean/kafka:$TAG_ZOOKEEPER + crane cp solsson/kafka:$TAG_INITUTILS ghcr.io/yolean/kafka:$TAG_INITUTILS + crane cp solsson/minio-deduplication@sha256:af91c49ce795eb8406c6303d41fd874e231459bd8a5897a35bb12e1cc8f762a6 ghcr.io/yolean/minio-deduplication + crane cp curlimages/curl:$TAG_CURL ghcr.io/yolean/curl:$TAG_CURL + crane cp busybox:$TAG_BUSYBOX ghcr.io/yolean/busybox:$TAG_BUSYBOX + crane cp mailgun/kafka-pixy:0.17.0@sha256:0b5f4795c0b0d80729fa7415ec70ae4d411e152c6149656dddf01b18184792e0 ghcr.io/yolean/kafka-pixy:0.17.0 + crane cp tinygo/tinygo:$TAG_TINYGO ghcr.io/yolean/tinygo:$TAG_TINYGO + crane cp liftm/kafkacat:$TAG_KAFKACAT ghcr.io/yolean/kafkacat:$TAG_KAFKACAT + - + name: Set up QEMU + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + + ### build steps below are generated ### + - + name: Build and push docker-base latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: docker-base + tags: | + ghcr.io/yolean/docker-base:latest + ghcr.io/yolean/docker-base:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/docker-base:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/docker-base:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push builder-base latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: builder-base + tags: | + ghcr.io/yolean/builder-base:latest + ghcr.io/yolean/builder-base:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/builder-base:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/builder-base:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push builder-base-gcc latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: builder-base-gcc + tags: | + ghcr.io/yolean/builder-base-gcc:latest + ghcr.io/yolean/builder-base-gcc:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/builder-base-gcc:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/builder-base-gcc:_buildcache,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push builder-base-gcloud latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: builder-base-gcloud + tags: | + ghcr.io/yolean/builder-base-gcloud:latest + ghcr.io/yolean/builder-base-gcloud:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/builder-base-gcloud:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/builder-base-gcloud:_buildcache,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push builder-tooling latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: builder-tooling + tags: | + ghcr.io/yolean/builder-tooling:latest + ghcr.io/yolean/builder-tooling:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/builder-tooling:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/builder-tooling:_buildcache,mode=max + build-contexts: | + yolean/builder-base-gcc=docker-image://ghcr.io/yolean/builder-base-gcc + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push builder-node latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: builder-node + tags: | + ghcr.io/yolean/builder-node:latest + ghcr.io/yolean/builder-node:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/builder-node:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/builder-node:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push builder-quarkus latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: builder-quarkus + tags: | + ghcr.io/yolean/builder-quarkus:latest + ghcr.io/yolean/builder-quarkus:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/builder-quarkus:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/builder-quarkus:_buildcache,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + yolean/builder-base-gcc=docker-image://ghcr.io/yolean/builder-base-gcc + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push git-init latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: git-init + tags: | + ghcr.io/yolean/git-init:latest + ghcr.io/yolean/git-init:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/git-init:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/git-init:_buildcache,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push toil latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: toil + tags: | + ghcr.io/yolean/toil:latest + ghcr.io/yolean/toil:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/toil:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/toil:_buildcache,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push toil-network latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: toil-network + tags: | + ghcr.io/yolean/toil-network:latest + ghcr.io/yolean/toil-network:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/toil-network:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/toil-network:_buildcache,mode=max + build-contexts: | + yolean/toil=docker-image://ghcr.io/yolean/toil + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-distroless latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-distroless + tags: | + ghcr.io/yolean/node-distroless:latest + ghcr.io/yolean/node-distroless:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-distroless:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-distroless:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push headless-chrome latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: headless-chrome + tags: | + ghcr.io/yolean/headless-chrome:latest + ghcr.io/yolean/headless-chrome:${{ github.sha }} + platforms: linux/amd64 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/headless-chrome:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/headless-chrome:_buildcache,mode=max + build-contexts: | + yolean/docker-base=docker-image://ghcr.io/yolean/docker-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push git-http-readonly latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: git-http-readonly + tags: | + ghcr.io/yolean/git-http-readonly:latest + ghcr.io/yolean/git-http-readonly:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/git-http-readonly:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/git-http-readonly:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: runtime-quarkus + tags: | + ghcr.io/yolean/runtime-quarkus:latest + ghcr.io/yolean/runtime-quarkus:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-deno latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: runtime-deno + tags: | + ghcr.io/yolean/runtime-deno:latest + ghcr.io/yolean/runtime-deno:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-deno:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/runtime-deno:_buildcache,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push homedir root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: homedir + tags: | + ghcr.io/yolean/homedir:root + ghcr.io/yolean/homedir:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/homedir:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/homedir:_buildcache-root,mode=max + build-contexts: | + yolean/docker-base=docker-image://ghcr.io/yolean/docker-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push homedir latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/homedir + tags: | + ghcr.io/yolean/homedir:latest + ghcr.io/yolean/homedir:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/homedir:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/homedir:_buildcache,mode=max + build-contexts: | + yolean/homedir:root=docker-image://ghcr.io/yolean/homedir:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push java root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: java + tags: | + ghcr.io/yolean/java:root + ghcr.io/yolean/java:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/java:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/java:_buildcache-root,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push java latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/java + tags: | + ghcr.io/yolean/java:latest + ghcr.io/yolean/java:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/java:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/java:_buildcache,mode=max + build-contexts: | + yolean/java:root=docker-image://ghcr.io/yolean/java:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node + tags: | + ghcr.io/yolean/node:root + ghcr.io/yolean/node:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node:_buildcache-root,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node + tags: | + ghcr.io/yolean/node:latest + ghcr.io/yolean/node:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node:_buildcache,mode=max + build-contexts: | + yolean/node:root=docker-image://ghcr.io/yolean/node:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-kafka + tags: | + ghcr.io/yolean/node-kafka:root + ghcr.io/yolean/node-kafka:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka:_buildcache-root,mode=max + build-contexts: | + yolean/node:root=docker-image://ghcr.io/yolean/node:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-kafka + tags: | + ghcr.io/yolean/node-kafka:latest + ghcr.io/yolean/node-kafka:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka:_buildcache,mode=max + build-contexts: | + yolean/node-kafka:root=docker-image://ghcr.io/yolean/node-kafka:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka-cache root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-kafka-cache + tags: | + ghcr.io/yolean/node-kafka-cache:root + ghcr.io/yolean/node-kafka-cache:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka-cache:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka-cache:_buildcache-root,mode=max + build-contexts: | + yolean/node-kafka:root=docker-image://ghcr.io/yolean/node-kafka:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka-cache latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-kafka-cache + tags: | + ghcr.io/yolean/node-kafka-cache:latest + ghcr.io/yolean/node-kafka-cache:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka-cache:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka-cache:_buildcache,mode=max + build-contexts: | + yolean/node-kafka-cache:root=docker-image://ghcr.io/yolean/node-kafka-cache:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka-duckdb root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-kafka-duckdb + tags: | + ghcr.io/yolean/node-kafka-duckdb:root + ghcr.io/yolean/node-kafka-duckdb:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka-duckdb:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka-duckdb:_buildcache-root,mode=max + build-contexts: | + yolean/node-kafka:root=docker-image://ghcr.io/yolean/node-kafka:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka-duckdb latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-kafka-duckdb + tags: | + ghcr.io/yolean/node-kafka-duckdb:latest + ghcr.io/yolean/node-kafka-duckdb:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka-duckdb:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka-duckdb:_buildcache,mode=max + build-contexts: | + yolean/node-kafka-duckdb:root=docker-image://ghcr.io/yolean/node-kafka-duckdb:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-watchexec root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-watchexec + tags: | + ghcr.io/yolean/node-watchexec:root + ghcr.io/yolean/node-watchexec:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-watchexec:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-watchexec:_buildcache-root,mode=max + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-watchexec latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-watchexec + tags: | + ghcr.io/yolean/node-watchexec:latest + ghcr.io/yolean/node-watchexec:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-watchexec:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-watchexec:_buildcache,mode=max + build-contexts: | + yolean/node-watchexec:root=docker-image://ghcr.io/yolean/node-watchexec:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka-watch root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-kafka-watch + tags: | + ghcr.io/yolean/node-kafka-watch:root + ghcr.io/yolean/node-kafka-watch:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka-watch:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka-watch:_buildcache-root,mode=max + build-contexts: | + yolean/node-watchexec:root=docker-image://ghcr.io/yolean/node-watchexec:root + yolean/node-kafka:root=docker-image://ghcr.io/yolean/node-kafka:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-kafka-watch latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-kafka-watch + tags: | + ghcr.io/yolean/node-kafka-watch:latest + ghcr.io/yolean/node-kafka-watch:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-kafka-watch:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-kafka-watch:_buildcache,mode=max + build-contexts: | + yolean/node-kafka-watch:root=docker-image://ghcr.io/yolean/node-kafka-watch:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-gcloud root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-gcloud + tags: | + ghcr.io/yolean/node-gcloud:root + ghcr.io/yolean/node-gcloud:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-gcloud:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-gcloud:_buildcache-root,mode=max + build-contexts: | + yolean/node:root=docker-image://ghcr.io/yolean/node:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-gcloud latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-gcloud + tags: | + ghcr.io/yolean/node-gcloud:latest + ghcr.io/yolean/node-gcloud:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-gcloud:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-gcloud:_buildcache,mode=max + build-contexts: | + yolean/node-gcloud:root=docker-image://ghcr.io/yolean/node-gcloud:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-vitest root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: node-vitest + tags: | + ghcr.io/yolean/node-vitest:root + ghcr.io/yolean/node-vitest:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-vitest:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/node-vitest:_buildcache-root,mode=max + build-contexts: | + yolean/node:root=docker-image://ghcr.io/yolean/node:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push node-vitest latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/node-vitest + tags: | + ghcr.io/yolean/node-vitest:latest + ghcr.io/yolean/node-vitest:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/node-vitest:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/node-vitest:_buildcache,mode=max + build-contexts: | + yolean/node-vitest:root=docker-image://ghcr.io/yolean/node-vitest:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-ubuntu root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: runtime-quarkus-ubuntu + tags: | + ghcr.io/yolean/runtime-quarkus-ubuntu:root + ghcr.io/yolean/runtime-quarkus-ubuntu:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu:_buildcache-root,mode=max + build-contexts: | + yolean/docker-base=docker-image://ghcr.io/yolean/docker-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-ubuntu latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/runtime-quarkus-ubuntu + tags: | + ghcr.io/yolean/runtime-quarkus-ubuntu:latest + ghcr.io/yolean/runtime-quarkus-ubuntu:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu:_buildcache,mode=max + build-contexts: | + yolean/runtime-quarkus-ubuntu:root=docker-image://ghcr.io/yolean/runtime-quarkus-ubuntu:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-deno root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: runtime-quarkus-deno + tags: | + ghcr.io/yolean/runtime-quarkus-deno:root + ghcr.io/yolean/runtime-quarkus-deno:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-deno:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-deno:_buildcache-root,mode=max + build-contexts: | + yolean/runtime-deno=docker-image://ghcr.io/yolean/runtime-deno + yolean/runtime-quarkus-ubuntu=docker-image://ghcr.io/yolean/runtime-quarkus-ubuntu + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-deno latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/runtime-quarkus-deno + tags: | + ghcr.io/yolean/runtime-quarkus-deno:latest + ghcr.io/yolean/runtime-quarkus-deno:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-deno:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-deno:_buildcache,mode=max + build-contexts: | + yolean/runtime-quarkus-deno:root=docker-image://ghcr.io/yolean/runtime-quarkus-deno:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-ubuntu-jre root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: runtime-quarkus-ubuntu-jre + tags: | + ghcr.io/yolean/runtime-quarkus-ubuntu-jre:root + ghcr.io/yolean/runtime-quarkus-ubuntu-jre:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu-jre:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu-jre:_buildcache-root,mode=max + build-contexts: | + yolean/java:root=docker-image://ghcr.io/yolean/java:root + yolean/runtime-quarkus-ubuntu:root=docker-image://ghcr.io/yolean/runtime-quarkus-ubuntu:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-ubuntu-jre latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/runtime-quarkus-ubuntu-jre + tags: | + ghcr.io/yolean/runtime-quarkus-ubuntu-jre:latest + ghcr.io/yolean/runtime-quarkus-ubuntu-jre:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu-jre:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-ubuntu-jre:_buildcache,mode=max + build-contexts: | + yolean/runtime-quarkus-ubuntu-jre:root=docker-image://ghcr.io/yolean/runtime-quarkus-ubuntu-jre:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-dev root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: runtime-quarkus-dev + tags: | + ghcr.io/yolean/runtime-quarkus-dev:root + ghcr.io/yolean/runtime-quarkus-dev:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-dev:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-dev:_buildcache-root,mode=max + build-contexts: | + yolean/builder-quarkus=docker-image://ghcr.io/yolean/builder-quarkus + yolean/runtime-quarkus-ubuntu:root=docker-image://ghcr.io/yolean/runtime-quarkus-ubuntu:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push runtime-quarkus-dev latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/runtime-quarkus-dev + tags: | + ghcr.io/yolean/runtime-quarkus-dev:latest + ghcr.io/yolean/runtime-quarkus-dev:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/runtime-quarkus-dev:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/runtime-quarkus-dev:_buildcache,mode=max + build-contexts: | + yolean/runtime-quarkus-dev:root=docker-image://ghcr.io/yolean/runtime-quarkus-dev:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push toil-storage root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: toil-storage + tags: | + ghcr.io/yolean/toil-storage:root + ghcr.io/yolean/toil-storage:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/toil-storage:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/toil-storage:_buildcache-root,mode=max + build-contexts: | + yolean/toil=docker-image://ghcr.io/yolean/toil + yolean/docker-base=docker-image://ghcr.io/yolean/docker-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push toil-storage latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/toil-storage + tags: | + ghcr.io/yolean/toil-storage:latest + ghcr.io/yolean/toil-storage:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/toil-storage:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/toil-storage:_buildcache,mode=max + build-contexts: | + yolean/toil-storage:root=docker-image://ghcr.io/yolean/toil-storage:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push curl-yq root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: curl-yq + tags: | + ghcr.io/yolean/curl-yq:root + ghcr.io/yolean/curl-yq:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/curl-yq:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/curl-yq:_buildcache-root,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push curl-yq latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/curl-yq + tags: | + ghcr.io/yolean/curl-yq:latest + ghcr.io/yolean/curl-yq:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/curl-yq:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/curl-yq:_buildcache,mode=max + build-contexts: | + yolean/curl-yq:root=docker-image://ghcr.io/yolean/curl-yq:root + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push duckdb root + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: duckdb + tags: | + ghcr.io/yolean/duckdb:root + ghcr.io/yolean/duckdb:${{ github.sha }}-root + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/duckdb:_buildcache-root + cache-to: type=registry,ref=ghcr.io/yolean/duckdb:_buildcache-root,mode=max + build-contexts: | + yolean/builder-base=docker-image://ghcr.io/yolean/builder-base + yolean/homedir=docker-image://ghcr.io/yolean/homedir + continue-on-error: false + timeout-minutes: 45 + - + name: Build and push duckdb latest + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + env: + SOURCE_DATE_EPOCH: 0 + BUILDKIT_PROGRESS: plain + DOCKER_BUILDKIT: 1 + with: + context: to-nonroot/duckdb + tags: | + ghcr.io/yolean/duckdb:latest + ghcr.io/yolean/duckdb:${{ github.sha }} + platforms: linux/amd64,linux/arm64/v8 + push: true + cache-from: type=registry,ref=ghcr.io/yolean/duckdb:_buildcache + cache-to: type=registry,ref=ghcr.io/yolean/duckdb:_buildcache,mode=max + build-contexts: | + yolean/duckdb:root=docker-image://ghcr.io/yolean/duckdb:root + continue-on-error: false + timeout-minutes: 45 diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index ffb1b3c..0000000 --- a/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM --platform=$TARGETPLATFORM ubuntu:20.04@sha256:669e010b58baf5beb2836b253c1fd5768333f0d1dbcb834f7c07a4dc93f474be diff --git a/README.md b/README.md index 37f359e..1943586 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,34 @@ # docker-base -https://hub.docker.com/r/yolean/ +Container images at https://ghcr.io/yolean/ -Note that `Dockerfile`s typically result in 'USER root` -but that [autobuilds](./hooks/build) append a [nonroot](./nonroot-footer.Dockerfile) step. +`Dockerfile`s build as `USER root`. +For each image in the TONONROOT list, a `:latest` tag is produced by appending +[nonroot-footer.Dockerfile](./nonroot-footer.Dockerfile) which switches to UID 65532. -Autobuilds are at https://hub.docker.com/r/solsson/y-docker-base -but push with git ref tags to https://hub.docker.com/r/yolean/. +## Build locally -## build locally +Build a single image and its dependencies: -``` -# Nopush is broken for multi-arch builds until we find a way to depend on local builds -# NOPUSH=true ./hooks/build -REGISTRY=docker.io ./hooks/build -``` + ./build.sh node-kafka + +Build multiple images: + + ./build.sh duckdb headless-chrome + +Build everything: + + ./build.sh --all + +Images are tagged as `yolean/{name}:{tag}` locally. + +## CI + +The workflow at `.github/workflows/images.yaml` is generated by `test.sh`. +After editing image lists in `images.sh` or build step templates in `test.sh`, +regenerate with: + + ./test.sh + +The workflow uses registry-based BuildKit cache (`type=registry`) stored +as `ghcr.io/yolean/{name}:_buildcache*` manifests. diff --git a/blobs/Dockerfile b/blobs/Dockerfile new file mode 100644 index 0000000..220f169 --- /dev/null +++ b/blobs/Dockerfile @@ -0,0 +1,121 @@ +FROM --platform=$TARGETPLATFORM alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b + +RUN set -eux; \ + apk add --no-cache \ + bzip2 \ + coreutils \ + curl \ + gcc \ + gnupg \ + linux-headers \ + make \ + musl-dev \ + patch \ + tzdata \ +# busybox's tar ironically does not maintain mtime of directories correctly (which we need for SOURCE_DATE_EPOCH / reproducibility) + tar \ + ; + +# pub 1024D/ACC9965B 2006-12-12 +# Key fingerprint = C9E9 416F 76E6 10DB D09D 040F 47B7 0C55 ACC9 965B +# uid Denis Vlasenko +# sub 1024g/2C766641 2006-12-12 +RUN mkdir -p ~/.gnupg && gpg --batch --keyserver keyserver.ubuntu.com --recv-keys C9E9416F76E610DBD09D040F47B70C55ACC9965B + +# https://busybox.net: 19 May 2023 +ENV BUSYBOX_VERSION 1.36.1 +ENV BUSYBOX_SHA256 b8cc24c9574d809e7279c3be349795c5d5ceb6fdf19ca709f80cde50e47de314 + +RUN set -eux; \ + tarball="busybox-${BUSYBOX_VERSION}.tar.bz2"; \ + curl -fL -o busybox.tar.bz2.sig "https://busybox.net/downloads/$tarball.sig"; \ + curl -fL -o busybox.tar.bz2 "https://busybox.net/downloads/$tarball"; \ + echo "$BUSYBOX_SHA256 *busybox.tar.bz2" | sha256sum -c -; \ + gpg --batch --verify busybox.tar.bz2.sig busybox.tar.bz2; \ +# Alpine... 😅 + mkdir -p /usr/src; \ + tar -xf busybox.tar.bz2 -C /usr/src "busybox-$BUSYBOX_VERSION"; \ + mv "/usr/src/busybox-$BUSYBOX_VERSION" /usr/src/busybox; \ + rm busybox.tar.bz2*; \ + \ +# save the tarball's filesystem timestamp persistently (in case building busybox modifies it) so we can use it for reproducible rootfs later + SOURCE_DATE_EPOCH="$(stat -c '%Y' /usr/src/busybox | tee /usr/src/busybox.SOURCE_DATE_EPOCH)"; \ + date="$(date -d "@$SOURCE_DATE_EPOCH" '+%Y%m%d%H%M.%S')"; \ + touch -t "$date" /usr/src/busybox.SOURCE_DATE_EPOCH; \ +# for logging validation/edification + date --date "@$SOURCE_DATE_EPOCH" --rfc-2822 + +WORKDIR /usr/src/busybox + +RUN set -eux; \ + \ +# build date/time gets embedded in the BusyBox binary -- SOURCE_DATE_EPOCH should override that + SOURCE_DATE_EPOCH="$(cat /usr/src/busybox.SOURCE_DATE_EPOCH)"; \ + export SOURCE_DATE_EPOCH; \ +# (has to be set in the config stage for making sure "AUTOCONF_TIMESTAMP" is embedded correctly) + \ + setConfs=' \ + CONFIG_LS=y \ + CONFIG_CP=y \ + CONFIG_AR=y \ + CONFIG_FEATURE_AR_CREATE=y \ + CONFIG_FEATURE_AR_LONG_FILENAMES=y \ +# CONFIG_LAST_SUPPORTED_WCHAR: see https://github.com/docker-library/busybox/issues/13 (UTF-8 input) + CONFIG_LAST_SUPPORTED_WCHAR=0 \ + CONFIG_STATIC=y \ + '; \ + \ + unsetConfs=' \ + CONFIG_FEATURE_SYNC_FANCY \ + \ +# see https://wiki.musl-libc.org/wiki/Building_Busybox + CONFIG_FEATURE_HAVE_RPC \ + CONFIG_FEATURE_INETD_RPC \ + CONFIG_FEATURE_UTMP \ + CONFIG_FEATURE_WTMP \ + '; \ + \ + make allnoconfig; \ + \ + for conf in $unsetConfs; do \ + sed -i \ + -e "s!^$conf=.*\$!# $conf is not set!" \ + .config; \ + done; \ + \ + for confV in $setConfs; do \ + conf="${confV%=*}"; \ + sed -i \ + -e "s!^$conf=.*\$!$confV!" \ + -e "s!^# $conf is not set\$!$confV!" \ + .config; \ + if ! grep -q "^$confV\$" .config; then \ + echo "$confV" >> .config; \ + fi; \ + done; + +RUN set -eux; \ + nproc="$(nproc)"; \ + make -j "$nproc" busybox; + +FROM --platform=$TARGETPLATFORM alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b as bin + +WORKDIR /target + +COPY --from=0 /usr/src/busybox/busybox ./busybox + +RUN set -eux; \ + ln -s ./busybox ./cp; \ + ln -s ./busybox ./ls; \ + ls -lh . + +FROM --platform=$TARGETPLATFORM scratch + +USER 65532:65534 + +COPY --from=bin /target /bin + +WORKDIR /blobs +ENTRYPOINT [ "/bin/cp" ] +# our binary has no help section +CMD [ "requires-cp-args", "/tmp/to/somewhere" ] diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..038c704 --- /dev/null +++ b/build.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +[ -z "$DEBUG" ] || set -x +set -eo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" +source "$SCRIPT_DIR/images.sh" + +[ -n "$TAG" ] || TAG="latest" + +usage() { + echo "Usage: $0 [--all] [image ...]" + echo + echo "Build images locally (host arch only) with dependency resolution." + echo + echo "Examples:" + echo " $0 node-kafka # builds node + node-kafka (with deps)" + echo " $0 duckdb headless-chrome # builds multiple targets" + echo " $0 --all # builds everything" + exit 1 +} + +if [ $# -eq 0 ]; then + usage +fi + +REQUESTED="" +if [ "$1" = "--all" ]; then + REQUESTED="$MULTIARCH_NONROOT $MULTIARCH_TONONROOT" +else + REQUESTED="$@" +fi + +# Check that all requested images exist +for IMG in $REQUESTED; do + if [ ! -d "$IMG" ]; then + echo "Error: no directory $IMG/ found" >&2 + exit 1 + fi +done + +# Resolve build order (includes transitive deps) +BUILD_ORDER=$(resolve_build_order $REQUESTED) + +echo "Build order:" +for IMG in $BUILD_ORDER; do + echo " $IMG" +done +echo + +# Generate nonroot Dockerfiles +generate_nonroot_dockerfiles + +is_tononroot() { + local IMG=$1 + for T in $MULTIARCH_TONONROOT; do + [ "$T" = "$IMG" ] && return 0 + done + return 1 +} + +build_image() { + local CONTEXT=$1 + local NAME=$2 + local IMG_TAG=$3 + + local DEPENDENCIES + DEPENDENCIES=$(get_yolean_deps "$CONTEXT/Dockerfile") + + local BUILD_CONTEXT_ARGS="" + for DEP_FULL in $DEPENDENCIES; do + BUILD_CONTEXT_ARGS="$BUILD_CONTEXT_ARGS --build-context $DEP_FULL=docker-image://$DEP_FULL" + done + + echo "==> Building yolean/$NAME:$IMG_TAG from $CONTEXT/" + docker buildx build \ + --load \ + $BUILD_CONTEXT_ARGS \ + --tag "yolean/$NAME:$IMG_TAG" \ + "$CONTEXT" +} + +for IMG in $BUILD_ORDER; do + if is_tononroot "$IMG"; then + build_image "$IMG" "$IMG" root + build_image "to-nonroot/$IMG" "$IMG" latest + else + build_image "$IMG" "$IMG" latest + fi +done + +echo +echo "Done. Built images:" +for IMG in $BUILD_ORDER; do + if is_tononroot "$IMG"; then + echo " yolean/$IMG:root" + echo " yolean/$IMG:latest" + else + echo " yolean/$IMG:latest" + fi +done diff --git a/builder-base-gcc/Dockerfile b/builder-base-gcc/Dockerfile index 7b9b14d..11ec05e 100644 --- a/builder-base-gcc/Dockerfile +++ b/builder-base-gcc/Dockerfile @@ -5,7 +5,7 @@ FROM --platform=$TARGETPLATFORM yolean/builder-base USER root RUN set -ex; \ export DEBIAN_FRONTEND=noninteractive; \ - runDeps='libsnappy1v5 libsnappy-jni liblz4-1 liblz4-jni libzstd1 libfreetype6'; \ + runDeps='libsnappy1v5 libsnappy-jni liblz4-1 liblz4-jni libzstd1 libfreetype6 fontconfig'; \ buildDeps='gcc g++ libc-dev make zlib1g-dev libsnappy-dev liblz4-dev libzstd-dev libfreetype6-dev'; \ apt-get update && apt-get install -y $runDeps $buildDeps --no-install-recommends; \ \ diff --git a/builder-base-gcloud/Dockerfile b/builder-base-gcloud/Dockerfile new file mode 100644 index 0000000..1b5d1e8 --- /dev/null +++ b/builder-base-gcloud/Dockerfile @@ -0,0 +1,30 @@ +FROM --platform=$TARGETPLATFORM google/cloud-sdk:slim as cloud-sdk + +RUN ls -l /usr/lib/google-cloud-sdk \ + && ls -l /usr/lib/google-cloud-sdk/platform \ + && cd /usr/lib/google-cloud-sdk && rm -rf \ + platform/anthoscli_licenses \ + platform/bq \ + platform/bundledpythonunix \ + platform/ext-runtime \ + lib/googlecloudsdk/appengine + +FROM --platform=$TARGETPLATFORM yolean/builder-base + +USER root +RUN set -ex; \ + export DEBIAN_FRONTEND=noninteractive; \ + runDeps='python3 rsync openssh-client'; \ + \ + apt-get update && apt-get install -y --no-install-recommends $runDeps $buildDeps; \ + \ + rm -rf /var/lib/apt/lists; \ + rm -rf /var/log/dpkg.log /var/log/alternatives.log /var/log/apt /root/.gnupg +USER nonroot:nogroup + +COPY --from=cloud-sdk /usr/lib/google-cloud-sdk /usr/lib/google-cloud-sdk +COPY --from=cloud-sdk /root/.config/gcloud /home/nonroot/.config/gcloud + +ENV PATH="${PATH}:/usr/lib/google-cloud-sdk/bin" + +RUN gsutil version diff --git a/builder-base/Dockerfile b/builder-base/Dockerfile index 115f552..f812f3d 100644 --- a/builder-base/Dockerfile +++ b/builder-base/Dockerfile @@ -1,4 +1,5 @@ -FROM --platform=$TARGETPLATFORM docker.io/yolean/ystack-runner:10011395e6d587067fe919becbd8697f327c9dcb@sha256:0d3450f89d51510eaf63b60b8bcd9b4708d1ac3bd378dad8f45abaf964fca036 as base +FROM --platform=$TARGETPLATFORM ghcr.io/yolean/ystack-runner:f0e7bc11d699cdcc84bd4c216b550391100d69d6@sha256:3ca5b7672a458d7b80caeac5bf47ca47087515a4315004c89536a4fa48a0706a \ + as base FROM base as nonroot USER root @@ -8,10 +9,7 @@ RUN set -e; \ mkdir workspace && chgrp nogroup workspace && chmod g+w workspace; \ mkdir -p usr/local/src/ystack/bin && chown nonroot usr/local/src/ystack/bin; \ mkdir -p home/nonroot/.cache/ystack-bin; \ - npm config set cache /home/nonroot/.cache/npm; \ - npm config list; \ mkdir -p home/nonroot/.cache/npm; \ - mv $HOME/.npmrc home/nonroot/.npmrc; \ chown root home; chown -R nonroot:nogroup home/nonroot FROM base @@ -20,4 +18,6 @@ WORKDIR /workspace ENV \ CI=true \ - YSTACK_BIN_DOWNLOAD_CACHE=/home/nonroot/.cache/ystack-bin + YSTACK_BIN_DOWNLOAD_CACHE=/home/nonroot/.cache/ystack-bin \ + npm_config_update_notifier=false + diff --git a/builder-java/Dockerfile b/builder-java/Dockerfile deleted file mode 100644 index fe4d61d..0000000 --- a/builder-java/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM --platform=$TARGETPLATFORM yolean/builder-base -ARG TARGETARCH - -RUN echo "TARGETARCH $TARGETARCH" && false - -USER root - -RUN runtimeDeps='default-jdk-headless maven unzip' \ - && set -ex \ - && export DEBIAN_FRONTEND=noninteractive \ - && apt-get update && apt-get install -y $runtimeDeps $buildDeps --no-install-recommends \ - && rm -rf /var/log/apt /var/log/dpkg.log /var/log/alternatives.log - -RUN set -e; \ - mkdir /opt/protoc; \ - cd /opt/protoc; \ - curl -sL -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.12.3/protoc-3.12.3-linux-x86_64.zip; \ - unzip protoc.zip; \ - ln -s /opt/protobuf/bin/protoc /usr/local/bin/protoc - -ENV GRADLE_VERSION=6.5.1 - -RUN set -e; \ - cd /opt; \ - curl -sL -o gradle.zip https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-all.zip; \ - unzip gradle.zip; \ - ln -s /opt/gradle-$GRADLE_VERSION/bin/gradle /usr/local/bin/gradle - -USER nonroot:nogroup diff --git a/builder-quarkus-polyglot/Dockerfile b/builder-quarkus-polyglot/Dockerfile deleted file mode 100644 index f232277..0000000 --- a/builder-quarkus-polyglot/Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -FROM maven:3.8.4-eclipse-temurin-11@sha256:3aa27fd4c83c86357477daf9ac23dc67708b567c70047fa73f57fb919563ec6d as maven - -FROM yolean/builder-base - -USER root - -RUN set -ex; \ - export DEBIAN_FRONTEND=noninteractive; \ - runDeps='libsnappy1v5 libsnappy-jni liblz4-1 liblz4-jni libzstd1'; \ - buildDeps='build-essential zlib1g-dev libsnappy-dev liblz4-dev libzstd-dev'; \ - apt-get update && apt-get install -y $runDeps $buildDeps --no-install-recommends; \ - \ - # Keeping build deps for native compile - #apt-get purge -y --auto-remove $buildDeps; \ - rm -rf /var/lib/apt/lists; \ - rm -rf /var/log/dpkg.log /var/log/alternatives.log /var/log/apt /root/.gnupg - -ARG graalvm_version=21.1.0 -ARG graalvm_variant=java11 -ARG graalvm_releases=graalvm/graalvm-ce-builds -ARG graalvm_build= -ENV graalvm_dist=https://github.com/${graalvm_releases}/releases/download/vm-${graalvm_version}${graalvm_build}/graalvm-ce-${graalvm_variant}-linux-amd64-${graalvm_version}.tar.gz - -RUN set -ex; \ - mkdir /opt/graalvm; \ - curl -sLS $graalvm_dist | \ - tar xzf - --strip-components=1 -C /opt/graalvm; \ - rm /opt/graalvm/lib/src.zip; \ - rm -r /opt/graalvm/lib/visualvm - -RUN [ "$PATH" = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/src/ystack/bin" ] -ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/src/ystack/bin:/opt/graalvm/bin - -RUN gu install native-image - -ENV CI=true - -COPY --from=maven /usr/share/maven /usr/share/maven -RUN ln -s /usr/share/maven/bin/mvn /usr/bin/mvn -ENV MAVEN_HOME=/usr/share/maven -ENV MAVEN_CONFIG=/home/nonroot/.m2 - -USER nonroot:nogroup diff --git a/builder-quarkus/Dockerfile b/builder-quarkus/Dockerfile index d311c7d..a7b7131 100644 --- a/builder-quarkus/Dockerfile +++ b/builder-quarkus/Dockerfile @@ -1,15 +1,16 @@ -FROM --platform=$TARGETPLATFORM maven:3.8.4-eclipse-temurin-11@sha256:ac478e512f8665c3fd5f853ea89e68a455a826996b4ed00712dfc9810a2b1f2d as maven +FROM --platform=$TARGETPLATFORM maven:3.9.12-eclipse-temurin-25@sha256:b8187abd63cd4ee8c596aae910ce698a10db6d27ad5be08d574f3b928526724e as maven + +FROM docker:29.3.1-cli@sha256:70303ed0d265aee7bf4be0ddffe20b0b6e4f69ffa125e2a20cbb3718b99688db AS dockerclient -# FROM quay.io/quarkus/ubi-quarkus-mandrel:22.0.0.2-Final-java11@sha256:b0a6375752732eb679dcf5e491537dca7d9403471d7593610d571116bf805a19 as mandrel FROM --platform=$TARGETPLATFORM yolean/builder-base as mandrel ARG TARGETARCH -ARG JAVA_VERSION=java11 -ARG MANDREL_VERSION=22.0.0.2-Final +ARG MANDREL_JAVA_VERSION=java25 +ARG MANDREL_VERSION=25.0.2.0-Final RUN set -ex; \ ARCH=$TARGETARCH; \ [ "$TARGETARCH" != "arm64" ] || ARCH=aarch64; \ - MANDREL_DIST=mandrel-$JAVA_VERSION-linux-$ARCH-$MANDREL_VERSION.tar.gz; \ + MANDREL_DIST=mandrel-$MANDREL_JAVA_VERSION-linux-$ARCH-$MANDREL_VERSION.tar.gz; \ MANDREL_DIST_URL=https://github.com/graalvm/mandrel/releases/download/mandrel-$MANDREL_VERSION/$MANDREL_DIST; \ MANDREL_DIST_SHA256=$(curl -sLSf "$MANDREL_DIST_URL.sha256"); \ [ -n "$MANDREL_DIST_SHA256" ]; \ @@ -17,7 +18,7 @@ RUN set -ex; \ curl -o $MANDREL_DIST -sLSf $MANDREL_DIST_URL; \ echo "$MANDREL_DIST_SHA256" | sha256sum -c -; \ mkdir ./mandrel; \ - cat $MANDREL_DIST | tar xzf - --strip-components=1 -C ./mandrel + tar xzf $MANDREL_DIST --strip-components=1 -C ./mandrel RUN rm -v /home/nonroot/mandrel/lib/src.zip @@ -25,13 +26,14 @@ FROM --platform=$TARGETPLATFORM yolean/builder-base-gcc COPY --from=maven /usr/share/maven /usr/share/maven COPY --from=mandrel /home/nonroot/mandrel /opt/mandrel +COPY --from=dockerclient /usr/local/bin/* /usr/local/bin/ +COPY --from=dockerclient /usr/local/libexec/docker /usr/local/libexec/docker COPY --chown=nonroot:nogroup y-build-* /usr/local/bin/ -RUN [ "$PATH" = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/src/ystack/bin" ] ENV \ CI=true \ GRAALVM_HOME=/opt/mandrel \ JAVA_HOME=/opt/mandrel \ MAVEN_HOME=/usr/share/maven \ MAVEN_CONFIG=/home/nonroot/.m2 \ - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/src/ystack/bin:/usr/share/maven/bin:/opt/mandrel/bin + PATH="${PATH}:/usr/share/maven/bin:/opt/mandrel/bin" diff --git a/builder-tooling/Dockerfile b/builder-tooling/Dockerfile index 10bf12e..1d70f09 100644 --- a/builder-tooling/Dockerfile +++ b/builder-tooling/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$TARGETPLATFORM golang:1.17.7-bullseye@sha256:f89b6b9ec155b8c5e04d18fc23f6cb915e17ad8fe3f1cf7e9c7b7122a6c509a9 as golang +FROM --platform=$TARGETPLATFORM golang:1.26.1-trixie@sha256:ab8c4944b04c6f97c2b5bffce471b7f3d55f2228badc55eae6cce87596d5710b as golang FROM --platform=$TARGETPLATFORM yolean/builder-base-gcc diff --git a/curl-yq/Dockerfile b/curl-yq/Dockerfile new file mode 100644 index 0000000..03724fe --- /dev/null +++ b/curl-yq/Dockerfile @@ -0,0 +1,14 @@ +ARG TAG_CURL=8.14.1 + +FROM --platform=$TARGETPLATFORM yolean/builder-base as ystack-runner + +FROM --platform=$TARGETPLATFORM ghcr.io/yolean/curl:${TAG_CURL} + +COPY --from=ystack-runner /usr/local/src/ystack/bin/y-yq-v* /usr/bin/yq + +# bypass entrypoint.sh +ENTRYPOINT ["/usr/bin/curl"] + +# so we get root/nonroot build +USER root +RUN apk add --no-cache bash diff --git a/docker-base/Dockerfile b/docker-base/Dockerfile new file mode 100644 index 0000000..0737726 --- /dev/null +++ b/docker-base/Dockerfile @@ -0,0 +1 @@ +FROM --platform=$TARGETPLATFORM ubuntu:26.04@sha256:f3d28607ddd78734bb7f71f117f3c6706c666b8b76cbff7c9ff6e5718d46ff64 diff --git a/duckdb/Dockerfile b/duckdb/Dockerfile new file mode 100644 index 0000000..2cf9fc0 --- /dev/null +++ b/duckdb/Dockerfile @@ -0,0 +1,38 @@ +FROM --platform=$BUILDPLATFORM yolean/builder-base +ARG TARGETARCH +ARG DUCKDB_TAG=v1.5.3 + +# Prebuilt, official DuckDB CLI plus the prebuilt, signed extensions we bundle for +# offline use. Nothing is compiled here, so the build is fast and cross-arch safe: +# the target-arch binary and extensions are only downloaded, never executed. +# httpfs — https:// and Google Cloud Storage gs:// access (also S3); core +# nanoarrow — Apache Arrow IPC (the "arrow" alias); community +RUN set -ex; \ + ARCH=$TARGETARCH; \ + PLATFORM=linux_${ARCH}; \ + EXT_DIR=/tmp/.duckdb/extensions/${DUCKDB_TAG}/${PLATFORM}; \ + mkdir -p $EXT_DIR; \ + curl -fL https://github.com/duckdb/duckdb/releases/download/${DUCKDB_TAG}/duckdb_cli-linux-${ARCH}.gz \ + | gunzip > /tmp/duckdb; \ + chmod +x /tmp/duckdb; \ + sha256sum /tmp/duckdb; \ + curl -fL https://extensions.duckdb.org/${DUCKDB_TAG}/${PLATFORM}/httpfs.duckdb_extension.gz \ + | gunzip > $EXT_DIR/httpfs.duckdb_extension; \ + curl -fL https://community-extensions.duckdb.org/${DUCKDB_TAG}/${PLATFORM}/nanoarrow.duckdb_extension.gz \ + | gunzip > $EXT_DIR/nanoarrow.duckdb_extension; \ + ls -l $EXT_DIR + +# https://github.com/duckdb/duckdb-ui/discussions/84 +RUN echo '#!/bin/sh' > /tmp/xdg-open && chmod u+x /tmp/xdg-open + +FROM --platform=$TARGETPLATFORM yolean/homedir + +# duckdb resolves its extension directory from $HOME; set it explicitly so the bundled +# extensions are found whether the image runs as root or (via to-nonroot) as nonroot. +ENV HOME=/home/nonroot + +COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=0 /tmp/duckdb /tmp/xdg-open /usr/local/bin/ +COPY --from=0 --chown=65532:65534 /tmp/.duckdb /home/nonroot/.duckdb + +ENTRYPOINT ["/usr/local/bin/duckdb"] diff --git a/git-http-readonly/Dockerfile b/git-http-readonly/Dockerfile index 9337047..c8683ee 100644 --- a/git-http-readonly/Dockerfile +++ b/git-http-readonly/Dockerfile @@ -1,4 +1,4 @@ -FROM httpd:2.4.52-bullseye@sha256:0954cc1af252d824860b2c5dc0a10720af2b7a3d3435581ca788dff8480c7b32 +FROM --platform=$TARGETPLATFORM httpd:2.4.58-bookworm@sha256:ba846154ade27292d216cce2d21f1c7e589f3b66a4a643bff0cdd348efd17aa3 RUN set -ex; \ export DEBIAN_FRONTEND=noninteractive; \ @@ -10,6 +10,7 @@ RUN set -ex; \ rm -rf /var/log/dpkg.log /var/log/alternatives.log /var/log/apt /root/.gnupg COPY httpd.conf conf/httpd.conf +COPY extra/* conf/extra/ VOLUME /srv/git diff --git a/git-http-readonly/extra/httpd-mpm.conf b/git-http-readonly/extra/httpd-mpm.conf new file mode 100644 index 0000000..2d35863 --- /dev/null +++ b/git-http-readonly/extra/httpd-mpm.conf @@ -0,0 +1,119 @@ +# +# Server-Pool Management (MPM specific) +# + +# +# PidFile: The file in which the server should record its process +# identification number when it starts. +# +# Note that this is the default PidFile for most MPMs. +# + + PidFile "logs/httpd.pid" + + +# +# Only one of the below sections will be relevant on your +# installed httpd. Use "apachectl -l" to find out the +# active mpm. +# + +# prefork MPM +# StartServers: number of server processes to start +# MinSpareServers: minimum number of server processes which are kept spare +# MaxSpareServers: maximum number of server processes which are kept spare +# MaxRequestWorkers: maximum number of server processes allowed to start +# MaxConnectionsPerChild: maximum number of connections a server process serves +# before terminating + + StartServers 1 + MinSpareServers 1 + MaxSpareServers 1 + MaxRequestWorkers 10 + MaxConnectionsPerChild 0 + + +# worker MPM +# StartServers: initial number of server processes to start +# MinSpareThreads: minimum number of worker threads which are kept spare +# MaxSpareThreads: maximum number of worker threads which are kept spare +# ThreadsPerChild: constant number of worker threads in each server process +# MaxRequestWorkers: maximum number of worker threads +# MaxConnectionsPerChild: maximum number of connections a server process serves +# before terminating + + StartServers 3 + MinSpareThreads 75 + MaxSpareThreads 250 + ThreadsPerChild 25 + MaxRequestWorkers 400 + MaxConnectionsPerChild 0 + + +# event MPM +# StartServers: initial number of server processes to start +# MinSpareThreads: minimum number of worker threads which are kept spare +# MaxSpareThreads: maximum number of worker threads which are kept spare +# ThreadsPerChild: constant number of worker threads in each server process +# MaxRequestWorkers: maximum number of worker threads +# MaxConnectionsPerChild: maximum number of connections a server process serves +# before terminating + + StartServers 3 + MinSpareThreads 75 + MaxSpareThreads 250 + ThreadsPerChild 25 + MaxRequestWorkers 400 + MaxConnectionsPerChild 0 + + +# NetWare MPM +# ThreadStackSize: Stack size allocated for each worker thread +# StartThreads: Number of worker threads launched at server startup +# MinSpareThreads: Minimum number of idle threads, to handle request spikes +# MaxSpareThreads: Maximum number of idle threads +# MaxThreads: Maximum number of worker threads alive at the same time +# MaxConnectionsPerChild: Maximum number of connections a thread serves. It +# is recommended that the default value of 0 be set +# for this directive on NetWare. This will allow the +# thread to continue to service requests indefinitely. + + ThreadStackSize 65536 + StartThreads 250 + MinSpareThreads 25 + MaxSpareThreads 250 + MaxThreads 1000 + MaxConnectionsPerChild 0 + + +# OS/2 MPM +# StartServers: Number of server processes to maintain +# MinSpareThreads: Minimum number of idle threads per process, +# to handle request spikes +# MaxSpareThreads: Maximum number of idle threads per process +# MaxConnectionsPerChild: Maximum number of connections per server process + + StartServers 2 + MinSpareThreads 5 + MaxSpareThreads 10 + MaxConnectionsPerChild 0 + + +# WinNT MPM +# ThreadsPerChild: constant number of worker threads in the server process +# MaxConnectionsPerChild: maximum number of connections a server process serves + + ThreadsPerChild 150 + MaxConnectionsPerChild 0 + + +# The maximum number of free Kbytes that every allocator is allowed +# to hold without calling free(). In threaded MPMs, every thread has its own +# allocator. When not set, or when set to zero, the threshold will be set to +# unlimited. + + MaxMemFree 2048 + + + MaxMemFree 100 + \ No newline at end of file diff --git a/git-http-readonly/httpd.conf b/git-http-readonly/httpd.conf index d141005..5a78581 100644 --- a/git-http-readonly/httpd.conf +++ b/git-http-readonly/httpd.conf @@ -216,7 +216,7 @@ LogLevel warn # Server-pool management (MPM specific) -#Include conf/extra/httpd-mpm.conf +Include conf/extra/httpd-mpm.conf # Real-time info on requests and configuration #Include conf/extra/httpd-info.conf diff --git a/git-init/Dockerfile b/git-init/Dockerfile index 69ef8c4..3a34edd 100644 --- a/git-init/Dockerfile +++ b/git-init/Dockerfile @@ -1,6 +1,14 @@ -FROM gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.32.1@sha256:02ffc8b09e575d1ee8cfcc5a82263cea56f3f5fe04ea1082bb06d98b5b83d5e4 +FROM --platform=$TARGETPLATFORM yolean/builder-base -RUN echo 'nonroot:x:65532:65534:nobody:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ - mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +COPY git-init-tekton-compatible.sh /usr/local/bin/ -USER nonroot:nobody +ENTRYPOINT [ "git-init-tekton-compatible.sh" ] + +ENV \ + GIT_HTTP_LOW_SPEED_LIMIT=1000 \ + GIT_HTTP_LOW_SPEED_TIME=60 + +RUN set -ex; \ + git config --global init.defaultBranch main; \ + git config --global advice.detachedHead false; \ + true diff --git a/git-init/git-init-tekton-compatible.sh b/git-init/git-init-tekton-compatible.sh new file mode 100755 index 0000000..d538e24 --- /dev/null +++ b/git-init/git-init-tekton-compatible.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +[ -z "$DEBUG" ] || set -x +set -eo pipefail + +# Replaces Tekton's git-init which lacks retries: https://github.com/tektoncd/pipeline/issues/3515 + +# typical use: + # args: + # - -url + # - $(params.giturl) + # - -revision + # - $(params.revision) + # - -path + # - /workspace/source + # - -submodules=false + # - -depth=1 + +[ $# != 8 ] && echo "Expected 8 args, got $# for $0: $@" && exit 1 +[ "$1" != "-url" ] && echo "First arg should be -url, was $1" && exit 1 +[ "$3" != "-revision" ] && echo "Third arg should be -revision, was $3" && exit 1 +[ "$5" != "-path" ] && echo "Fifth arg should be -path, was $5" && exit 1 +[ "$7" != "-submodules=false" ] && echo "Seventh arg should be -submodules=false, was $7" && exit 1 +[ "$8" != "-depth=1" ] && echo "Eighth arg should be -depth=1, was $8" && exit 1 + +URL="$2" +[ -z "$URL" ] && echo "Second arg should be URL" && exit 1 + +REVISION="$4" +[ -z "$REVISION" ] && echo "Fourth arg should be revision" && exit 1 + +CLONEPATH="$6" +[ -z "$CLONEPATH" ] && echo "Sixth arg should be clonepath" && exit 1 + +[ -d $CLONEPATH ] || mkdir -m 700 -p $CLONEPATH + +cd $CLONEPATH + +[ -d "$CLONEPATH/.git" ] && git remote -v && git remote set-url origin $URL || { + git init + git remote add origin $URL +} + +# https://github.com/tektoncd/pipeline/blob/v0.41.0/pkg/git/git.go#L285 +git config core.sparsecheckout true + +retries=3 +until git fetch --depth=1 origin --update-head-ok --force $REVISION; do + [ $retries -gt 0 ] || exit 1 + retries=$(( $retries - 1 )) + wait=$((10 + $RANDOM % 50)) + echo "Git failed, retrying in ${wait}s" + sleep $wait +done + +git show-ref "origin/$REVISION" \ + && git checkout -f -B $REVISION origin/$REVISION \ + || git checkout -f $REVISION diff --git a/git/Dockerfile b/git/Dockerfile index 72c4763..10ca3c4 100644 --- a/git/Dockerfile +++ b/git/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:bullseye-slim@sha256:b0d53c872fd640c2af2608ba1e693cfc7dedea30abcd8f584b23d583ec6dadc7 +FROM --platform=$TARGETPLATFORM yolean/docker-base RUN groupadd --gid 1000 git \ && useradd --uid 1000 --gid git --shell /bin/bash --create-home git diff --git a/headless-chrome/Dockerfile b/headless-chrome/Dockerfile new file mode 100644 index 0000000..9f09419 --- /dev/null +++ b/headless-chrome/Dockerfile @@ -0,0 +1,47 @@ +FROM --platform=$TARGETPLATFORM yolean/docker-base +ARG chrome_stage=stable +#ARG chrome_pin="=125.0.6422.141-1" +ARG chrome_pin + +ENV CHROME_VERSION="${chrome_stage}${chrome_pin}" + +# Install deps + add Chrome Stable + purge all the things +RUN runtimeDeps='procps ca-certificates' \ + && buildDeps='apt-transport-https curl gnupg' \ + && set -ex \ + && export DEBIAN_FRONTEND=noninteractive \ + && apt-get update && apt-get install -y $runtimeDeps $buildDeps --no-install-recommends \ + && install -d -m 0755 /etc/apt/keyrings \ + && curl -sSL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg \ + && echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \ + && apt-get update \ + && apt-get -s install google-chrome-stable | grep chrome \ + && apt-get -s install google-chrome-beta | grep chrome \ + && apt-get install -y \ + google-chrome-$CHROME_VERSION \ + --no-install-recommends \ + && apt-get purge -y --auto-remove $buildDeps \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /var/log/apt /var/log/dpkg.log /var/log/alternatives.log + +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot && \ + usermod -a -G audio,video nonroot +USER nonroot:nogroup + +EXPOSE 9222 + +ENTRYPOINT [ "google-chrome" ] +CMD [ "--headless=new", \ + "--disable-gpu", \ + "--remote-debugging-address=0.0.0.0", \ + "--remote-debugging-port=9222", \ + "--safebrowsing-disable-auto-update", \ + "--disable-background-networking", \ + "--disable-extensions", \ + "--disable-translate", \ + "--disable-sync", \ + "--user-data-dir=/home/nonroot/userdata", \ + "--enable-logging", \ + "--v=2" ] diff --git a/homedir/Dockerfile b/homedir/Dockerfile new file mode 100644 index 0000000..ef8eeed --- /dev/null +++ b/homedir/Dockerfile @@ -0,0 +1,11 @@ +FROM --platform=$TARGETPLATFORM yolean/docker-base \ + as base + +FROM base as nonroot +WORKDIR /nonroot +RUN set -e; \ + mkdir -p home/nonroot/.cache; \ + chown root home; chown -R 65532:65534 home/nonroot + +FROM base +COPY --from=nonroot /nonroot / diff --git a/hooks/build b/hooks/build deleted file mode 100755 index c5f3499..0000000 --- a/hooks/build +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bash -[ -z "$DEBUG" ] || set -x -set -eo pipefail - -[ -n "$PLATFORM" ] || PLATFORM="--platform=linux/amd64,linux/arm64/v8" - -[ -z "$REGISTRY" ] || PREFIX="$REGISTRY/" - -SOURCE_COMMIT=$(git rev-parse --verify HEAD 2>/dev/null || echo '') -if [[ ! -z "$SOURCE_COMMIT" ]]; then - GIT_STATUS=$(git status --untracked-files=normal --porcelain=v2) - if [[ ! -z "$GIT_STATUS" ]]; then - SOURCE_COMMIT="$SOURCE_COMMIT-dirty" - fi -fi - -MULTIARCH_NONROOT=" -builder-base -builder-base-gcc -builder-tooling -builder-node -builder-quarkus -toil -" - -MULTIARCH_TONONROOT=" -java -node -node-kafka -node-kafka-cache -runtime-quarkus-ubuntu -runtime-quarkus-ubuntu-jre -runtime-quarkus-dev -" - -AMD64ONLY=" -git-init -runtime-quarkus -runtime-quarkus-deno -runtime-deno -git-http-readonly -" - -XTAG="" - -[ -n "$NOPUSH" ] || BUILDX_PUSH="--push" - -cat ./Dockerfile | \ - docker buildx build $BUILDX_PUSH --progress=plain $PLATFORM \ - -t yolean/docker-base -t ${PREFIX}yolean/docker-base:$SOURCE_COMMIT$XTAG - - -for CONTEXT in $MULTIARCH_NONROOT; do - ! (grep -r FROM ./$CONTEXT | grep -v 'FROM --platform=') - cat ./$CONTEXT/Dockerfile | \ - docker buildx build $BUILDX_PUSH --progress=plain $PLATFORM -f - \ - -t yolean/$CONTEXT -t ${PREFIX}yolean/$CONTEXT:$SOURCE_COMMIT$XTAG ./$CONTEXT -done - -for CONTEXT in $MULTIARCH_TONONROOT; do - ! (grep -r FROM ./$CONTEXT | grep -v 'FROM --platform=') - cat ./$CONTEXT/Dockerfile | \ - docker buildx build $BUILDX_PUSH --progress=plain $PLATFORM -f - \ - -t yolean/$CONTEXT:root -t ${PREFIX}yolean/$CONTEXT:$SOURCE_COMMIT$XTAG-root ./$CONTEXT -done -for CONTEXT in $MULTIARCH_TONONROOT; do - cat ./$CONTEXT/Dockerfile ./nonroot-footer.Dockerfile | \ - docker buildx build $BUILDX_PUSH --progress=plain $PLATFORM -f - \ - -t yolean/$CONTEXT -t ${PREFIX}yolean/$CONTEXT:$SOURCE_COMMIT$XTAG ./$CONTEXT -done - -PUSH="" - -for CONTEXT in $AMD64ONLY; do - IMAGE=${PREFIX}yolean/$CONTEXT:$SOURCE_COMMIT$XTAG - docker build --platform=linux/amd64 -t yolean/$CONTEXT -t $IMAGE ./$CONTEXT - PUSH="$PUSH $IMAGE" - if [ "" = "$(docker image inspect -f='{{.Config.User}}' $IMAGE)" ]; then - docker tag $IMAGE $IMAGE-root - PUSH="$PUSH $IMAGE-root" - cat ./$CONTEXT/Dockerfile ./nonroot-footer.Dockerfile | \ - docker build --platform=linux/amd64 -f - -t yolean/$CONTEXT -t $IMAGE ./$CONTEXT - fi -done - -echo "amd64-only PUSH list contains: $PUSH" -[ -z "$NOPUSH" ] || exit 0 -for P in $PUSH; do docker push $P; done diff --git a/images.sh b/images.sh new file mode 100755 index 0000000..58ab513 --- /dev/null +++ b/images.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# images.sh — shared image lists and helper functions for test.sh and build.sh + +# note that docker-base isn't actually nonroot, we just want to build that first +MULTIARCH_NONROOT=" +docker-base +builder-base +builder-base-gcc +builder-base-gcloud +builder-tooling +builder-node +builder-quarkus +git-init +toil +toil-network +node-distroless +headless-chrome +git-http-readonly +runtime-quarkus +runtime-deno +" + +MULTIARCH_TONONROOT=" +homedir +java +node +node-kafka +node-kafka-cache +node-kafka-duckdb +node-watchexec +node-kafka-watch +node-gcloud +node-vitest +runtime-quarkus-ubuntu +runtime-quarkus-deno +runtime-quarkus-ubuntu-jre +runtime-quarkus-dev +toil-storage +curl-yq +duckdb +" + +DEPRECATED=" +runtime-quarkus-deno +runtime-deno +" + +# Images that are only buildable on amd64 +SINGLE_ARCH_AMD64="headless-chrome" + +# Generate nonroot Dockerfiles for TONONROOT images +generate_nonroot_dockerfiles() { + for CONTEXT in $MULTIARCH_TONONROOT; do + mkdir -p to-nonroot/$CONTEXT + echo "FROM --platform=\$TARGETPLATFORM yolean/$CONTEXT:root" > to-nonroot/$CONTEXT/Dockerfile + cat nonroot-footer.Dockerfile >> to-nonroot/$CONTEXT/Dockerfile + done +} + +# Get yolean/ dependencies from a Dockerfile's FROM lines +# Returns space-separated list of "yolean/name" or "yolean/name:tag" references +get_yolean_deps() { + local DOCKERFILE=$1 + (grep -e 'FROM --platform=$TARGETPLATFORM yolean/' -e 'FROM --platform=$BUILDPLATFORM yolean/' "$DOCKERFILE" || true) | cut -d' ' -f3 +} + +# Resolve build order: given image names, return them plus all transitive +# dependencies in the order they appear in the master lists. +resolve_build_order() { + local NEEDED="" + + _collect_deps() { + local IMG=$1 + case " $NEEDED " in *" $IMG "*) return ;; esac + NEEDED="$NEEDED $IMG" + + local DOCKERFILE="$IMG/Dockerfile" + [ -f "$DOCKERFILE" ] || return 0 + + local DEPS + DEPS=$(get_yolean_deps "$DOCKERFILE") + for DEP_FULL in $DEPS; do + local DEP_NAME="${DEP_FULL#yolean/}" + DEP_NAME="${DEP_NAME%%:*}" + _collect_deps "$DEP_NAME" + done + } + + for IMG in "$@"; do + _collect_deps "$IMG" + done + + local ALL_IMAGES="$MULTIARCH_NONROOT $MULTIARCH_TONONROOT" + for IMG in $ALL_IMAGES; do + case " $NEEDED " in *" $IMG "*) echo "$IMG" ;; esac + done +} diff --git a/java/Dockerfile b/java/Dockerfile index 604b405..4e24714 100644 --- a/java/Dockerfile +++ b/java/Dockerfile @@ -1 +1 @@ -FROM --platform=$TARGETPLATFORM eclipse-temurin:11.0.14.1_1-jre-focal@sha256:246f0a07f7ba2c52b48d1879aa6f294d80619575f719ea31eaec0885560b803e +FROM --platform=$TARGETPLATFORM eclipse-temurin:25.0.2_10-jre@sha256:43a7b50abf8679d77d6d41d52072402a18312a47b4390864046b393e2570137b diff --git a/node-distroless/Dockerfile b/node-distroless/Dockerfile new file mode 100644 index 0000000..069ac3c --- /dev/null +++ b/node-distroless/Dockerfile @@ -0,0 +1,4 @@ +FROM --platform=$TARGETPLATFORM gcr.io/distroless/nodejs24-debian13:nonroot@sha256:b087b405441cd3e8eab9bd53ae3dd1c2b824e7ce13f25c5e9bb353fbdb3f4544 + +WORKDIR /app +CMD [ "./main.js" ] diff --git a/node-gcloud/Dockerfile b/node-gcloud/Dockerfile new file mode 100644 index 0000000..4896a63 --- /dev/null +++ b/node-gcloud/Dockerfile @@ -0,0 +1,31 @@ +FROM --platform=$TARGETPLATFORM yolean/node:root + +RUN set -ex; \ + export DEBIAN_FRONTEND=noninteractive; \ + runDeps='python3 google-cloud-cli rsync unzip'; \ + buildDeps='gnupg2'; \ + \ + apt-get update && apt-get install -y --no-install-recommends $buildDeps; \ + echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" > /etc/apt/sources.list.d/google-cloud-sdk.list; \ + curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor > /usr/share/keyrings/cloud.google.gpg; \ + \ + apt-get update && apt-get install -y --no-install-recommends $runDeps $buildDeps; \ + gcloud version; \ + gsutil version; \ + \ + apt-get purge -y --auto-remove $buildDeps; \ + rm -rf /var/lib/apt/lists; \ + rm -rf /var/log/dpkg.log /var/log/alternatives.log /var/log/apt /root/.gnupg + +ARG TARGETARCH +ARG PROTOBUF_VERSION=25.1 +RUN set -ex; \ + ARCH=$TARGETARCH; \ + [ "$TARGETARCH" != "arm64" ] || ARCH=aarch_64; \ + [ "$TARGETARCH" != "amd64" ] || ARCH=x86_64; \ + mkdir /opt/protobuf; \ + cd /opt/protobuf; \ + curl -sL -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-linux-$ARCH.zip; \ + unzip protoc.zip; \ + ln -s /opt/protobuf/bin/protoc /usr/local/bin/protoc; \ + rm protoc.zip diff --git a/node-kafka-cache/Dockerfile b/node-kafka-cache/Dockerfile index 26cce6c..d7f7b93 100644 --- a/node-kafka-cache/Dockerfile +++ b/node-kafka-cache/Dockerfile @@ -1,6 +1,6 @@ FROM --platform=$TARGETPLATFORM yolean/node-kafka:root -ENV KAFKA_CACHE_VERSION=Yolean/kafka-cache#a451bd3fc013925e7204b329fe50253c323e5374 +ENV KAFKA_CACHE_VERSION=Yolean/kafka-cache#4db623eee2faf25f5bfcd4f578822234f2b14aae RUN set -ex; \ su node -c "npm install -g --only=prod --ignore-scripts kafka-cache@${KAFKA_CACHE_VERSION}"; \ diff --git a/node-kafka-duckdb/Dockerfile b/node-kafka-duckdb/Dockerfile new file mode 100644 index 0000000..a4fc0b6 --- /dev/null +++ b/node-kafka-duckdb/Dockerfile @@ -0,0 +1,5 @@ +FROM --platform=$TARGETPLATFORM yolean/node-kafka:root + +COPY package.json /app/ + +RUN npm install --ignore-scripts diff --git a/node-kafka-duckdb/package.json b/node-kafka-duckdb/package.json new file mode 100644 index 0000000..9d82834 --- /dev/null +++ b/node-kafka-duckdb/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "dependencies": { + "@duckdb/node-bindings": "1.5.3-r.1", + "@google-cloud/pubsub": "5.3.0" + } +} diff --git a/node-kafka-watch/Dockerfile b/node-kafka-watch/Dockerfile new file mode 100644 index 0000000..3b682c5 --- /dev/null +++ b/node-kafka-watch/Dockerfile @@ -0,0 +1,19 @@ +FROM --platform=$TARGETPLATFORM yolean/node-watchexec:root as watchexec + +FROM --platform=$TARGETPLATFORM yolean/node-kafka:root + +COPY --from=watchexec --chown=0:0 /usr/local/bin/watchexec /usr/local/bin + +WORKDIR /app + +COPY --from=watchexec --chown=nonroot:nogroup /app/main.js main.js + +ENTRYPOINT [ "/usr/local/bin/watchexec", \ + "--print-events", \ + "--debounce=500", \ + "--shell=none", \ + "--watch=/app", \ + "-r", \ + "--", \ + "/usr/local/bin/node" ] +CMD [ "./main.js" ] diff --git a/node-kafka-watch/main-wait.js b/node-kafka-watch/main-wait.js new file mode 100644 index 0000000..e8e1d77 --- /dev/null +++ b/node-kafka-watch/main-wait.js @@ -0,0 +1,3 @@ +const log = () => console.log('waiting for replacement at', process.argv[1]); +log(); +setInterval(log, 5000); diff --git a/node-kafka/Dockerfile b/node-kafka/Dockerfile index 49569e1..bb651f4 100644 --- a/node-kafka/Dockerfile +++ b/node-kafka/Dockerfile @@ -1,13 +1,12 @@ FROM --platform=$TARGETPLATFORM yolean/node:root ENV NODE_PATH=/usr/local/lib/node_modules \ - NODE_RDKAFKA_VERSION=v2.12.0 \ - SEMVER_VERSION=7.3.5 \ - SNAPPY_VERSION=6.3.5 + NODE_RDKAFKA_VERSION=v3.6.1 \ + SNAPPY_VERSION=7.3.3 RUN set -ex; \ export DEBIAN_FRONTEND=noninteractive; \ - runDeps='libssl1.1 libsasl2-2 zlib1g libsnappy1v5 liblz4-1 libzstd1'; \ + runDeps='libssl3 libsasl2-2 zlib1g libsnappy1v5 liblz4-1 libzstd1'; \ buildDeps=' \ build-essential \ python3 \ diff --git a/node-vitest/Dockerfile b/node-vitest/Dockerfile new file mode 100644 index 0000000..cf2c989 --- /dev/null +++ b/node-vitest/Dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:1.4 + +FROM --platform=$TARGETPLATFORM yolean/node:root + +ENV NODE_PATH=/usr/local/lib/node_modules + +RUN mkdir /workspace && chown 65532:65534 /workspace +COPY package.json /workspace/ + +WORKDIR /workspace +RUN npm install --ignore-scripts && chown 65532:65534 node_modules +ENTRYPOINT ["./node_modules/.bin/vitest"] +CMD ["run"] diff --git a/node-vitest/package.json b/node-vitest/package.json new file mode 100644 index 0000000..726a6e8 --- /dev/null +++ b/node-vitest/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "type": "module", + "devDependencies": { + "vitest": "4.0.18" + } +} diff --git a/node-watchexec/Dockerfile b/node-watchexec/Dockerfile new file mode 100644 index 0000000..747f67f --- /dev/null +++ b/node-watchexec/Dockerfile @@ -0,0 +1,3 @@ +# syntax=docker/dockerfile:1.4 + +FROM --platform=$TARGETPLATFORM ghcr.io/turbokube/nodejs-watch:3aae8576dc59310eae311dcfa00b880b66f8661a@sha256:dad36373d539d1060eeae0fba8ed682e6503ec88eeac01b339661dbb1400aa19 diff --git a/node/Dockerfile b/node/Dockerfile index b05c030..ae1f217 100644 --- a/node/Dockerfile +++ b/node/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$TARGETPLATFORM node:16.14.0-bullseye-slim@sha256:22841c8578ef743f8e517ae194bdd6688537364b4c929f61a140b37578365d6c +FROM --platform=$TARGETPLATFORM node:24.15.0-trixie-slim@sha256:291be77873bc04731968cacf82f0fcef17cee8cf200c6b6951e2bcab41560eb7 RUN runtimeDeps='procps git curl ca-certificates' \ && set -ex \ @@ -6,6 +6,9 @@ RUN runtimeDeps='procps git curl ca-certificates' \ && apt-get update && apt-get install -y $runtimeDeps $buildDeps --no-install-recommends \ && rm -rf /var/log/apt /var/log/dpkg.log /var/log/alternatives.log -CMD [ "node" ] - RUN chmod g+w /usr/src && chgrp nogroup /usr/src + +ENV npm_config_update_notifier=false + +ENTRYPOINT [ "/usr/local/bin/node" ] +WORKDIR /app diff --git a/print-provenance.sh b/print-provenance.sh new file mode 100755 index 0000000..161bff5 --- /dev/null +++ b/print-provenance.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat >&2 < [--raw] [--debug] + --raw Print full attestation JSON (can repeat for multiple) + --debug Show crane commands executed +Defaults to :latest if no tag provided. +EOF +} + +if ! command -v crane >/dev/null 2>&1; then + echo "crane not found in PATH" >&2; exit 1; fi +if ! command -v jq >/dev/null 2>&1; then + echo "jq not found in PATH" >&2; exit 1; fi + +[ $# -ge 1 ] || { usage; exit 1; } + +IMAGE="$1"; shift || true +RAW="false"; DEBUG="false" +while [ $# -gt 0 ]; do + case "$1" in + --raw) RAW="true";; + --debug) DEBUG="true";; + -h|--help) usage; exit 0;; + *) echo "Unknown arg: $1" >&2; usage; exit 1;; + esac + shift +done + +# Add :latest if no explicit tag or digest +if [[ "$IMAGE" != *:@* && "$IMAGE" != *:*/*:* && "$IMAGE" != *:*:* && "$IMAGE" != *@sha256:* ]]; then + # has no :tag part after last slash + if [[ "$IMAGE" != *:* ]]; then + IMAGE+=":latest" + fi +fi + +echo "Inspecting provenance for $IMAGE" >&2 + +# Obtain manifest list (or single manifest) JSON +if ! MANIFEST_JSON=$(crane manifest "$IMAGE" 2>/dev/null); then + echo "Failed to fetch manifest for $IMAGE" >&2; exit 1; +fi + +# If it's a single-platform manifest, wrap to unify processing +if ! echo "$MANIFEST_JSON" | jq -e '.manifests' >/dev/null 2>&1; then + MANIFEST_LIST_JSON='{"manifests":[]}' +else + MANIFEST_LIST_JSON="$MANIFEST_JSON" +fi + +UNKNOWN_DIGESTS=$(echo "$MANIFEST_LIST_JSON" | jq -r '.manifests[]? | select(.platform.os=="unknown" and .platform.architecture=="unknown") | .digest') +if [ -z "$UNKNOWN_DIGESTS" ]; then + echo "No unknown/unknown platform manifests (attestations) found." >&2 + echo "Hint: ensure builds set provenance and sbom (buildkit) or attest step." >&2 + exit 2 +fi + +FOUND=0 +REGISTRY="${IMAGE%%/*}" # crude but ok for ghcr.io/owner/name:tag +REPO_TAG=${IMAGE#*/} +# Split repo and tag/digest +if [[ "$REPO_TAG" == *"@sha256:"* ]]; then + REPO="${REPO_TAG%@sha256:*}"; REF="${REPO_TAG#*@}"; REF_TYPE=digest +else + REPO="${REPO_TAG%%:*}"; REF="${REPO_TAG##*:}"; REF_TYPE=tag +fi + +IMAGE_PATH=${IMAGE#*/} # remove registry +REPO_PATH=${IMAGE_PATH%%@*} # drop @digest if any +REPO_PATH=${REPO_PATH%%:*} # drop :tag + +[ "$DEBUG" = "true" ] && echo "+ crane manifest $IMAGE # top-level" >&2 + +for DGST in $UNKNOWN_DIGESTS; do + BASE_REF=${IMAGE%%@*}; BASE_REF=${BASE_REF%%:*} # registry/owner/name + SUB_JSON=$(crane manifest "${BASE_REF}@${DGST}" 2>/dev/null) || continue + [ "$DEBUG" = "true" ] && echo "+ crane manifest ${BASE_REF}@${DGST}" >&2 + LAYER_DIGESTS=$(echo "$SUB_JSON" | jq -r '.layers[]? | select(.mediaType | test("in-toto")) | .digest') + [ -z "$LAYER_DIGESTS" ] && continue + for LD in $LAYER_DIGESTS; do + FOUND=1 + [ "$DEBUG" = "true" ] && echo "Sub-manifest digest: $DGST" >&2 && echo "In-toto layer digest: $LD" >&2 + # Retrieve attestation layer (handle crane versions expecting single arg) + [ "$DEBUG" = "true" ] && echo "+ crane blob ${BASE_REF}@${LD}" >&2 + ATTESTATION=$(crane blob "${BASE_REF}@${LD}" 2>/dev/null || crane blob "${IMAGE%@*}@${LD}" 2>/dev/null || true) + [ -z "$ATTESTATION" ] && continue + if [ "$RAW" = "true" ]; then + echo "$ATTESTATION" | jq '.' + continue + fi + echo "--- Attestation layer $LD (sub-manifest $DGST) ---" + JQ_SUMMARY='def dockerfiles: [ (.. | objects | to_entries[]? | select(.key|test("dockerfile";"i")) | .value) ] | flatten | map(tostring) | unique | .; + def mats: (.materials // .predicate.materials // []); + def norm(u; d): + if (u|startswith("docker-image://")) then + (u | sub("^docker-image://";"")) as $ref | + if (d|length>0) and ($ref|test("@sha256:" )|not) then ($ref|split("@")|.[0]) + "@sha256:" + d else $ref end + elif (u|startswith("pkg:docker/")) then + (u | sub("^pkg:docker/";"") | split("?") | .[0]) as $ref | + if (d|length>0) and ($ref|test("@sha256:" )|not) then ($ref|split("@")|.[0]) + "@sha256:" + d else $ref end + else + if (d|length>0) and (u|test("@sha256:" )|not) then (u + "@sha256:" + d) else u end + end; + def base_images: mats | map( ( .uri // .uri_ // empty ) as $u | ( .digest.sha256? // "" ) as $d | select($u != "") | norm($u; $d) ) | unique; + def bkmeta: .predicate.metadata["https://mobyproject.org/buildkit@v1#metadata"].vcs? // {}; + def guess_source: (bkmeta.source // .predicate.invocation.environment.GIT_URL? // .predicate.buildConfig.sourceProvenance.resolvedRepoSource.repoUrl? // empty); + def guess_revision: (bkmeta.revision // .predicate.invocation.environment.GITHUB_SHA? // .predicate.invocation.environment.GIT_COMMIT_SHA? // empty); + ["Dockerfiles:"] + (dockerfiles| if length==0 then ["(none found)"] else . end) + + ["Base images (materials):"] + (base_images | if length==0 then ["(none found)"] else . end) + + ["VCS source:", (guess_source // "(unknown)"), + "VCS revision:", (guess_revision // "(unknown)"), + "Build started:", (.predicate.metadata.buildStartedOn? // "(unknown)"), + "Build finished:", (.predicate.metadata.buildFinishedOn? // "(unknown)")] | .[]' + [ "$DEBUG" = "true" ] && echo "+ jq -r " >&2 && echo "$JQ_SUMMARY" | sed 's/^/| /' >&2 + SUMMARY=$(echo "$ATTESTATION" | jq -r "$JQ_SUMMARY") + if [ -z "${PREV_LAST:-}" ]; then + echo "$SUMMARY" + else + DIFF_PRINTED=false + while IFS= read -r line; do + if ! printf '%s\n' "$PREV_LAST" | grep -Fxq "$line"; then + [ "$DIFF_PRINTED" = false ] && echo "(diff from previous attestation)" && DIFF_PRINTED=true + echo "$line" + fi + done <<< "$SUMMARY" + [ "$DIFF_PRINTED" = false ] && echo "(no diff from previous attestation)" + fi + PREV_LAST="$SUMMARY" + done +done + +if [ $FOUND -eq 0 ]; then + echo "No attestation (in-toto) layers found in unknown/unknown manifests." >&2 + exit 3 +fi diff --git a/runtime-deno/Dockerfile b/runtime-deno/Dockerfile index a51b12c..5e41612 100644 --- a/runtime-deno/Dockerfile +++ b/runtime-deno/Dockerfile @@ -1,15 +1,9 @@ -FROM yolean/builder-quarkus as libs +FROM --platform=$TARGETPLATFORM denoland/deno:distroless-2.1.1@sha256:8c7fbba4e216e9535ac9869744ce36e225814aa3adc7754fdeb5930a2a86f34f AS deno -RUN y-deno -V +FROM --platform=$TARGETPLATFORM gcr.io/distroless/static-debian13:nonroot@sha256:e3f945647ffb95b5839c07038d64f9811adf17308b9121d8a2b87b6a22a80a39 -FROM gcr.io/distroless/static-debian11:nonroot@sha256:80c956fb0836a17a565c43a4026c9c80b2013c83bea09f74fa4da195a59b7a99 +COPY --from=deno \ + /bin/deno /usr/local/bin/deno -COPY --from=libs \ - /usr/lib/x86_64-linux-gnu/libgcc_s.so.* \ - /usr/lib/x86_64-linux-gnu/ - -COPY --from=libs \ - /usr/local/src/ystack/bin/deno /deno - -ENTRYPOINT ["/deno"] +ENTRYPOINT ["/usr/local/bin/deno"] CMD ["-V"] diff --git a/runtime-quarkus-deno/Dockerfile b/runtime-quarkus-deno/Dockerfile index 4851207..e0da5c2 100644 --- a/runtime-quarkus-deno/Dockerfile +++ b/runtime-quarkus-deno/Dockerfile @@ -1,8 +1,6 @@ -FROM yolean/builder-base as base +FROM --platform=$TARGETPLATFORM yolean/runtime-deno AS runtime-deno -RUN y-deno -V +FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-ubuntu -FROM yolean/runtime-quarkus-ubuntu - -COPY --from=base \ - /usr/local/src/ystack/bin/deno /usr/local/bin/deno +COPY --from=runtime-deno \ + /usr/local/bin/deno /usr/local/bin/deno diff --git a/runtime-quarkus-dev/Dockerfile b/runtime-quarkus-dev/Dockerfile index c522a60..26b0e31 100644 --- a/runtime-quarkus-dev/Dockerfile +++ b/runtime-quarkus-dev/Dockerfile @@ -3,7 +3,7 @@ FROM --platform=$TARGETPLATFORM yolean/builder-quarkus as maven RUN mkdir -p /home/nonroot/.m2 # Note the hardcoded JAVA_VERSION string below, and in runtime-quarkus-ubuntu-jre -FROM --platform=$TARGETPLATFORM eclipse-temurin:11.0.14.1_1-jdk-focal@sha256:e1b5c25bb18d8651d17ebde11127ee72b4b45ce84d7ed09d14deb0167b3393ea as jdk +FROM --platform=$TARGETPLATFORM eclipse-temurin:25.0.2_10-jdk@sha256:ddd55eda5ad0ef851a6c6b5169a83d6f9c9481449de77ae511a3118a3cf8fe91 as jdk RUN echo "JAVA_VERSION=$JAVA_VERSION" @@ -11,7 +11,7 @@ FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-ubuntu:root # Version here must match that of JRE above # Path must be that of runtime-quarkus + $JAVA_HOME/bin -ENV JAVA_VERSION=jdk-11.0.14.1+1 \ +ENV JAVA_VERSION=jdk-25.0.2+10 \ JAVA_HOME=/opt/java/openjdk \ MAVEN_HOME=/usr/share/maven \ MAVEN_CONFIG=/home/nonroot/.m2 \ diff --git a/runtime-quarkus-ubuntu-jre/Dockerfile b/runtime-quarkus-ubuntu-jre/Dockerfile index b490c79..fe993c7 100644 --- a/runtime-quarkus-ubuntu-jre/Dockerfile +++ b/runtime-quarkus-ubuntu-jre/Dockerfile @@ -5,8 +5,8 @@ RUN echo "JAVA_VERSION=$JAVA_VERSION" FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-ubuntu:root # Version here must match that of JRE above -# Path must be that of runtime-quarkus + $JAVA_HOME/bin -ENV JAVA_VERSION=jdk-11.0.14.1+1 \ +# Path must be that of runtime-quarkus-dev + $JAVA_HOME/bin +ENV JAVA_VERSION=jdk-25.0.2+10 \ JAVA_HOME=/opt/java/openjdk \ PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/runtime-quarkus-ubuntu/Dockerfile b/runtime-quarkus-ubuntu/Dockerfile index 1742e5b..aa4db71 100644 --- a/runtime-quarkus-ubuntu/Dockerfile +++ b/runtime-quarkus-ubuntu/Dockerfile @@ -1,9 +1,9 @@ # ystack/runner -FROM --platform=$TARGETPLATFORM ubuntu:20.04@sha256:669e010b58baf5beb2836b253c1fd5768333f0d1dbcb834f7c07a4dc93f474be +FROM --platform=$TARGETPLATFORM yolean/docker-base RUN set -ex; \ export DEBIAN_FRONTEND=noninteractive; \ - runDeps='libsnappy1v5 libsnappy-jni liblz4-1 liblz4-jni libzstd1 libfreetype6'; \ + runDeps='libsnappy1v5 libsnappy-jni liblz4-1 liblz4-jni libzstd1 libfreetype6 fontconfig'; \ apt-get update && apt-get install -y $runDeps --no-install-recommends; \ \ rm -rf /var/lib/apt/lists; \ diff --git a/runtime-quarkus/Dockerfile b/runtime-quarkus/Dockerfile index b5becc3..a41fe04 100644 --- a/runtime-quarkus/Dockerfile +++ b/runtime-quarkus/Dockerfile @@ -1,6 +1,6 @@ # For JNI/snappy such as kafka clients use runtime-quarkus-ubuntu instead -FROM gcr.io/distroless/static-debian11:nonroot@sha256:80c956fb0836a17a565c43a4026c9c80b2013c83bea09f74fa4da195a59b7a99 +FROM --platform=$TARGETPLATFORM gcr.io/distroless/static-debian13:nonroot@sha256:e3f945647ffb95b5839c07038d64f9811adf17308b9121d8a2b87b6a22a80a39 ENTRYPOINT ["/usr/local/bin/quarkus", "-Djava.util.logging.manager=org.jboss.logmanager.LogManager"] CMD ["-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=8080"] diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..3badb92 --- /dev/null +++ b/test.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +[ -z "$DEBUG" ] || set -x +set -eo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/images.sh" + +[ -n "$PLATFORMS" ] || PLATFORMS="linux/amd64,linux/arm64/v8" +[ -n "$PLATFORM" ] || PLATFORM="--platform=$PLATFORMS" + +[ -z "$REGISTRY" ] || PREFIX="$REGISTRY/" + +SOURCE_COMMIT=$(git rev-parse --verify HEAD 2>/dev/null || echo '') +if [[ ! -z "$SOURCE_COMMIT" ]]; then + GIT_STATUS=$(git status --untracked-files=normal --porcelain=v2 | grep -v ' hooks/build' || true) + if [[ ! -z "$GIT_STATUS" ]]; then + SOURCE_COMMIT="$SOURCE_COMMIT-dirty" + fi +fi + +BEGIN=" ### build steps below are generated ###" +CURRENT=.github/workflows/images.yaml +ACTIONS=$(mktemp) +sed "/^$BEGIN\$/q" $CURRENT > $ACTIONS + +function base_action { + local CONTEXT=$1 + local NAME=$2 + local TAG=$3 + local TAGSUFFIX="" + [ "$TAG" = "latest" ] || local TAGSUFFIX="-$TAG" + + # Get dependencies for build-contexts + local DEPENDENCIES="$(get_yolean_deps "$CONTEXT/Dockerfile")" + + # Determine platforms (override if in SINGLE_ARCH_AMD64) + local PLATFORMS="linux/amd64,linux/arm64/v8" + for ONLY_AMD64 in $SINGLE_ARCH_AMD64; do + if [ "$NAME" = "$ONLY_AMD64" ]; then + PLATFORMS="linux/amd64" + break + fi + done + + cat <> $ACTIONS +done + +generate_nonroot_dockerfiles + +for CONTEXT in $MULTIARCH_TONONROOT; do + base_action "$CONTEXT" "$CONTEXT" root >> $ACTIONS + base_action "to-nonroot/$CONTEXT" "$CONTEXT" latest >> $ACTIONS +done + +cp $ACTIONS $CURRENT +GIT_STATUS=$(git status --untracked-files=no --porcelain=v2) +[ -z "$GIT_STATUS" ] && echo "Done, no local diff" || echo "Done, with local diff" diff --git a/to-nonroot/curl-yq/Dockerfile b/to-nonroot/curl-yq/Dockerfile new file mode 100644 index 0000000..029fa7e --- /dev/null +++ b/to-nonroot/curl-yq/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/curl-yq:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/duckdb/Dockerfile b/to-nonroot/duckdb/Dockerfile new file mode 100644 index 0000000..febea44 --- /dev/null +++ b/to-nonroot/duckdb/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/duckdb:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/homedir/Dockerfile b/to-nonroot/homedir/Dockerfile new file mode 100644 index 0000000..c14e942 --- /dev/null +++ b/to-nonroot/homedir/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/homedir:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/java/Dockerfile b/to-nonroot/java/Dockerfile new file mode 100644 index 0000000..527b12f --- /dev/null +++ b/to-nonroot/java/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/java:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-gcloud/Dockerfile b/to-nonroot/node-gcloud/Dockerfile new file mode 100644 index 0000000..fe0623c --- /dev/null +++ b/to-nonroot/node-gcloud/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-gcloud:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-kafka-cache/Dockerfile b/to-nonroot/node-kafka-cache/Dockerfile new file mode 100644 index 0000000..202c485 --- /dev/null +++ b/to-nonroot/node-kafka-cache/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-kafka-cache:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-kafka-duckdb/Dockerfile b/to-nonroot/node-kafka-duckdb/Dockerfile new file mode 100644 index 0000000..bdd48f1 --- /dev/null +++ b/to-nonroot/node-kafka-duckdb/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-kafka-duckdb:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-kafka-watch/Dockerfile b/to-nonroot/node-kafka-watch/Dockerfile new file mode 100644 index 0000000..685a828 --- /dev/null +++ b/to-nonroot/node-kafka-watch/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-kafka-watch:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-kafka/Dockerfile b/to-nonroot/node-kafka/Dockerfile new file mode 100644 index 0000000..29916a4 --- /dev/null +++ b/to-nonroot/node-kafka/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-kafka:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-vitest/Dockerfile b/to-nonroot/node-vitest/Dockerfile new file mode 100644 index 0000000..23b1e36 --- /dev/null +++ b/to-nonroot/node-vitest/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-vitest:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node-watchexec/Dockerfile b/to-nonroot/node-watchexec/Dockerfile new file mode 100644 index 0000000..1c03b72 --- /dev/null +++ b/to-nonroot/node-watchexec/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node-watchexec:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/node/Dockerfile b/to-nonroot/node/Dockerfile new file mode 100644 index 0000000..e3427d3 --- /dev/null +++ b/to-nonroot/node/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/node:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/runtime-quarkus-deno/Dockerfile b/to-nonroot/runtime-quarkus-deno/Dockerfile new file mode 100644 index 0000000..9628d40 --- /dev/null +++ b/to-nonroot/runtime-quarkus-deno/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-deno:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/runtime-quarkus-dev/Dockerfile b/to-nonroot/runtime-quarkus-dev/Dockerfile new file mode 100644 index 0000000..0fef915 --- /dev/null +++ b/to-nonroot/runtime-quarkus-dev/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-dev:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/runtime-quarkus-ubuntu-jre/Dockerfile b/to-nonroot/runtime-quarkus-ubuntu-jre/Dockerfile new file mode 100644 index 0000000..1ef38ad --- /dev/null +++ b/to-nonroot/runtime-quarkus-ubuntu-jre/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-ubuntu-jre:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/runtime-quarkus-ubuntu/Dockerfile b/to-nonroot/runtime-quarkus-ubuntu/Dockerfile new file mode 100644 index 0000000..c455af8 --- /dev/null +++ b/to-nonroot/runtime-quarkus-ubuntu/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/runtime-quarkus-ubuntu:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/to-nonroot/toil-storage/Dockerfile b/to-nonroot/toil-storage/Dockerfile new file mode 100644 index 0000000..4f43d6f --- /dev/null +++ b/to-nonroot/toil-storage/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=$TARGETPLATFORM yolean/toil-storage:root + +# Appends the same nonroot directives as https://github.com/Yolean/kubernetes-kafka/tree/master/nonroot +# i.e. https://github.com/solsson/dockerfiles/tree/native/kafka-nonroot +RUN grep 'nonroot:x:65532' /etc/passwd || \ + echo 'nonroot:x:65532:65534:nonroot:/home/nonroot:/usr/sbin/nologin' >> /etc/passwd && \ + mkdir -p /home/nonroot && touch /home/nonroot/.bash_history && chown -R 65532:65534 /home/nonroot +USER nonroot:nogroup diff --git a/toil-network/Dockerfile b/toil-network/Dockerfile new file mode 100644 index 0000000..dab97bf --- /dev/null +++ b/toil-network/Dockerfile @@ -0,0 +1,13 @@ +FROM --platform=$TARGETPLATFORM yolean/toil + +USER root +RUN set -ex; \ + export DEBIAN_FRONTEND=noninteractive; \ + runDeps='iproute2 traceroute net-tools dnsutils tshark iputils-ping python3'; \ + buildDeps=''; \ + apt-get update; \ + apt-get install -y --no-install-recommends $runDeps $buildDeps; \ + \ + apt-get purge -y --auto-remove $buildDeps; \ + rm -rf /var/lib/apt/lists/*; \ + rm -rf /var/log/dpkg.log /var/log/alternatives.log /var/log/apt /root/.gnupg diff --git a/toil-storage/Dockerfile b/toil-storage/Dockerfile new file mode 100644 index 0000000..3d56109 --- /dev/null +++ b/toil-storage/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1.4 + +FROM --platform=$TARGETPLATFORM yolean/toil as toil + +FROM --platform=$TARGETPLATFORM yolean/docker-base + +RUN set -ex; \ + export DEBIAN_FRONTEND=noninteractive; \ + runDeps=' \ + ca-certificates curl \ + jq \ + '; \ + buildDeps=' \ + '; \ + apt-get update && apt-get install -y $runDeps $buildDeps --no-install-recommends; \ + \ + [ -z "$buildDeps" ] || apt-get purge -y --auto-remove $buildDeps; \ + rm -rf /var/lib/apt/lists/*; \ + rm -rf /var/log/apt /var/log/dpkg.log /var/log/alternatives.log /root/.gnupg; + +COPY --from=toil /usr/local/src/ystack/bin/y-rpk-v* /usr/local/bin/rpk +COPY --from=toil /usr/local/bin/mc /usr/local/bin/ diff --git a/toil/Dockerfile b/toil/Dockerfile index 2e18664..ce74a17 100644 --- a/toil/Dockerfile +++ b/toil/Dockerfile @@ -1,19 +1,20 @@ FROM --platform=linux/amd64 solsson/kafka:native-cli@sha256:16813cae4712b1b3933a4205850300043193f2932b0de4603d9bc07da2dcf033 as kafka-cli -FROM --platform=linux/amd64 liftm/kafkacat:1.7.0@sha256:7545a6199bcbd07961fb8a2dee4ddee5e2e9556eaffc7324b126a7a6db6ffebb as kafkacat-static +FROM --platform=$TARGETPLATFORM liftm/kafkacat:1.7.0@sha256:8658c1fa53632764bfcc3f9fad3dbf8b1d1a74f05244cd3a0ce9825e3344dc98 as kafkacat-static # images above do not support arm64 -FROM --platform=$TARGETPLATFORM grafana/logcli:2.4.1-amd64@sha256:c5243634a8586178ab29faefbbcb760d96615a8caab79d019c9c65966af49ce1 as logcli +ARG TARGETARCH +FROM --platform=$TARGETPLATFORM grafana/logcli:2.9.1-$TARGETARCH as logcli -FROM --platform=$TARGETPLATFORM minio/mc:RELEASE.2022-01-07T06-01-38Z@sha256:22cf686789cced8bfbb4643f82faf6b4ccc9b99a5b3ae0b395f0bd70fd815955 as mc +FROM --platform=$TARGETPLATFORM minio/mc:RELEASE.2023-09-22T05-07-46Z@sha256:814b17be3f895a51295113aecea806b83e74f25a3048dea443935f3dc066cd90 as mc FROM --platform=$TARGETPLATFORM yolean/builder-base as apt USER root RUN set -ex; \ export DEBIAN_FRONTEND=noninteractive; \ - runDeps='netcat-openbsd dnsutils findutils'; \ + runDeps='netcat-openbsd dnsutils findutils bsdextrautils zip'; \ buildDeps=''; \ apt-get update; \ apt-get install -y --no-install-recommends $runDeps $buildDeps; \ @@ -22,35 +23,25 @@ RUN set -ex; \ rm -rf /var/lib/apt/lists/*; \ rm -rf /var/log/dpkg.log /var/log/alternatives.log /var/log/apt /root/.gnupg +# Stage the binaries plus their shared-library closure under /usr/lib so the +# final image can run them without installing the packages. Deriving the libs +# from ldd (rather than a hardcoded list) keeps this working across Ubuntu and +# bind9 upgrades, which rename the bind9 sonames and shift dependencies (e.g. +# 9.20 dropped libirs/libbind9 and added liburcu/libjemalloc). RUN set -e; \ PKG_PREFIX="$(uname -m)-linux-gnu"; \ mkdir -p /opt/toil/lib/$PKG_PREFIX /opt/toil/bin; \ - cp -dav \ - /usr/lib/$PKG_PREFIX/libbsd.so.* \ - /usr/lib/$PKG_PREFIX/libedit.so.* \ - /usr/lib/$PKG_PREFIX/libdns.so.* \ - /usr/lib/$PKG_PREFIX/libirs.so.* \ - /usr/lib/$PKG_PREFIX/libbind9.so.* \ - /usr/lib/$PKG_PREFIX/libisccfg.so.* \ - /usr/lib/$PKG_PREFIX/libisc.so.* \ - /usr/lib/$PKG_PREFIX/libjson-c.so.* \ - /usr/lib/$PKG_PREFIX/libxml2.so.* \ - /usr/lib/$PKG_PREFIX/libmaxminddb.so.* \ - /usr/lib/$PKG_PREFIX/liblmdb.so.* \ - /usr/lib/$PKG_PREFIX/libns.so.* \ - /usr/lib/$PKG_PREFIX/libuv.so.* \ - /usr/lib/$PKG_PREFIX/libicuuc.so.* \ - /usr/lib/$PKG_PREFIX/libicudata.so.* \ - /opt/toil/lib/$PKG_PREFIX/; \ cp \ /usr/bin/nc* \ /usr/bin/nslookup \ /usr/bin/find \ /usr/bin/xargs \ - /opt/toil/bin/; - -# TODO verify that symlinks are preserved -#RUN ls -l /opt/toil/lib/$(uname -m)-linux-gnu/libxml2* && false + /usr/bin/zip \ + /opt/toil/bin/; \ + ldd /opt/toil/bin/* \ + | awk '$3 ~ /^\/usr\/lib\// { print $3 }' \ + | sort -u \ + | while read -r lib; do cp -L "$lib" /opt/toil/lib/$PKG_PREFIX/; done FROM --platform=$TARGETPLATFORM yolean/builder-base @@ -84,4 +75,5 @@ RUN set -ex; \ jq --version; \ yq --version; \ logcli --version; \ + zip --version | grep 'This is Zip'; \ pwd && touch workspace-file && rm workspace-file