├── .gitignore ├── LANGS.md ├── README.md ├── download ├── 12factor.epub_en.pdf ├── 12factor_en.epub └── 12factor_zh_cn.epub ├── en ├── README.md ├── SUMMARY.md ├── admin-processes.md ├── background.md ├── backing-services.md ├── build-release-run.md ├── codebase.md ├── concurrency.md ├── config.md ├── dependencies.md ├── dev-prod-parity.md ├── disposability.md ├── intro.md ├── logs.md ├── port-binding.md ├── processes.md ├── toc.md └── who.md ├── images ├── attached-resources.png ├── codebase-deploys.png ├── favicon.ico ├── process-types.png ├── release.png └── symbol.png └── zh_cn ├── README.md ├── SUMMARY.md ├── admin-processes.md ├── background.md ├── backing-services.md ├── build-release-run.md ├── codebase.md ├── concurrency.md ├── config.md ├── dependencies.md ├── dev-prod-parity.md ├── disposability.md ├── intro.md ├── logs.md ├── port-binding.md ├── processes.md ├── toc.md └── who.md /.gitignore: -------------------------------------------------------------------------------- 1 | _book 2 | -------------------------------------------------------------------------------- /LANGS.md: -------------------------------------------------------------------------------- 1 | * [简体中文](zh_cn/) 2 | * [English](en/) 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THE TWELVE-FACTOR APP in GitBook version 2 | 3 | ## Multiple Language Versions 4 | * [简体中文](zh_cn/) 5 | * [English](en/) 6 | 7 | ## 说明 8 | 虽然 12-Factor 的原文书籍都是发布在其官网上,但因为网络问题和格式问题,不是很方便阅读,我将其转化了为 GitBook 格式,并架设在网易蜂巢平台上,同时开源将源书开源在 GitHub 上,方便大家阅读和下载: 9 | 10 | - 在线阅读地址:http://12.bingohuang.com 11 | - GitHub 开源地址:https://github.com/bingohuang/12factor-gitbook 12 | - pdf/epub下载地址::https://github.com/bingohuang/12factor-gitbook/download 13 | - GitBook 地址:https://www.gitbook.com/book/bingohuang/12factor/details 14 | -------------------------------------------------------------------------------- /download/12factor.epub_en.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/download/12factor.epub_en.pdf -------------------------------------------------------------------------------- /download/12factor_en.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/download/12factor_en.epub -------------------------------------------------------------------------------- /download/12factor_zh_cn.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/download/12factor_zh_cn.epub -------------------------------------------------------------------------------- /en/README.md: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | In the modern era, software is commonly delivered as a service: called *web apps*, or *software-as-a-service*. The twelve-factor app is a methodology for building software-as-a-service apps that: 5 | 6 | * Use **declarative** formats for setup automation, to minimize time and cost for new developers joining the project; 7 | * Have a **clean contract** with the underlying operating system, offering **maximum portability** between execution environments; 8 | * Are suitable for **deployment** on modern **cloud platforms**, obviating the need for servers and systems administration; 9 | * **Minimize divergence** between development and production, enabling **continuous deployment** for maximum agility; 10 | * And can **scale up** without significant changes to tooling, architecture, or development practices. 11 | 12 | The twelve-factor methodology can be applied to apps written in any programming language, and which use any combination of backing services (database, queue, memory cache, etc). 13 | 14 | 15 | Background 16 | ========== 17 | 18 | The contributors to this document have been directly involved in the development and deployment of hundreds of apps, and indirectly witnessed the development, operation, and scaling of hundreds of thousands of apps via our work on the Heroku platform. 19 | 20 | This document synthesizes all of our experience and observations on a wide variety of software-as-a-service apps in the wild. It is a triangulation on ideal practices for app development, paying particular attention to the dynamics of the organic growth of an app over time, the dynamics of collaboration between developers working on the app's codebase, and avoiding the cost of software erosion. 21 | 22 | Our motivation is to raise awareness of some systemic problems we've seen in modern application development, to provide a shared vocabulary for discussing those problems, and to offer a set of broad conceptual solutions to those problems with accompanying terminology. The format is inspired by Martin Fowler's books *Patterns of Enterprise Application Architecture* and *Refactoring*. 23 | 24 | 25 | Who should read this document? 26 | ============================== 27 | 28 | Any developer building applications which run as a service. Ops engineers who deploy or manage such applications. 29 | -------------------------------------------------------------------------------- /en/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [I. Codebase](codebase.md) 5 | * [II. Dependencies](dependencies.md) 6 | * [III. Config](config.md) 7 | * [IV. Backing services](backing-services.md) 8 | * [V. Build, release, run](build-release-run.md) 9 | * [VI. Processes](processes.md) 10 | * [VII. Port binding](port-binding.md) 11 | * [VIII. Concurrency](concurrency.md) 12 | * [IX. Disposability](disposability.md) 13 | * [X. Dev/prod parity](dev-prod-parity.md) 14 | * [XI. Logs](logs.md) 15 | * [XII. Admin processes](admin-processes.md) 16 | -------------------------------------------------------------------------------- /en/admin-processes.md: -------------------------------------------------------------------------------- 1 | ## XII. Admin processes 2 | ### Run admin/management tasks as one-off processes 3 | 4 | The [process formation](./concurrency) is the array of processes that are used to do the app's regular business (such as handling web requests) as it runs. Separately, developers will often wish to do one-off administrative or maintenance tasks for the app, such as: 5 | 6 | * Running database migrations (e.g. `manage.py migrate` in Django, `rake db:migrate` in Rails). 7 | * Running a console (also known as a [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) to run arbitrary code or inspect the app's models against the live database. Most languages provide a REPL by running the interpreter without any arguments (e.g. `python` or `perl`) or in some cases have a separate command (e.g. `irb` for Ruby, `rails console` for Rails). 8 | * Running one-time scripts committed into the app's repo (e.g. `php scripts/fix_bad_records.php`). 9 | 10 | One-off admin processes should be run in an identical environment as the regular [long-running processes](./processes) of the app. They run against a [release](./build-release-run), using the same [codebase](./codebase) and [config](./config) as any process run against that release. Admin code must ship with application code to avoid synchronization issues. 11 | 12 | The same [dependency isolation](./dependencies) techniques should be used on all process types. For example, if the Ruby web process uses the command `bundle exec thin start`, then a database migration should use `bundle exec rake db:migrate`. Likewise, a Python program using Virtualenv should use the vendored `bin/python` for running both the Tornado webserver and any `manage.py` admin processes. 13 | 14 | Twelve-factor strongly favors languages which provide a REPL shell out of the box, and which make it easy to run one-off scripts. In a local deploy, developers invoke one-off admin processes by a direct shell command inside the app's checkout directory. In a production deploy, developers can use ssh or other remote command execution mechanism provided by that deploy's execution environment to run such a process. 15 | -------------------------------------------------------------------------------- /en/background.md: -------------------------------------------------------------------------------- 1 | Background 2 | ========== 3 | 4 | The contributors to this document have been directly involved in the development and deployment of hundreds of apps, and indirectly witnessed the development, operation, and scaling of hundreds of thousands of apps via our work on the Heroku platform. 5 | 6 | This document synthesizes all of our experience and observations on a wide variety of software-as-a-service apps in the wild. It is a triangulation on ideal practices for app development, paying particular attention to the dynamics of the organic growth of an app over time, the dynamics of collaboration between developers working on the app's codebase, and avoiding the cost of software erosion. 7 | 8 | Our motivation is to raise awareness of some systemic problems we've seen in modern application development, to provide a shared vocabulary for discussing those problems, and to offer a set of broad conceptual solutions to those problems with accompanying terminology. The format is inspired by Martin Fowler's books *Patterns of Enterprise Application Architecture* and *Refactoring*. 9 | 10 | -------------------------------------------------------------------------------- /en/backing-services.md: -------------------------------------------------------------------------------- 1 | ## IV. Backing services 2 | ### Treat backing services as attached resources 3 | 4 | A *backing service* is any service the app consumes over the network as part of its normal operation. Examples include datastores (such as [MySQL](http://dev.mysql.com/) or [CouchDB](http://couchdb.apache.org/)), messaging/queueing systems (such as [RabbitMQ](http://www.rabbitmq.com/) or [Beanstalkd](http://kr.github.com/beanstalkd/)), SMTP services for outbound email (such as [Postfix](http://www.postfix.org/)), and caching systems (such as [Memcached](http://memcached.org/)). 5 | 6 | Backing services like the database are traditionally managed by the same systems administrators as the app's runtime deploy. In addition to these locally-managed services, the app may also have services provided and managed by third parties. Examples include SMTP services (such as [Postmark](http://postmarkapp.com/)), metrics-gathering services (such as [New Relic](http://newrelic.com/) or [Loggly](http://www.loggly.com/)), binary asset services (such as [Amazon S3](http://aws.amazon.com/s3/)), and even API-accessible consumer services (such as [Twitter](http://dev.twitter.com/), [Google Maps](http://code.google.com/apis/maps/index.html), or [Last.fm](http://www.last.fm/api)). 7 | 8 | **The code for a twelve-factor app makes no distinction between local and third party services.** To the app, both are attached resources, accessed via a URL or other locator/credentials stored in the [config](./config). A [deploy](./codebase) of the twelve-factor app should be able to swap out a local MySQL database with one managed by a third party (such as [Amazon RDS](http://aws.amazon.com/rds/)) without any changes to the app's code. Likewise, a local SMTP server could be swapped with a third-party SMTP service (such as Postmark) without code changes. In both cases, only the resource handle in the config needs to change. 9 | 10 | Each distinct backing service is a *resource*. For example, a MySQL database is a resource; two MySQL databases (used for sharding at the application layer) qualify as two distinct resources. The twelve-factor app treats these databases as *attached resources*, which indicates their loose coupling to the deploy they are attached to. 11 | 12 | A production deploy attached to four backing services. 13 | 14 | Resources can be attached and detached to deploys at will. For example, if the app's database is misbehaving due to a hardware issue, the app's administrator might spin up a new database server restored from a recent backup. The current production database could be detached, and the new database attached -- all without any code changes. 15 | -------------------------------------------------------------------------------- /en/build-release-run.md: -------------------------------------------------------------------------------- 1 | ## V. Build, release, run 2 | ### Strictly separate build and run stages 3 | 4 | A [codebase](./codebase) is transformed into a (non-development) deploy through three stages: 5 | 6 | * The *build stage* is a transform which converts a code repo into an executable bundle known as a *build*. Using a version of the code at a commit specified by the deployment process, the build stage fetches vendors [dependencies](./dependencies) and compiles binaries and assets. 7 | * The *release stage* takes the build produced by the build stage and combines it with the deploy's current [config](./config). The resulting *release* contains both the build and the config and is ready for immediate execution in the execution environment. 8 | * The *run stage* (also known as "runtime") runs the app in the execution environment, by launching some set of the app's [processes](./processes) against a selected release. 9 | 10 | ![Code becomes a build, which is combined with config to create a release.](../images/release.png) 11 | 12 | **The twelve-factor app uses strict separation between the build, release, and run stages.** For example, it is impossible to make changes to the code at runtime, since there is no way to propagate those changes back to the build stage. 13 | 14 | Deployment tools typically offer release management tools, most notably the ability to roll back to a previous release. For example, the [Capistrano](https://github.com/capistrano/capistrano/wiki) deployment tool stores releases in a subdirectory named `releases`, where the current release is a symlink to the current release directory. Its `rollback` command makes it easy to quickly roll back to a previous release. 15 | 16 | Every release should always have a unique release ID, such as a timestamp of the release (such as `2011-04-06-20:32:17`) or an incrementing number (such as `v100`). Releases are an append-only ledger and a release cannot be mutated once it is created. Any change must create a new release. 17 | 18 | Builds are initiated by the app's developers whenever new code is deployed. Runtime execution, by contrast, can happen automatically in cases such as a server reboot, or a crashed process being restarted by the process manager. Therefore, the run stage should be kept to as few moving parts as possible, since problems that prevent an app from running can cause it to break in the middle of the night when no developers are on hand. The build stage can be more complex, since errors are always in the foreground for a developer who is driving the deploy. 19 | -------------------------------------------------------------------------------- /en/codebase.md: -------------------------------------------------------------------------------- 1 | ## I. Codebase 2 | ### One codebase tracked in revision control, many deploys 3 | 4 | A twelve-factor app is always tracked in a version control system, such as [Git](http://git-scm.com/), [Mercurial](http://mercurial.selenic.com/), or [Subversion](http://subversion.apache.org/). A copy of the revision tracking database is known as a *code repository*, often shortened to *code repo* or just *repo*. 5 | 6 | A *codebase* is any single repo (in a centralized revision control system like Subversion), or any set of repos who share a root commit (in a decentralized revision control system like Git). 7 | 8 | ![One codebase maps to many deploys](../images/codebase-deploys.png) 9 | 10 | There is always a one-to-one correlation between the codebase and the app: 11 | 12 | * If there are multiple codebases, it's not an app -- it's a distributed system. Each component in a distributed system is an app, and each can individually comply with twelve-factor. 13 | * Multiple apps sharing the same code is a violation of twelve-factor. The solution here is to factor shared code into libraries which can be included through the [dependency manager](./dependencies). 14 | 15 | There is only one codebase per app, but there will be many deploys of the app. A *deploy* is a running instance of the app. This is typically a production site, and one or more staging sites. Additionally, every developer has a copy of the app running in their local development environment, each of which also qualifies as a deploy. 16 | 17 | The codebase is the same across all deploys, although different versions may be active in each deploy. For example, a developer has some commits not yet deployed to staging; staging has some commits not yet deployed to production. But they all share the same codebase, thus making them identifiable as different deploys of the same app. 18 | -------------------------------------------------------------------------------- /en/concurrency.md: -------------------------------------------------------------------------------- 1 | ## VIII. Concurrency 2 | ### Scale out via the process model 3 | 4 | Any computer program, once run, is represented by one or more processes. Web apps have taken a variety of process-execution forms. For example, PHP processes run as child processes of Apache, started on demand as needed by request volume. Java processes take the opposite approach, with the JVM providing one massive uberprocess that reserves a large block of system resources (CPU and memory) on startup, with concurrency managed internally via threads. In both cases, the running process(es) are only minimally visible to the developers of the app. 5 | 6 | ![Scale is expressed as running processes, workload diversity is expressed as process types.](../images/process-types.png) 7 | 8 | **In the twelve-factor app, processes are a first class citizen.** Processes in the twelve-factor app take strong cues from [the unix process model for running service daemons](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Using this model, the developer can architect their app to handle diverse workloads by assigning each type of work to a *process type*. For example, HTTP requests may be handled by a web process, and long-running background tasks handled by a worker process. 9 | 10 | This does not exclude individual processes from handling their own internal multiplexing, via threads inside the runtime VM, or the async/evented model found in tools such as [EventMachine](http://rubyeventmachine.com/), [Twisted](http://twistedmatrix.com/trac/), or [Node.js](http://nodejs.org/). But an individual VM can only grow so large (vertical scale), so the application must also be able to span multiple processes running on multiple physical machines. 11 | 12 | The process model truly shines when it comes time to scale out. The [share-nothing, horizontally partitionable nature of twelve-factor app processes](./processes) means that adding more concurrency is a simple and reliable operation. The array of process types and number of processes of each type is known as the *process formation*. 13 | 14 | Twelve-factor app processes [should never daemonize](http://dustin.github.com/2010/02/28/running-processes.html) or write PID files. Instead, rely on the operating system's process manager (such as [Upstart](http://upstart.ubuntu.com/), a distributed process manager on a cloud platform, or a tool like [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) in development) to manage [output streams](./logs), respond to crashed processes, and handle user-initiated restarts and shutdowns. 15 | -------------------------------------------------------------------------------- /en/config.md: -------------------------------------------------------------------------------- 1 | ## III. Config 2 | ### Store config in the environment 3 | 4 | An app's *config* is everything that is likely to vary between [deploys](./codebase) (staging, production, developer environments, etc). This includes: 5 | 6 | * Resource handles to the database, Memcached, and other [backing services](./backing-services) 7 | * Credentials to external services such as Amazon S3 or Twitter 8 | * Per-deploy values such as the canonical hostname for the deploy 9 | 10 | Apps sometimes store config as constants in the code. This is a violation of twelve-factor, which requires **strict separation of config from code**. Config varies substantially across deploys, code does not. 11 | 12 | A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without compromising any credentials. 13 | 14 | Note that this definition of "config" does **not** include internal application config, such as `config/routes.rb` in Rails, or how [code modules are connected](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) in [Spring](http://spring.io/). This type of config does not vary between deploys, and so is best done in the code. 15 | 16 | Another approach to config is the use of config files which are not checked into revision control, such as `config/database.yml` in Rails. This is a huge improvement over using constants which are checked into the code repo, but still has weaknesses: it's easy to mistakenly check in a config file to the repo; there is a tendency for config files to be scattered about in different places and different formats, making it hard to see and manage all the config in one place. Further, these formats tend to be language- or framework-specific. 17 | 18 | **The twelve-factor app stores config in *environment variables*** (often shortened to *env vars* or *env*). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard. 19 | 20 | Another aspect of config management is grouping. Sometimes apps batch config into named groups (often called "environments") named after specific deploys, such as the `development`, `test`, and `production` environments in Rails. This method does not scale cleanly: as more deploys of the app are created, new environment names are necessary, such as `staging` or `qa`. As the project grows further, developers may add their own special environments like `joes-staging`, resulting in a combinatorial explosion of config which makes managing deploys of the app very brittle. 21 | 22 | In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as "environments", but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime. 23 | -------------------------------------------------------------------------------- /en/dependencies.md: -------------------------------------------------------------------------------- 1 | ## II. Dependencies 2 | ### Explicitly declare and isolate dependencies 3 | 4 | Most programming languages offer a packaging system for distributing support libraries, such as [CPAN](http://www.cpan.org/) for Perl or [Rubygems](http://rubygems.org/) for Ruby. Libraries installed through a packaging system can be installed system-wide (known as "site packages") or scoped into the directory containing the app (known as "vendoring" or "bundling"). 5 | 6 | **A twelve-factor app never relies on implicit existence of system-wide packages.** It declares all dependencies, completely and exactly, via a *dependency declaration* manifest. Furthermore, it uses a *dependency isolation* tool during execution to ensure that no implicit dependencies "leak in" from the surrounding system. The full and explicit dependency specification is applied uniformly to both production and development. 7 | 8 | For example, [Bundler](https://bundler.io/) for Ruby offers the `Gemfile` manifest format for dependency declaration and `bundle exec` for dependency isolation. In Python there are two separate tools for these steps -- [Pip](http://www.pip-installer.org/en/latest/) is used for declaration and [Virtualenv](http://www.virtualenv.org/en/latest/) for isolation. Even C has [Autoconf](http://www.gnu.org/s/autoconf/) for dependency declaration, and static linking can provide dependency isolation. No matter what the toolchain, dependency declaration and isolation must always be used together -- only one or the other is not sufficient to satisfy twelve-factor. 9 | 10 | One benefit of explicit dependency declaration is that it simplifies setup for developers new to the app. The new developer can check out the app's codebase onto their development machine, requiring only the language runtime and dependency manager installed as prerequisites. They will be able to set up everything needed to run the app's code with a deterministic *build command*. For example, the build command for Ruby/Bundler is `bundle install`, while for Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) it is `lein deps`. 11 | 12 | Twelve-factor apps also do not rely on the implicit existence of any system tools. Examples include shelling out to ImageMagick or `curl`. While these tools may exist on many or even most systems, there is no guarantee that they will exist on all systems where the app may run in the future, or whether the version found on a future system will be compatible with the app. If the app needs to shell out to a system tool, that tool should be vendored into the app. 13 | -------------------------------------------------------------------------------- /en/dev-prod-parity.md: -------------------------------------------------------------------------------- 1 | ## X. Dev/prod parity 2 | ### Keep development, staging, and production as similar as possible 3 | 4 | Historically, there have been substantial gaps between development (a developer making live edits to a local [deploy](./codebase) of the app) and production (a running deploy of the app accessed by end users). These gaps manifest in three areas: 5 | 6 | * **The time gap:** A developer may work on code that takes days, weeks, or even months to go into production. 7 | * **The personnel gap**: Developers write code, ops engineers deploy it. 8 | * **The tools gap**: Developers may be using a stack like Nginx, SQLite, and OS X, while the production deploy uses Apache, MySQL, and Linux. 9 | 10 | **The twelve-factor app is designed for [continuous deployment](http://www.avc.com/a_vc/2011/02/continuous-deployment.html) by keeping the gap between development and production small.** Looking at the three gaps described above: 11 | 12 | * Make the time gap small: a developer may write code and have it deployed hours or even just minutes later. 13 | * Make the personnel gap small: developers who wrote code are closely involved in deploying it and watching its behavior in production. 14 | * Make the tools gap small: keep development and production as similar as possible. 15 | 16 | Summarizing the above into a table: 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
Traditional appTwelve-factor app
Time between deploysWeeksHours
Code authors vs code deployersDifferent peopleSame people
Dev vs production environmentsDivergentAs similar as possible
40 | 41 | [Backing services](./backing-services), such as the app's database, queueing system, or cache, is one area where dev/prod parity is important. Many languages offer libraries which simplify access to the backing service, including *adapters* to different types of services. Some examples are in the table below. 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
TypeLanguageLibraryAdapters
DatabaseRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
QueuePython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CacheMemory, filesystem, Memcached
69 | 70 | Developers sometimes find great appeal in using a lightweight backing service in their local environments, while a more serious and robust backing service will be used in production. For example, using SQLite locally and PostgreSQL in production; or local process memory for caching in development and Memcached in production. 71 | 72 | **The twelve-factor developer resists the urge to use different backing services between development and production**, even when adapters theoretically abstract away any differences in backing services. Differences between backing services mean that tiny incompatibilities crop up, causing code that worked and passed tests in development or staging to fail in production. These types of errors create friction that disincentivizes continuous deployment. The cost of this friction and the subsequent dampening of continuous deployment is extremely high when considered in aggregate over the lifetime of an application. 73 | 74 | Lightweight local services are less compelling than they once were. Modern backing services such as Memcached, PostgreSQL, and RabbitMQ are not difficult to install and run thanks to modern packaging systems, such as [Homebrew](http://mxcl.github.com/homebrew/) and [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Alternatively, declarative provisioning tools such as [Chef](http://www.opscode.com/chef/) and [Puppet](http://docs.puppetlabs.com/) combined with light-weight virtual environments such as [Vagrant](http://vagrantup.com/) allow developers to run local environments which closely approximate production environments. The cost of installing and using these systems is low compared to the benefit of dev/prod parity and continuous deployment. 75 | 76 | Adapters to different backing services are still useful, because they make porting to new backing services relatively painless. But all deploys of the app (developer environments, staging, production) should be using the same type and version of each of the backing services. 77 | -------------------------------------------------------------------------------- /en/disposability.md: -------------------------------------------------------------------------------- 1 | ## IX. Disposability 2 | ### Maximize robustness with fast startup and graceful shutdown 3 | 4 | **The twelve-factor app's [processes](./processes) are *disposable*, meaning they can be started or stopped at a moment's notice.** This facilitates fast elastic scaling, rapid deployment of [code](./codebase) or [config](./config) changes, and robustness of production deploys. 5 | 6 | Processes should strive to **minimize startup time**. Ideally, a process takes a few seconds from the time the launch command is executed until the process is up and ready to receive requests or jobs. Short startup time provides more agility for the [release](./build-release-run) process and scaling up; and it aids robustness, because the process manager can more easily move processes to new physical machines when warranted. 7 | 8 | Processes **shut down gracefully when they receive a [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** signal from the process manager. For a web process, graceful shutdown is achieved by ceasing to listen on the service port (thereby refusing any new requests), allowing any current requests to finish, and then exiting. Implicit in this model is that HTTP requests are short (no more than a few seconds), or in the case of long polling, the client should seamlessly attempt to reconnect when the connection is lost. 9 | 10 | For a worker process, graceful shutdown is achieved by returning the current job to the work queue. For example, on [RabbitMQ](http://www.rabbitmq.com/) the worker can send a [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); on [Beanstalkd](http://kr.github.com/beanstalkd/), the job is returned to the queue automatically whenever a worker disconnects. Lock-based systems such as [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) need to be sure to release their lock on the job record. Implicit in this model is that all jobs are [reentrant](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), which typically is achieved by wrapping the results in a transaction, or making the operation [idempotent](http://en.wikipedia.org/wiki/Idempotence). 11 | 12 | Processes should also be **robust against sudden death**, in the case of a failure in the underlying hardware. While this is a much less common occurrence than a graceful shutdown with `SIGTERM`, it can still happen. A recommended approach is use of a robust queueing backend, such as Beanstalkd, that returns jobs to the queue when clients disconnect or time out. Either way, a twelve-factor app is architected to handle unexpected, non-graceful terminations. [Crash-only design](http://lwn.net/Articles/191059/) takes this concept to its [logical conclusion](http://docs.couchdb.org/en/latest/intro/overview.html). 13 | 14 | 15 | -------------------------------------------------------------------------------- /en/intro.md: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | In the modern era, software is commonly delivered as a service: called *web apps*, or *software-as-a-service*. The twelve-factor app is a methodology for building software-as-a-service apps that: 5 | 6 | * Use **declarative** formats for setup automation, to minimize time and cost for new developers joining the project; 7 | * Have a **clean contract** with the underlying operating system, offering **maximum portability** between execution environments; 8 | * Are suitable for **deployment** on modern **cloud platforms**, obviating the need for servers and systems administration; 9 | * **Minimize divergence** between development and production, enabling **continuous deployment** for maximum agility; 10 | * And can **scale up** without significant changes to tooling, architecture, or development practices. 11 | 12 | The twelve-factor methodology can be applied to apps written in any programming language, and which use any combination of backing services (database, queue, memory cache, etc). 13 | -------------------------------------------------------------------------------- /en/logs.md: -------------------------------------------------------------------------------- 1 | ## XI. Logs 2 | ### Treat logs as event streams 3 | 4 | *Logs* provide visibility into the behavior of a running app. In server-based environments they are commonly written to a file on disk (a "logfile"); but this is only an output format. 5 | 6 | Logs are the [stream](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) of aggregated, time-ordered events collected from the output streams of all running processes and backing services. Logs in their raw form are typically a text format with one event per line (though backtraces from exceptions may span multiple lines). Logs have no fixed beginning or end, but flow continuously as long as the app is operating. 7 | 8 | **A twelve-factor app never concerns itself with routing or storage of its output stream.** It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to `stdout`. During local development, the developer will view this stream in the foreground of their terminal to observe the app's behavior. 9 | 10 | In staging or production deploys, each process' stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment. Open-source log routers (such as [Logplex](https://github.com/heroku/logplex) and [Fluent](https://github.com/fluent/fluentd)) are available for this purpose. 11 | 12 | The event stream for an app can be routed to a file, or watched via realtime tail in a terminal. Most significantly, the stream can be sent to a log indexing and analysis system such as [Splunk](http://www.splunk.com/), or a general-purpose data warehousing system such as [Hadoop/Hive](http://hive.apache.org/). These systems allow for great power and flexibility for introspecting an app's behavior over time, including: 13 | 14 | * Finding specific events in the past. 15 | * Large-scale graphing of trends (such as requests per minute). 16 | * Active alerting according to user-defined heuristics (such as an alert when the quantity of errors per minute exceeds a certain threshold). 17 | -------------------------------------------------------------------------------- /en/port-binding.md: -------------------------------------------------------------------------------- 1 | ## VII. Port binding 2 | ### Export services via port binding 3 | 4 | Web apps are sometimes executed inside a webserver container. For example, PHP apps might run as a module inside [Apache HTTPD](http://httpd.apache.org/), or Java apps might run inside [Tomcat](http://tomcat.apache.org/). 5 | 6 | **The twelve-factor app is completely self-contained** and does not rely on runtime injection of a webserver into the execution environment to create a web-facing service. The web app **exports HTTP as a service by binding to a port**, and listening to requests coming in on that port. 7 | 8 | In a local development environment, the developer visits a service URL like `http://localhost:5000/` to access the service exported by their app. In deployment, a routing layer handles routing requests from a public-facing hostname to the port-bound web processes. 9 | 10 | This is typically implemented by using [dependency declaration](./dependencies) to add a webserver library to the app, such as [Tornado](http://www.tornadoweb.org/) for Python, [Thin](http://code.macournoyer.com/thin/) for Ruby, or [Jetty](http://jetty.codehaus.org/jetty/) for Java and other JVM-based languages. This happens entirely in *user space*, that is, within the app's code. The contract with the execution environment is binding to a port to serve requests. 11 | 12 | HTTP is not the only service that can be exported by port binding. Nearly any kind of server software can be run via a process binding to a port and awaiting incoming requests. Examples include [ejabberd](http://www.ejabberd.im/) (speaking [XMPP](http://xmpp.org/)), and [Redis](http://redis.io/) (speaking the [Redis protocol](http://redis.io/topics/protocol)). 13 | 14 | Note also that the port-binding approach means that one app can become the [backing service](./backing-services) for another app, by providing the URL to the backing app as a resource handle in the [config](./config) for the consuming app. 15 | -------------------------------------------------------------------------------- /en/processes.md: -------------------------------------------------------------------------------- 1 | ## VI. Processes 2 | ### Execute the app as one or more stateless processes 3 | 4 | The app is executed in the execution environment as one or more *processes*. 5 | 6 | In the simplest case, the code is a stand-alone script, the execution environment is a developer's local laptop with an installed language runtime, and the process is launched via the command line (for example, `python my_script.py`). On the other end of the spectrum, a production deploy of a sophisticated app may use many [process types, instantiated into zero or more running processes](./concurrency). 7 | 8 | **Twelve-factor processes are stateless and [share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Any data that needs to persist must be stored in a stateful [backing service](./backing-services), typically a database. 9 | 10 | The memory space or filesystem of the process can be used as a brief, single-transaction cache. For example, downloading a large file, operating on it, and storing the results of the operation in the database. The twelve-factor app never assumes that anything cached in memory or on disk will be available on a future request or job -- with many processes of each type running, chances are high that a future request will be served by a different process. Even when running only one process, a restart (triggered by code deploy, config change, or the execution environment relocating the process to a different physical location) will usually wipe out all local (e.g., memory and filesystem) state. 11 | 12 | Asset packagers (such as [Jammit](http://documentcloud.github.com/jammit/) or [django-compressor](http://django-compressor.readthedocs.org/)) use the filesystem as a cache for compiled assets. A twelve-factor app prefers to do this compiling during the [build stage](./build-release-run), such as the [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html), rather than at runtime. 13 | 14 | Some web systems rely on ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- that is, caching user session data in memory of the app's process and expecting future requests from the same visitor to be routed to the same process. Sticky sessions are a violation of twelve-factor and should never be used or relied upon. Session state data is a good candidate for a datastore that offers time-expiration, such as [Memcached](http://memcached.org/) or [Redis](http://redis.io/). 15 | 16 | -------------------------------------------------------------------------------- /en/toc.md: -------------------------------------------------------------------------------- 1 | The Twelve Factors 2 | ================== 3 | 4 | ## [I. Codebase](./codebase) 5 | ### One codebase tracked in revision control, many deploys 6 | 7 | ## [II. Dependencies](./dependencies) 8 | ### Explicitly declare and isolate dependencies 9 | 10 | ## [III. Config](./config) 11 | ### Store config in the environment 12 | 13 | ## [IV. Backing services](./backing-services) 14 | ### Treat backing services as attached resources 15 | 16 | ## [V. Build, release, run](./build-release-run) 17 | ### Strictly separate build and run stages 18 | 19 | ## [VI. Processes](./processes) 20 | ### Execute the app as one or more stateless processes 21 | 22 | ## [VII. Port binding](./port-binding) 23 | ### Export services via port binding 24 | 25 | ## [VIII. Concurrency](./concurrency) 26 | ### Scale out via the process model 27 | 28 | ## [IX. Disposability](./disposability) 29 | ### Maximize robustness with fast startup and graceful shutdown 30 | 31 | ## [X. Dev/prod parity](./dev-prod-parity) 32 | ### Keep development, staging, and production as similar as possible 33 | 34 | ## [XI. Logs](./logs) 35 | ### Treat logs as event streams 36 | 37 | ## [XII. Admin processes](./admin-processes) 38 | ### Run admin/management tasks as one-off processes 39 | -------------------------------------------------------------------------------- /en/who.md: -------------------------------------------------------------------------------- 1 | Who should read this document? 2 | ============================== 3 | 4 | Any developer building applications which run as a service. Ops engineers who deploy or manage such applications. 5 | -------------------------------------------------------------------------------- /images/attached-resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/images/attached-resources.png -------------------------------------------------------------------------------- /images/codebase-deploys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/images/codebase-deploys.png -------------------------------------------------------------------------------- /images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/images/favicon.ico -------------------------------------------------------------------------------- /images/process-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/images/process-types.png -------------------------------------------------------------------------------- /images/release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/images/release.png -------------------------------------------------------------------------------- /images/symbol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bingohuang/12factor-gitbook/31ffe5051c72a820406fb04b37afdfa84a4d35bb/images/symbol.png -------------------------------------------------------------------------------- /zh_cn/README.md: -------------------------------------------------------------------------------- 1 | 简介 2 | ============ 3 | 如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论: 4 | 5 | * 使用**标准化**流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。 6 | * 和操作系统之间尽可能的**划清界限**,在各个系统中提供**最大的可移植性**。 7 | * 适合**部署**在现代的**云计算平台**,从而在服务器和系统管理方面节省资源。 8 | * 将开发环境和生产环境的**差异降至最低**,并使用**持续交付**实施敏捷开发。 9 | * 可以在工具、架构和开发流程不发生明显变化的前提下实现**扩展**。 10 | 11 | 这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。 12 | 13 | 14 | 背景 15 | ========== 16 | 17 | 本文的贡献者者参与过数以百计的应用程序的开发和部署,并通过 [Heroku](http://www.heroku.com/) 平台间接见证了数十万应用程序的开发,运作以及扩展的过程。 18 | 19 | 本文综合了我们关于 SaaS 应用几乎所有的经验和智慧,是开发此类应用的理想实践标准,并特别关注于应用程序如何保持良性成长,开发者之间如何进行有效的代码协作,以及如何 [避免软件污染](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/) 。 20 | 21 | 我们的初衷是分享在现代软件开发过程中发现的一些系统性问题,并加深对这些问题的认识。我们提供了讨论这些问题时所需的共享词汇,同时使用相关术语给出一套针对这些问题的广义解决方案。本文格式的灵感来自于 Martin Fowler 的书籍: *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* , *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)* 。 22 | 23 | 读者应该是哪些人? 24 | ============================== 25 | 26 | 任何 SaaS 应用的开发人员。部署和管理此类应用的运维工程师。 27 | -------------------------------------------------------------------------------- /zh_cn/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [简介](README.md) 4 | * [I. 基准代码](codebase.md) 5 | * [II. 依赖](dependencies.md) 6 | * [III. 配置](config.md) 7 | * [IV. 后端服务](backing-services.md) 8 | * [V. 构建,发布,运行](build-release-run.md) 9 | * [VI. 进程](processes.md) 10 | * [VII. 端口绑定](port-binding.md) 11 | * [VIII. 并发](concurrency.md) 12 | * [IX. 易处理](disposability.md) 13 | * [X. 开发环境与线上环境等价](dev-prod-parity.md) 14 | * [XI. 日志](logs.md) 15 | * [XII. 管理进程](admin-processes.md) 16 | -------------------------------------------------------------------------------- /zh_cn/admin-processes.md: -------------------------------------------------------------------------------- 1 | ## XII. 管理进程 2 | ### 后台管理任务当作一次性进程运行 3 | 4 | [进程构成](./concurrency)(process formation)是指用来处理应用的常规业务(比如处理 web 请求)的一组进程。与此不同,开发人员经常希望执行一些管理或维护应用的一次性任务,例如: 5 | 6 | * 运行数据移植(Django 中的 `manage.py migrate`, Rails 中的 `rake db:migrate`)。 7 | * 运行一个控制台(也被称为 [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell),来执行一些代码或是针对线上数据库做一些检查。大多数语言都通过解释器提供了一个 REPL 工具(`python` 或 `perl`) ,或是其他命令(Ruby 使用 `irb`, Rails 使用 `rails console`)。 8 | * 运行一些提交到代码仓库的一次性脚本。 9 | 10 | 一次性管理进程应该和正常的 [常驻进程](./processes) 使用同样的环境。这些管理进程和任何其他的进程一样使用相同的 [代码](./codebase) 和 [配置](./config) ,基于某个 [发布版本](./build-release-run) 运行。后台管理代码应该随其他应用程序代码一起发布,从而避免同步问题。 11 | 12 | 所有进程类型应该使用同样的 [依赖隔离](./dependencies) 技术。例如,如果Ruby的web进程使用了命令 `bundle exec thin start` ,那么数据库移植应使用 `bundle exec rake db:migrate` 。同样的,如果一个 Python 程序使用了 Virtualenv,则需要在运行 Tornado Web 服务器和任何 `manage.py` 管理进程时引入 `bin/python` 。 13 | 14 | 12-factor 尤其青睐那些提供了 REPL shell 的语言,因为那会让运行一次性脚本变得简单。在本地部署中,开发人员直接在命令行使用 shell 命令调用一次性管理进程。在线上部署中,开发人员依旧可以使用ssh或是运行环境提供的其他机制来运行这样的进程。 15 | -------------------------------------------------------------------------------- /zh_cn/background.md: -------------------------------------------------------------------------------- 1 | 背景 2 | ========== 3 | 4 | 本文的贡献者者参与过数以百计的应用程序的开发和部署,并通过 [Heroku](http://www.heroku.com/) 平台间接见证了数十万应用程序的开发,运作以及扩展的过程。 5 | 6 | 本文综合了我们关于 SaaS 应用几乎所有的经验和智慧,是开发此类应用的理想实践标准,并特别关注于应用程序如何保持良性成长,开发者之间如何进行有效的代码协作,以及如何 [避免软件污染](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/) 。 7 | 8 | 我们的初衷是分享在现代软件开发过程中发现的一些系统性问题,并加深对这些问题的认识。我们提供了讨论这些问题时所需的共享词汇,同时使用相关术语给出一套针对这些问题的广义解决方案。本文格式的灵感来自于 Martin Fowler 的书籍: *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* , *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)* 。 9 | 10 | -------------------------------------------------------------------------------- /zh_cn/backing-services.md: -------------------------------------------------------------------------------- 1 | ## IV. 后端服务 2 | ### 把后端服务(*backing services*)当作附加资源 3 | 4 | *后端服务*是指程序运行所需要的通过网络调用的各种服务,如数据库([MySQL](http://dev.mysql.com/),[CouchDB](http://couchdb.apache.org/)),消息/队列系统([RabbitMQ](http://www.rabbitmq.com/),[Beanstalkd](http://kr.github.com/beanstalkd/)),SMTP 邮件发送服务([ Postfix](http://www.postfix.org/)),以及缓存系统([Memcached](http://memcached.org/))。 5 | 6 | 类似数据库的后端服务,通常由部署应用程序的系统管理员一起管理。除了本地服务之外,应用程序有可能使用了第三方发布和管理的服务。示例包括 SMTP(例如 [Postmark](http://postmarkapp.com/)),数据收集服务(例如 [New Relic](http://newrelic.com/) 或 [Loggly](http://www.loggly.com/)),数据存储服务(如 [Amazon S3](http://http://aws.amazon.com/s3/)),以及使用 API 访问的服务(例如 [Twitter](http://dev.twitter.com/), [Google Maps](http://code.google.com/apis/maps/index.html), [Last.fm](http://www.last.fm/api))。 7 | 8 | **12-Factor 应用不会区别对待本地或第三方服务。** 对应用程序而言,两种都是附加资源,通过一个 url 或是其他存储在 [配置](./config) 中的服务定位/服务证书来获取数据。12-Factor 应用的任意 [部署](./codebase) ,都应该可以在不进行任何代码改动的情况下,将本地 MySQL 数据库换成第三方服务(例如 [Amazon RDS](http://aws.amazon.com/rds/))。类似的,本地 SMTP 服务应该也可以和第三方 SMTP 服务(例如 Postmark )互换。上述 2 个例子中,仅需修改配置中的资源地址。 9 | 10 | 每个不同的后端服务是一份 *资源* 。例如,一个 MySQL 数据库是一个资源,两个 MySQL 数据库(用来数据分区)就被当作是 2 个不同的资源。12-Factor 应用将这些数据库都视作 *附加资源* ,这些资源和它们附属的部署保持松耦合。 11 | 12 | 一种部署附加4个后端服务 13 | 14 | 部署可以按需加载或卸载资源。例如,如果应用的数据库服务由于硬件问题出现异常,管理员可以从最近的备份中恢复一个数据库,卸载当前的数据库,然后加载新的数据库 -- 整个过程都不需要修改代码。 15 | -------------------------------------------------------------------------------- /zh_cn/build-release-run.md: -------------------------------------------------------------------------------- 1 | ## V. 构建,发布,运行 2 | ### 严格分离构建和运行 3 | 4 | [基准代码](./codebase) 转化为一份部署(非开发环境)需要以下三个阶段: 5 | 6 | * *构建阶段* 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包 [依赖项](./dependencies),编译成二进制文件和资源文件。 7 | * *发布阶段* 会将构建的结果和当前部署所需 [配置](./config) 相结合,并能够立刻在运行环境中投入使用。 8 | * *运行阶段* (或者说“运行时”)是指针对选定的发布版本,在执行环境中启动一系列应用程序 [进程](./processes)。 9 | 10 | ![代码被构建,然后和配置结合成为发布版本](../images/release.png) 11 | 12 | **12-facfor 应用严格区分构建,发布,运行这三个步骤。** 举例来说,直接修改处于运行状态的代码是非常不可取的做法,因为这些修改很难再同步回构建步骤。 13 | 14 | 部署工具通常都提供了发布管理工具,最引人注目的功能是退回至较旧的发布版本。比如, [Capistrano](https://github.com/capistrano/capistrano/wiki) 将所有发布版本都存储在一个叫 `releases` 的子目录中,当前的在线版本只需映射至对应的目录即可。该工具的 `rollback` 命令可以很容易地实现回退版本的功能。 15 | 16 | 每一个发布版本必须对应一个唯一的发布 ID,例如可以使用发布时的时间戳(`2011-04-06-20:32:17`),亦或是一个增长的数字(`v100`)。发布的版本就像一本只能追加的账本,一旦发布就不可修改,任何的变动都应该产生一个新的发布版本。 17 | 18 | 新的代码在部署之前,需要开发人员触发构建操作。但是,运行阶段不一定需要人为触发,而是可以自动进行。如服务器重启,或是进程管理器重启了一个崩溃的进程。因此,运行阶段应该保持尽可能少的模块,这样假设半夜发生系统故障而开发人员又捉襟见肘也不会引起太大问题。构建阶段是可以相对复杂一些的,因为错误信息能够立刻展示在开发人员面前,从而得到妥善处理。 19 | -------------------------------------------------------------------------------- /zh_cn/codebase.md: -------------------------------------------------------------------------------- 1 | ## I. 基准代码 2 | ### 一份基准代码(*Codebase*),多份部署(*deploy*) 3 | 4 | 12-Factor应用(译者注:应该是说一个使用本文概念来设计的应用,下同)通常会使用版本控制系统加以管理,如[Git](http://git-scm.com/), [Mercurial](http://mercurial.selenic.com/), [Subversion](http://subversion.apache.org/)。一份用来跟踪代码所有修订版本的数据库被称作 *代码库*(code repository, code repo, repo)。 5 | 6 | 在类似 SVN 这样的集中式版本控制系统中,*基准代码* 就是指控制系统中的这一份代码库;而在 Git 那样的分布式版本控制系统中,*基准代码* 则是指最上游的那份代码库。 7 | 8 | ![一份代码库对应多份部署](../images/codebase-deploys.png) 9 | 10 | 基准代码和应用之间总是保持一一对应的关系: 11 | 12 | * 一旦有多个基准代码,就不能称为一个应用,而是一个分布式系统。分布式系统中的每一个组件都是一个应用,每一个应用可以分别使用 12-Factor 进行开发。 13 | * 多个应用共享一份基准代码是有悖于 12-Factor 原则的。解决方案是将共享的代码拆分为独立的类库,然后使用 [依赖管理](./dependencies) 策略去加载它们。 14 | 15 | 尽管每个应用只对应一份基准代码,但可以同时存在多份部署。每份 *部署* 相当于运行了一个应用的实例。通常会有一个生产环境,一个或多个预发布环境。此外,每个开发人员都会在自己本地环境运行一个应用实例,这些都相当于一份部署。 16 | 17 | 所有部署的基准代码相同,但每份部署可以使用其不同的版本。比如,开发人员可能有一些提交还没有同步至预发布环境;预发布环境也有一些提交没有同步至生产环境。但它们都共享一份基准代码,我们就认为它们只是相同应用的不同部署而已。 18 | -------------------------------------------------------------------------------- /zh_cn/concurrency.md: -------------------------------------------------------------------------------- 1 | ## VIII. 并发 2 | ### 通过进程模型进行扩展 3 | 4 | 任何计算机程序,一旦启动,就会生成一个或多个进程。互联网应用采用多种进程运行方式。例如,PHP 进程作为 Apache 的子进程存在,随请求按需启动。Java 进程则采取了相反的方式,在程序启动之初 JVM 就提供了一个超级进程储备了大量的系统资源(CPU 和内存),并通过多线程实现内部的并发管理。上述 2 个例子中,进程是开发人员可以操作的最小单位。 5 | 6 | ![扩展表现为运行中的进程,工作多样性表现为进程类型。](../images/process-types.png) 7 | 8 | **在 12-factor 应用中,进程是一等公民。**12-Factor 应用的进程主要借鉴于 [unix 守护进程模型](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/) 。开发人员可以运用这个模型去设计应用架构,将不同的工作分配给不同的 *进程类型* 。例如,HTTP 请求可以交给 web 进程来处理,而常驻的后台工作则交由 worker 进程负责。 9 | 10 | 这并不包括个别较为特殊的进程,例如通过虚拟机的线程处理并发的内部运算,或是使用诸如 [EventMachine](http://rubyeventmachine.com/), [Twisted](http://twistedmatrix.com/trac/), [Node.js](http://nodejs.org/) 的异步/事件触发模型。但一台独立的虚拟机的扩展有瓶颈(垂直扩展),所以应用程序必须可以在多台物理机器间跨进程工作。 11 | 12 | 上述进程模型会在系统急需扩展时大放异彩。 [12-Factor 应用的进程所具备的无共享,水平分区的特性](./processes) 意味着添加并发会变得简单而稳妥。这些进程的类型以及每个类型中进程的数量就被称作 *进程构成* 。 13 | 14 | 12-Factor 应用的进程 [不需要守护进程](http://dustin.github.com/2010/02/28/running-processes.html) 或是写入 PID 文件。相反的,应该借助操作系统的进程管理器(例如 [Upstart](http://upstart.ubuntu.com/) ,分布式的进程管理云平台,或是类似 [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) 的工具),来管理 [输出流](/logs) ,响应崩溃的进程,以及处理用户触发的重启和关闭超级进程的请求。 15 | -------------------------------------------------------------------------------- /zh_cn/config.md: -------------------------------------------------------------------------------- 1 | ## III. 配置 2 | ### 在环境中存储配置 3 | 4 | 通常,应用的 *配置* 在不同 [部署](./codebase) (预发布、生产环境、开发环境等等)间会有很大差异。这其中包括: 5 | 6 | * 数据库,Memcached,以及其他 [后端服务](./backing-services) 的配置 7 | * 第三方服务的证书,如 Amazon S3、Twitter 等 8 | * 每份部署特有的配置,如域名等 9 | 10 | 有些应用在代码中使用常量保存配置,这与 12-Factor 所要求的**代码和配置严格分离**显然大相径庭。配置文件在各部署间存在大幅差异,代码却完全一致。 11 | 12 | 判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息。 13 | 14 | 需要指出的是,这里定义的"配置"并**不**包括应用的内部配置,比如 Rails 的 `config/routes.rb`,或是使用 [Spring](http://spring.io/) 时 [代码模块间的依赖注入关系](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) 。这类配置在不同部署间不存在差异,所以应该写入代码。 15 | 16 | 另外一个解决方法是使用配置文件,但不把它们纳入版本控制系统,就像 Rails 的 `config/database.yml` 。这相对于在代码中使用常量已经是长足进步,但仍然有缺点:总是会不小心将配置文件签入了代码库;配置文件的可能会分散在不同的目录,并有着不同的格式,这让找出一个地方来统一管理所有配置变的不太现实。更糟的是,这些格式通常是语言或框架特定的。 17 | 18 | **12-Factor推荐将应用的配置存储于 *环境变量* 中**( *env vars*, *env* )。环境变量可以非常方便地在不同的部署间做修改,却不动一行代码;与配置文件不同,不小心把它们签入代码库的概率微乎其微;与一些传统的解决配置问题的机制(比如 Java 的属性配置文件)相比,环境变量与语言和系统无关。 19 | 20 | 配置管理的另一个方面是分组。有时应用会将配置按照特定部署进行分组(或叫做“环境”),例如Rails中的 `development`,`test`, 和 `production` 环境。这种方法无法轻易扩展:更多部署意味着更多新的环境,例如 `staging` 或 `qa` 。 随着项目的不断深入,开发人员可能还会添加他们自己的环境,比如 `joes-staging` ,这将导致各种配置组合的激增,从而给管理部署增加了很多不确定因素。 21 | 22 | 12-Factor 应用中,环境变量的粒度要足够小,且相对独立。它们永远也不会组合成一个所谓的“环境”,而是独立存在于每个部署之中。当应用程序不断扩展,需要更多种类的部署时,这种配置管理方式能够做到平滑过渡。 23 | -------------------------------------------------------------------------------- /zh_cn/dependencies.md: -------------------------------------------------------------------------------- 1 | ## II. 依赖 2 | ### 显式声明依赖关系( *dependency* ) 3 | 4 | 大多数编程语言都会提供一个打包系统,用来为各个类库提供打包服务,就像 Perl 的 [CPAN](http://www.cpan.org/) 或是 Ruby 的 [Rubygems](http://rubygems.org/) 。通过打包系统安装的类库可以是系统级的(称之为 "site packages"),或仅供某个应用程序使用,部署在相应的目录中(称之为 "vendoring" 或 "bunding")。 5 | 6 | **12-Factor规则下的应用程序不会隐式依赖系统级的类库。** 它一定通过 *依赖清单* ,确切地声明所有依赖项。此外,在运行过程中通过 *依赖隔离* 工具来确保程序不会调用系统中存在但清单中未声明的依赖项。这一做法会统一应用到生产和开发环境。 7 | 8 | 例如, Ruby 的 [Bundler](https://bundler.io/) 使用 `Gemfile` 作为依赖项声明清单,使用 `bundle exec` 来进行依赖隔离。Python 中则可分别使用两种工具 -- [Pip](http://www.pip-installer.org/en/latest/) 用作依赖声明, [Virtualenv](http://www.virtualenv.org/en/latest/) 用作依赖隔离。甚至 C 语言也有类似工具, [Autoconf](http://www.gnu.org/s/autoconf/) 用作依赖声明,静态链接库用作依赖隔离。无论用什么工具,依赖声明和依赖隔离必须一起使用,否则无法满足 12-Factor 规范。 9 | 10 | 显式声明依赖的优点之一是为新进开发者简化了环境配置流程。新进开发者可以检出应用程序的基准代码,安装编程语言环境和它对应的依赖管理工具,只需通过一个 *构建命令* 来安装所有的依赖项,即可开始工作。例如,Ruby/Bundler 下使用 `bundle install`,而 Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) 则是 `lein deps`。 11 | 12 | 12-Factor 应用同样不会隐式依赖某些系统工具,如 ImageMagick 或是`curl`。即使这些工具存在于几乎所有系统,但终究无法保证所有未来的系统都能支持应用顺利运行,或是能够和应用兼容。如果应用必须使用到某些系统工具,那么这些工具应该被包含在应用之中。 13 | -------------------------------------------------------------------------------- /zh_cn/dev-prod-parity.md: -------------------------------------------------------------------------------- 1 | ## X. 开发环境与线上环境等价 2 | ### 尽可能的保持开发,预发布,线上环境相同 3 | 4 | 从以往经验来看,开发环境(即开发人员的本地 [部署](./codebase))和线上环境(外部用户访问的真实部署)之间存在着很多差异。这些差异表现在以下三个方面: 5 | 6 | * **时间差异:** 开发人员正在编写的代码可能需要几天,几周,甚至几个月才会上线。 7 | * **人员差异:** 开发人员编写代码,运维人员部署代码。 8 | * **工具差异:** 开发人员或许使用 Nginx,SQLite,OS X,而线上环境使用 Apache,MySQL 以及 Linux。 9 | 10 | **12-Factor 应用想要做到 [持续部署](http://www.avc.com/a_vc/2011/02/continuous-deployment.html) 就必须缩小本地与线上差异。** 再回头看上面所描述的三个差异: 11 | 12 | * 缩小时间差异:开发人员可以几小时,甚至几分钟就部署代码。 13 | * 缩小人员差异:开发人员不只要编写代码,更应该密切参与部署过程以及代码在线上的表现。 14 | * 缩小工具差异:尽量保证开发环境以及线上环境的一致性。 15 | 16 | 将上述总结变为一个表格如下: 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
传统应用12-Factor 应用
每次部署间隔数周几小时
开发人员 vs 运维人员不同的人相同的人
开发环境 vs 线上环境不同尽量接近
40 | 41 | [后端服务](./backing-services) 是保持开发与线上等价的重要部分,例如数据库,队列系统,以及缓存。许多语言都提供了简化获取后端服务的类库,例如不同类型服务的 *适配器* 。下列表格提供了一些例子。 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
类型语言类库适配器
数据库Ruby/RailsActiveRecordMySQL, PostgreSQL, SQLite
队列Python/DjangoCeleryRabbitMQ, Beanstalkd, Redis
缓存Ruby/RailsActiveSupport::CacheMemory, filesystem, Memcached
69 | 70 | 开发人员有时会觉得在本地环境中使用轻量的后端服务具有很强的吸引力,而那些更重量级的健壮的后端服务应该使用在生产环境。例如,本地使用 SQLite 线上使用 PostgreSQL;又如本地缓存在进程内存中而线上存入 Memcached。 71 | 72 | **12-Factor 应用的开发人员应该反对在不同环境间使用不同的后端服务** ,即使适配器已经可以几乎消除使用上的差异。这是因为,不同的后端服务意味着会突然出现的不兼容,从而导致测试、预发布都正常的代码在线上出现问题。这些错误会给持续部署带来阻力。从应用程序的生命周期来看,消除这种阻力需要花费很大的代价。 73 | 74 | 与此同时,轻量的本地服务也不像以前那样引人注目。借助于[Homebrew](http://mxcl.github.com/homebrew/),[apt-get](https://help.ubuntu.com/community/AptGet/Howto)等现代的打包系统,诸如Memcached、PostgreSQL、RabbitMQ 等后端服务的安装与运行也并不复杂。此外,使用类似 [Chef](http://www.opscode.com/chef/) 和 [Puppet](http://docs.puppetlabs.com/) 的声明式配置工具,结合像 [Vagrant](http://vagrantup.com/) 这样轻量的虚拟环境就可以使得开发人员的本地环境与线上环境无限接近。与同步环境和持续部署所带来的益处相比,安装这些系统显然是值得的。 75 | 76 | 不同后端服务的适配器仍然是有用的,因为它们可以使移植后端服务变得简单。但应用的所有部署,这其中包括开发、预发布以及线上环境,都应该使用同一个后端服务的相同版本。 77 | -------------------------------------------------------------------------------- /zh_cn/disposability.md: -------------------------------------------------------------------------------- 1 | ## IX. 易处理 2 | ### 快速启动和优雅终止可最大化健壮性 3 | 4 | **12-Factor 应用的 [进程](./processes) 是 *易处理(disposable)*的,意思是说它们可以瞬间开启或停止。** 这有利于快速、弹性的伸缩应用,迅速部署变化的 [代码](./codebase) 或 [配置](./config) ,稳健的部署应用。 5 | 6 | 进程应当追求 **最小启动时间** 。 理想状态下,进程从敲下命令到真正启动并等待请求的时间应该只需很短的时间。更少的启动时间提供了更敏捷的 [发布](./build-release-run) 以及扩展过程,此外还增加了健壮性,因为进程管理器可以在授权情形下容易的将进程搬到新的物理机器上。 7 | 8 | 进程 **一旦接收 [终止信号(`SIGTERM`)](http://en.wikipedia.org/wiki/SIGTERM) 就会优雅的终止** 。就网络进程而言,优雅终止是指停止监听服务的端口,即拒绝所有新的请求,并继续执行当前已接收的请求,然后退出。此类型的进程所隐含的要求是HTTP请求大多都很短(不会超过几秒钟),而在长时间轮询中,客户端在丢失连接后应该马上尝试重连。 9 | 10 | 对于 worker 进程来说,优雅终止是指将当前任务退回队列。例如,[RabbitMQ](http://www.rabbitmq.com/) 中,worker 可以发送一个[`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack)信号。 [Beanstalkd](http://kr.github.com/beanstalkd/) 中,任务终止并退回队列会在worker断开时自动触发。有锁机制的系统诸如 [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) 则需要确定释放了系统资源。此类型的进程所隐含的要求是,任务都应该 [可重复执行](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29) , 这主要由将结果包装进事务或是使重复操作 [幂等](http://en.wikipedia.org/wiki/Idempotence) 来实现。 11 | 12 | 进程还应当**在面对突然死亡时保持健壮**,例如底层硬件故障。虽然这种情况比起优雅终止来说少之又少,但终究有可能发生。一种推荐的方式是使用一个健壮的后端队列,例如 [Beanstalkd](http://kr.github.com/beanstalkd/) ,它可以在客户端断开或超时后自动退回任务。无论如何,12-Factor 应用都应该可以设计能够应对意外的、不优雅的终结。[Crash-only design](http://lwn.net/Articles/191059/) 将这种概念转化为 [合乎逻辑的理论](http://couchdb.apache.org/docs/overview.html)。 13 | 14 | -------------------------------------------------------------------------------- /zh_cn/intro.md: -------------------------------------------------------------------------------- 1 | 简介 2 | ============ 3 | 如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论: 4 | 5 | * 使用**标准化**流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。 6 | * 和操作系统之间尽可能的**划清界限**,在各个系统中提供**最大的可移植性**。 7 | * 适合**部署**在现代的**云计算平台**,从而在服务器和系统管理方面节省资源。 8 | * 将开发环境和生产环境的**差异降至最低**,并使用**持续交付**实施敏捷开发。 9 | * 可以在工具、架构和开发流程不发生明显变化的前提下实现**扩展**。 10 | 11 | 这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。 12 | -------------------------------------------------------------------------------- /zh_cn/logs.md: -------------------------------------------------------------------------------- 1 | ## XI. 日志 2 | ### 把日志当作事件流 3 | 4 | *日志* 使得应用程序运行的动作变得透明。在基于服务器的环境中,日志通常被写在硬盘的一个文件里,但这只是一种输出格式。 5 | 6 | 日志应该是 [事件流](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) 的汇总,将所有运行中进程和后端服务的输出流按照时间顺序收集起来。尽管在回溯问题时可能需要看很多行,日志最原始的格式确实是一个事件一行。日志没有确定开始和结束,但随着应用在运行会持续的增加。 7 | 8 | **12-factor应用本身从不考虑存储自己的输出流。** 不应该试图去写或者管理日志文件。相反,每一个运行的进程都会直接的标准输出(`stdout`)事件流。开发环境中,开发人员可以通过这些数据流,实时在终端看到应用的活动。 9 | 10 | 在预发布或线上部署中,每个进程的输出流由运行环境截获,并将其他输出流整理在一起,然后一并发送给一个或多个最终的处理程序,用于查看或是长期存档。这些存档路径对于应用来说不可见也不可配置,而是完全交给程序的运行环境管理。类似 [Logplex](https://github.com/heroku/logplex) 和 [Fluent](https://github.com/fluent/fluentd) 的开源工具可以达到这个目的。 11 | 12 | 这些事件流可以输出至文件,或者在终端实时观察。最重要的,输出流可以发送到 [Splunk](http://www.splunk.com/) 这样的日志索引及分析系统,或 [Hadoop/Hive](http://hive.apache.org/) 这样的通用数据存储系统。这些系统为查看应用的历史活动提供了强大而灵活的功能,包括: 13 | 14 | * 找出过去一段时间特殊的事件。 15 | * 图形化一个大规模的趋势,比如每分钟的请求量。 16 | * 根据用户定义的条件实时触发警报,比如每分钟的报错超过某个警戒线。 17 | -------------------------------------------------------------------------------- /zh_cn/port-binding.md: -------------------------------------------------------------------------------- 1 | ## VII. 端口绑定 2 | ### 通过端口绑定(*Port binding*)来提供服务 3 | 4 | 互联网应用有时会运行于服务器的容器之中。例如 PHP 经常作为 [Apache HTTPD](http://httpd.apache.org/) 的一个模块来运行,正如 Java 运行于 [Tomcat](http://tomcat.apache.org/) 。 5 | 6 | **12-Factor 应用完全自我加载** 而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用 **通过端口绑定来提供服务** ,并监听发送至该端口的请求。 7 | 8 | 本地环境中,开发人员通过类似`http://localhost:5000/`的地址来访问服务。在线上环境中,请求统一发送至公共域名而后路由至绑定了端口的网络进程。 9 | 10 | 通常的实现思路是,将网络服务器类库通过 [依赖声明](./dependencies) 载入应用。例如,Python 的 [Tornado](http://www.tornadoweb.org/), Ruby 的[Thin](http://code.macournoyer.com/thin/) , Java 以及其他基于 JVM 语言的 [Jetty](http://jetty.codehaus.org/jetty/)。完全由 *用户端* ,确切的说应该是应用的代码,发起请求。和运行环境约定好绑定的端口即可处理这些请求。 11 | 12 | HTTP 并不是唯一一个可以由端口绑定提供的服务。其实几乎所有服务器软件都可以通过进程绑定端口来等待请求。例如,使用 [XMPP](http://xmpp.org/) 的 [ejabberd](http://www.ejabberd.im/) , 以及使用 [Redis 协议](http://redis.io/topics/protocol) 的 [Redis](http://redis.io/) 。 13 | 14 | 还要指出的是,端口绑定这种方式也意味着一个应用可以成为另外一个应用的 [后端服务](/backing-services) ,调用方将服务方提供的相应 URL 当作资源存入 [配置](/config) 以备将来调用。 15 | -------------------------------------------------------------------------------- /zh_cn/processes.md: -------------------------------------------------------------------------------- 1 | ## VI. 进程 2 | ### 以一个或多个无状态进程运行应用 3 | 4 | 运行环境中,应用程序通常是以一个和多个 *进程* 运行的。 5 | 6 | 最简单的场景中,代码是一个独立的脚本,运行环境是开发人员自己的笔记本电脑,进程由一条命令行(例如`python my_script.py`)。另外一个极端情况是,复杂的应用可能会使用很多 [进程类型](./concurrency) ,也就是零个或多个进程实例。 7 | 8 | **12-Factor 应用的进程必须无状态且 [无共享](http://en.wikipedia.org/wiki/Shared_nothing_architecture) 。** 任何需要持久化的数据都要存储在 [后端服务](./backing-services) 内,比如数据库。 9 | 10 | 内存区域或磁盘空间可以作为进程在做某种事务型操作时的缓存,例如下载一个很大的文件,对其操作并将结果写入数据库的过程。12-Factor应用根本不用考虑这些缓存的内容是不是可以保留给之后的请求来使用,这是因为应用启动了多种类型的进程,将来的请求多半会由其他进程来服务。即使在只有一个进程的情形下,先前保存的数据(内存或文件系统中)也会因为重启(如代码部署、配置更改、或运行环境将进程调度至另一个物理区域执行)而丢失。 11 | 12 | 源文件打包工具([Jammit](http://documentcloud.github.com/jammit/), [django-compressor](http://django-compressor.readthedocs.org/)) 使用文件系统来缓存编译过的源文件。12-Factor 应用更倾向于在 [构建步骤](./build-release-run) 做此动作——正如 [Rails资源管道](http://guides.rubyonrails.org/asset_pipeline.html) ,而不是在运行阶段。 13 | 14 | 一些互联网系统依赖于 “[粘性 session ](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence)”, 这是指将用户 session 中的数据缓存至某进程的内存中,并将同一用户的后续请求路由到同一个进程。粘性 session 是 12-Factor 极力反对的。Session 中的数据应该保存在诸如 [Memcached](http://memcached.org/) 或 [Redis](http://redis.io/) 这样的带有过期时间的缓存中。 15 | -------------------------------------------------------------------------------- /zh_cn/toc.md: -------------------------------------------------------------------------------- 1 | 12-factors 2 | ================== 3 | 4 | ## [I. 基准代码](./codebase) 5 | ### 一份基准代码,多份部署 6 | 7 | ## [II. 依赖](./dependencies) 8 | ### 显式声明依赖关系 9 | 10 | ## [III. 配置](./config) 11 | ### 在环境中存储配置 12 | 13 | ## [IV. 后端服务](./backing-services) 14 | ### 把后端服务当作附加资源 15 | 16 | ## [V. 构建,发布,运行](./build-release-run) 17 | ### 严格分离构建和运行 18 | 19 | ## [VI. 进程](./processes) 20 | ### 以一个或多个无状态进程运行应用 21 | 22 | ## [VII. 端口绑定](./port-binding) 23 | ### 通过端口绑定提供服务 24 | 25 | ## [VIII. 并发](./concurrency) 26 | ### 通过进程模型进行扩展 27 | 28 | ## [IX. 易处理](./disposability) 29 | ### 快速启动和优雅终止可最大化健壮性 30 | 31 | ## [X. 开发环境与线上环境等价](./dev-prod-parity) 32 | ### 尽可能的保持开发,预发布,线上环境相同 33 | 34 | ## [XI. 日志](./logs) 35 | ### 把日志当作事件流 36 | 37 | ## [XII. 管理进程](./admin-processes) 38 | ### 后台管理任务当作一次性进程运行 39 | -------------------------------------------------------------------------------- /zh_cn/who.md: -------------------------------------------------------------------------------- 1 | 读者应该是哪些人? 2 | ============================== 3 | 4 | 任何 SaaS 应用的开发人员。部署和管理此类应用的运维工程师。 5 | --------------------------------------------------------------------------------