caprover
caprover copied to clipboard
[Question] Converting custom container certbot service to a one-shot service using the official certbot container
Currently, Caprover is using a custom version of the certbot image, which modifies it in such a way that it stays running for (essentially) an indefinite amount of time.
I feel like this is unnecessary, as Docker services allow the specification of services that do not restart automatically unless a failure occurs (or even do not restart automatically at all).
In other words, it is quite possible for CapRover to, instead of entering a shell within a running service's container in order to interact with certbot, create a one-shot service with the proper command set in the service specification (without certbot, as certbot is the entrypoint therefore the command is passed as arguments to the certbot binary), and either reuse the same service while modifying the command property appropriately, or clean it up and create new ones as required.
This would, among other things, make updating the underlying certbot image and binaries easier, as all that would be required of CapRover maintainers in such case, would be to update the certbot image tag (or even just use the latest tag if they're comfortable with that).
It would also make my efforts of patching and subsequently building ARM64 versions of CapRover for people to use easier, as it would mean one less image to build when it gets updated.
I personally have stopped using CapRover recently, as it was no longer enough for my use case, but I have no issues in continuing to provide support to ARM64 users of CapRover in the sense of patching, building and publishing images of CapRover and supporting containers, required to run CapRover on ARM64.
So, my question is, is this something the CapRover Maintainers would be willing to do?
Thanks for bringing it up - the issue with recreating images on ARM is not something that I had considered.
Regarding the one-off services, as far as I know there is not way to keep the service alive an just continue running the bash command on it. Without that, one off services are prone to race condition and there might be a lot of edge cases where two containers create a conflict.
But that doesn't mean that we can't have a better solution. One thing we can experiment with is to avoid having to use the prebuilt image on Docker hub. Instead, we can pull the image and just change the entry point so that it'll stay alive. This can be done by rebuilding the image. Since Docker caches the image layers, this won't be resource intensive. It'll be equivalent to just pulling the image - which we already do.
I think that the whole point of a one-off service is that it runs a command that, under normal circumstances, exits once it's finished with it's work. And my whole point was that that would be how they behaved.
As for them being prone to race conditions, as long as the service is configured to have only one replica, and the update strategy is stop first rather than start first, you won't have a scenario where two certbot instances would be running at the same time, performing clashing actions, as the docker daemon will first stop the currently running container before running the new one.
The only thing I'd be potentially afraid of would be trying to run a new command on certbot before the old one has finished. But that's something that could be rather easily checked by looking at the tasks of the service and checking that there aren't any running tasks, or tasks waiting to be run.
Now, ideally of course, you'd have docker queue up the "versions" of the service one after another, and wait for the tasks to terminate on their own, but afaik, there isn't a mechanism for that directly in docker.
One other option, that, in my opinion is still better than using a custom image of certbot, is including the certbot cli inside the caprover image itself, which makes more sense than trying to run certbot in a service, as certbot isn't a service in the first place.
The third and final option I see would be dropping nginx in it's entirety, and replacing it with something like traefik, which is a) made for running on docker swarm (among other things) in the first place, b) already integrates an ACME client for Let's Encrypt and automatically manages certificates for the services it serves, and finally c) uses standard docker mechanisms, rather than quite error-prone configuration files, to configure things like routing rules, request/response pre-processing, etc.
I personally am quite a fan of the third option, as I got to play around with Traefik for a bit, and ended up using it on my cluster even if just because of how easy it is to work with. I do however understand that it might be too much of a change for both CapRover's users and for the developers to implement into CapRover.