diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..5e0660ec --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.github/ +.husky/ +.idea/ +.vscode/ diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml new file mode 100644 index 00000000..a1f15a17 --- /dev/null +++ b/.github/workflows/publish-image.yml @@ -0,0 +1,50 @@ +name: Publish Image + +on: + push: + branches: ['release'] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + attestations: write + id-token: write + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..efcad33f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,77 @@ +ARG BRANCH=master +ARG DEBIAN_CODE=trixie +ARG NODE_VERSION=24 +ARG PYTHON_VERSION=3.13 +ARG USER_NAME=spacebar +ARG USER_GROUP=$USER_NAME +ARG USER_UID=1000 +ARG USER_GID=1000 +ARG WORKDIR=/spacebar + + +FROM python:${PYTHON_VERSION}-slim-${DEBIAN_CODE} AS base_python + + +FROM node:${NODE_VERSION}-${DEBIAN_CODE}-slim AS base + +COPY --from=base_python /usr/local/bin/python* /usr/local/bin/ +COPY --from=base_python /usr/local/bin/pip* /usr/local/bin/ +COPY --from=base_python /usr/local/lib/python* /usr/local/lib/ +COPY --from=base_python /usr/local/lib/libpython* /usr/local/lib/ + + +FROM base AS builder + +ARG BRANCH + +WORKDIR /build + +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential pkg-config && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /build/server + +COPY . . + +RUN npm i \ + && npm run setup + + +FROM base AS final + +ARG USER_NAME +ARG USER_GROUP +ARG USER_UID +ARG USER_GID +ARG WORKDIR + +RUN mkdir -p "${WORKDIR}/server" \ + && chown -R "${USER_UID}:${USER_GID}" "${WORKDIR}" + +RUN deluser node 2>/dev/null || true \ + && delgroup node 2>/dev/null || true \ + && rm -fr /home/node \ + && addgroup --gid "$USER_GID" "$USER_GROUP" \ + && adduser \ + --disabled-password \ + --gecos "" \ + --uid "$USER_UID" \ + --gid "$USER_GID" \ + --home "$WORKDIR" \ + --no-create-home \ + "$USER_NAME" + +USER ${USER_NAME} + +#@todo: only bring what we need +COPY --chown=${USER_NAME}:${USER_GROUP} --from=builder /build/server "${WORKDIR}/server" + +ENV PORT="8080" +ENV CONFIG_PATH="${WORKDIR}/config.json" +ENV DATABASE="${WORKDIR}/database.db" + +WORKDIR "${WORKDIR}/server" + +ENTRYPOINT [ "npm", "run" ] +CMD [ "start" ]