Cloud Native programming with Golang
上QQ阅读APP看书,第一时间看更新

The twelve-factor app

The twelve-factor app methodology is a set of rules for building scalable and resilient cloud applications. It was published by Heroku, one of the dominant PaaS providers. However, it can be applied to all kinds of cloud applications, independent of concrete infrastructure or platform providers. It is also independent of programming languages and persistence services and can equally be applied to Go programming and, for example, Node.js programming. The twelve-factor app methodology describes (unsurprisingly) twelve factors that you should consider in your application for it to be easily scalable, resilient, and platform independent. You can read up on the full description on each factor on https://12factor.net. For the purpose of this book, we will highlight some factors that we deem especially important:

  • Factor II: Dependencies—Explicitly declare and isolate dependencies: This factor deserves special mention because it is actually not as important in Go programming as in other languages. Typically, a cloud application should never rely on any required library or external tool being already present on a system. Dependencies should be explicitly declared (for example, using an npm package.json file for a Node.js application) so that a package manager can pull all these dependencies when deploying a new instance of the application. In Go, an application is typically deployed as a statically compiled binary that already contains all required libraries. However, even a Go application can be dependent on external system tools (for example, it can fork out to tools such as ImageMagick) or on existing C libraries. Ideally, you should deploy tools like these alongside your application. This is where container engines, such as Docker, shine.
  • Factor III: Config—Store config in the environment: Configuration is any kind of data that might vary for different deployment, for example, connection data and credentials for external services and databases. These kinds of data should be passed to the application via environment variables. In a Go application, retrieving these is then as easy as calling os.Getenv ("VARIABLE_NAME"). In more complex cases (for example, when you have many configuration variables), you can also resort to libraries such as github.com/tomazk/envcfg or github.com/caarlos0/env. For heavy lifting, you can use the github.com/spf13/viper library.
  • Factor IV: Backing Services—Treat backing services as attached resources: Ensure that services that your app depends on (such as databases, messaging systems, or external APIs) are easily swappable by configuration. For example, your app could accept an environment variable, such as DATABASE_URL, that might contain mysql://root:root@localhost/test for a local development deployment and mysql://root:XXX@prod.XXXX.eu-central-1.rds.amazonaws.com in your production setup.
  • Factor VI: Processes—Execute the app as one or more stateless processes: Running application instances should be stateless; any kind of data that should persist beyond a single request/transaction needs to be stored in an external persistence service.
    One important case to keep in mind is user sessions in web applications. Often, user session data is stored in the process's memory (or is persisted to the local filesystem) in the expectancy that subsequent requests of the same user will be served by the same instance of your application. Instead, try to keep user sessions stateless or move the session state into an external data store, such as Redis or Memcached.
  • Factor IX: Disposability—Maximize robustness with fast startup and graceful shutdown: In a cloud environment, sudden termination (both intentional, for example, in case of downscaling, and unintentional, in case of failures) needs to be expected. A twelve-factor app should have fast startup times (typically in the range of a few seconds), allowing it to rapidly deploy new instances. Besides, fast startup and graceful termination is another requirement. When a server shut down, the operating system will typically tell your application to shut down by sending a SIGTERM signal that the application can catch and react to accordingly (for example, by stopping to listen on the service port, finishing requests that are currently being processed, and then exiting).
  • Factor XI: Logs—Treat logs as event streams: Log data is often useful for debugging and monitoring your application's behavior. However, a twelve-factor app should not concern itself with the routing or storage of its own log data. The easiest and simplest solution is to simply write your log stream to the process's standard output stream (for example, just using fmt.Println(...)). Streaming events to stdout allows a developer to simply watch the event stream on their console when developing the application. In production setups, you can configure the execution environment to catch the process output and send the log stream to a place where it can be processed (the possibilities here are endless—you could store them in your server's journald, send them to a syslog server, store your logs in an ELK setup, or send them to an external cloud service).