bastilimbach / docker-MagicMirror

Docker image for the Magic Mirror 2 project by Michael Teeuw.
https://hub.docker.com/r/bastilimbach/docker-magicmirror/
MIT License
185 stars 54 forks source link

Use smaller base image #46

Open sthuber90 opened 4 years ago

sthuber90 commented 4 years ago

To use smaller base image, alpine is used as a new base. To keep only required files multi-stage builds are used. In addition, unnecessary files are cleaned up from node_modules folder.

This PR is intended to fix #44

The overall size reduction on linux/amd64 (Mac) can be seen here: Bildschirmfoto 2020-07-06 um 17 31 38

As you can see MagicMirror still works: Bildschirmfoto 2020-07-06 um 17 32 26

bastilimbach commented 4 years ago

Wow the size difference is huge! Thank you for your contribution 😊

sthuber90 commented 4 years ago

Thank you for your input. I reduced the COPYing between the stages. package.json and package-lock.json are needed for MagicMirror to run, otherwise it errors with a message mentioning those files are missing.

As git is not part of the alpine based image the following error occures.

[2020-07-08 07:04:20.600] [LOG]    Ready to go! Please point your browser to: http://0.0.0.0:8080
[2020-07-08 07:05:12.323] [LOG]    Create new calendar fetcher for url: http://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics - Interval: 300000
[2020-07-08 07:05:12.435] [LOG]    Create new news fetcher for url: http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml - Interval: 300000
[2020-07-08 07:05:12.474] [ERROR]  Error: spawn git ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:267:19)
    at onErrorNT (internal/child_process.js:469:16)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)
[2020-07-08 07:05:12.969] [INFO]   Newsfeed-Fetcher: Broadcasting 57 items.

The error doesn't seem to affect MagicMirror. Everything seems to work as usual.

Adding gitadds 18 MB to the image size and another error appears, while the previously mentioned disappears:

[2020-07-08 07:18:18.900] [LOG]    Ready to go! Please point your browser to: http://0.0.0.0:8080
[2020-07-08 07:19:25.987] [LOG]    Create new calendar fetcher for url: http://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics - Interval: 300000
[2020-07-08 07:19:26.005] [LOG]    Create new news fetcher for url: http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml - Interval: 300000
[2020-07-08 07:19:26.038] [ERROR]  fatal: not a git repository (or any of the parent directories): .git

[2020-07-08 07:19:26.494] [INFO]   Newsfeed-Fetcher: Broadcasting 57 items.

Adding the .git folder from MagicMirror to the docker image as well resolves the errors, but it feels weird to have git in a production image.

The new image size with git and .git would then be 330 MB on linux/amd64

What are your thoughts on this?

khassel commented 4 years ago

My thoughts:

sthuber90 commented 4 years ago

It is clear that space is not as huge of a cost factor as it used to be. Nevertheless, I don't see the point of using up almost 2 GB of my raspberry's space when also ~330 MB will do. I still strongly believe that having a smaller image is desireable

Legion2 commented 4 years ago

I like the idea of having the normal debian based image as default and the alpine image with a -alpine tag

khassel commented 4 years ago

I think @bastilimbach have to decide if he wants to maintain both images.

A long time ago I discussed with him the idea not only providing images for server only mode. He didn't want this at that time so I decided to make my own docker setup. And here I decided already to provide both image types (alpine and debian).

I think we should bring these things together again, so may take a look at this setup for deciding what of the stuff should also implemented here.

Beside the size (the debian image is currently 544MB) there are may other things to discuss as running as non-root and copying default modules in entrypoint.

sthuber90 commented 4 years ago

On a side note the 544 MB you mentioned are only shown like this on Docker hub. If you pull the image the size is above 1 GB

Bildschirmfoto 2020-07-10 um 10 50 32

The images tagged with 2.12.0 are the ones I created during my work in progress. The one with the latest tag was pulled just now from Docker Hub docker pull bastilimbach/docker-magicmirror:latest.

Like the idea of having one repository for MagicMirror in docker. Honestly, started with my own Docker Image as well but came to my senses and thought that in the end everybody benefits if it's all maintainable in one repository.

In the end, it's still your decision @bastilimbach

In the meantime, maybe I will have some time to try to setup a draft of how we can build both debian and alpine images

khassel commented 4 years ago

The 544 MB are the result building with this Dockerfile using slim base image.

The build setup could be similiar to mine, building debian first and copying the mm-folder to the alpine image.

