diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e9529bc3..15042d17 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,9 +8,9 @@ ARG TARGETARCH ENV NODE_VERSION 22.14.0 ENV PNPM_VERSION 10.6.5 -ENV NODE_CHECKSUM_ARM64 8cf30ff7250f9463b53c18f89c6c606dfda70378215b2c905d0a9a8b08bd45e0 +ENV NODE_CHECKSUM_ARM64 69b09dba5c8dcb05c4e4273a4340db1005abeafe3927efda2bc5b249e80437ec ENV PNPM_CHECKSUM_ARM64 9b9d1d3f026f969b33596dbf6c46f31a8078f0fce412231b2093d7e6a36aaa5c -ENV NODE_CHECKSUM_X64 9d942932535988091034dc94cc5f42b6dc8784d6366df3a36c4c9ccb3996f0c2 +ENV NODE_CHECKSUM_X64 69b09dba5c8dcb05c4e4273a4340db1005abeafe3927efda2bc5b249e80437ec ENV PNPM_CHECKSUM_X64 75a7f1c70d3ce7ff7f6f0a0815010246ff14142418f66126a2c2be83a65f284d RUN apt-get update \ @@ -37,9 +37,9 @@ RUN </dev/null 2>&1 -} - -build_and_run() { - IMAGE_ID=$($1 build . | tail -1) - $1 run --rm -p 5284:5284 \ - -e PORT=5284 -e PROXY_ORIGIN=^http:\\/\\/localhost:5173$ \ - -it $IMAGE_ID -} - -if command_exists podman; then - build_and_run podman -elif command_exists docker; then - build_and_run docker -else - echo -e "${ERROR}Install Podman or Docker${NC}" - exit 1 -fi +source "$(dirname "$0")/../../scripts/image-utils.sh" +build_and_run 5284 "-e PROXY_ORIGIN=^http:\\/\\/localhost:5173$" diff --git a/scripts/image-utils.sh b/scripts/image-utils.sh new file mode 100644 index 00000000..a5210ce0 --- /dev/null +++ b/scripts/image-utils.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Common functions for testing production environments with Podman or Docker + +ERROR='\033[0;31m' +WARNING='\033[0;33m' +NC='\033[0m' # No Color + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +run_container() { + local container_tool=$1 + local port=$2 + local envs=$3 + local image_id=$4 + + $container_tool run --rm -p "$port:$port" -e PORT=$port $envs -it "$image_id" +} + +build_and_run() { + local port=$1 + local envs=$2 + + # Select container tool (podman or docker) + local tool + if command_exists podman; then + tool="podman" + elif command_exists docker; then + tool="docker" + else + echo -e "${ERROR}Install Podman or Docker${NC}" + exit 1 + fi + + echo "Building image with $tool" + BUILD_OUTPUT=$($tool build . 2>&1) || { + echo -e "${ERROR}Build failed:${NC}\n$BUILD_OUTPUT" + exit 1 + } + IMAGE_ID=$(echo "$BUILD_OUTPUT" | tail -1) + + SIZE=$($tool image inspect "$IMAGE_ID" --format='{{.Size}}' | \ + awk '{printf "%d MB", $1/1024/1024}') + echo -e "${WARNING}Image size: ${SIZE}${NC}" + + run_container "$tool" "$port" "$envs" "$IMAGE_ID" +} + diff --git a/scripts/update-env.ts b/scripts/update-env.ts index 87e90de8..7e5c3c2f 100644 --- a/scripts/update-env.ts +++ b/scripts/update-env.ts @@ -11,9 +11,7 @@ interface Release { version: string } -type Architecture = 'arm64' | 'x64' - -type Architectures = Record +type Architectures = { arm64: string; musl?: string; x64: string } async function getLatestNodeVersion(major: string): Promise { let response = await fetch('https://nodejs.org/dist/index.json') @@ -31,20 +29,27 @@ async function getLatestPnpmVersion(): Promise { } async function getNodeSha256(version: string): Promise { - let response = await fetch( - `https://nodejs.org/dist/v${version}/SHASUMS256.txt` - ) - let data = await response.text() - let lines = data.split('\n') + let [official, unofficial] = await Promise.all([ + fetch(`https://nodejs.org/dist/v${version}/SHASUMS256.txt`), + fetch( + `https://unofficial-builds.nodejs.org/download/release/v${version}/SHASUMS256.txt` + ) + ]) + let [officialText, unofficialText] = await Promise.all([ + official.text(), + unofficial.text() + ]) + let lines = officialText.split('\n').concat(unofficialText.split('\n')) return { - arm64: lines.find(i => i.endsWith('-linux-arm64.tar.gz'))!.split(' ')[0]!, - x64: lines.find(i => i.endsWith('-linux-x64.tar.gz'))!.split(' ')[0]! + arm64: lines.find(i => i.endsWith('-linux-x64.tar.xz'))!.split(' ')[0]!, + musl: lines.find(i => i.endsWith('-linux-x64-musl.tar.xz'))!.split(' ')[0]!, + x64: lines.find(i => i.endsWith('-linux-x64.tar.xz'))!.split(' ')[0]! } } async function getPnpmSha256( version: string, - arch: Architecture + arch: 'arm64' | 'x64' ): Promise { let binary = await fetch( 'https://github.com/pnpm/pnpm/releases/download/' + @@ -99,8 +104,8 @@ function replaceVersionEnv( let name = `${tool}_CHECKSUM_${arch.toUpperCase()}` fixed = replaceEnv(fixed, name, checksum) } - } else if (content.includes('_CHECKSUM ')) { - fixed = replaceEnv(fixed, `${tool}_CHECKSUM`, 'sha256:' + checksums.x64) + } else if (content.includes('_CHECKSUM ') && checksums.musl) { + fixed = replaceEnv(fixed, `${tool}_CHECKSUM`, 'sha256:' + checksums.musl) } return fixed } diff --git a/server/Dockerfile b/server/Dockerfile index 955ef58a..96cb8ef7 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,21 +1,25 @@ -# syntax=docker/dockerfile:1.6 -FROM registry.access.redhat.com/ubi9/ubi:9.5 as builder +FROM docker.io/alpine:3.21.3 as base ENV NODE_VERSION 22.14.0 -ENV NODE_CHECKSUM sha256:9d942932535988091034dc94cc5f42b6dc8784d6366df3a36c4c9ccb3996f0c2 +ENV NODE_CHECKSUM sha256:87f163387ac85df69df6eeb863a6b6a1aa789b49cda1c495871c0fe360634db3 -ADD --checksum=$NODE_CHECKSUM https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz /node.tar.gz -RUN tar --remove-files -C /usr/local/ -xz --strip-components=1 -f /node.tar.gz - -FROM registry.access.redhat.com/ubi9/ubi-micro:9.5 - -COPY --from=builder /usr/local/bin/node /usr/bin/node -COPY --from=builder /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so.6 +RUN apk add --no-cache libstdc++ +ADD --checksum=$NODE_CHECKSUM https://unofficial-builds.nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64-musl.tar.xz /node.tar.xz +RUN tar -xf "node.tar.xz" --strip-components=1 -C /usr/local/ \ + "node-v${NODE_VERSION}-linux-x64-musl/bin/node" && rm "node.tar.xz" +FROM scratch +WORKDIR /var/app ENV NODE_ENV production ENV LOGUX_HOST 0.0.0.0 ENV LOGUX_LOGGER json -WORKDIR /var/app + +COPY --from=base /bin/sh /bin/sh +COPY --from=base /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 +COPY --from=base /usr/lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1 +COPY --from=base /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6 +COPY --from=base /usr/local/bin/node /usr/local/bin/node + COPY ./dist/ /var/app/ COPY ./web/ /var/web/ diff --git a/server/db/index.ts b/server/db/index.ts index b5aff2e8..64330de7 100644 --- a/server/db/index.ts +++ b/server/db/index.ts @@ -41,7 +41,9 @@ if ( } setInterval(dumpDb, 60 * 60 * 1000) } else { - pglite = new PGlite(config.db) + // eslint-disable-next-line no-console + console.log('DB Location:', config.db) + pglite = new PGlite(config.db, { debug: 1 }) } let drizzlePglite = devDrizzle(pglite, { schema }) await devMigrate(drizzlePglite, MIGRATE_CONFIG) diff --git a/server/scripts/run-image.sh b/server/scripts/run-image.sh index 3c16a977..a600a33a 100755 --- a/server/scripts/run-image.sh +++ b/server/scripts/run-image.sh @@ -1,25 +1,5 @@ #!/bin/bash -# Use Podman instead of Docker if it is avaiable to run image in production mode +# Test real production environment with Podman or Docker -ERROR='\033[0;31m' -NC='\033[0m' # No Color - -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -build_and_run() { - IMAGE_ID=$($1 build . | tail -1) - $1 run --rm -p 31337:31337 \ - -e DATABASE_URL=memory:// -e ASSETS=1 \ - -it $IMAGE_ID -} - -if command_exists podman; then - build_and_run podman -elif command_exists docker; then - build_and_run docker -else - echo -e "${ERROR}Install Podman or Docker${NC}" - exit 1 -fi +source "$(dirname "$0")/../../scripts/image-utils.sh" +build_and_run 31337 "-e DATABASE_URL=memory:// -e ASSETS=1" diff --git a/web/scripts/run-image.sh b/web/scripts/run-image.sh index 050f8384..fdb5b2e6 100755 --- a/web/scripts/run-image.sh +++ b/web/scripts/run-image.sh @@ -1,25 +1,5 @@ #!/bin/bash -# Use Podman instead of Docker if it is avaiable to run image in production mode +# Test real production environment with Podman or Docker -ERROR='\033[0;31m' -OK='\033[1;32m' -NC='\033[0m' # No Color - -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -build_and_run() { - IMAGE_ID=$($1 build . | tail -1) - echo -e "${OK}Web server is running on http://localhost:8080${NC}" - $1 run --rm -p 8080:8080 -e PORT=8080 -it $IMAGE_ID -} - -if command_exists podman; then - build_and_run podman -elif command_exists docker; then - build_and_run docker -else - echo -e "${ERROR}Install Podman or Docker${NC}" - exit 1 -fi +source "$(dirname "$0")/../../scripts/image-utils.sh" +build_and_run 8080