Update: This article is no longer relevant. The NOW API referred to below is depcrecated and I've since moved on to running Dokku on a VPS.
I recently had the opportunity to play around with zeit.co's deployment service (also where this blog is hosted). I used Gitlab's pipelines to set up a docker container deployment workflow that includes automated review and staging builds and a manual step for deploying master to production.
Update: I edited the gitlab pipeline to clean previous deployments and name deployments with prefixed $APPS_DOMAIN in order to have a less confusing list on zeit.co's deployment list. Also, all but production builds now clean previous deployments automatically on a new deployment. The $NOW_REGION variable is no longer necessary, instead all region specific settings are in now.json using "scale".
Update 2: now updated to use their serverless Docker infrastructure. Handle no existing deployments when trying to remove old deployments. Dockerfile: remove devDepencencies after build.
For this to work properly, you need to be able to run now from your local machine (e.g. now.json config or a now-key in package.json and a Dockerfile). If your deployment runs fine locally, it will - quite probably - do so in a Gitlab runner instance.
While testing zeit.co without applying any scaling I noticed that the TTFB is significantly higher than with my previous hosting environment. Somewhere in a constant 800ms range - from brussels. And I guess this is why: containers on now that do not have scaling configured will be frozen after a certain timeout. With scaling configured (e.g. in now.json), TTFB is almost halved. I guess that non-scaling deployments are behind a different load balancer setup than scaled deployments. Or something like that…
I switched off zeit.co's domain CDN to save a few bucks (nobody cares if this blog loads in 400ms or 1.5s…), turned on scaling and voila, the datacenter in Brussels seems to be doing just fine for European traffic. I ran a few tests on pingdom.com via San Jose and the TTFB from the eastern US is about 2.5s. I'm not concerned with that currently but might extend my config to spin up 2 instances in SFO and BRU, just to see what would be possible.
now.json: name the project the same as $APP_DOMAIN-production in order for it to pick up aliases. I set the region to "bru1" for europe and set "scale" to minimum 1 instance and maximum 3. Set this according to your requirements.
It takes a while to build during rush hours (well, I'm using Gitlab's free runners, so I don't expect any miracles). But all in all, this is a very simple, very effective way to run some minor devops for a nextjs app.
For completeness, here's my Dockerfile: