Closed truong0vanchien closed 2 years ago
Hi,
there is not much for me to see here. What did you do to start the extra containers? How are they configured?
Have a look at https://github.com/mkuf/prind/issues/22, there I described two ways to achieve this.
Thinking about this again, running the stack multiple times might not work, as container labels will overlap between stacks and traefik will pick up containers from outside the current stack.
This might cause the behaviour, you're experiencing. Without knowing how you got to this point, I can't give you any advice on how to proceed.
You're probably better off, writing your own compose file that houses multiple klipper and moonraker services, that are not proxied by traefik. You can still use traefik for proxying webcam services and the frontend of your choice.
-Markus
Hi Mkuf, I used the second method you mentioned in #22
Alternatively, you could start the whole stack multiple times. Clone prind into a different subdirectory and reconfigure the portbindings for traefik in your docker-compose.override.yaml. You can then access all Services via a different Port (in this case 81). Keep using different Ports for each printer that you'd like to run.
services: traefik: ports:
- 81:80 This comes with the Downside that supporting Services such as traefik or the web frontends run multiple times. This requires more resources but is probably the easiest way if you do not want to deal with writing compose files yourself.
As I observed, the problem should be from overlapping Klipper and moonraker twice in the same port. Anyway, thanks for supporting. I will try another method to deal with multiple printers. Regards.
You could just go ahead and use the templating that is already in place for the klipper service to create new instances of klipper.
There is no templating for moonraker in place, but you could easily adapt that and also create multiple moonraker instances from a common template. I'd omit the traefik labels on those moonraker services and add a portbinding for every printer you'd like to run.
Keep in mind, that for every printer you'd like to run, you will also need a unique set of docker-volumes. The config directory might be shared between all services, but every service needs its own config file.
Let me know how this works for you. I'd be happy to add multi printer support for everybody to use. I'm afraid that, usability wise, this is not as straight forward. With multiple instances of the same service, we are reaching the limits of what docker compose can achieve, without being to complicated for novice users.
-Markus
Thinking about this further, multiple printers as a extension of the current functionality is not possible without breaking things or worsen the user experience.
If anyone can come up with a solution that integrates well with the current docker file without adding too much around the vanilla docker compose configs (e.g. extensive scripting to build templates on the fly), I'm happy to discuss this in a PR.
For the Time being, anyone interested in using the Container Images in their own compose file, this might be a starting point.
## Common Templates
x-klipper-svc: &klipper-svc
image: mkuf/klipper:latest
restart: unless-stopped
volumes:
- ./config:/opt/cfg
- run:/opt/run
- gcode:/opt/gcode
- log:/opt/log
x-moonraker-svc: &moonraker-svc
image: mkuf/moonraker:latest
restart: unless-stopped
volumes:
- /dev/null:/opt/klipper/config/null
- /dev/null:/opt/klipper/docs/null
- ./config:/opt/cfg
- run:/opt/run
- gcode:/opt/gcode
- log:/opt/log
## Service Definitions
services:
## Printer1
## Access api via port 8001/tcp
printer1-klipper:
<<: *klipper-svc
command: -I run/printer1-klipper.tty -a run/printer1-klipper.sock cfg/printer1.cfg -l log/printer1-klippy.log
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
printer1-moonraker:
<<: *moonraker-svc
command: -c cfg/printer1-moonraker.cfg -l log/printer1-moonraker.log
ports:
- 8001:7125
## Printer2
## Access api via port 8002/tcp
printer2-klipper:
<<: *klipper-svc
command: -I run/printer2-klipper.tty -a run/printer2-klipper.sock cfg/printer2.cfg -l log/printer2-klippy.log
devices:
- /dev/ttyUSB1:/dev/ttyUSB1
printer2-moonraker:
<<: *moonraker-svc
command: -c cfg/printer2-moonraker.cfg -l log/printer2-moonraker.log
ports:
- 8002:7125
## Use Mainsail as Frontend
mainsail:
image: ghcr.io/mainsail-crew/mainsail:edge
restart: unless-stopped
ports:
- 80:80
volumes:
run:
gcode:
log:
The template from https://github.com/mkuf/prind/issues/28#issuecomment-1179405557 has been updated to work with the most resent image versions and added to main in https://github.com/mkuf/prind/commit/ff4ca0222645677ef88b765666e7a54d67d53fc1
@mkuf Thank for the multiple printer compose file. My use case is a bit different where by my printers are not always online at the same time. I tried running the standard prind compose multiple times from different directories but that has colliding name spaces. I was wondering if it is possible to enhance the multiple printer compose file to restart Klipper/Moonraker containers for one printer while other is online.
Right now, I am doing this by running two printers in 2 VM's and running prind on each VM. That is obviously very wasteful way of doing it. But my compose knowledge is terrible and I am wondering if you help or give me some pointers on what to do to achieve this.
@rizwansarwar this is probably related to https://github.com/mkuf/prind/issues/51
There is nothing on the docker or compose side that can be done to start/stop services depending on the device plugged in.
You can create udev rules on your host that do the work for you.
The following is untested but would be my approach to automate this.
The script arguments vary based on the action of the device, where the first argument is the same value as the label value for org.prind.printer
and the second argument is the docker command that should be executed, in this case restart
or stop
. This assumes that you use the labeling proposed in the custom example.
ACTION=="add",SUBSYSTEM=="tty",ATTRS{idVendor}=="0000",ATTRS{idProduct}=="0000",RUN+="/opt/printerupdown.sh printer1 restart"
ACTION=="remove",SUBSYSTEM=="tty",ENV{ID_VENDOR_ID}=="0000",ENV{ID_MODEL_ID}=="0000",RUN+="/opt/printerupdown.sh printer1 stop"
ACTION=="add",SUBSYSTEM=="tty",ATTRS{idVendor}=="0001",ATTRS{idProduct}=="0000",RUN+="/opt/printerupdown.sh printer2 restart"
ACTION=="remove",SUBSYSTEM=="tty",ENV{ID_VENDOR_ID}=="0001",ENV{ID_MODEL_ID}=="0000",RUN+="/opt/printerupdown.sh printer2 stop"
See https://unix.stackexchange.com/questions/28548/how-to-run-custom-scripts-upon-usb-device-plug-in for further info on how to set your idVendor and idProduct or other attributes of your device.
You'll probably have to do some digging yourself, as this stackexchange thread suggests that the remove action should use ENV
instead of ATTRS
which I can not verify.
https://stackoverflow.com/questions/31055611/how-do-i-use-udev-to-run-a-shell-script-when-a-usb-device-is-removed
The script that gets called is just a wrapper for docker and starts/stops containers by their label.
#!/bin/bash
printer=${1}
action=${2}
docker ${action} $(docker ps -aqf "label=org.prind.printer=${printer}")
-Markus
@mkuf wow, so quick response. Actually I already use the uDev rules to attach printers to proper TTY so I could extend it to use above.
I think you have given the answer to what I was really after. I was under the impression that I needed to restart the entire stack, but as you pointed out, I could just restart the relevant printer container. Thank you so much.
Hi Mkuf, I am using Fluidd of your repo. Since It is run by docker so I am going to use two Fluidd docker images connecting two my printers. I managed to run those at 2 different ports (port 80 and port 4040) and different names. Does your repo support it? Since I have no luck on this, if I run one printer, it worked fine but the second docker always got "gateway timeout" when accessing, this is my docker ps:
Could you give me some advice? Thanks in advance.