-
-
Notifications
You must be signed in to change notification settings - Fork 274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Version 0.15.4 #2096
Version 0.15.4 #2096
Changes from 10 commits
051f439
5043b9c
84f57bb
2bf4231
b7fb086
cb2b28c
afdca50
dfe7b0d
68ff84c
c042c24
3de04bd
fbc099d
76d46ec
47c4011
cc240f4
a879358
858ccd7
c008cc9
5b5121a
995c8a4
eba3010
d2a40dd
714936a
6a7532b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,106 @@ | ||
FROM node:20.2.0-slim | ||
FROM node:20.2.0-slim as compiler | ||
|
||
#RUN apt-get update && apt-get -y install git wget openssl | ||
|
||
WORKDIR /app | ||
|
||
# Define node.js environment variables | ||
#RUN git clone https://github.com/ajnart/homarr.git . | ||
COPY . . | ||
|
||
RUN yarn install | ||
COPY .env.example .env | ||
RUN yarn build | ||
|
||
|
||
FROM node:20.2.0-alpine3.18 | ||
|
||
#ARGS is only for build | ||
|
||
ARG PORT=7575 | ||
|
||
# Keep free id >= 1000 for user, under node:x image by default node user uses 1000:1000 | ||
ARG NODE_UID=800 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bulk of this I commented on from the original PR, and discourage the approach taken. There is a feature with Docker that should arrive in future for the concern with better mapping container writes to volume mounts with different UID/GID. Usually the issue for users is just inconvenience if they want to interact with the files from the host, as otherwise they could keep it in a named data volume which avoids some issues ( I haven't looked at the issue that motivated these changes with PUID/PGID, but I assume it's not actually breaking functionality. |
||
ARG NODE_GID=800 | ||
|
||
#PUID can be set during build and run time | ||
ARG PUID=801 | ||
ARG PGID=801 | ||
|
||
#it must be the same as the host, temporary 802 or any, automatically changed at runtime | ||
ARG DOCKER_GID=802 | ||
|
||
#By default, ping group using gid 999, keep free to possible docker host gid | ||
ARG PING_GID=803 | ||
|
||
# Expose the default application port | ||
EXPOSE $PORT | ||
ENV PORT=${PORT} | ||
|
||
# Define node.js environment variables | ||
ENV NEXT_TELEMETRY_DISABLED 1 | ||
ENV NODE_ENV production | ||
ENV NODE_OPTIONS '--no-experimental-fetch' | ||
|
||
COPY next.config.js ./ | ||
COPY public ./public | ||
COPY package.json ./temp_package.json | ||
COPY yarn.lock ./temp_yarn.lock | ||
# App environment variables | ||
ENV DATABASE_URL "file:/app/data/db.sqlite" | ||
ENV NEXTAUTH_URL "http://localhost:7575" | ||
ENV NEXTAUTH_SECRET NOT_IN_USE_BECAUSE_JWTS_ARE_UNUSED | ||
|
||
# Must be same as host user when using bind mount volumes | ||
ENV PUID $PUID | ||
ENV PGID $PGID | ||
|
||
RUN apk update && apk add --no-cache \ | ||
supervisor docker-cli shadow | ||
|
||
RUN usermod -u $NODE_UID node | ||
RUN groupmod -g $NODE_GID node | ||
|
||
RUN groupmod -g $PING_GID ping | ||
|
||
# Creating local homarr user and group | ||
RUN groupadd -g $PGID homarr | ||
RUN useradd homarr -u $PUID -g homarr --home-dir /app --shell /sbin/nologin | ||
RUN usermod -aG node homarr | ||
|
||
# Creating a local Docker group and add docker group to homarr user | ||
RUN groupadd -g $DOCKER_GID docker | ||
RUN usermod -aG docker homarr | ||
|
||
# Enable sudo for homarr user, only for debug and testing purposes | ||
#RUN apk add sudo | ||
#RUN echo "homarr ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers | ||
|
||
# Configure entrypoint | ||
COPY ./docker/entrypoint / | ||
RUN chmod +x /entrypoint.sh | ||
RUN chmod +x /docker-entrypoint.d/*.sh | ||
|
||
# Configure supervisord | ||
COPY ./docker/etc/supervisord.conf /etc/supervisord.conf | ||
COPY ./docker/etc/supervisor /etc/supervisor | ||
|
||
#RUN chown homarr:homarr /app | ||
USER node | ||
WORKDIR /app | ||
|
||
COPY --from=compiler --chown=node:homarr /app/next.config.js ./ | ||
COPY --from=compiler --chown=node:homarr /app/public ./public | ||
COPY --from=compiler --chown=node:homarr /app/package.json ./temp_package.json | ||
COPY --from=compiler --chown=node:homarr /app/yarn.lock ./temp_yarn.lock | ||
# Automatically leverage output traces to reduce image size | ||
# https://nextjs.org/docs/advanced-features/output-file-tracing | ||
COPY .next/standalone ./ | ||
COPY .next/static ./.next/static | ||
COPY ./scripts/run.sh ./scripts/run.sh | ||
RUN chmod +x ./scripts/run.sh | ||
COPY ./drizzle ./drizzle | ||
|
||
COPY ./drizzle/migrate ./migrate | ||
COPY ./tsconfig.json ./migrate/tsconfig.json | ||
COPY ./cli ./cli | ||
COPY --from=compiler --chown=node:homarr /app/.next/standalone ./ | ||
COPY --from=compiler --chown=node:homarr /app/.next/static ./.next/static | ||
|
||
RUN mkdir /data | ||
COPY --from=compiler --chown=node:homarr /app/scripts/run.sh ./scripts/run.sh | ||
RUN chmod +x ./scripts/run.sh | ||
COPY --from=compiler --chown=node:homarr /app/drizzle ./drizzle | ||
|
||
# Install dependencies | ||
RUN apt update && apt install -y openssl wget | ||
COPY --from=compiler --chown=node:homarr /app/drizzle/migrate ./migrate | ||
COPY --from=compiler --chown=node:homarr /app/tsconfig.json ./migrate/tsconfig.json | ||
COPY --from=compiler --chown=node:homarr /app/cli ./cli | ||
|
||
# Move node_modules to temp location to avoid overwriting | ||
RUN mv node_modules _node_modules | ||
|
@@ -45,22 +118,16 @@ RUN mv node_modules ./migrate/node_modules | |
# Copy temp node_modules of app to app folder | ||
RUN mv _node_modules node_modules | ||
|
||
RUN echo '#!/bin/bash\nnode /app/cli/cli.js "$@"' > /usr/bin/homarr | ||
RUN chmod +x /usr/bin/homarr | ||
RUN cd /app/cli && yarn --immutable | ||
|
||
# Expose the default application port | ||
EXPOSE $PORT | ||
ENV PORT=${PORT} | ||
# Root is needed for supervisord | ||
USER root | ||
|
||
ENV DATABASE_URL "file:/data/db.sqlite" | ||
ENV NEXTAUTH_URL "http://localhost:7575" | ||
ENV PORT 7575 | ||
ENV NEXTAUTH_SECRET NOT_IN_USE_BECAUSE_JWTS_ARE_UNUSED | ||
RUN echo '#!/bin/bash\nnode /app/cli/cli.js "$@"' > /usr/bin/homarr | ||
RUN chmod +x /usr/bin/homarr | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to use an If you use the distroless image suggestion, you don't have to worry about the |
||
HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=3 \ | ||
CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT} || exit 1 | ||
|
||
VOLUME [ "/app/data/configs" ] | ||
VOLUME [ "/data" ] | ||
ENTRYPOINT ["sh", "./scripts/run.sh"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since there was talking about reverting such changes. I do want to point out that you should avoid They create anonymous data volumes per container instance. Those will accumulate with each container created unless the container is disposed of (eg: It is worse for Docker Compose which will be more common in usage, as destroying containers does not remove these anonymous volumes they're tied to the project and service name, thus if you did for some reason want to rely on this implicit persistence it's more difficult to reset/discard it should the need arise ( Instead it's much better to just document these locations, either in proper docs or a Users that want to persist data should provide explicit config to indicate that, otherwise so long as a container is not destroyed it will persist any filesystem state it has when stopped/restarted (sometimes a source of bugs), whereas |
||
ENTRYPOINT [ "/entrypoint.sh" ] | ||
CMD [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
version: "2.1" | ||
services: | ||
#---------------------------------------------------------------------# | ||
# Homarr - A simple, yet powerful dashboard for your server. # | ||
#---------------------------------------------------------------------# | ||
homarr: | ||
container_name: homarr | ||
#image: ghcr.io/ajnart/homarr:latest | ||
build: # only for dev branch... | ||
context: . | ||
dockerfile: Dockerfile | ||
restart: unless-stopped | ||
environment: | ||
- PUID=1000 | ||
- PGID=1000 | ||
- DOCKER_GID=999 # Must be same as host docker group id | ||
- DATABASE_URL=file:/app/data/configs/db.sqlite | ||
volumes: | ||
- /var/run/docker.sock:/var/run/docker.sock # Optional, only if you want docker integration | ||
- ./homarr_persistence/configs:/app/data/configs | ||
- ./homarr_persistence/icons:/app/public/icons | ||
ports: | ||
- '7575:7575' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/bin/sh | ||
|
||
HOMARR_USER_PATHS="/app/data /app/public/icons" | ||
|
||
for path in $HOMARR_USER_PATHS | ||
do | ||
if [ ! -d "$path" ]; then | ||
mkdir -p $path | ||
fi | ||
|
||
find $path ! -user $PUID -print0 | while read -d $'\0' FILE | ||
do | ||
echo "${FILE} is not own by current user, fixing..." | ||
chown $PUID:$PGID ${FILE} | ||
done | ||
done | ||
|
||
echo Setting homarr UID to $PUID and GID to $PGID please wait... | ||
usermod -u $PUID homarr | ||
groupmod -g $PGID homarr | ||
|
||
DOCKER_GID=$(stat -c %g /var/run/docker.sock 2>/dev/null) | ||
if [[ $? -eq 0 ]]; then | ||
echo "SETTING DOCKER GID TO ${DOCKER_GID}" | ||
groupmod -g $DOCKER_GID docker | ||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#!/bin/sh | ||
# vim:sw=4:ts=4:et | ||
|
||
set -e | ||
echo "Entering entrypoint..." | ||
|
||
echo "Param \$1: $1" | ||
echo "User: "$(whoami) | ||
|
||
|
||
entrypoint_log() { | ||
if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then | ||
echo "$@" | ||
fi | ||
} | ||
|
||
if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then | ||
entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" | ||
|
||
entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" | ||
find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do | ||
case "$f" in | ||
*.envsh) | ||
if [ -x "$f" ]; then | ||
entrypoint_log "$0: Sourcing $f"; | ||
. "$f" | ||
else | ||
# warn on shell scripts without exec bit | ||
entrypoint_log "$0: Ignoring $f, not executable"; | ||
fi | ||
;; | ||
*.sh) | ||
if [ -x "$f" ]; then | ||
entrypoint_log "$0: Launching $f"; | ||
"$f" | ||
else | ||
# warn on shell scripts without exec bit | ||
entrypoint_log "$0: Ignoring $f, not executable"; | ||
fi | ||
;; | ||
*) entrypoint_log "$0: Ignoring $f";; | ||
esac | ||
done | ||
|
||
entrypoint_log "$0: Configuration complete; ready for start up" | ||
else | ||
entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" | ||
fi | ||
|
||
#exec "$@" | ||
|
||
# sys container init: | ||
# | ||
# If no command is passed to the container, supervisord becomes init and | ||
# starts all its configured programs (per /etc/supervisord.conf). | ||
# | ||
# If a command is passed to the container, it runs in the foreground; | ||
# supervisord runs in the background and starts all its configured | ||
# programs. | ||
# | ||
# In either case, supervisord always starts its configured programs. | ||
|
||
if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then | ||
exec supervisord -n "$@" | ||
else | ||
supervisord -c /etc/supervisord.conf & | ||
exec "$@" | ||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[program:homarr] | ||
command=/app/scripts/run.sh | ||
environment=HOME="/app",USER="homarr",LOGNAME="homarr" | ||
user=homarr | ||
stdout_logfile=/dev/stdout | ||
stdout_logfile_maxbytes=0 | ||
stderr_logfile=/dev/stderr | ||
stderr_logfile_maxbytes=0 | ||
autorestart=true | ||
startretries=0 | ||
stopasgroup=true | ||
killasgroup=true | ||
stopsignal=KILL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Careful with Alpine as a base image. Ensure that you're actually getting worthwhile benefits by using it, it's often a source of troubleshooting gotchas that are not fun to debug (memory leaks, poor performance, DNS, glibc vs musl, are all known issues projects have had with Alpine).
It's typically chosen for the smaller size and attribution of that being more secure as a smaller attack surface. Just be sure you're not giving too much of a trade-off with that choice when you can get fairly competitive sized images by using alternatives when this matters.
Fedora for example can install a minimal image with
dnf --installroot
, although for NodeJS that is 124MB, Alpine is about half of that. For context:node:slim
debian image you're using in the build stage is 217 MB.node:alpine
is 154MB.So Fedora is probably a win for you regardless size wise, while the
--installroot
approach would minimize deps (no package manager, minimal deps).Similar to Alpine, fedora releases are a bit more frequently than Debian, but Fedora releases do get updates to packages over time too (vs Debian releases which besides age don't tend to upgrade packages much between releases beyond security fixes). Whereas your
node
images have the benefit of being pinned (you can pin the package withdnf
too).The Docker image support isn't that critical to the project. Since you're already familiar with Debian /
apt
, perhaps stay with that and optionally take advantage of the image suggestion below (Debian too) as the final stage.That said you could try Google's debian based distroless NodeJS image too:
It weighs in at 143MB and as you can see above is quite minimal for internal contents. This is for a final stage image only that you
COPY
your build into as there is no other programs to run, nor package manager available.For security benefits that should serve you much better and keep things fairly simple.