There are many projects that allow you to configure and manage the automated deployment of a service. From our experience, we have found that the small learning curve, mature tooling, generality, and widespread ecosystem support of Docker make for a relatively painless and sufficiently reliable deployment.
Upon first glance, using a single Dockerfile to start all services required by the node may sound antithetical to best practices. However, we have found that restricting blockchain node deployment to a single container makes the orchestration of multiple nodes much easier because of coordinated start/stop and single volume mounting.
Some blockchain nodes and their dependent services must be started and stopped in some explicit order to function correctly and prevent corruption. With distributed services (in multiple containers), this sequencing of operations can require a custom deployer for each network. Building and maintaining these deployers can take a lot of communication with asset issuers and a lot of testing to ensure correctness. It is easier to just utilize a script imported into the Dockerfile that can start and stop the node(and its dependent services) correctly.
Single Volume Mounting
When a deployment is started from a single Dockerfile it is straightforward to mount a single volume to the new container and manage all of its state. Node deployments can be easily scaled by duplicating this volume to any number of new hosts without any sophisticated tooling. As mentioned previously, coordinated start/stop of all services provides strong guarantees around the corruption of the state that would be much more difficult to achieve with distributed services as there may be specific ordering restrictions to prevent corruption.
Running multiple instances of a node configuration can get complicated quickly if the node utilizes multiple stateful containers (ex: a node that stores historical state in an external database). In this scenario, the node orchestration engine must manage which node deployment talks to which services based on which state the node runtime is in. Furthermore, it is more time-intensive to scale up a node deployment as a deployment and all its services must be synced from scratch to ensure correctness or the volumes of another deployment's stateful containers must be used to bootstrap the new deployment (which can be a manual procedure).
Standard Storage Location
All persistent data must be written to the /data directory. If your node utilizes a database (like Postgres) to store data reliably, ensure this is configured to save information to this directory (and in a manner that would not corrupt any data stored by the core node process or other necessary services). It should be possible to stop all services defined in the Dockerfile and restart them (without corruption) using only the state stored in this /data directory with a single command.
Configurable Storage Pruning
It must be possible to prune persistent data storage using block number. For example, anyone running your node should be able to configure the node to delete blocks that are over 1000 blocks old.