I see a lot of start.sh scripts in Balena examples, but I thought the whole point of the CMD and ENTRYPOINT directives in Docker/Balena were to make PID 1 the running application. If an application within start.sh crashes, then Docker/Balena cannot know, therefore the service can crash right? Am I misunderstanding something?
I’m not entirely sure what you mean here. As long as the script is run with the exec form of
CMD, then these will be run as PID 1. I’m a bit confused by the statement about a start script crashing means the service can crash? The script is the executable for that service, and indeed if an error occurs in the script being executed (or the CMD being executed), then this will return a non-zero error code and the service will be restarted.
Could you please point us at one of examples where you believe this is an issue, so we can discuss it?
If we kill octoprint, does the container restart? If we kill mjpg-streamer-experimental, does the container restart?
If mjpg-streamer-experimental dies of its own accord, does that kill octoprint?
Or does nothing restart if anything dies?
Neither of these scenarios are acceptable, which is why they need to be ran as separate containers which are handled independently, there’s a term someone in the #docker irc on freenode used that I can’t recall right now to describe using something like start.sh, which is basically against the docker philosophy, or is not how things are supposed to be implemented.
The rule I gleamed from him was “One executable per entrypoint”.
So, that said, how am I supposed to run logic in my container such as “rotate the screen if #ROTATE=1” without using xrandr or some executable in a start.sh script?
Edit: Actually, I understand why this is fine for oneshot things that require logic. But I cannot understand how it’s fine for forking processes.
Thanks, that gives me a lot of context and I now understand what you’re talking about.
Yes, should any of those particular services die in startup in the script, then it absolutely will restart the service container. I think it’s extremely important to point out that this particular project predates the ability to run multicontainer projects on a balena device, and has not been updated since. As such, only one service container could be run, and because of this every independent service that was required as part of a project had to be executed via a startup script. Obviously, this is no longer the case as multicontainer support was released early last year.
I’d point to our projects since then, particularly the multicontainer getting started project itself which uses three separate services, each of which run their executable via
CMD. This conforms completely to the principals behind multiple docker/balena services.
I believe all of our recent demo projects use multicontainer and the single service methodology to full effect, some examples being:
At a quick glance, all of these do indeed use multiple services which are responsible for a single part of the system.
We obviously welcome PRs to our projects if you would like to contribute and shore up any issues you find!
Right, so now that you understand my context, how am I intended to rotate the screen without this snippet in a start.sh?
# rotate screen if env variable is set [normal, inverted, left or right] if [[ ! -z "$ROTATE_DISPLAY" ]]; then echo "YES" (sleep 3 && DISPLAY=:0 xrandr -o $ROTATE_DISPLAY) & fi
How am I intended to mount a samba share without start.sh? In this particular example
mkdir /media/open-share && echo "//$SAMBA_SERVER/does-samba/open-share /media/open-share cifs uid=0,iocharset=utf8,noperm,username=everyone,password=everyone 0 0" > /etc/fstab
Running this in start.sh is the only way I can get fstab to mount the disk to my current knowledge. Do you have a better approach?
I can understand why this is fine, though I was wondering if there’s a better way to do all of this.
So in the case of these particular cases, this is what we consider part of a sub-service, ie. these are required for one of the services to run. As such, no, there is not a better way to achieve this and putting them in a start script we would consider not a problem. The reason for this is there is no failsafe mode. If what you’re requiring the service to do fails because one of its dependencies fails (ie. the mounting of the SAMBA share), then the service itself is in a position where is inevitably also going to fail.
This is still a clear delineation between other services that may be running though, for example the UI service that attempts to talk to the service using the SAMBA share, noting it cannot and informing a user that there is a problem. For us, the key is to split these services as atomically as possible to ensure a safe, degraded failure mode. For direct hardware/network/software dependencies that a particular, atomicised service requires to not be present indicates that the service itself has failed.
Hopefully that makes sense, and thank you for an interesting discussion!