[{"content":"The blog is up. Posts live in content/blog/ as Markdown files.\nhugo new content blog/my-post.md hugo server -D ","permalink":"http://phinguin.dev/blog/hello-world/","summary":"First post on the new blog.","title":"Hello, World"},{"content":"Side project — an online judge for IB CS practice problems. Server is Oracle\u0026rsquo;s free tier Ampere A1 (4 cores, 24GB RAM, free, 갓라클!!). Problem is basically everything QingdaoU/OnlineJudge ships is built for x86. ARM doesn\u0026rsquo;t run that.\nOne way is to use QEMU but obviously since it is an emulator it is too heavy. A judge that compiles and runs student code under a time limit doesn\u0026rsquo;t have room to also be emulating a different CPU architecture while it does it, so skipped that. Meant building the whole stack — Django backend, Vue frontend, the C/Python judge server — natively for arm64 instead of just pulling images.\nDid most of this with Gemini. But I guess because it was only 3.1 Pro at that time (which kinda sucks a lot..), it was quite misleading many of the times\u0026hellip; So here is my experience with it building a cross platform service.\nProblem 1: Frontend has no Dockerfile OnlineJudgeFE just doesn\u0026rsquo;t have one. Gemini\u0026rsquo;s first answer was that the prebuilt frontend image is x86-specific so I\u0026rsquo;d need my own for ARM. Didn\u0026rsquo;t really buy that — it\u0026rsquo;s compiled Vue output, static JS/CSS, that\u0026rsquo;s not an architecture thing the way a compiled binary is. Whatever the actual reason the repo ships without one, I built it myself anyway since I wanted to control the build instead of depending on a downloaded clone. node:16 stage, npm run build:dll then npm run build, copied the output into the backend image later.\n# frontend build stage, bookworm instead of buster (more on that below) FROM node:16-bookworm AS frontend-builder WORKDIR /frontend COPY frontend/package.json frontend/yarn.lock ./ RUN npm install COPY frontend/ . ENV NODE_ENV=production RUN npm run build:dll RUN npm run build # then in the actual backend stage COPY --from=frontend-builder /frontend/dist /app/dist/ Problem 2: Judge server was missing half of what it needs First draft of the judge-server Dockerfile just installed Python and gcc. I went and grabbed the actual upstream Dockerfile off GitHub, pasted it in, told Gemini to recheck itself against the real one. Turns out it missed a lot — needs a compiler for every language submissions can be in (ended up with openjdk-17-jdk, golang-go, gcc, g++, nodejs), plus three specific Linux users the C sandbox expects by exact UID — compiler (901), code (902), spj (903) — and the container has to run privileged: true or libseccomp just doesn\u0026rsquo;t work (which is very important as a security researcher). None of that was in the first version. If I hadn\u0026rsquo;t checked, every submission would\u0026rsquo;ve failed with permission errors and zero obvious reason why. This I guess is the reason one can\u0026rsquo;t just vibe code everything on their own (though I would also argue that at the time of writing this\u0026hellip; like Opus 5.5 out now\u0026hellip; it really does everything for me with one limitation of 5 hour session limit).\nRUN apt-get update \u0026amp;\u0026amp; apt-get install -y \\ python3-minimal python3-venv libpython3-stdlib libpython3-dev \\ golang-go \\ openjdk-17-jdk \\ gcc g++ \\ nodejs npm \\ strace \\ libseccomp-dev \\ curl gnupg \\ \u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/* # for C sandbox RUN useradd -u 901 -r -s /sbin/nologin -M compiler \u0026amp;\u0026amp; \\ useradd -u 902 -r -s /sbin/nologin -M code \u0026amp;\u0026amp; \\ useradd -u 903 -r -s /sbin/nologin -M -G code spj # docker-compose.yml services: oj-judge-server: build: context: ./judge-server privileged: true # libseccomp needs this, especially on ARM environment: SERVICE_URL: http://oj-judge-server:8080 BACKEND_URL: http://oj-backend:8000/api/judge_server_heartbeat/ TOKEN: \u0026#34;CHANGE_THIS_SECRET\u0026#34; cpu_core: 4 Problem 3: requirements.txt that doesn\u0026rsquo;t exist, twice Build failed looking for requirements.txt in the judge-server context. Gemini\u0026rsquo;s answer: your clone is probably broken, re-clone it. I\u0026rsquo;d already looked — there\u0026rsquo;s no requirements.txt in that repo and dependencies are hardcoded into the install step instead. Prompted again and gave me a \u0026ldquo;fix\u0026rdquo; that still had COPY requirements.txt . in it somewhere, failed the exact same way again.\n# this \u0026#34;fix\u0026#34; still failed, same error, different line number COPY requirements.txt . RUN python3 -m venv .venv \u0026amp;\u0026amp; \\ .venv/bin/pip install --no-cache-dir -r requirements.txt \u0026amp;\u0026amp; \\ .venv/bin/pip install /app/dist/*.whl Only the second time did it actually drop the file reference and just hardcode the real list — flask, gunicorn, idna, psutil, requests. Which, to be fair, is exactly what the official Dockerfile installs. Just took insisting twice before it stopped assuming I\u0026rsquo;d messed up the clone.\n# what actually worked, no requirements.txt involved RUN python3 -m venv .venv \u0026amp;\u0026amp; \\ .venv/bin/pip install --no-cache-dir flask gunicorn idna psutil requests \u0026amp;\u0026amp; \\ .venv/bin/pip install /app/dist/*.whl Found the setup.py thing before it did Building the Python bindings for the C sandbox used to be python3 setup.py bdist_wheel. Failed — no setup.py. Before asking anything I just looked at what was actually in that folder: _judger, .gitignore, pyproject.toml, setup.cfg. No setup.py. Figured the project moved to pyproject.toml packaging and said so. Gemini confirmed and gave me the current command for it:\n# old, no longer works once a project drops setup.py for pyproject.toml python3 setup.py bdist_wheel # current pip install build python3 -m build Reads pyproject.toml, spits out the same .whl the old command used to.\nBuster\u0026rsquo;s dead so don\u0026rsquo;t use Separate from all of the above — backend base image was python:3.9-slim-buster, apt-get update started 404ing on every mirror. Buster got moved to Debian\u0026rsquo;s EOL archive. Nothing to catch here, just an old base image.\nE: The repository \u0026#39;http://deb.debian.org/debian buster Release\u0026#39; does not have a Release file. E: The repository \u0026#39;http://deb.debian.org/debian-security buster/updates Release\u0026#39; does not have a Release file. # before FROM python:3.9-slim-buster # after FROM python:3.9-slim-bookworm Swapped to python:3.9-slim-bookworm and it was fine.\nMoved the build context, broke every COPY Needed the backend Dockerfile to grab the frontend\u0026rsquo;s build output, so I changed the Compose build context from backend/ to the repo root. Broke literally every COPY in the backend Dockerfile since they were all written assuming they ran from inside backend/. Fix was just simple — COPY requirements.txt . became COPY backend/requirements.txt ., same for the rest of the file.\n# docker-compose.yml services: oj-backend: build: context: . # was ./backend, now the repo root dockerfile: backend/Dockerfile # before (Dockerfile assumed build context was backend/) COPY requirements.txt . COPY deploy/requirements.txt /app/deploy/ # after (build context is now the repo root, every path needs the prefix) COPY backend/requirements.txt . COPY backend/deploy/requirements.txt /app/deploy/ ","permalink":"http://phinguin.dev/blog/online-judge-on-oracle-arm/","summary":"Building QingdaoU/OnlineJudge natively for arm64 on Oracle\u0026rsquo;s free tier, and where Gemini got it wrong.","title":"Building an Online Judge on Oracle ARM (with Gemini)"},{"content":"Hi, I\u0026rsquo;m phinguin. This is my blog.\nGitHub: phinguin123 ","permalink":"http://phinguin.dev/about/","summary":"\u003cp\u003eHi, I\u0026rsquo;m phinguin. This is my blog.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eGitHub: \u003ca href=\"https://github.com/phinguin123\"\u003ephinguin123\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"About"}]