docker: support HOST_UID/HOST_GID across images; make container-created files owned by host user; update compose and README
This commit is contained in:
parent
c64fa651a2
commit
d33687d025
34
Dockerfile
34
Dockerfile
@ -1,5 +1,10 @@
|
|||||||
FROM ubuntu:noble
|
FROM ubuntu:noble
|
||||||
|
|
||||||
|
# Allow the caller to specify the host UID/GID so files created by the
|
||||||
|
# container match host ownership when volumes are mounted. Defaults to 1000.
|
||||||
|
ARG HOST_UID=1000
|
||||||
|
ARG HOST_GID=1000
|
||||||
|
|
||||||
RUN apt-get -q update \
|
RUN apt-get -q update \
|
||||||
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
ca-certificates curl gnupg \
|
ca-certificates curl gnupg \
|
||||||
@ -47,4 +52,33 @@ WORKDIR /server
|
|||||||
COPY /Dockerfile /Dockerfile
|
COPY /Dockerfile /Dockerfile
|
||||||
COPY /.env /.env
|
COPY /.env /.env
|
||||||
|
|
||||||
|
# Create a host-mapped user and group so container files are written with
|
||||||
|
# the host UID/GID. Do this late in the build so earlier root-only build
|
||||||
|
# steps are unaffected. Then ensure server and client directories are
|
||||||
|
# owned by that user and switch to it for runtime.
|
||||||
|
## Create a group with the requested GID if it doesn't exist, otherwise reuse
|
||||||
|
RUN if ! getent group ${HOST_GID} >/dev/null 2>&1; then \
|
||||||
|
groupadd -g ${HOST_GID} hostgroup; \
|
||||||
|
else \
|
||||||
|
EXISTING=$(getent group ${HOST_GID} | cut -d: -f1) && echo "Using existing group $EXISTING for GID ${HOST_GID}"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
## Create a user with the requested UID if it doesn't exist; if a user with
|
||||||
|
## that UID already exists, don't try to recreate it (we'll chown by numeric
|
||||||
|
## UID later). Create a home directory if missing.
|
||||||
|
RUN if ! getent passwd ${HOST_UID} >/dev/null 2>&1; then \
|
||||||
|
useradd -m -u ${HOST_UID} -g ${HOST_GID} -s /bin/bash hostuser || true; \
|
||||||
|
else \
|
||||||
|
EXISTING_USER=$(getent passwd ${HOST_UID} | cut -d: -f1) && echo "Found existing user $EXISTING_USER with UID ${HOST_UID}"; \
|
||||||
|
mkdir -p /home/hostuser || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
## Ensure runtime dirs are owned by the numeric UID:GID if hostuser/group
|
||||||
|
## weren't created, or by the names if they were.
|
||||||
|
RUN chown -R ${HOST_UID}:${HOST_GID} /server || true
|
||||||
|
RUN chown -R ${HOST_UID}:${HOST_GID} /client || true
|
||||||
|
|
||||||
|
ENV HOME=/home/hostuser
|
||||||
|
USER ${HOST_UID}:${HOST_GID}
|
||||||
|
|
||||||
CMD ["npm", "start"]
|
CMD ["npm", "start"]
|
||||||
|
@ -1,10 +1,32 @@
|
|||||||
FROM node:20-alpine
|
FROM node:20-alpine
|
||||||
|
|
||||||
RUN apk add --no-cache sqlite
|
# Build args for host UID/GID to create a matching user inside the image.
|
||||||
|
ARG HOST_UID=1000
|
||||||
|
ARG HOST_GID=1000
|
||||||
|
|
||||||
|
RUN apk add --no-cache sqlite shadow
|
||||||
|
|
||||||
WORKDIR /server
|
WORKDIR /server
|
||||||
|
|
||||||
# For dev, we install in container, but to speed up, perhaps copy package and install
|
# Create host user/group and ensure /server is owned by them so mounted
|
||||||
# But since volumes mount, just run npm install in command
|
# files appear with the desired ownership on the host.
|
||||||
|
RUN if ! getent group ${HOST_GID} >/dev/null 2>&1; then \
|
||||||
|
addgroup -g ${HOST_GID} hostgroup; \
|
||||||
|
else \
|
||||||
|
echo "group for GID ${HOST_GID} already exists"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN if ! getent passwd ${HOST_UID} >/dev/null 2>&1; then \
|
||||||
|
adduser -D -u ${HOST_UID} -G hostgroup hostuser; \
|
||||||
|
else \
|
||||||
|
echo "user for UID ${HOST_UID} already exists"; \
|
||||||
|
mkdir -p /home/hostuser || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN chown -R ${HOST_UID}:${HOST_GID} /server || true
|
||||||
|
|
||||||
|
ENV HOME=/home/hostuser
|
||||||
|
USER ${HOST_UID}:${HOST_GID}
|
||||||
|
|
||||||
|
# For dev, we install in container at runtime since volumes mount.
|
||||||
CMD ["sh", "-c", "cd /server && npm install --no-audit --no-fund --silent && npm rebuild sqlite3 && npm run start:dev"]
|
CMD ["sh", "-c", "cd /server && npm install --no-audit --no-fund --silent && npm rebuild sqlite3 && npm run start:dev"]
|
@ -1,5 +1,10 @@
|
|||||||
FROM node:20-bullseye
|
FROM node:20-bullseye
|
||||||
|
|
||||||
|
# Allow host UID/GID to be provided so test artifacts are created with
|
||||||
|
# matching ownership when the workspace volume is mounted.
|
||||||
|
ARG HOST_UID=1000
|
||||||
|
ARG HOST_GID=1000
|
||||||
|
|
||||||
# Install Chromium and related deps at image build time so test runs are fast
|
# Install Chromium and related deps at image build time so test runs are fast
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends chromium ca-certificates fonts-liberation curl \
|
&& apt-get install -y --no-install-recommends chromium ca-certificates fonts-liberation curl \
|
||||||
@ -23,5 +28,24 @@ COPY tools/puppeteer-test/ /opt/puppeteer-test/
|
|||||||
|
|
||||||
WORKDIR /opt/puppeteer-test
|
WORKDIR /opt/puppeteer-test
|
||||||
|
|
||||||
|
## Create a host user so files created during test runs have the host UID/GID
|
||||||
|
RUN if ! getent group ${HOST_GID} >/dev/null 2>&1; then \
|
||||||
|
groupadd -g ${HOST_GID} hostgroup; \
|
||||||
|
else \
|
||||||
|
echo "group for GID ${HOST_GID} already exists"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN if ! getent passwd ${HOST_UID} >/dev/null 2>&1; then \
|
||||||
|
useradd -m -u ${HOST_UID} -g ${HOST_GID} -s /bin/bash hostuser; \
|
||||||
|
else \
|
||||||
|
echo "user for UID ${HOST_UID} already exists"; \
|
||||||
|
mkdir -p /home/hostuser || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN chown -R ${HOST_UID}:${HOST_GID} /opt/puppeteer-test || true
|
||||||
|
|
||||||
|
ENV HOME=/home/hostuser
|
||||||
|
USER ${HOST_UID}:${HOST_GID}
|
||||||
|
|
||||||
# Default entrypoint runs the test; the workspace is mounted by docker-compose
|
# Default entrypoint runs the test; the workspace is mounted by docker-compose
|
||||||
ENTRYPOINT ["node", "test.js"]
|
ENTRYPOINT ["node", "test.js"]
|
||||||
|
18
README.md
18
README.md
@ -38,6 +38,24 @@ docker compose down --remove-orphans
|
|||||||
|
|
||||||
# Build images
|
# Build images
|
||||||
docker compose build
|
docker compose build
|
||||||
|
|
||||||
|
### Ensuring container-created files match your host UID/GID
|
||||||
|
|
||||||
|
When running containers that mount the workspace (dev/test), files created by the container may be owned by root which can be inconvenient on the host. To avoid this, images in this repo accept build-time args `HOST_UID` and `HOST_GID` and create a matching user inside the image. Set these to your current UID/GID before building so runtime-created files use your ownership.
|
||||||
|
|
||||||
|
Example (bash):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export HOST_UID=$(id -u)
|
||||||
|
export HOST_GID=$(id -g)
|
||||||
|
# Build images with the host UID/GID baked in
|
||||||
|
docker compose build peddlers-test peddlers-of-ketran peddlers-client peddlers-of-ketran-dev
|
||||||
|
|
||||||
|
# Then run in dev mode as usual (hot-reload):
|
||||||
|
PRODUCTION=0 docker compose up -d --profile dev
|
||||||
|
```
|
||||||
|
|
||||||
|
If you prefer to set these in `.env`, add `HOST_UID=...` and `HOST_GID=...` to the file in the repo root.
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Development Mode
|
#### Development Mode
|
||||||
|
@ -5,6 +5,9 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- HOST_UID=${HOST_UID:-1000}
|
||||||
|
- HOST_GID=${HOST_GID:-1000}
|
||||||
restart: always
|
restart: always
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@ -23,6 +26,9 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.dev
|
dockerfile: Dockerfile.dev
|
||||||
|
args:
|
||||||
|
- HOST_UID=${HOST_UID:-1000}
|
||||||
|
- HOST_GID=${HOST_GID:-1000}
|
||||||
volumes:
|
volumes:
|
||||||
- ./server:/server:rw
|
- ./server:/server:rw
|
||||||
- ./db:/db:rw
|
- ./db:/db:rw
|
||||||
@ -41,6 +47,9 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- HOST_UID=${HOST_UID:-1000}
|
||||||
|
- HOST_GID=${HOST_GID:-1000}
|
||||||
working_dir: /client
|
working_dir: /client
|
||||||
volumes:
|
volumes:
|
||||||
- ./client:/client:rw
|
- ./client:/client:rw
|
||||||
@ -73,6 +82,9 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.test
|
dockerfile: Dockerfile.test
|
||||||
|
args:
|
||||||
|
- HOST_UID=${HOST_UID:-1000}
|
||||||
|
- HOST_GID=${HOST_GID:-1000}
|
||||||
working_dir: /opt/puppeteer-test
|
working_dir: /opt/puppeteer-test
|
||||||
# Mount the workspace so test artifacts (screenshots) are written back to host
|
# Mount the workspace so test artifacts (screenshots) are written back to host
|
||||||
volumes:
|
volumes:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user