Skip to content
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

Add Dockerfile #253

Closed
wants to merge 1 commit into from
Closed

Add Dockerfile #253

wants to merge 1 commit into from

Conversation

mkuf
Copy link
Contributor

@mkuf mkuf commented Oct 26, 2021

Hi There,

for a recent Project of mine called prind, I build moonraker Docker Images on a daily basis.

These Images are decoupled from the actual Source-Repo and use git to fetch the code.
Based on my work I created a Dockerfile that can be used directly with this Repo.

The Image itself is a multistage Docker file to keep the runtime image as small as possible.

As per install-moonraker.sh there are multiple Apt packages installed in the runtime image, on which I am not sure if they are actually needed at runtime.
Any Input here would be welcome, as omitting these Packages would slim down the Image even more.

-Markus

This Commit adds a Dockerfile to build a Runtime Image of Moonraker

Signed-off-by: Markus Kueffner <kueffner.markus@gmail.com>
EXPOSE 7125
VOLUME ["/opt/run", "/opt/cfg", "/opt/gcode", "/opt/db"]
ENTRYPOINT ["/opt/venv/bin/python", "moonraker/moonraker/moonraker.py"]
CMD ["-c", "cfg/moonraker.cfg"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation refers to the config files a moonraker.conf a few times [1] [2], so it seems like it would be a good idea to follow that convention.

@dudeofawesome
Copy link

I'm running your image in my setup and everything seems to be working, but I do see some logs about Moonraker expecting to find systemd. I don't think this will cause any issues, but it was a bit confusing to see these errors.

[shell_command.py:_create_subprocess()] - shell_command: Command (systemctl list-units --all --type=service) failed
Traceback (most recent call last):
  File "/opt/moonraker/moonraker/components/shell_command.py", line 256, in _create_subprocess
    transport, protocol = await loop.subprocess_exec(
  File "/usr/local/lib/python3.10/asyncio/base_events.py", line 1652, in subprocess_exec
    transport = await self._make_subprocess_transport(
  File "/usr/local/lib/python3.10/asyncio/unix_events.py", line 207, in _make_subprocess_transport
    transp = _UnixSubprocessTransport(self, protocol, args, shell,
  File "/usr/local/lib/python3.10/asyncio/base_subprocess.py", line 36, in __init__
    self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
  File "/usr/local/lib/python3.10/asyncio/unix_events.py", line 799, in _start
    self._proc = subprocess.Popen(
  File "/usr/local/lib/python3.10/subprocess.py", line 966, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/local/lib/python3.10/subprocess.py", line 1842, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'systemctl'

I wonder if there's a way to get Moonraker to skip the service check in machine.py?

@Arksine
Copy link
Owner

Arksine commented Nov 3, 2021

I recently added some patches for Moonraker to detect if its running in a container, so it would be possible to disable the systemctl commands. The issue is that I know of at least one other user that has set up a container which "fakes" systemctl by symlinking it to supervisor.

Generally speaking I don't have an issue with adding a dockerfile to Moonraker, but I think perhaps that it might be better for it have its own repo with its own maintainer. Also I'm not sure if the particular approach in this dockerfile is the correct one. I know that the general idea is that you have "one service per container", however in this case it might be better to have "one instance per container", where the container encapsulates an instance of Klipper, Moonraker, and and any 3rd party agents that are tied to an instance.

@dudeofawesome
Copy link

I would personally recommend keeping the Moonraker container separate from a Klipper container, just since that's how Docker typically is expected to work. It also allows for more specific permissions for each container.

Both mkuf's configuration and mine (work in progress) run Klipper in its own container.

@Arksine
Copy link
Owner

Arksine commented Nov 4, 2021

I would personally recommend keeping the Moonraker container separate from a Klipper container, just since that's how Docker typically is expected to work. It also allows for more specific permissions for each container.

I don't really agree, there is no expectation that a Docker image contain only a single service. This is often how its used, but it is not uncommon for a docker image to contain a set of services. When you separate Moonraker and Klipper you lose containment of the unix socket. This allows any instance of Moonraker to communicate with any instance of Klipper on the system. IMO this increases complexity for the user, which defeats the purpose of using a containers.

@mkuf
Copy link
Contributor Author

mkuf commented Nov 4, 2021

Following the offical Docker Docs, there is - as you said - no expectation to run only a single Process per container,
but it should generally be avoided, as Docker provides the infrastructure (network & volumes) to allow communication between containers.

It’s ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application. You can connect multiple containers using user-defined networks and shared volumes.

(via https://docs.docker.com/config/containers/multi-service_container/)

This allows any instance of Moonraker to communicate with any instance of Klipper on the system.

Which is also true if multiple moonraker processes reside on the same machine.
Using Containers in this context does not make a difference, it is merely another method to start a moonraker process.

In my experience working with containers for several years in various enterprise settings,
multi-process Images are quite rare and only cover super specific usecases, which moonraker and klipper are not.

-Markus

@Arksine
Copy link
Owner

Arksine commented Nov 5, 2021

Which is also true if multiple moonraker processes reside on the same machine.
Using Containers in this context does not make a difference, it is merely another method to start a moonraker process.

I think there is a misunderstanding here. In my view, if you are using containers, it is not a good thing to expose the unix socket to the entire machine. Encapsulating the unix socket would guarantee that Moonraker is connected to the correct instance of Klipper and prevent the need to assign the sockets different names.

In my experience working with containers for several years in various enterprise settings,
multi-process Images are quite rare and only cover super specific usecases, which moonraker and klipper are not.

I would be curious as to what circumstances would be defined as an acceptable use case, and why the Klipper ecosystem would not meet that requirement.

Regardless, I think we are going a bit off tangent. Given that there are multiple approaches to creating a docker image I think that the Dockerfile would better reside in its own project repo. Moonraker could add links to such repos (and dockerhub links if appropriate) in its documentation.

@Piezoid
Copy link

Piezoid commented Nov 5, 2021

One downside of running both Klipper and Moonraker inside docker doesn't offer a way of supervising multiple processes inside a container. Moonraker will either have to support another supervisor than systemd, or managing the Klipper process by himself.

A multi-container setup is more flexible, but Moonraker's management of process (stop/restart), and component updates, will have to go through some orchestration boundaries.

I think the management features currently offered by Moonraker are great, but a bit too opinionated. Thankfully they are optional and interfacing systemd and git is a good compromise. A possibility could be delegating this to interchangeable providers.

For my rpis setup, I've built a custom vagrant like tool for embedded deployment. It uses layered squashfs for storage and leverages systemd-machined to run systemd daemon in each container/"machine". It's far from production ready, but offers interesting possibilities.

@mkuf
Copy link
Contributor Author

mkuf commented Nov 5, 2021

Oh, that was a misunderstanding indeed.

The relationship between moonraker and klipper would be considered a multi-container application.
Such applications are generally managed via dedicated tools like docker compose or even kubernetes.
These tools take care of generating the (in this case 1-to-1) relation between Containers.
Creating a new Deployment with such a tool would take care of creating and naming volumes and containers.

Running moonraker and klipper within the same container would get rid of the extra volumes, but the
socket can not be considered safe or isolated from other processes, as it is still available to the host via the overlay2 filesystem.

That said, I think it depends on what the goal of providing a moonraker docker image is.
My intent is to provide images as building blocks to enable users to set up this software for their specific usecase, which requires the image to be as generic as possible.
My intent is not to protect them from themselves or create a competitor to something like octopi or fluiddpi Images based on docker.

This is also reflected in the docker-compose.yaml for prind, where every component is considered a building block and depending on the profile you choose to start, they get glued together in a different way.

I'd also be fine with maintaining the Dockerfile loosely coupled to the moonraker project as part of prind.

-Markus

@Arksine
Copy link
Owner

Arksine commented Nov 5, 2021

One downside of running both Klipper and Moonraker inside docker doesn't offer a way of supervising multiple processes inside a container. Moonraker will either have to support another supervisor than systemd, or managing the Klipper process by himself.

Generally I agree with this. I do have plans to support interfacing with systemd via DBus, and the logical way of of doing this would be through an interface that can be derived to support multiple providers, for example: systemd-cli, systemd-dbus, supervisord-cli, supvervisord-xml.

@mkuf Thanks for the explanation, that indeed clarifies your approach and it makes sense. In the short term I propose that I add a section to Moonraker's readme for Docker Images and provide a link to prind with a brief description. At a later date I'll look into updating the documentation with either a description of alternative methods of installation or links to such.

@mkuf
Copy link
Contributor Author

mkuf commented Nov 5, 2021

@mkuf Thanks for the explanation, that indeed clarifies your approach and it makes sense. In the short term I propose that I add a section to Moonraker's readme for Docker Images and provide a link to prind with a brief description. At a later date I'll look into updating the documentation with either a description of alternative methods of installation or links to such.

Sounds good to me. 👍
I'll close this PR then.

-Markus

@mkuf mkuf closed this Nov 5, 2021
@mkuf mkuf mentioned this pull request Feb 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants