I’ve just migrated from Heroku and I’m very pleased with render.
One thing I’m missing are release-commands.
Heroku offers a very simple way to run only-once one-off commands during the release of a new version. Those commands are entries in the
release: bundle exec rake db:migrate
As the example shows, those release-commands can be used to run migrations before the new version is released.
We don’t currently offer release commands, precisely like that, but do you think adding the command to your service’s
startCommand would help? This will make sure that the command is run, every time you have a new build. For instance, the following will first run the copy command and then start the application. Let me know if this helps.
cp file.txt src/ ; yarn start
No, this won’t guarantee the “only once” character of the command if I run on more than one instance.
Actually, it should be “exactly once”
Looks like the intended use is to add this to a build-script. Seen in the Rails example https://render.com/docs/deploy-rails#create-a-build-script
Does the build script work for migrations with the Docker environment?
Yes- the build phase is a good place for migrations with Docker as well. It’s not quite the same in that it’s not an actual “build script” field like in other languages, but you can just put it in your Dockerfile as it will be built with every deploy.
Wait I do the DB migrations in the Dockerfile build? That doesn’t seem normal or secure as then I would need to pass the DB connect as a build arg which is saved in the final docker image. It does look like you pass environment args to build args so I will go ahead and do that for now but it is a bummer as local dev will now have to have a different container vs render one. Also, that image now will always have those values in its metadata (A tableau of crimes and misfortunes: the ever-useful `docker history`). You would have to use the new Buildkit --secret for it not to be in the image history. So I hope you are running a very secure image repo locally.
In other pipelines, I have worked on, we normally have a step after the docker image build that runs the docker image with a different command to do the migrations of anything before spinning up the new images. Having a post-build step to run commands would really help here.
Also you all should really consider not passing all environment variables to the docker build as build args but instead support a different param for it to just be safe and use the Buildkit --secrets to use it.
We agree it’s pretty unusual. We’re aware of the need for some service lifecycle hooks for things like running migrations and that’s something we’re looking into building. That is to say, we don’t have a hook right now to run migrations. The workaround that many have done is to incorporate it into their build scripts, but that can be less-than-ideal for some use cases. Docker services is one of those. We’re happy to add this to feedback.render.com which we take into account when planning our work.
We also have an open issue of manually triggering jobs (e.g. migrations) which people have worked around by creating cron jobs that run extremely infrequently (or even are suspended). Perhaps this would work for you. The idea is to create a Docker cron job and add your migration command as its run command (no Dockerfile changes needed). Then you can control when you run your migrations.
As for BuildKit secrets, you might be happy to know that we do support them backed by secret files. We don’t have official docs on that yet, but you can see the approach in this short thread.
Could you provide an example with blueprint?
We actually had a ticket open with Chunlea about this but to post here, when using Docker, right now the best option for migrations is:
- Put migrations command in a build.sh or start.sh in the Dockerfile that are part of a
- Run migrations manually via SSH
Adding a release phase is a much requested feature (https://render.canny.io/admin/feedback/features/p/release-phase-script?boards=features&search=release) so I’d encourage anyone to upvote that,
How can I do that, if ruby interpeter is not available when I connect through SSH?
Here is what I’ve got:
$ ruby -v
/bin/sh: 4: ruby: not found
I’d like to open this topic back up. What is the best way to run a script on release that’s guaranteed to run exactly once?
If Render doesn’t support the Heroku-esque release phase, then what might be useful is an environment variable indicating that the current instance is the “leader” of the deployment—that way it’s easy to write something that should be run exactly once as @Peter_Schroder said.
Thanks @Peter_Schroder but does the build script execute on all instances, or exactly one?
It does exactly what you want.
What’s the failure mode of the build script?
What if another commit is pushed to the repo when an existing
build script is executing?
- Does the current
build script get cancelled and the new one is executed?
- Does the new build script get enqueued and wait for the current one to finish before running?
- The build scripts from the two separate commits are executed simultaneously based on the time of the commit push?
Option 2 seems the best outcome, while 1 is bad for migrations that get killed halfway and 3 is patently against the intention of
exactly once migration semantics.
Psst…we’ve just started design and eng work for this request.