About a year agowe introduced now
to the world. We set out to validate very simple hypotheses. Deployment should generally not take more than one command. It should be serverless and you shouldn’t generally have to touch many knobs to scale.
Most importantly, that itshould be built on open standards, be open source and use no proprietary APIs. Today, a quarter million deployments later and thousands of domains in production, we are happy to announce that Now is becoming auniversal interface to every cloud provider.
Without further ado, here’s a simpleNode.js deployment to AWS, using Lambda and API Gateway under the hood:
Sounds familiar, doesn't it? Just deploy with now
What do we mean by universal? The following example, deploying the same project toGoogle Cloud Platform, should explain:
The same command, but check out the output!
Under the hood
Most cloud providers have created different proprietary APIs to expose lightweight services to the cloud. We’ve extended the Now client to incorporate this concept directly into ouropen-source client.
To set up your deployments to ourhttps://now.shpublic cloud, you typically run:
$ now login
What happens, however, if your company or organization has already spent months of engineering around, for example, a Google Cloud VPN? Simple! Just run:
$ now gcp login
As far as implementation goes, our codebase has been structured around mapping subcommands to providers. The main premise is that the now contract is retained: deployments are immutable, aliases are mutable (used to associate domains with deployments), no new protocols or proprietary APIs, etc.
COMMAND
PURPOSE
NOW.SH
AWS
GCP
KUBERNETES
now [deploy]
CREATE A NEW DEPLOYMENT
SINGLE REST API CALL
AWS LAMBDA
AWS API GATEWAY
GCP FUNCTIONS
GCP ENDPOINTS
POD API
now alias
EXPOSE A DEPLOYMENT
SINGLE REST API CALL
AWS API GATEWAY
AWS ROUTE 53
AWS CERT MANAGER
LB SSL CERTIFICATES
INGRESS CONTROLLERS
now logs
VISUALIZE LOGS
SINGLE REST / WS API
STACKDRIVER API
POD LOGS API
now domains
MANAGE DOMAINS
SINGLE REST API CALL
AWS ROUTE 53
GOOGLE DOMAINS
-
now secrets
MANAGE DEPLOYMENT SECRETS
SINGLE REST API CALL
AWS KMS
GCP KMS
SECRETS API
Implementations are organized in the codebase under theproviders/
folder where each subcommand is defined:
sh/
aws/
index.jsRegisters provider and exposes subcommands
deploy.jsInvoked when `now gcp` or `now gcp deploy` is run
……
Example of the structure of the new directory
Each command exports a callback, invoked with the following parameters:
config
The global configuration object (~/.now/config.json
)authConfig
The global credentials config object (~/.now/config/credentials.json
)argv
The supplied arguments. Equivalent toprocess.argv
, but easier to test
From then on, commands are not forced into any specific structure, and they’re free to call any APIs or bring in any utilities or third-party modules.
As the table above shows, providers offer solutions for each major category of functionality. For example, all of AWS, Google Cloud and Azure have a concept of “function as a service” that can be exposed over HTTP, but their APIs vary slightly.
For those cases, src/serverless/*
exposes some common utilities that these providers can reuse (like building a project into a zip file).
This solves a major painpoint for users:Now unifies those APIs under open, predictable and easy-to-use protocols. New providers can be added, configured and removed with ease during the lifetime of a project or organization.
Universal API
To stress that last point, let’s take a quick look at the function signatures of the three major cloud providers:
1exports.handler = (ev, fn) => {2 // custom lambda API3 ev.headers['content-type']4 ev.queryStringParameters.param5 ev.body.message6fn(null, { statusCode: 200 })7}
1exports.handler = (req, res) => {2 // node.js "express" API3 req.get('content-type')4 req.query.param5 req.body.message6res.status(200).end()7}
1module.exports = (ctx, req) => {2 // custom azure API3 ev.headers['content-type']4 ev.query.param5ctx.res = { status: 200 }6 ctx.done()7}
With Now, this becomes:
1require('http').createServer((req, res) => {2 // the normal HTTP API3 req.headers['content-type']4 req.url5 req.on('data', fn)6 res.end('Hello world')7}).listen(process.env.PORT)
Just expose a simple HTTP server, in any programming language, and Now takes care of the rest. Notice that even when FaaS providers expose a HTTP request / response model, the API details vary drastically.
The remaining differences come down to what runtimesare supported by each of these providers. What particulary sets ourhttps://now.shbackend apart in this regard is our supportDockerfile, which allows you to define the entire execution environment in an open way.
For other providers, in the mean time, we can create bridges and deploy ELF Linux binaries to get as close as possible to a completely flexible and runtime-agnostic environment.
Universal Configuration
Each project deployable with now
includes a simple now.json
file that describes what type of project it is (for example:nodejs
orstatic
), and other metadata such asname
ordescription
.
We intend for this configuration file to provide a unification of how projects are specified. It should answer questions like:
- What region(s) should the project be deployed to?
- What directory within the project should be deployed? (defaulting to the root)
- What environmental variables should be supplied by the user upon deployment?
- Are there existing secrets that should be automatically mapped to env variables?
- What hardware resources are required for the project to run successfully?
In all cases, we want to keep the file as objective and unopinionated as possible. We are currently looking for community feedback on ourinitial v1 specification(so feel free tochat with us!)
In all cases, differences between providers will exist, and persist. For that reason, we embrace the idea of extending the configuration by passing custom parameters that are specific to a provider. You are free to define anaws
key with custom settings inside, for example.
Goals and Directions
You can check out the preview release of Now with support for multiple providers onGitHub. It's 100% open source and we look forward to your contributions and feedback. If you haven't already, please join ourSlack Community!
With our new providers support, we hope to bring the experience that our https://now.shcustomers have been enjoying to an even broader audience. We strive and will continue to strive to make it the fastest, easiest to use and most standards-compliant deployment backend in the market.
Over the coming weeks, we will continue to refine our support for Amazon Web Services, Google Cloud and introduced Microsoft Azure.
Aside from "Function as a Service" providers, we also are working hard on bringing the Now experience to container management solutions such asKubernetes. These systems provide a lot of power to their administrators, but typically don't offer a great "last mile" experience for product developers and designers.
Finally, we are thrilled to announce our open-source desktop app,Now Desktop, will feature event feeds of what you and your team are working on, across all these solutions (and others to come!)
We think this paves the way to many exciting usecases of Now in the enterprise. Whether it’s inside a private cloud network, an existing infrastructure provider or completely on-premise, rest assured that you will be only one command away from the cloud, at all times.