sthuber90 commented 4 years ago

Alright, I was able to put a little something together. Didn't have the time to have a throughout look into your repo @khassel Bildschirmfoto 2020-07-13 um 18 35 40 As you can see, Travis now builds MagicMirror version 2.12.0 on NodeJS 12 and 14 for Debian and Alpine with different tags. I mean this as a kinda proposal of what could be done. Currently, only buster based images get tagged with "latest" but not alpine to avoid any conflicts with solutions built on top of the current Debian based image.

To Do:

Looking forward to your feedback and input

Legion2 commented 4 years ago

@bastilimbach can we merge #45 first?

Legion2 commented 4 years ago

we can also create a GitHub action which checks for new releases of Magic Mirror and creates a pull request here with the generated dockerfiles for the new release.

khassel commented 4 years ago

Looking forward to your feedback and input

I feel not very comfortable only commenting things here ...

sthuber90 commented 4 years ago

The templating was inspired by the official Docker images available for NodeJS, Go, etc. and how those repositories are set up and how their images are build. It may not be necessary to got that far here, if your proposed ARG solution works.

Git will be added, as we discussed. Sorry, if I forgot it. Nonetheless, I think using multi-stage builds is valid. This way we will not package otherwise unneccessary files such as tests from the MagicMirror repo in the Docker image. Even though it may only be small size difference, I don't see the point why we shouldn't use multi-stage builds.

Instead of starting a discussion on buster-slim vs buster. Would it be acceptable to have a -slim tag?

Tag base image
2.12.0 node:lts-buster
2.12.0-slim node:lts-buster-slim
2.12.0-alpine node:lts-alpine

Instead of lts should the Node version be frozen to 12 (LTS) or 14 or just using the lts Docker tag?

khassel commented 4 years ago

I don't see the point why we shouldn't use multi-stage builds.

the idea was to do the stuff in one stage (see no image size diff to multi stage), this is untested:

FROM node:12-alpine

ENV NODE_ENV production

# get magic mirror
ARG branch=master
RUN set -o pipefail \
    apk update && apk add --no-cache git \
    && apk add --no-cache --update libintl \
    && apk add --no-cache --virtual build_deps gettext \
    && cp /usr/bin/envsubst /usr/local/bin/envsubst \
    && apk del build_deps \
    && mv /usr/local/bin/envsubst /usr/bin/envsubst
    && mkdir -p /tmp/magic_mirror \
    && cd /tmp/magic_mirror \
    && git clone --depth 1 -c advice.detachedHead=false -b ${branch} https://github.com/MichMich/MagicMirror.git .
    && mkdir -p /opt/magic_mirror \
    && cp -R config /opt/magic_mirror/default_config \
    && cp -R modules /opt/magic_mirror/default_modules \
    && npm set unsafe-perm true \
    && npm ci \
    # prune unnecessary files from ./node_modules, such as markdown, typescript source files, and so on. https://github.com/tj/node-prune
    && wget -q https://install.goreleaser.com/github.com/tj/node-prune.sh | sh \
    # it is intentional that modules are not copied to /opt/magic_mirror folder. Please keep alphabetically sorted
    && cp -R \
        .git \
        config \
        css \
        fonts \
        index.html \
        js \
        node_modules \
        package.json \ 
        package-lock.json \ 
        serveronly \
        translations \
        vendor /opt/magic_mirror \
    && rm -rf /tmp/magic_mirror

WORKDIR /opt/magic_mirror

EXPOSE 8080

The other questions (how many and which images) should be answered by the owner of this repo. We can think about many options, but he has to merge in the end ...

sthuber90 commented 4 years ago

We both just have different ways of solving the same problem, I guess. Personally, I am not so fond of big RUN statements. I agree with you though that whatever comes next needs to be @bastilimbach decision

xbgmsharp commented 4 years ago

That is great that this repository support multiple architecture. However there is still a image size issue. My docker image is half the bastilimbach/docker-magicmirror image for the same content.

# docker images | grep magic
xbgmsharp/docker-magicmirror      latest              1f351bd4aa49        20 hours ago        412MB
bastilimbach/docker-magicmirror   latest              95bfee9026c3        5 weeks ago         970MB
sthuber90 commented 4 years ago

@xbgmsharp as you can tell from the discussion, the changes I proposed to make the image smaller have not (yet) been merged.

Legion2 commented 4 years ago

also see #48