diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..63743bdf2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.rvmrc +.bundle +.tool-versions +.DS_Store \ No newline at end of file diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000..be94e6f53 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2.2 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..abd61d3d2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: ruby +rvm: + - 2.6.6 +script: exit 0 +sudo: false diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..522fa4a0f --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# Comment line immediately above ownership line is reserved for related gus information. Please be careful while editing. +#ECCN:Open Source diff --git a/Gemfile b/Gemfile index 2d7d5aa87..37e58a16f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,10 @@ source 'http://rubygems.org' -gem 'sinatra', '1.2.6' -gem 'thin', '1.2.7' -gem 'maruku', '0.6.0' +ruby '3.2.2' + +gem 'sinatra' +gem 'thin' +gem 'maruku' +gem 'i18n' +gem 'rack-ssl-enforcer' +gem 'rexml' diff --git a/Gemfile.lock b/Gemfile.lock index 5a934fa1d..93251c83e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,25 +1,44 @@ GEM remote: http://rubygems.org/ specs: - daemons (1.1.3) - eventmachine (0.12.10) - maruku (0.6.0) - syntax (>= 1.0.0) - rack (1.3.0) - sinatra (1.2.6) - rack (~> 1.1) - tilt (>= 1.2.2, < 2.0) - syntax (1.0.0) - thin (1.2.7) - daemons (>= 1.0.9) - eventmachine (>= 0.12.6) - rack (>= 1.0.0) - tilt (1.3.2) + concurrent-ruby (1.2.2) + daemons (1.4.1) + eventmachine (1.2.7) + i18n (1.13.0) + concurrent-ruby (~> 1.0) + maruku (0.7.3) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) + rack (2.2.7) + rack-protection (3.0.6) + rack + rack-ssl-enforcer (0.2.9) + rexml (3.2.5) + ruby2_keywords (0.0.5) + sinatra (3.0.6) + mustermann (~> 3.0) + rack (~> 2.2, >= 2.2.4) + rack-protection (= 3.0.6) + tilt (~> 2.0) + thin (1.8.2) + daemons (~> 1.0, >= 1.0.9) + eventmachine (~> 1.0, >= 1.0.4) + rack (>= 1, < 3) + tilt (2.1.0) PLATFORMS ruby DEPENDENCIES - maruku (= 0.6.0) - sinatra (= 1.2.6) - thin (= 1.2.7) + i18n + maruku + rack-ssl-enforcer + rexml + sinatra + thin + +RUBY VERSION + ruby 3.2.2p53 + +BUNDLED WITH + 2.4.10 diff --git a/Readme.md b/Readme.md index 124a7ca56..95657346e 100644 --- a/Readme.md +++ b/Readme.md @@ -1,19 +1,19 @@ The Twelve-Factor App ===================== -Source for the content app running at: http://www.12factor.net/ +Source for the content app running at: https://12factor.net/ Development ----------- bundle install - foreman start + heroku local:start open http://localhost:5000 Production deploy ----------------- - heroku create -s cedar + heroku create git push heroku master heroku open @@ -27,5 +27,24 @@ Daigle, Mark Imbriaco, Keith Rarick, Will Leinweber, Jesper Jørgensen, James Ward, Adam Seligman, Phil Hagelberg, Jon Mountjoy, Matthew Turland, Daniel Jomphe, Mattt Thompson, Anand Narasimhan, Lucas Fais, Pete Hodgson -Released under the MIT License: http://www.opensource.org/licenses/mit-license.php - +Translations and edits by: +[@sigerello](https://github.com/sigerello), +[@mahnunchik](https://github.com/mahnunchik), +[@francescomalatesta](https://github.com/francescomalatesta), +[@astralhpi](https://github.com/astralhpi), +[@liangshan](https://github.com/liangshan), +[@orangain](https://github.com/orangain), +[@Keirua](https://github.com/Keirua), +Clément Camin, +Bob Marteen, +[@dmathieu](https://github.com/dmathieu), +[@fernandes](https://github.com/fernandes), +[@gwmoura](https://github.com/gwmoura), +[@lfilho](https://github.com/lfilho), +[@Arturszott](https://github.com/Arturszott), +[@melikeyurtoglu](https://github.com/melikeyurtoglu), +[@filiphanes](https://github.com/filiphanes) +and [more](https://github.com/heroku/12factor/graphs/contributors). + +Released under the MIT License: +https://opensource.org/licenses/MIT diff --git a/app.json b/app.json new file mode 100644 index 000000000..6a233a8ea --- /dev/null +++ b/app.json @@ -0,0 +1,17 @@ +{ + "name": "12factor", + "stack": "heroku-22", + "scripts": { + }, + "env": { + }, + "addons": [ + ], + "environments": { + "test": { + "scripts": { + "test": "exit 0" + } + } + } +} diff --git a/content/admin-processes.md b/content/admin-processes.md deleted file mode 100644 index 3ae04eeea..000000000 --- a/content/admin-processes.md +++ /dev/null @@ -1,14 +0,0 @@ -## XII. Admin processes -### Run admin/management tasks as one-off processes - -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: - -* Running database migrations (e.g. `manage.py syncdb` in Django, `rake db:migrate` in Rails). -* 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 `erl`) or in some cases have a separate command (e.g. `irb` for Ruby, `rails console` for Rails). -* Running one-time scripts committed into the app's repo (e.g. `php scripts/fix_bad_records.php`). - -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 [code](/code) and [config](/config) as any process run against that release. Admin code must ship with application code to avoid synchronization issues. - -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. - -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. diff --git a/content/background.md b/content/background.md deleted file mode 100644 index af26e1431..000000000 --- a/content/background.md +++ /dev/null @@ -1,9 +0,0 @@ -Background -========== - -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](http://www.heroku.com/) platform. - -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 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](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). - -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](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* and *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. - diff --git a/content/backing-services.md b/content/backing-services.md deleted file mode 100644 index 1b6f77c1d..000000000 --- a/content/backing-services.md +++ /dev/null @@ -1,15 +0,0 @@ -## IV. Backing Services -### Treat backing services as attached resources - -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/)). - -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)). - -**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. - -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. - -A production deploy attached to four backing services. - -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. - diff --git a/content/cs/admin-processes.md b/content/cs/admin-processes.md new file mode 100644 index 000000000..d940c09c7 --- /dev/null +++ b/content/cs/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Admin procesy +### Spouštějte administrativní úlohy jako jednorázové procesy. + +[Formace procesů](./concurrency) je sada procesů, které aplikace používá pro svůj běh (jako je například obsluha příchozích požadavků). Kromě toho potřebují vývojáři často spouštět i jednorázové administrativní nebo úlohy údržby, jako například: + +* Spuštění databázové migrace (jako `manage.py migrate` v Django, `rake db:migrate` v Rails). +* Spuštění konzole (známé také jako [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) pro vykonání libovolného kódu nebo k prohlížení aplikačních modelů v živé databázi. Většina jazyků poskytuje REPL spuštěním interpreteru bez argumentů (kupříkladu `python` nebo `perl`) nebo v některých případech samostatným příkazem (jako `irb` u Ruby, `rails console` pro Rails). +* Spuštění jednorázových skriptů uložených v repozitáři aplikace (například `php scripts/fix_bad_records.php`). + +Jednorázové administrativní procesy by měly být spouštěny ve stejném prostředí jako běžné [dlouho běžící procesy](./processes) aplikace. Běží proti [vydání](./build-release-run) za použití stejného [kódu](./codebase) a [konfigurace ](./config) jako ostatní procesy daného vydání. Administrativní kód musí být dodáván spolu s aplikací, aby se zabránilo problémům se synchronizací. + +Stejné techniky [izolace závislostí](./dependencies) by měly být použity na všechny typy procesů. Například, pokud Ruby webový proces používá příkaz `bundle exec thin start`, tak databázová migrace by měla používat `bundle exec rake db:migrate`. Obdobně by pak měl program v Pythonu, využívající Virtualenv, používat přibalený `bin/python` pro spouštění jak Tornado webserveru, tak i pro spouštění `manage.py` administrativního procesu. + +Twelve-factor metodika silně preferuje jazyky, které poskytují REPL shell v základu a umožňují tak snadno spouštět jednorázové skripty. V lokálním nasazení spouštějí vývojáři jednorázový administrativní proces příkazem přímo v shellu uvnitř repozitáře. V produkčním nasazení mohou vývojáři použít SSH nebo jiný způsob vzdáleného spouštění příkazů, který je v daném nasazení pro spouštění procesů k dispozici. diff --git a/content/cs/background.md b/content/cs/background.md new file mode 100644 index 000000000..1886b2dca --- /dev/null +++ b/content/cs/background.md @@ -0,0 +1,8 @@ +Pozadí +========== + +Přispěvatelé tohoto dokumentu se přímo podíleli na vývoji a nasazení stovek aplikací a byli svědky vývoje, provozu a škálování stovek tisíc aplikací prostřednictvím své práce na platformě Heroku. + +Tento dokument shromažďuje všechny naše zkušenosti a postřehy týkající se široké škály aplikací typu software-as-a-service v divočině. Jedná se o sadu ideálních postupů pro vývoj aplikací se zvláštní pozorností věnovanou dynamice organického růstu aplikace v průběhu času, dynamice spolupráce mezi vývojáři pracujícími na kódu aplikace a vyhýbání se nákladům na erozi softwaru. + +Naší motivací je zvyšovat povědomí o některých systémových problémech, které jsme zaznamenali v moderním vývoji aplikací, poskytnout společnou slovní zásobu pro diskusi o těchto problémech a nabídnout rozsáhlou sadu koncepčních řešení těchto problémů s doprovodnou terminologií. Formát je inspirován knihami Martina Fowlera *Patterns of Enterprise Application Architecture* a *Refactoring*. diff --git a/content/cs/backing-services.md b/content/cs/backing-services.md new file mode 100644 index 000000000..d904baf00 --- /dev/null +++ b/content/cs/backing-services.md @@ -0,0 +1,14 @@ +## IV. Podpůrné služby +### Nakládejte s podpůrnými službami jako s připojenými zdroji. + +*Podpůrná* služba je jakákoliv služba, kterou aplikace konzumuje přes síť jako součást svého normálního běhu. Příklady zahrnují databáze (jako například [MySQL](http://dev.mysql.com/) nebo [CouchDB](http://couchdb.apache.org/)), messaging/queueing systémy (jako jsou [RabbitMQ](http://www.rabbitmq.com/) nebo [Beanstalkd](https://beanstalkd.github.io)), SMTP služby pro odchozí emaily (jako [Postfix](http://www.postfix.org/)) a cachovací systémy (jako je [Memcached](http://memcached.org/)). + +Podpůrné služby, jako například databáze, jsou obvykle spravovány stejnými systémovými inženýry jako samotné nasazení aplikace. K těmto lokálně spravovaným službám může aplikace navíc využívat služby provozované a spravované třetí stranou. To mohou být například SMTP služby (jako je [Postmark](http://postmarkapp.com/)), služby na sbírání metrik (jako [New Relic](http://newrelic.com/) nebo [Loggly](http://www.loggly.com/)), datová uložistě (jako [Amazon S3](http://aws.amazon.com/s3/)) a dokonce i služby přístupné přes API (jako jsou například [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/) nebo [Last.fm](http://www.last.fm/api)). + +**Kód twelve-factor aplikace nedělá rozdíly mezi lokální službou a službou třetí strany.** Z pohledu aplikace jsou to připojené zdroje přístupné přes URL nebo jiné přístupové/přihlašovací údaje uložené v [konfiguraci](./config). Nasazení twelve-factor aplikace by mělo být schopné vyměnit lokální MySQL databázi za databázi spravovanou třetí stranou (jako je například [Amazon RDS](http://aws.amazon.com/rds/)) bez jakýchkoliv změn v aplikačním kódu. Obdobně může být lokální SMTP server nahrazen SMTP službou třetí strany (jako Postmark) bez změn v kódu. V obou případech se změní pouze přístupové a přihlašovací údaje v konfiguraci. + +Každá podpůrná služba je *zdroj*. Například MySQL databáze je zdroj, dvě MySQL databáze (použité pro sharding na aplikační úrovni) kvalifikujeme jako dva různé zdroje. Twelve-factor aplikace nakládá s těmito databázemi jako *připojenými zdroji*, což naznačuje i jejich volné spojení se souvisejícím nasazením. + +Produkční nasazení připojené k podpůrným službám. + +Zdroje je možné připojovat a odpojovat z nasazení dle libosti. Například pokud je databáze z důvodu hardwarových problémů nestabilní, systémový inženýr může rozběhnout nový databázový server z aktuální zálohy. Aktuální produkční databáze pak může být odpojena a nová databáze připojena na její místo, vše beze změn v kódu. diff --git a/content/cs/build-release-run.md b/content/cs/build-release-run.md new file mode 100644 index 000000000..a7097de12 --- /dev/null +++ b/content/cs/build-release-run.md @@ -0,0 +1,19 @@ +## V. Sestavení, vydání, spuštění +### Striktně oddělte fáze sestavení, vydání a spuštění. + +[Zdrojový kód](./codebase) je transformován do (nevývojářského) nasazení ve třech fázích: + +* Fáze *sestavení (build)* je transformace, která převede zdrojový kód do spustitelného balíčku zvaného *sestavení*. Z verze kódu v čase příslušného commitu a dle postupu nasazení, dojde ve fázi sestavení ke stažení [závislostí](./dependencies), zkompilování binárek a připojení assetů. +* Fáze *vydání (release)* vezme sestavení vytvořené v předchozím kroku a zkombinuje ho [konfigurací](./config) pro dané nasazení. Výsledná kombinace je *vydáním*, které je připravené k okamžitému spuštění v běhovém prostředí. +* Fáze *spuštění (run)* (známá též jako "runtime") spustí aplikaci v běhovém prostředí nastartováním aplikačních [procesů](./processes) oproti danému vydání. + +![Kód se stane sestavením, které v kombinaci s příslušnou konfigurací tvoří vydání.](/images/release.png) + +**Twelve-factor aplikace striktně rozlišují mezi fází sestavení, vydání a spuštění.** Je například nemožné provedět změny ve spuštěném kódu, protože není cesty, jak tyto změny propagovat zpět do fáze sestavení. + +Nástroje pro nasazení obvykle poskytují i správu vydání a zejména pak schopnost vrátit se zpět k předchozímu vydání. Například nástroj [Capistrano](https://github.com/capistrano/capistrano/wiki) si ukládá nasazení v podadresáři zvaném `releases` a aktuální vydání je pak symlink na příslušný adresář s aktuální verzí. Příkaz `rollback` pak velmi snadno zajistí návrat k předchozímu vydání. + +Každé vydaní by mělo mít vždy unikátní ID, jako je například časová značka ( `2011-04-06-20:32:17`) nebo inkrementální číslo (například `v100`). Vydání již nelze po vytvoření jakkoliv upravovat, libovolná změna musí vždy vytvořit nové vydání. + +Sestavení iniciují vývojáři aplikace, kdykoliv se nasazuje nový kód. Naopak ke spuštění v běhovém prostředí může dojít automaticky v případě restartu serveru nebo restartem havarovaného procesu pomocí správce procesů. Proto by měla mít fáze spuštění co nejméně pohyblivých částí, jelikož problémy bránící aplikaci v běhu mohou nastat uprostřed noci, kdy nejsou žádní vývojáři k dispozici. Fáze sestavení pak může být složitější, protože chyby jsou více na očích pro vývojáře kontrolující nasazení aplikace. + diff --git a/content/cs/codebase.md b/content/cs/codebase.md new file mode 100644 index 000000000..916e83704 --- /dev/null +++ b/content/cs/codebase.md @@ -0,0 +1,18 @@ +## I. Zdrojový kód +### Mějte jeden zdrojový kód ve verzovacím systému a mnoho nasazení. + +Twelve-factor aplikace je vždy sledována ve verzovacím systému, jako je například [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/) nebo [Subversion](http://subversion.apache.org/). Kopie verzovací databáze se nazývá *kódový repozitář*, často zkracováno jako *repozitář* nebo jen *repo*. + +*Zdrojový kód* je jakýkoliv repozitář (v centralizovaném verzovacím systému jako je Subversion), nebo jakákoliv skupina repozitářů, které mají společný kořenový commit (v decentralizovaném verzovacím systému jako je Git). + +![Jeden zdrojový kód má mnoho nasazení](/images/codebase-deploys.png) + +Vždy existuje korelace jedna-ku-jedné mezi zdrojovým kódem a aplikací: + +* Pokud existuje více zdrojových kódů, nejedná se o aplikaci, ale o distribuovaný systém. Každá komponenta distribuovaného systému je dílčí aplikace, která může samostatně podléhat twelve-factor metodice. +* Více aplikací sdílejících stejný kód je porušení twelve-factor metodiky. Řešením je oddělení sdíleného kódu do knihovny, která se připojí pomocí [systému na správu závislostí](./dependencies). + +Každá aplikace má pouze jeden zdrojový kód, ale nasazení jedné aplikace bude vícero. *Nasazení* je běžící instance aplikace. Typicky je to produkční web a jeden nebo více testovacích webů. Každý vývojář má navíc lokální vývojovou kopii běžící aplikace, každou takovou kopii lze také považovat za nasazení. + +Zdrojový kód je stejný ve všech nasazeních, v každém nasazení však mohou být aktivní různé verze. Například vývojář má několik commitů, které ještě nejsou nasazeny v testovacím prostředí a na testovacím prostředí jsou commity, které zatím nejsou na produkci. Všechny verze však sdílejí jeden zdrojový kód a dá se tedy říct, že jsou různými nasazeními téže aplikace. + diff --git a/content/cs/concurrency.md b/content/cs/concurrency.md new file mode 100644 index 000000000..24cd5d96f --- /dev/null +++ b/content/cs/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Souběh +### Škálujte do šířky použitím proces modelu. + +Každý počítačový program se po spuštění prezentuje jako jeden nebo více procesů. Webové aplikace mají různé formy vykonávání procesů. Například PHP procesy běží jako potomci Apache procesu, spouštěné na požádání dle množství požadavků. Java procesy mají opačný přístup, kde JVM poskytuje jeden masivní super proces, který si po spuštění vyhradí velké množství systémovývh požadavků (CPU a paměti) a souběh si řídí interně pomocí vláken. V obou případech jsou běžící procesy jen málo viditelné pro vývojáře aplikace. + +![Škálování je vyjádřeno běžícími procesy, různorodost funkcionality pak typy procesů.](/images/process-types.png) + +**Ve twelve-factor aplikaci jsou procesy prominentními občany.** Procesy twelve-factor aplikace čerpají inspiraci z [unixového proces modelu pro démony služeb](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Použitím tohoto modelu může vývojář navrhnout aplikaci tak, aby různou práci vykonávaly různé typy procesů. Například HTTP požadavky může obsluhovat webový proces a dlouho běžící procesy na pozadí může obstarat worker proces. + +To nevylučuje, že si jednotlivé procesy nemohou spravovat interní multiplexování přes vlákna nebo pomocí async/event modelu, jako je tomu v [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/) nebo [Node.js](http://nodejs.org/). Jednotlivé VM však mohou růst jen omezeně (vertikální škálování), aplikace tedy musí být schopná i běhu v několika procesech na více fyzických strojích. + +Proces model obzvlášť vyniká, když přijde čas na škálování. [Nesdílená a horizontálně dělitelná podstata procesů twelve-factor aplikace](./processes) znamená, že přidání větší souběžnosti je jednoduchá a spolehlivá operace. Sada typu procesů a množství procesů každého typu se nazývá *formace procesů*. + +Procesy twelve-factor aplikace by [nikdy neměly démonizovat](http://dustin.github.com/2010/02/28/running-processes.html) nebo zapisovat PID soubory. Namísto toho by se měly spoléhat na správce procesů operačního systému (jako je například [systemd](https://www.freedesktop.org/wiki/Software/systemd/), správce distribuovaných procesů na cloudové platformě nebo nástroje typu [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) během vývoje), který obstará [výstupní proudy](./logs), reakci na havarované procesy a obsluhu uživatelem vyvolaných restartů a zastavení. diff --git a/content/cs/config.md b/content/cs/config.md new file mode 100644 index 000000000..cdf66b99d --- /dev/null +++ b/content/cs/config.md @@ -0,0 +1,22 @@ +## III. Konfigurace +### Konfigurace ukládejte do prostředí. + +*Konfigurace* aplikace je všechno, co se liší mezi [nasazeními](./codebase) (testovací, produkční, vývojové prostředí, atd.). To zahrnuje: + +* Přihlašovací údaje k databázím, Memcached a dalším [podpůrným službám](./backing-services). +* Přístupové údaje k externím službám jako je Amazon S3 nebo Twitter. +* Specifické hodnoty pro dané nasazení jako například kanonické názvy hostitelů. + +Aplikace si někdy ukládají konfiguraci jako konstanty v kódu. To je porušení twelve-factor metodiky, která vyžaduje **přísné oddělení konfigurace od kódu**. Konfigurace se mezi nasazeními značně liší, kód však nikoliv. + +Test lakmusovým papírkem na správné oddělení konfigurace od kódu je fakt, že aplikace by mohla být kdykoliv uvolněna jako open source bez kompromitace přístupových údajů. + +Nutno podotknout, že do definice "konfigurace" *nepatří* interní nastavení aplikace jako je například `config/routes.rb` v Rails nebo nastavení [propojení základních modulů](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) ve [Springu](http://spring.io/). Tento typ konfigurace se neliší mezi nasazeními a je nejlepší ho ponechat v kódu. + +Další možností jak přistupovat ke konfiguracím je mít konfigurační soubory, které nejsou uložené ve verzovacím systému, jak je tomu například u `config/database.yml` v Rails. To je obrovské zlepšení oproti konstantám uloženým v repozitáři, tento přístup má však stále několik slabin: je velmi jednoduché omylem uložit tento soubor do repozitáře; chtě nechtě jsou tyto soubory obvykle rozmístěny na několika místech a v různých formátech, což komplikuje jejich centrální správu. Navíc jsou tyto konfigurační soubory často specifické pro daný jazyk či framework. + +**Twelve-factor aplikace ukládají konfiguraci do proměnných prostředí** (často zkracováno jak *env vars* nebo *env*). Proměnné prostředí se dají jednoduše měnit mezi nasazeními bez zásahu do kódu. Oproti konfiguračním souborům je zde velmi malá šance, že by byly omylem uloženy do repozitáře a narozdíl od vlastních konfiguračních souborů a jiných konfiguračních mechanismů, jako například Java System Properties, jsou nezávislé na jazyce a operačním systému. + +Dalším úskalím správy konfigurace je seskupování. Aplikace někdy seskupují konfigurace do pojmenovaných skupin (často nazývaných jako "prostředí"), rozlišených podle specifického nasazení, jako například `vývojové`, `testovací` nebo `produkční` prostředí. Tento přístup lze jen velmi težko čistě škálovat. Jak přibývají nasazení jsou zapotřebí nová prostředí, jako například `staging` nebo `qa`. Jakmile projekt začne narůstat, vývojáři přidávají svoje specifická prostředí jako třeba `joes-staging`, což má za následek kombinatorickou explozi konfigurací a správa nasazení se tak stáva velmi delikátní záležitostí. + +Ve twelve-factor aplikaci jsou proměnné prostředí jako vzájemně nezávislé ovládací prvky. Ty nejsou nikdy seskupovány do "prostředí", namísto toho jsou všechny spravovány nezávisle pro každé nasazení. Tento model plynule škáluje s přirozeně se rozrůstající aplikací a narůstajícím počtem nasazení během celého životního cyklu aplikace. diff --git a/content/cs/dependencies.md b/content/cs/dependencies.md new file mode 100644 index 000000000..cf9baf84f --- /dev/null +++ b/content/cs/dependencies.md @@ -0,0 +1,12 @@ +## II. Závislosti +### Explicitně deklarujte a izololujte závislosti. + +Většina programovacých jazyků poskytuje balíčkovací systém pro distribuci podpůrných knihoven, například [CPAN](http://www.cpan.org/) pro Perl nebo [Rubygems](http://rubygems.org/) pro Ruby. Knihovny instalované skrze balíčkovací systém mohou být instalovány globálně pro celý systém (nazýváme "site packages") nebo pouze lokálně v rámci adresáře dané aplikace (nazýváme "vendoring" nebo "bundling"). + +**Twelve-factor aplikace se nikdy nespoléhá na implicitní existenci globálních systémových balíčků.** Svoje závislosti deklaruje úplně a přesně pomocí manifestu *deklarovaných závislostí*. Dále používá nástroje pro *izolaci závislostí*, aby bylo zajištěno, že při běhu aplikace žádné implicitní zavislosti neprosakují z okolního systému. Úplná explicitní deklarace závislostí je použita jednotně pro produkci i vývoj. + +Například [Bundler](https://bundler.io/) pro Ruby poskytuje `Gemfile` manifest formát pro deklaraci závislostí a `bundle exec` pro izolaci závislostí. Pro Python jsou to dva rozdílné nástroje, [Pip](http://www.pip-installer.org/en/latest/) je použit pro deklaraci závislostí a [Virtualenv](http://www.virtualenv.org/en/latest/) pro jejich izolaci. Dokonce i C má [Autoconf](http://www.gnu.org/s/autoconf/) pro deklaraci závislostí a statické linkování poskytuje izolaci závislostí. Nehledě na použitou sadu nástrojů, deklarace a izolace závislostí musí být vždy aplikovány společně, použití pouze jednoho nebo pouze druhého není dostatečné pro splnění podmínek twelve-factor metodiky. + +Jednou z výhod explicitní deklarace závislostí je to, že zjednodušuje počáteční rozběhnutí aplikace pro nové vývojáře. Nový vývojář si jen naklonuje repozitář aplikace do svého vývojového prostředí a jako prerekvizity mu postačí nainstalované běhové prostředí jazyka a příslušný správce závislostí. Vše potřebné pro rozběhnutí aplikace se zajistí deterministicky *build příkazem* . Například, build příkaz pro Ruby/Bundler je `bundle install`, pro Cloujure/[Leiningen](https://github.com/technomancy/leiningen#readme) je to `lein deps`. + +Twelve-factor aplikace se nespoléhají na implicitní existenci jakýchkoli systémových nástrojů. Příkladem může být spouštění ImageMagick nebo `curl` přes shell. I když tyto nástroje existují na mnoha a možná i většině aktuálně používaných systémů, neexistuje žadná záruka, že tyto nástroje budou existovat na systémech, kde aplikace poběží v budoucnu a nebo že budou na budoucích systémech dostupné v kompatibilní verzi. Pokud aplikace potřebuje spouštět nějaký nástroj přes shell, tak by měl být daný nástroj součástí aplikace. \ No newline at end of file diff --git a/content/cs/dev-prod-parity.md b/content/cs/dev-prod-parity.md new file mode 100644 index 000000000..53cd2cf63 --- /dev/null +++ b/content/cs/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Podobnost Vývoj/Produkce +### Udržujte si co nejmenší rozdíly mezi vývojovým, testovacím a produkčním prostředím. + +Historicky byly vždy velké rozdíly mezi vývojovým (vývojář provádí změny v lokálním nasazení [zdrojového kódu](./codebase)) a produkčním prostředím (běžící nasazení aplikace přístupné koncovým uživatelům). To se projevuje jako mezery v těchto oblastech: + +* **Časová mezera**: Vývojář může pracovat na kódu, který se dostane na produkci až za několik dnů, týdnů nebo i měsíců. +* **Personální mezera**: Vývojáři píší kód, systémoví inženýři ho nasazují. +* **Nástrojová mezera**: Vývojáři mohou používat Nginx, SQLite a OS X, přitom na produkci běží Apache, MySQL a Linux. + +**Twelve-factor aplikace je navržena pro [průběžné nasazování](http://avc.com/2011/02/continuous-deployment/) tak, že si udržuje jen minimální rozdíly mezi vývojovým a produkčním prostředím.** Podíváme-li se na předchozí mezery touto optikou: + +* Zmenšování časové mezery: Vývojář napíše kód a nasadí ho v řádu hodin či dokonce minut. +* Zmenšování personální mezery: Vývojáři píšící kód jsou úzce zapojeni do nasazení a sledují jeho chování na produkci. +* Zmenšování nástrojové mezery: Udržujeme co nejmenší rozdíly mezi vývojovým a produkčním prostředím. + +Souhrn výše popsaného v tabulce: + + + + + + + + + + + + + + + + + + + + + + +
Tradiční aplikaceTwelve-factor aplikace
Čas mezi nasazenímiTýdnyHodiny
Autoři kódu vs ti, kdo kód nasazujíRozdílní lidéStejní lidé
Vývojové vs Produkční prostředíRozdílnéMinimální rozdíly
+ +[Podpůrné služby](./backing-services), jako je například databáze, fronty nebo cache jsou oblastí, kde je podobnost vývojového a produkčního prostředí velmi důležitá. Mnoho jazyků nabízí knihovny zjednodušující přístup k podpůrným službám, včetně *adaptérů* pro různé druhy služeb. Některé příklady jsou uvedeny v tabulce níže: + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypJazykKnihovnaAdaptér
DatabázeRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
FrontaPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CachePamět, Souborový systém, Memcached
+ +Vývojáři někdy rádi používají odlehčené varianty podpůrných služeb pro lokální vývoj, přestože na produkci budou použity jejich plnohodnotné varianty. Například použití SQLite lokálně a PostgreSQL na produkci nebo lokální pamět použitá jako cache pro vývoj oproti Memcached v produkci. + +**Twelve-factor vývojáři dokáží odolat nutkání používat rozdílné podpůrné služby ve vývojovém a produkčním prostředí** i přesto, že adaptéry teoreticky odstraňují jakékoliv rozdíly v podpůrných službách. Rozdíly mezi podpůrnými službami a drobné nekompatibility se vždy vynoří a způsobí, že kód který prošel testy ve vývojovém a testovacím prostředí pak nefunguje na produkci. Tento typ chyb způsobuje obtíže a odrazuje od průběžného nasazování. Náklady spojené s těmito obtížemi a následným útlumem v průběžném nasazování jsou velmi vysoké, zvažujeme-li je souhrně za celou dobu životnosti aplikace. + +Odlehčené varianty služeb jsou méně lákavé než bývaly dříve. Moderní podpůrné služby jako Memcached, PostgreSQL a RabbitMQ nejsou díky moderním balíčkovacím systémům jako [Homebrew](http://mxcl.github.com/homebrew/) a [apt-get](https://help.ubuntu.com/community/AptGet/Howto) složité na instalaci. Deklarativní nástroje pro provisioning, jako jsou například [Chef](http://www.opscode.com/chef/), či [Puppet](http://docs.puppetlabs.com/) v kombinaci s odlehčenými virtuálními prostředími typu [Docker](https://www.docker.com/) nebo [Vagrant](http://vagrantup.com/), umožňují vývojářům provozovat lokální vývojové prostředí, které velmi věrně odpovídá tomu produkčnímu. Cena za instalaci a provoz těchto systémů je poměrně nízká v porovnání s výhodami, které přináší podobnost vývoj/produkce a průběžné nasazování. + +Adaptéry pro různé podpůrné služby mají stále svůj význam, protože umožňují přechod na nové podpůrné služby poměrně bezbolestně. Všechna nasazení aplikace (vývojové, testovací a produkční) by však měla používat stejný typ a verzi každé podpůrné služby. diff --git a/content/cs/disposability.md b/content/cs/disposability.md new file mode 100644 index 000000000..a8b63120b --- /dev/null +++ b/content/cs/disposability.md @@ -0,0 +1,15 @@ +## IX. Zahoditelnost +### Maximalizujte robustnost pomocí rychlého spouštění a korektního vypnutí. + + +**[Procesy](./processes) twelve-factor aplikace jsou *zahoditelné*, to znamená, že mohou být kdykoliv spuštěny nebo vypnuty.** Usnadňuje to elastické škálování, rychlé nasazování [kódu](./codebase), změny [konfigurace](./config) a zvyšuje se robustnost celého produkčního nasazení. + +Procesy by se měly snažit **minimalizovat čas spuštění**. Ideálně by procesu mělo zabrat jen pár sekund od spuštění příkazu, do doby, kdy je připraven přijímat požadavky nebo úlohy. Krátký čas spuštění přináší větší obratnost pro procesy zajišťující [nasazení](./build-release-run) a škálování. Napomáhá také celkové robustnosti, protože správce procesů může v případě potřeby snadno přesouvat procesy na nové fyzické stroje. + +Procesy **se korektně ukončí po přijetí signálu [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** od správce procesů. Pro webový proces znamená korektní ukončení to, že přestane naslouchat na příslušném portu (tedy začne odmítat nové požadavky), aktuálně běžící požadavky zpracuje a pak se vypne. V tomto modelu předpokládáme, že HTTP požadavky jsou poměrně krátké (ne delší než pár sekund). V případě dlouho trvajícího spojení by se měl klient umět znovu sám připojit, dojde-li ke ztrátě spojení. + +Pro proces typu worker je korektní ukončení dosaženo vrácením aktuální úlohy zpět do pracovní fronty. Například v [RabbitMQ](http://www.rabbitmq.com/) může worker poslat [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack), u [Beanstalkd](https://beanstalkd.github.io) se úloha vrátí do fronty automaticky, pokud se worker odpojí. Systémy postavené na zamykání, jako například [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) musí uvolnit zámek pro záznam své úlohy. V tomto modelu předpokládáme, že všechny úlohy jsou [opakovatelné](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), čehož se typicky dosáhne obalením výsledku do transakce anebo tím, že operaci učiníme [idempotentní](http://en.wikipedia.org/wiki/Idempotence). + +Procesy by měly být dostatečně **robustní pro případ náhle smrti**, dojde-li například k selhání podkladového hardwaru. I když se to stává velmi zřídka narozdíl od koretního ukončení signálem `SIGTERM`, stále se to ale může stát. Doporučený postup je použít robustní systém, jako je Beanstalkd, který vrací úlohy zpět do fronty v případě odpojení klienta nebo vypršení časového limitu. V každém případě, twelve-factor aplikace je navržena tak, aby zvládna neočekávané a nekorektní ukončení. [Crash-only design](http://lwn.net/Articles/191059/) je tedy pro tento koncept [logickým východiskem](http://docs.couchdb.org/en/latest/intro/overview.html). + + diff --git a/content/cs/intro.md b/content/cs/intro.md new file mode 100644 index 000000000..bbac62fda --- /dev/null +++ b/content/cs/intro.md @@ -0,0 +1,12 @@ +Úvod +============ + +V moderní době je software často dodáván jako služba, což označujeme pojmem *webová aplikace* nebo *software-as-a-service (SaaS)*. Twelve-factor metodika slouží pro vytváření (SaaS) aplikací, které: + +* Používají **deklarativní** formáty pro nastavení automatizace, což vede k minimalizaci času a nákladů potřebných pro začlenění nových vývojářů do projektu; +* Mají **jasný kontrakt** s operačním systémem ve kterém běží, čímž je umožněna **maximální přenositelnost** mezi různými běhovými prostředími; +* Jsou vhodné pro **nasazení** na moderních **cloudových platformách**, což eliminuje potřebu správy serverů a podpůrných systémů; +* **Minimalizují rozdíly** mezi vývojovým a produkčním prostředím, čímž umožňují **průběžné nasazovaní** a maximální flexibilitu; +* Umožňují **vyškálování** bez výrazných změn v nástrojích, architektuře nebo vývojových postupech. + +Twelve-factor metodiku lze použít na aplikace napsané v jakémkoliv programovacím jazyce a používající libovolnou kombinaci podpůrných služeb (databáze, fronty, vyrovnávací paměť atd.). \ No newline at end of file diff --git a/content/cs/logs.md b/content/cs/logs.md new file mode 100644 index 000000000..30b5542b5 --- /dev/null +++ b/content/cs/logs.md @@ -0,0 +1,16 @@ +## XI. Logy +### S logy zacházejte jako s proudy událostí. + +*Logy* poskytují náhled na chování běžící aplikace. V prostředí serveru se obvykle zapisují do souboru na disku ("logfile"), ale to je jen výstupní formát. + +Logy jsou [proudy](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) agregovaných a časově seřazených událostí, posbíraných z výstupních proudů všech běžících procesů a podpůrných služeb. Logy jsou ve své syrové formě typicky v textovém formátu s jednou událostí na řádek (avšak výpis výjimky může zabírat i více řádků). Logy nemají žádný pevný začátek ani konec, ale plynule proudí po celou dobu běhu aplikace. + +**Twelve-factor aplikace se nikdy nestará o routování anebo ukládání svého výstupního proudu.** Neměla by se ani pokoušet zapisovat nebo si spravovat své log soubory. Místo toho zapisuje každy její běžící proces nebufferovaně na `stdout`. Během lokálního vývoje vidí vývojář proud událostí ve svém terminálu a sleduje chování aplikace. + +V testovacím a produkčním prostředí je proud každého procesu zachycen běhovým prostředím, spojen s ostatnímy proudy aplikace a nasměrován do jedné nebo více cílových destinací, určených pro zobrazení nebo k dlouhodobé archivaci logů. Tyto cílové destinace nejsou pro aplikaci viditelné ani konfigurovatelné, jejich správa je plně pod kontrolou běhového prostředí. Open source směrovače logů (jako jsou [Logplex](https://github.com/heroku/logplex) a [Fluentd](https://github.com/fluent/fluentd) slouží přesně k těmto účelům. + +Proudy událostí aplikace mohou být směrovány do souboru, nebo sledovány v reálněm čase přes tail v terminálu. Důležitější však je, že tyto proudy mohou být zaslány do systému na indexaci a analýzu logů, jako je například [Splunk](http://www.splunk.com/) anebo do univerzálnějších systémů pro datové sklady jako je [Hadoop/Hive](http://hive.apache.org/). Tyto systémy jsou flexibilní a velmi mocné, chceme-li zkoumát chování aplikace v průběhu času, například při: + +* Hledání konkrétních událostí v minulosti. +* Velkoplošném vykreslení trendů (požadavky za minutu) do grafu. +* Aktivním alertingu dle uživatelsky definovaných heuristik (například pokud množství chyb za minutu přesáhne stanovenou hranici). diff --git a/content/cs/port-binding.md b/content/cs/port-binding.md new file mode 100644 index 000000000..51e412c39 --- /dev/null +++ b/content/cs/port-binding.md @@ -0,0 +1,14 @@ +## VII. Vazba s portem +### Exportujte služby pomocí vazby na port. + +Webové aplikace jsou někdy vykonávány uvnitř webového serveru. Například PHP aplikace mohou běžet jako modul uvnitř [Apache HTTPD](http://httpd.apache.org/) nebo Java aplikace mohou běžet uvnitř [Tomcatu](http://tomcat.apache.org/). + +**Twelve-factor aplikace jsou úplně soběstačné** a nespoléhají se na vsunutí webserveru do běhového prostředí k vytvoření webové služby. Webová aplikace **exportuje HTTP jako službu vázanou na port** a naslouchá požadavkům přicházejícím na daný port. + +V lokálním vývojovém prostředí přistupuje vývojář na službu exportovanou jeho aplikací přes URL jako je `http://localhost:5000/`. U nasazení přesměrovává směrovací vrstva požadavky z veřejně dostupné domény na port webového procesu. + +To se typicky realizuje přidáním knihovny webserveru přímo do aplikace za pomoci [deklarace závislostí](./dependencies). Například [Tornado](http://www.tornadoweb.org/) pro Python, [Thin](http://code.macournoyer.com/thin/) pro Ruby, nebo [Jetty](http://www.eclipse.org/jetty/) pro Javu a jiné jazyky založené na JVM. Toto se děje výhradně v *uživatelském prostoru*, tedy v kódu aplikace. Dohoda s běhovým prostředím je pak pouze vazba na port pro obsluhu požadavků. + +HTTP není jediná služba, kterou je možné exportovat přes port. Téměř libovolný serverový software může běžet na otevřeném portu a naslouchat příchozím požadavkům. Například [ejabberd](http://www.ejabberd.im/) (komunikující pomocí [XMPP](http://xmpp.org/)) nebo [Redis](http://redis.io/) (komunikující [Redis protokolem](http://redis.io/topics/protocol)). + +Všimněte si také, že přístupem pomocí vazby na port se jedna aplikace může stát [podpůrnou službou](./backing-services) pro jinou aplikaci, poskytnutím URL podpůrné služby jako zdroje pro [konfiguraci](./config) konzumující aplikace. diff --git a/content/cs/processes.md b/content/cs/processes.md new file mode 100644 index 000000000..f740f698f --- /dev/null +++ b/content/cs/processes.md @@ -0,0 +1,14 @@ +## VI. Procesy +### Spouštějte aplikaci jako jeden nebo více bezestavových procesů. + +Aplikace je vykonávána v běhovém prostředí jako jeden nebo více *procesů*. + +V nejjednodušším případě je kód samostatný skript, běhové prostředí je laptop vývojáře s naistalovaným interpreterem daného jazyka a proces je spouštěn z příkazové řádky (například jako `python my_script.py`). Na druhé straně spektra je produkční nasazení sofistikované aplikace využívající vícero [typů procesu, instancovaných do nula nebo více běžících procesů](./concurrency). + +**Twelve-factor procesy jsou bezestavové a [nic nesdílejí](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Jakákoliv data, která potřebují být uchována, musí být uložena ve stavové [podpůrné službě](./backing-services), typicky v databázi. + +Paměť nebo souborový systém procesu mohou být využity jako krátkodobá cache pro jednu transakci. Například ke stažení velkého souboru, práce s ním a následné uložení výsledku do databáze. Twelve-factor aplikace nikdy nespoléhá, že cokoliv je nacachované v paměti nebo na disku, bude dostupné i v dalším požadavku. Při velkém počtu běžících procesů je vysoká pravděpodobnost, že další požadavek bude odbaven jiným procesem. I kdyby běžel pouze jeden proces, restart (způsobený nasazením nového kódu, změnou konfigurace nebo přemístěním procesu na jiné fyzické umístění) obvykle smaže všechny lokální (například pamět nebo souborový systém) stavy. + +Balíčkovače jako je [django-assetpackager](http://code.google.com/p/django-assetpackager/) používají souborový systém jako dočasné uložiště pro zkompilované soubory. Twelve-factor aplikace preferují kompilaci během [fáze sestavení](/build-release-run). Balíčkovače jako jsou [Jammit](http://documentcloud.github.com/jammit/) a [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html) mohou být nastaveny tak, že soubory zabalí již během fáze sestavení. + +Některé webové aplikace spoléhají na ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence), tedy cachování uživatelských session v paměti procesu a směrování budoucích požadavků stejného návštěvníka na stejný proces. Sticky session jsou porušením twelve-factor metodiky a neměli by se používat a ani by se na ně nemělo jakkoliv spoléhat. Sticky session data jsou vhodným kandidátem pro uložiště, která podporují časovou expiraci dat, jako jsou například [Memcached](http://memcached.org/) nebo [Redis](http://redis.io/). \ No newline at end of file diff --git a/content/cs/toc.md b/content/cs/toc.md new file mode 100644 index 000000000..b12fd6f9f --- /dev/null +++ b/content/cs/toc.md @@ -0,0 +1,38 @@ +The Twelve Factors +================== + +## [I. Zdrojový kód](./codebase) +### Mějte jeden zdrojový kód ve verzovacím systému a mnoho nasazení. + +## [II. Závislosti](./dependencies) +### Explicitně deklarujte a izololujte závislosti. + +## [III. Konfigurace](./config) +### Konfigurace ukládejte do prostředí. + +## [IV. Podpůrné služby](./backing-services) +### Nakládejte s podpůrnými službami jako s připojenými zdroji. + +## [V. Sestavení, vydání, spuštění](./build-release-run) +### Striktně oddělte fáze sestavení, vydání a spuštění. + +## [VI. Procesy](./processes) +### Spouštějte aplikaci jako jeden nebo více bezestavových procesů. + +## [VII. Vazba s portem](./port-binding) +### Exportujte služby pomocí vazby na port. + +## [VIII. Souběh](./concurrency) +### Škálujte do šířky použitím proces modelu. + +## [IX. Zahoditelnost](./disposability) +### Maximalizujte robustnost pomocí rychlého spouštění a korektního vypnutí. + +## [X. Podobnost Vývoj/Produkce](./dev-prod-parity) +### Udržujte si co nejmenší rozdíly mezi vývojovým, testovacím a produkčním prostředím. + +## [XI. Logy](./logs) +### S logy zacházejte jako s proudy událostí. + +## [XII. Admin procesy](./admin-processes) +### Spouštějte administrativní úlohy jako jednorázové procesy. diff --git a/content/cs/who.md b/content/cs/who.md new file mode 100644 index 000000000..834f3fdbe --- /dev/null +++ b/content/cs/who.md @@ -0,0 +1,4 @@ +Kdo by měl číst tento dokument? +============================== + +Každý vývojář pracující na aplikaci, která běží jako služba. Systémoví inženýři, kteří takové aplikace nasazují nebo spravují. \ No newline at end of file diff --git a/content/de/admin-processes.md b/content/de/admin-processes.md new file mode 100644 index 000000000..7cfcc074c --- /dev/null +++ b/content/de/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Admin-Prozesse +### Admin/Management-Aufgaben als einmalige Vorgänge behandeln + +Die [Prozess-Formation](./concurrency) ist das Bündel von Prozessen zur Erledigung der üblichen Aufgaben einer App (wie die Abarbeitung von Web-Requests) während sie läuft. Daneben möchten Entwickler oft einmalige Administrativ- oder Wartungsaufgaben an der App erledigen, wie zum Beispiel: + +* Datenbank-Migrationen starten (z.B. `manage.py migrate` in Django, `rake db:migrate` in Rails) +* Eine Konsole starten (auch bekannt als [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) Shell) um beliebigen Code zu starten oder die Modelle der App gegen die Live-Datenbank zu prüfen. Die meisten Sprachen stellen eine REPL zur Verfügung, wenn man den Interpreter ohne Argumente startet (z.B. `python` oder `perl`) oder in manchen Fällen mit einem anderen Kommando (z.B. `irb` für Ruby, `rails console` für Rails). +* Einmalig auszuführende Skripte aus dem Repo der App starten (z.B. `php scripts/fix_bad_records.php`). + +Einmalige Administrationsprozesse sollten in einer Umgebung laufen, die identisch ist zu der Umgebung der üblichen [langlaufenden Prozesse](./processes). Sie laufen gegen einen [Release](./build-release-run) und benutzen dieselbe [Codebase](./codebase) und [Konfiguration](./config) wie jeder Prozess, der gegen einen Release läuft. Administrationscode wird mit dem App-Code ausgeliefert um Synchronisationsprobleme zu vermeiden. + +Dieselben Techniken zur [Isolation von Abhängigkeiten](./dependencies) sollten für alle Prozessarten verwendet werden. Wenn zum Beispiel ein Ruby-Web-Prozess das Kommando `bundle exec thin start` verwendet, dann sollte eine Datenbankmigration `bundle exec rake db:migrate` verwenden. Wenn ein Python-Programm Virtualenv nutzt, sollte es sein mitgeliefertes `bin/python` sowohl zum Start des Tornado Webservers als auch für alle `manage.py` Admin-Prozesse verwenden. + +Die Zwölf Faktoren bevorzugen Sprachen, die eine REPL Shell direkt mitbringen. Das erleichtert das Starten von einmal auszuführenden Skripten. In einem lokalen Deploy rufen Entwickler einmal auszuführende Admin-Prozesse direkt über ein Shell-Kommando im Checkout-Verzeichnis der App auf. In einem Produktions-Deploy können Entwickler ssh oder andere Kommando-Fernsteuerungs-Mechanismen benutzen, die die Ausführungsumgebung dieses Deploys für das Starten eines solchen Prozesses bereitstellt. diff --git a/content/de/background.md b/content/de/background.md new file mode 100644 index 000000000..b2184d896 --- /dev/null +++ b/content/de/background.md @@ -0,0 +1,8 @@ +Hintergrund +========== + +Die Mitwirkenden an diesem Dokument waren direkt beteiligt an der Entwicklung und dem Deployment von hunderten von Apps und wurden Zeugen bei der Entwicklung, beim Betrieb und der Skalierung von hunderttausenden von Apps im Rahmen unserer Arbeit an der [Heroku](http://www.heroku.com/)-Plattform. + +Dieses Dokument ist eine Synthese all unserer Erfahrungen und der Beobachtungen einer großen Bandbreite von Software-As-A-Service Apps. Es ist eine Bestimmung der idealen Praktiken bei der App-Entwicklung mit besonderem Augenmerk auf die Dynamik des organischen Wachstums einer App über die Zeit, die Dynamik der Zusammenarbeit zwischen den Entwicklern die an einer Codebase zusammenarbeiten und der [Vermeidung der Kosten von Software-Erosion](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Unsere Motivation ist, das Bewusstsein zu schärfen für systembedingte Probleme in der aktuellen Applikationsentwicklung, ein gemeinsames Vokabular zur Diskussion dieser Probleme zu liefern und ein Lösungsportfolio zu diesen Problemen mit einer zugehörigen Terminologie anzubieten. Das Format ist angelehnt an Martin Fowlers Bücher *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* und *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. diff --git a/content/de/backing-services.md b/content/de/backing-services.md new file mode 100644 index 000000000..283ed2d0d --- /dev/null +++ b/content/de/backing-services.md @@ -0,0 +1,14 @@ +## IV. Unterstützende Dienste +### Unterstützende Dienste als angehängte Ressourcen behandeln + +Ein *unterstützender Dienst* ist jeder Dienst, den die App über das Netzwerk im Rahmen ihrer normalen Arbeit konsumiert. Beispiele sind Datenspeicher (wie [MySQL](http://dev.mysql.com/) oder [CouchDB](http://couchdb.apache.org/)), Messaging/Queueing-Systeme (wie [RabbitMQ](http://www.rabbitmq.com/) oder [Beanstalkd](https://beanstalkd.github.io)), SMTP-Dienste für das Senden von Mail (wie [Postfix](http://www.postfix.org/)), und Cache-Systeme (wie [Memcached](http://memcached.org/)). + +Unterstützende Dienste wie Datenbanken werden traditionell von denselben Systemadministratoren verwaltet, die die App deployen. Außer diesen intern verwalteten Diensten können der App auch von Dritten verwaltete Dienste zur Verfügung stehen. Dazu gehören SMTP-Dienste (wie [Postmark](http://postmarkapp.com/)), Metrik-Sammler (wie [New Relic](http://newrelic.com/) oder [Loggly](http://www.loggly.com/)), Binary-Asset-Dienste (wie [Amazon S3](http://aws.amazon.com/s3/)), und auch über eine API zugängliche Dienste (wie [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), oder [Last.fm](http://www.last.fm/api)). + +**Der Code einer Zwölf-Faktor-App macht keinen Unterschied zwischen lokalen Diensten und solchen von Dritten.** Für die App sind sie beide unterstützende Dienste, zugreifbar über eine URL oder andere Lokatoren/Credentials, die in der [Konfiguration](./config) gespeichert sind. Ein [Deploy](./codebase) einer Zwölf-Faktoren-App könnte eine lokale MySQL-Datenbank, durch eine von Dritten zur Verfügung gestellten, ersetzen (wie [Amazon RDS](http://aws.amazon.com/rds/)). Genauso ohne Codeänderung kann ein lokaler SMTP-Server durch einen von Dritten zur Verfügung gestellten SMTP-Dienst ersetzt werden. In beiden Fällen muss sich nur der Resource-Handle in der Konfiguration ändern. + +Jeder einzelne unterstützende Dienst ist eine *Ressource*. So ist zum Beispiel eine MySQL-Datenbank eine Ressource; zwei MySQL-Datenbanken (die für ein Sharding auf Applikationsebene verwendet werden) stellen zwei Ressourcen dar. Dass die Zwölf-Faktor-App diese Datenbanken als *angehängte Ressourcen* behandelt, zeigt ihre lose Kopplung, zu dem Deploy an dem sie hängen. + +Ein Produktions-Deploy der an vier unterstützenden Diensten hängt. + +Ressourcen können beliebig an Deploys an- und abgehängt werden. Wenn zum Beispiel die Datenbank einer App aufgrund von Hardwareproblemen aus der Rolle fällt, könnte der App-Administrator eine neue Datenbank aus einem Backup aufsetzen. Die aktuelle Produktionsdatenbank könnte abgehängt und die neue Datenbank angehängt werden -- ganz ohne Codeänderung. diff --git a/content/de/build-release-run.md b/content/de/build-release-run.md new file mode 100644 index 000000000..34e499f32 --- /dev/null +++ b/content/de/build-release-run.md @@ -0,0 +1,18 @@ +## V. Build, release, run +### Build- und Run-Phase strikt trennen + +Eine [Codebase](./codebase) wird durch drei Phasen in einen (Nicht-Entwicklungs)-Deploy transformiert: + +* Die *Build-Phase* ist eine Transformation, die ein Code-Repository in ein ausführbarers Code-Bündel übersetzt, das man auch *Build* nennt. Ausgehend von einer Code-Version eines Commits, der im Deployment-Prozess festgelegt wurde, holt sie [Abhängigkeiten](./dependencies), verpackt sie zum Mitliefern, und kompiliert Binaries und Assets. +* Die *Release-Phase* übernimmt den Build von der Build-Phase und kombiniert ihn mit der zum Deploy passenden [Konfiguration](./config). Der so erzeugte *Release* enthält sowohl den Build, als auch die Konfiguration und kann direkt in einer Ausführungsumgebung ausgeführt werden. + +* Die *Run-Phase* (auch "Laufzeit" genannt) führt die App in einer Ausführungsumgebung aus, indem sie eine Menge der [Prozesse](./processes) der App gegen einen ausgewählten Release ausführt. +![Code wird zum Build und zusammen mit einer Konfiguration ergibt sich ein Release](/images/release.png) + +**Die Zwölf-Faktor-App trennt strikt zwischen Build-, Release- und Run-Phase.** Es ist nicht möglich, Code-Änderungen zur Laufzeit zu machen, weil es keinen Weg gibt, diese Änderungen zurück in die Build-Phase zu schicken. + +Deployment-Werkzeuge bieten meist eine Release-Verwaltung an. Am bekanntesten ist die Funktion auf einen früheren Release zurückzusetzen. Zum Beispiel speichert das Deployment-Werkzeug [Capistrano](https://github.com/capistrano/capistrano/wiki) Releases in einem Unterverzeichnis mit Namen `releases`. Der aktuelle Release ist ein symbolischer Link auf aktuelle Release-Verzeichnis. Mit dem Kommando `rollback` kann einfach und schnell auf einen früheren Release zurückgesetzt werden. + +Jeder Release sollte eine eindeutige Release-ID haben, wie zum Beispiel einen Zeitstempel des Releases (`2011-04-06-20:32:17`) oder eine laufende Nummer (`v100`). Releases werden nie gelöscht und ein Release kann nicht verändert werden, wenn er einmal angelegt ist. Jede Änderung erzeugt einen neuen Release. + +Builds werden durch die Entwickler der App angestoßen, wenn neuer Code deployt wird. Im Gegensatz dazu kann die Ausführung zur Laufzeit automatisch erfolgen, wenn ein Server neu gebootet wird oder ein abgestürzter Prozess von der Prozessverwaltung neu gestartet wird. Deswegen sollte die Run-Phase auf so wenig bewegliche Teile wie möglich beschränkt sein, denn Probleme, die eine App vom Laufen abhalten, können sie mitten in der Nacht zusammenbrechen lassen, wenn keine Entwickler zur Verfügung stehen. Die Build-Phase kann komplexer sein, denn Fehler sind immer sichtbar für den Entwickler, der den Deploy vorantreibt. diff --git a/content/de/codebase.md b/content/de/codebase.md new file mode 100644 index 000000000..88dc49eeb --- /dev/null +++ b/content/de/codebase.md @@ -0,0 +1,17 @@ +## I. Codebase +### Eine im Versionsmanagementsystem verwaltete Codebase, viele Deployments + +Eine Zwölf-Faktor-App wird immer in einem Versionsmanagementsystem verwaltet, wie zum Beispiel [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/) oder [Subversion](http://subversion.apache.org/). Eine Kopie der Versionsdatenbank wird *Code Repository* genannt, kurz *Code Repo* oder auch nur *Repo*. + +Eine *Codebase* ist jedes einzelne Repo (in einem zentralisierten Versionsmanagementsystem wie Subversion) oder jede Menge von Repos, die einen ursprünglichen Commit teilen (in dezentralisierten Versionsmanagementsystemen wie git). + +![Eine Codebase bildet sich in viele Deploys ab.](/images/codebase-deploys.png) + +Es gibt immer eine eineindeutige Korrelation zwischen einer Codebase und einer App: + +* Wenn es mehrere Codebases gibt, ist es keine App -- sondern ein verteiltes System. Jede Komponente in einem verteilten System ist eine App, und Jede kann für sich den zwölf Faktoren entsprechen. +* Wenn mehrere Apps denselben Code teilen, verletzt dies die zwölf Faktoren. Lösen lässt sich dies, indem man den gemeinsamen Code in Bibliotheken auslagert und über die [Abhängigkeitsverwaltung](./dependencies) lädt. + +Es gibt nur eine Codebase pro App aber viele Deploys der App. Ein *Deploy* ist eine laufende Instanz der App. Meist gibt es ein Produktionssystem und eines oder mehrere Staging-Systeme. Zusätzlich hat jeder Entwickler eine Kopie der App in seiner lokalen Entwicklungsumgebung, das sind auch Deploys. + +Die Codebase ist über alle diese Deploys hinweg dieselbe, auch wenn bei jedem Deploy unterschiedliche Versionen aktiv sind. So hat zum Beispiel ein Entwickler manche Commits noch nicht nach Staging deployt; Staging hat manche Commits noch nicht nach Produktion deployt. Aber alle teilen dieselbe Codebase, was sie als verschiedene Deploys derselben App auszeichnet. diff --git a/content/de/concurrency.md b/content/de/concurrency.md new file mode 100644 index 000000000..e6166d174 --- /dev/null +++ b/content/de/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Nebenläufigkeit +### Mit dem Prozess-Modell skalieren + +Jedes Computerprogramm wird, wenn es läuft, repräsentiert durch einen oder mehrere Prozesse. Webapps nutzen verschiedenste Arten der Prozess-Ausführung. Zum Beispiel laufen PHP-Prozesse als Kind-Prozesse von Apache und werden nach Bedarf gestartet, wenn Requests kommen. Java-Prozesse gehen anders vor: die JVM stellt einen massiven Über-Prozess zur Verfügung der große Mengen an Systemressourcen (Speicher und CPU) reserviert und die Nebenläufigkeit wird intern über Threads verwaltet. In beiden Fällen sind die laufenden Prozesse für die Entwickler der App nur minimal zu sehen. + +![Die Skalierung wird dargestellt als laufende Prozesse, die Diversität der Workload wird dargestellt als Prozesstypen.](/images/process-types.png) + +**In der Zwölf-Faktor-App sind Prozesse First Class Citizens.** Die Prozesse der Zwölf-Faktor-App orientieren sich am [Unix-Prozess-Modell für Service Daemons](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Mit diesem Model können Entwickler ihre App für die Bearbeitung verschiedenster Aufgaben konzipieren in dem sie jeder Aufgabe einen *Prozesstyp* zuweisen. Zum Beispiel können HTTP-Requests durch einen Web-Prozess bedient werden und langlaufende Hintergrundarbeiten durch einen Worker-Prozess. + +Dies hindert die einzelnen Prozesse nicht daran, ihr internes Multiplexing zu verwalten, mittels Threads in der Laufzeit-VM oder mit dem Async/Event-Modell von Werkzeugen wie [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/) oder [Node.js](http://nodejs.org/). Aber eine einzelne VM ist in der Größe dadurch beschränkt (vertikale Skalierung), dass eine App noch in der Lage sein muss, mehrere Prozesse auf mehreren physikalischen Maschinen zu starten. + +Das Prozess-Modell glänzt besonders, wenn es um Skalierung geht. Die [Share-Nothing, horizontal teilbare Art und Weise der Prozesse der Zwölf-Faktor-App](./processes) hat zur Folge, dass weitere Nebenläufigkeit einfach und zuverlässig hinzugefügt werden kann. Das Bündel von Prozesstypen und die Zahl der Prozesse wird auch *Prozess-Formation* genannt. + +Die Prozesse einer Zwölf-Faktor-App [sollten nie als Daemons laufen](http://dustin.github.com/2010/02/28/running-processes.html) oder PID-Dateien schreiben. Stattdessen sollen sie sich auf den Prozessmanager des Betriebssystems verlassen (wie [systemd](https://www.freedesktop.org/wiki/Software/systemd/), den verteilten Prozessmanager einer Cloud-Plattform oder ein Werkzeug wie [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) während der Entwicklung) um [Output-Streams](./logs) zu verwalten, auf abgestürzte Prozesse zu reagieren und mit von Benutzern angestoßenen Restarts und Shutdowns umzugehen. diff --git a/content/de/config.md b/content/de/config.md new file mode 100644 index 000000000..641ab0ec5 --- /dev/null +++ b/content/de/config.md @@ -0,0 +1,23 @@ +## III. Konfiguration +### Die Konfiguration in Umgebungsvariablen ablegen + +Die *Konfiguration* einer App ist alles, was sich wahrscheinlich zwischen den [Deploys](./codebase) ändern wird (Staging, Produktion, Entwicklungsumgebungen, usw.). Dies umfasst: + +* Resource-Handles für Datenbanken, Memcached und andere [unterstützende Dienste](./backing-services) +* Credentials für externe Dienste wie Amazon S3 oder Twitter +* Direkt vom Deploy abhängige Werte wie der kanonische Hostname für den Deploy + +Manchmal speichern Apps die Konfiguration als Konstanten im Code. Dies ist eine Verletzung der zwölf Faktoren. Sie fordern **strikte Trennung der Konfiguration vom Code**. Die Konfiguration ändert sich deutlich von Deploy zu Deploy, ganz im Gegensatz zu Code. + +Ein Lackmustest, ob eine App die Konfiguration vollständig ausgelagert hat, ist, wenn die Codebase jederzeit als Open Source veröffentlicht werden könnte, ohne Credentials preiszugeben. + +Es sei darauf hingewiesen, dass diese Definition von "Konfiguration" die interne Anwendungskonfiguration **nicht einschließt**, wie `config/routes.rb` in Rails oder wie Code-Module [mit Spring verdrahtet sind](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html). Diese Art von Konfiguration ändert sich nicht von Deploy zu Deploy und gehört daher zum Code. + + +Als Konfiguration könnte man auch Dateien verwenden, die nicht ins Versionsmanagement eingecheckt sind wie `config/database.yml` in Rails. Dies ist eine deutliche Verbesserung gegenüber der Verwendung von Konstanten, die ins Versionsmanagement eingecheckt sind, hat aber Schwächen. Es ist relativ einfach, versehentlich eine Konfigurationsdatei ins Repo einzuchecken. Zusätzlich gibt es Tendenzen, Konfigurationsdateien an verschiedenen Orten und in verschiedenen Formaten zu streuen. Das macht es schwer die Konfiguration von einem Punkt aus zu managen. Desweiteren sind diese Formate oft sprach- oder plattformspezifisch. + +**Die Zwölf-Faktor-App speichert die Konfiguration in *Umgebungsvariablen*** (kurz auch *env vars* oder *env*). Umgebungsvariablen von Deploy zu Deploy zu ändern ist einfach; im Gegensatz zu Konfigurationsdateien ist es unwahrscheinlich, dass sie versehentlich ins Code Repository eingecheckt werden und im Gegensatz zu speziellen Konfigurationsdateien oder anderen Konfigurationsmechanismen wie den Java Properties sind sie Sprach- und Betriebssystemunabhängig. + +Ein anderer Aspekt des Konfigurationsmanagements ist die Gruppierung. Manchmal sammeln Apps die Konfiguration in benamten Gruppen (oft "Umgebungen" genannt), benannt nach bestimmten Deploys wie zum Beispiel die Umgebungen `development`, `test` und `production` in Rails. Diese Methode skaliert nicht sauber: Je mehr Deploys einer App es gibt, desto mehr Umgebungsnamen werden benötigt, wie zum Beispiel `staging` oder `qa`. Wenn das Projekt noch weiter wächst, könnten Entwickler ihre eigenen speziellen Umgebungen wie `joes-staging` hinzufügen. Am Ende explodiert die Konfiguration kombinatorisch und die Verwaltung der Deploys wird fehleranfällig. + +In einer Zwölf-Faktor-App sind Umgebungsvariablen granulare Stellschrauben und vollständig orthogonal zueinander. Sie werden nie als "Umgebungen" zusammengefasst, sondern können für jeden Deploy unabhängig verwaltet werden. Dieses Modell skaliert reibungslos aufwärts, wenn die App sich natürlicherweise über ihre Lebenszeit hinweg auf mehr Deploys ausdehnt. diff --git a/content/de/dependencies.md b/content/de/dependencies.md new file mode 100644 index 000000000..a4c6f46e1 --- /dev/null +++ b/content/de/dependencies.md @@ -0,0 +1,12 @@ +## II. Abhängigkeiten +### Abhängigkeiten explizit deklarieren und isolieren + +Die meisten Programmiersprachen bieten ein System an, um unterstützende Bibliotheken zu verbreiten, wie [CPAN](http://www.cpan.org/) für Perl oder [Rubygems](http://rubygems.org/) für Ruby. Aus einem Paketsystem stammende Bibliotheken können systemweit installiert werden (auch "Site Packages" genannt) oder in ein Verzeichnis der App beschränkt werden (genannt "vendoring" oder "bundling" - deutsch auch "mitliefern"). + +**Eine Zwölf-Faktor-App verlässt sich nie auf die Existenz von systemweiten Paketen.** Sie deklariert alle Abhängigkeiten vollständig und korrekt über eine *Abhängigkeitsdeklaration*. Weiter benutzt sie zur Laufzeit ein Werkzeug zur *Isolation von Abhängigkeiten* um sicherzustellen, dass keine impliziten Abhängigkeiten aus dem umgebenden System "hereinsickern". Die vollständige und explizite Spezifikation der Abhängigkeiten wird gleichermaßen in Produktion und Entwicklung angewandt. + +So bietet zum Beispiel [Bundler](https://bundler.io/) für Ruby das Format `Gemfile` zur Abhängigkeitsdeklaration und `bundle exec` zur Isolation von Abhängigkeiten. In Python gibt es für diese Schritte zwei unterschiedliche Werkzeuge -- [Pip](http://www.pip-installer.org/en/latest/) für die Deklaration und [Virtualenv](http://www.virtualenv.org/en/latest/) für die Isolation. Selbst C hat [Autoconf](http://www.gnu.org/s/autoconf/) zur Deklaration der Abhängigkeiten, und statisches Linken kann für Isolation sorgen. Unabhängig von den Werkzeugen müssen Abhängigkeitsdeklaration und Isolation immer zusammen benutzt werden -- eines alleine genügt für die zwölf Faktoren nicht. + +Ein Nutzen der expliziten Abhängigkeitsdeklaration ist das einfachere Aufsetzen der App für neue Entwickler. Neue Entwickler können die Codebase der App auf ihre Entwicklungsmaschine auschecken und brauchen dazu nur eine Sprach-Runtime und eine Abhängigkeitsverwaltung. Um die App zum Laufen zu bringen wird lediglich ein deterministisches *Build-Kommando* benötigt. So ist zum Beispiel das Build-Kommando für Ruby/Bundler `bundle install` und für Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) ist es `lein deps`. + +Zwölf-Faktor-Apps verlassen sich auch nicht auf die implizite Existenz irgendwelcher Systemwerkzeuge. Beispiele dafür sind Shell-Aufrufe von ImageMagick oder `curl`. Auch wenn diese Werkzeuge auf vielen und sogar den meisten Systemen vorhanden sind, gibt es keine Garantie, dass sie auf allen Systemen vorhanden sind, auf denen die App in Zukunft laufen wird, oder dass die Werkzeug-Version die in Zukunft auf einem System vorhanden sein wird, kompatibel ist. Wenn die App per Shell auf ein Systemwerkzeug zugreift, sollte die App das Werkzeug mitliefern. diff --git a/content/de/dev-prod-parity.md b/content/de/dev-prod-parity.md new file mode 100644 index 000000000..bab87138a --- /dev/null +++ b/content/de/dev-prod-parity.md @@ -0,0 +1,76 @@ +##X. Dev-Prod-Vergleichbarkeit +### Entwicklung, Staging und Produktion so ähnlich wie möglich halten + +Historisch gibt es große Lücken zwischen Entwicklung (wo ein Entwickler live an einem lokalen [Deploy](./codebase) der App Änderungen macht) und Produktion (ein laufender Deploy der App, auf den Endbenutzer zugreifen). Diese Lücken zeigen sich auf drei Gebieten: + +* **Die Zeit-Lücke** Ein Entwickler arbeitet an Code der Tage, Wochen oder sogar Monate braucht um in Produktion zu gehen. +* **Die Personal-Lücke**: Entwickler schreiben Code, Operatoren deployen ihn. +* **Die Werkzeug-Lücke**: Entwickler nutzen vielleicht einen Stack wie Nginx, SQLite und OS X - die Produktion nutzt Apache, MySQL und Linux. + +**Die Zwölf-Faktor-App ist ausgelegt auf [Continuous Deployment](http://avc.com/2011/02/continuous-deployment/) indem sie die Lücke zwischen Entwicklung und Produktion klein hält.** Mit Blick auf die oben beschriebenen drei Lücken: + +* Die Zeit-Lücke klein halten: Ein Entwickler kann Code schreiben, der Stunden oder sogar Minuten später deployed wird. +* Die Personal-Lücke klein halten: Entwickler die Code schreiben sind intensiv am Deployment und der Überwachung des Verhaltens auf Produktion beteiligt. +* Die Werkzeug-Lücke klein halten: Entwicklung und Produktion so ähnlich wie möglich halten. + +Das Gesagte in einer Tabelle: + + + + + + + + + + + + + + + + + + + + + + +
Traditionelle AppZwölf-Faktor-App
Zeit zwischen DeploymentsWochenStunden
Code-Autoren und Code-DeployerAndere MenschenDieselben Menschen
Entwicklungs- und Produktions-UmgebungUnterschiedlichSo ähnlich wie möglich
+ +Im Bereich der [unterstützenden Dienste](./backing-services) wie der Datenbank der App, dem Queue-System oder dem Cache ist die Dev-Prod-Vergleichbarkeit wichtig. Viele Sprachen bieten Bibliotheken, die den Zugriff auf die unterstützenden Dienste vereinfachen und ebenso *Adapter* für unterschiedliche Arten von Diensten. + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArtSpracheBibliothekAdapter
DatenbankRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
QueuePython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CacheSpeicher, Dateisystem, Memcached
+ +Für Entwickler ist es sehr elegant, einen leichtgewichtigen unterstützenden Dienst in der lokalen Umgebung zu benutzen, während ein ernst zu nehmender und robuster unterstützender Dienst in Produktion verwendet wird. So kann man SQLite lokal und PostgreSQL in Produktion benutzen; oder zum Cachen den lokalen Speicher in Entwicklung und Memcached in Produktion. + +**Der Zwölf-Faktor-Entwickler widersteht dem Drang, verschiedene unterstützende Dienste in Entwicklung und Produktion zu verwenden**, selbst wenn Adapter über alle Unterschiede hinweg abstrahieren. Unterschiede zwischen den unterstützenden Diensten verursachen kleinste Inkompatiblitäten, und Code, der in Entwicklung oder Staging funktioniert und Tests besteht, scheitert in Produktion. Diese Reibungskosten und die dann notwendige Dämpfung des Continuous Deployment sind sehr hoch, wenn man sie über die Lebensdauer einer App aggregiert. + +Leichtgewichtige lokale Dienste überzeugen weniger als früher. Moderne unterstützende Dienste wie Memcached, PostgreSQL und RabbitMQ sind dank moderner Paketierungs-Systeme wie [Homebrew](http://mxcl.github.com/homebrew/) und [apt-get](https://help.ubuntu.com/community/AptGet/Howto) nicht schwierig zu installieren und zu starten. Auch deklarative Installationssysteme wie [Chef](http://www.opscode.com/chef/) oder [Puppet](http://docs.puppetlabs.com/) in Kombination mit leichtgewichtigen virtuellen Umgebungen wie [Vagrant](http://vagrantup.com/) setzen Entwickler in den Stand, lokale Umgebungen ans Laufen zu bringen, die nahe an Produktionsumgebungen herankommen. Die Installations- und Betriebskosten dieser Systeme sind gering verglichen mit dem Nutzen der Dev-Prod-Vergleichbarkeit und einem Continuous Deployment. + +Adapter für unterschiedliche unterstützende Dienste sind weiterhin von Nutzen, weil sie das Portieren auf andere unterstützende Dienste schmerzlos machen. Aber alle Deploys der App (Entwicklungsumgebungen, Staging, Produktion) sollten denselben Typ und dieselbe Version eines jeden unterstützenden Dienstes benutzen. diff --git a/content/de/disposability.md b/content/de/disposability.md new file mode 100644 index 000000000..3d15f925e --- /dev/null +++ b/content/de/disposability.md @@ -0,0 +1,12 @@ +## IX. Einweggebrauch +### Robuster mit schnellem Start und problemlosen Stopp + +**Die Prozesse einer Zwölf-Faktor-App können *weggeworfen* werden, sie können also schnell gestartet und gestoppt werden.** Dies erleichtert schnelles elastisches Skalieren, schnelles Deployment von [Code](./codebase) oder [Konfigurationsänderungen](./config) und macht Produktionsdeployments robuster. + +Prozesse sollten **möglichst geringe Startup-Zeiten** haben. Idealerweise braucht ein Prozess wenige Sekunden vom Startkommando bis der Prozess läuft und Requests oder Jobs entgegennehmen kann. Eine kurze Startup-Zeit gibt dem [Release-Prozess](./build-release-run) und der Skalierung mehr Agilität; sie hilft der Robustheit, weil ein Prozessmanager bei Bedarf einfacher Prozesse auf neue physikalische Maschinen verschieben kann. + +Prozesse **fahren ohne Schwierigkeiten herunter, wenn sie ein [SIGTERM-Signal](http://en.wikipedia.org/wiki/SIGTERM)** vom Prozessmanager bekommen. Für einen Web-Prozess kann ein problemloses Herunterfahren erreicht werden, indem er aufhört an seinem Service-Port zu lauschen (und damit alle neuen Requests ablehnt), die laufenden Requests zuende bearbeitet und sich dann beendet. Diesem Modell eigen ist, dass HTTP-Requests kurz sind (höchstens ein paar Sekunden) oder im Falle von Long-Polling, der Client sich nahtlos neu verbindet, wenn die Verbindung verloren geht. + +Für einen Worker-Prozess wird ein problemloser Stopp erreicht, indem er seinen laufenden Job an die Workqueue zurück gibt. Zum Beispiel kann bei [RabbitMQ](http://www.rabbitmq.com/) ein Worker einen [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); bei [Beanstalkd](https://beanstalkd.github.io) wird der Job automatisch an die Queue zurückgegeben, wenn ein Worker die Verbindung beendet. Lock-basierte Systeme wie [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) sollten sicherstellen, dass ihr Lock im Job-Record freigegeben wird. Diesem Modell eigen ist, dass alle Jobs [reentrant](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29) sind, was üblicherweise erreicht wird indem man die Ergebnisse in eine Transaktion einpackt oder den Vorgang [idempotent](https://de.wikipedia.org/wiki/Idempotenz) gestaltet. + +Prozesse sollte auch **robust gegen plötzlichen Tod** sein - falls die zugrundeliegende Hardware versagt. Auch wenn dies viel seltener ist als ein reguläres Herunterfahren mit `SIGTERM`, so kommt es dennoch vor. Wir empfehlen ein robustes Queue-Backend wie Beanstalkd, das Jobs an die Queue zurückgibt falls Clients die Verbindung beenden oder nicht mehr antworten. Wie auch immer ist eine Zwölf-Faktor-App darauf ausgelegt mit unerwarteten, irregulären Stopps umgehen zu können. [Crash-only design](http://lwn.net/Articles/191059/) führt dieses Konzept zu seinem [logischen Schluss](http://docs.couchdb.org/en/latest/intro/overview.html). diff --git a/content/de/intro.md b/content/de/intro.md new file mode 100644 index 000000000..8319637cd --- /dev/null +++ b/content/de/intro.md @@ -0,0 +1,12 @@ +Einführung +============ + +Heute wird Software oft als Dienst geliefert - auch *Web App* oder *Software-As-A-Service* genannt. Die Zwölf-Faktoren-App ist eine Methode um Software-As-A-Service Apps zu bauen die: + +* **deklarative** Formate benutzen für die Automatisierung der Konfiguration, um Zeit und Kosten für neue Entwickler im Projekt zu minimieren; +* einen **sauberen Vertrag** mit dem zugrundeliegenden Betriebssystem haben, **maximale Portierbarkeit** zwischen Ausführungsumgebungen bieten; +* sich für das **Deployment** auf modernen **Cloud-Plattformen** eignen, die Notwendigkeit von Servern und Serveradministration vermeiden; +* die **Abweichung minimieren** zwischen Entwicklung und Produktion, um **Continuous Deployment** für maximale Agilität ermöglichen; +* und **skalieren** können ohne wesentliche Änderungen im Tooling, in der Architektur oder in den Entwicklungsverfahren. + +Die Zwölf-Faktoren-Methode kann auf Apps angewendet werden, die in einer beliebigen Programmiersprache geschrieben sind, und die eine beliebige Kombination von unterstützenden Diensten benutzen (Datenbank, Queue, Cache, ...) diff --git a/content/de/logs.md b/content/de/logs.md new file mode 100644 index 000000000..940bdff5c --- /dev/null +++ b/content/de/logs.md @@ -0,0 +1,16 @@ +## XI. Logs +### Logs als Strom von Ereignissen behandeln + +*Logs* machen das Verhalten einer laufenden App sichtbar. In Server-basierten Umgebungen werden sie üblicherweise in eine Datei auf der Platte geschrieben (eine Logdatei) - das ist aber nur ein Ausgabeformat. + +Logs sind der [Stream](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) von aggregierten, nach Zeit sortierten Ereignissen und zusammengefasst aus den Output Streams aller laufenden Prozesse und unterstützenden Dienste. Logs in ihrer rohen Form sind üblicherweise ein Textformat mit einem Ereignis pro Zeile (obwohl Backtraces von Exceptions über mehrere Zeilen gehen können) + +**Eine Zwölf-Faktor-App kümmert sich nie um das Routing oder die Speicherung ihres Output Streams.** Sie sollte nicht versuchen, in Logdateien zu schreiben oder diese zu verwalten. Statt dessen schreibt jeder laufende Prozess seinen Stream von Ereignissen ungepuffert auf `stdout`. Bei einem lokalen Deployment sichtet ein Entwickler diesen Stream im Vordergrund seines Terminals um das Verhalten der App zu beobachten. + +Auf Staging- oder Produktionsdeploys werden die Streams aller Prozesse von der Laufzeitumgebung erfasst, mit allen anderen Streams der App zusammengefasst und zu einem oder mehreren Zielen geleitet, zur Ansicht oder langzeitigen Archivierung. Diese Archivierungsziele sind für die App weder sichtbar noch konfigurierbar - sie werden vollständig von der Laufzeitumgebung aus verwaltet. Open-Source Log Router (wie [Logplex](https://github.com/heroku/logplex) und [Fluentd](https://github.com/fluent/fluentd)) stehen dafür zur Verfügung. + +Der Stream von Ereignissen für eine App kann in eine Datei geleitet werden oder mit einem Echtzeit-Tail in einem Terminal beobachtet werden. Sehr bedeutsam ist es, das der Stream in ein Log-Indexierungs- und Analyse-System wie [Splunk](http://www.splunk.com/) oder in ein allgemein verwendbares Data-Warehouse-System wie [Hadoop/Hive](http://hive.apache.org/) gelenkt werden kann. Mit diesem System kann das Verhalten einer App leistungsfähig und flexibel beobachtet werden. Dies schließt ein: + +* Bestimmte Ereignisse in der Vergangenheit zu finden +* Umfangreiche graphische Darstellungen (wie Requests pro Minute) +* Aktives Alarmieren aufgrund benutzerdefinierter Heuristiken (wie ein Alarm wenn die Anzahl von Fehlern pro Minute eine gewisse Grenze überschreitet) diff --git a/content/de/port-binding.md b/content/de/port-binding.md new file mode 100644 index 000000000..71666fa67 --- /dev/null +++ b/content/de/port-binding.md @@ -0,0 +1,14 @@ +## VII. Bindung an Ports +### Dienste durch das Binden von Ports exportieren + +Web-Apps laufen manchmal in einem Webserver als Container. Zum Beispiel laufen PHP-Apps als Modul in [Apache HTTPD](http://httpd.apache.org/), oder Java-Apps laufen manchmal in [Tomcat](http://tomcat.apache.org/). + +**Die Zwölf-Faktor-App ist vollständig eigenständig** und verlässt sich nicht darauf, dass ein externer Webserver zur Laufzeit injiziert wird, um dem Web einen Dienst zur Verfügung zu stellen. Die Web-App **exportiert HTTP als Dienst, indem sie sich an einen Port bindet** und wartet an diesem Port auf Requests. + +In einer lokalen Entwicklungsumgebung öffnet ein Entwickler eine Dienst-URL wie `http://localhost:5000/`, um auf den Dienst der App zuzugreifen. Beim Deployment sorgt eine Routing-Schicht dafür, dass Requests von einem öffentlich sichtbaren Hostnamen zu den an die Ports gebundenen Prozessen kommen. + +Üblicherweise wird dies mittels [Abhängigkeitsdeklaration](./dependencies) implementiert. Zu der App fügt man eine Webserver-Bibliothek hinzu wie [Tornado](http://www.tornadoweb.org/) für Python, [Thin](http://code.macournoyer.com/thin/) für Ruby oder [Jetty](http://www.eclipse.org/jetty/) für Java und andere JVM-basierenden Sprachen. Dies findet vollständig im *User Space* statt, also im Code der App. Der Vertrag mit der Laufzeitumgebung ist das Binden an einen Port um Requests zu bedienen. + +HTTP ist nicht der einzige Dienst, der durch Portbindung exportiert werden kann. Fast jede Server-Software kann betrieben werden, indem ein Prozess an einen Port gebunden wird und auf ankommende Requests wartet. Einige Beispiele sind [ejabberd](http://www.ejabberd.im/) (spricht [XMPP](http://xmpp.org/)) und [Redis](http://redis.io/) (spricht das [Redis-Protokoll](http://redis.io/topics/protocol)). + +Es sei auch erwähnt, dass durch Portbindung eine App ein [unterstützender Dienst](./backing-services) für eine andere App werden kann, indem die URL der unterstützenden App der konsumierenden App als Resource-Handle zur Verfügung gestellt wird. diff --git a/content/de/processes.md b/content/de/processes.md new file mode 100644 index 000000000..93a484656 --- /dev/null +++ b/content/de/processes.md @@ -0,0 +1,14 @@ +## VI. Prozesse +### Die App als einen oder mehrere Prozesse ausführen + +Die App wird als ein oder mehrere *Prozesse* ausgeführt. + +Im einfachsten Fall ist der Code ein Stand-alone-Skript, die Ausführungsumgebung ist der lokale Laptop eines Entwicklers mit einer installierten Laufzeitumgebung einer Sprache, und der Prozess wird von der Kommandozeile gestartet (zum Beispiel `python my_script.py`). Am anderen Ende des Spektrums kann eine hochentwickelte App viele [Prozesstypen benutzen, die in keinen oder mehreren Prozessen laufen](./concurrency). + +**Zwölf-Faktor-Apps sind zustandslos und [Shared Nothing](https://de.wikipedia.org/wiki/Shared_Nothing_Architecture).** Alle Daten werden in [unterstützenden Diensten](./backing-services) gespeichert, normalerweise einer Datenbank. + +Der RAM oder das Dateisystem des Prozesses kann als kurzfristiger Cache für die Dauer einer Transaktion verwendet werden. Zum Beispiel kann ein Prozess eine Datei herunterladen, sie verarbeiten und die Ergebnisse in einer Datenbank speichern. Die Zwölf-Faktor-App geht nie davon aus, dass irgendetwas aus dem RAM oder im Dateisystem zwischengespeichertes für einen künftigen Request oder Job verfügbar sein wird. Es ist gut möglich, dass ein künftiger Request von einem anderen Prozess bedient wird. Selbst wenn nur ein Prozess läuft, wird ein Neustart (verursacht durch Code Deployment, Konfigurationsänderung oder der Verlagerung der Ausführungsumgebung auf einen anderen physikalischen Ort) den gesamten lokalen Zustand (RAM und Dateisystem) löschen. + +Asset-Paketierer (wie [Jammit](http://documentcloud.github.com/jammit/) oder [django-compressor](http://django-compressor.readthedocs.org/)) benutzen das Dateisystem als Cache für kompilierte Assets. Eine Zwölf-Faktor-App wie die [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html) würde diese Art von Kompilation eher in der [Build-Phase](./build-release-run) erledigen anstatt zur Laufzeit. + +Manche Web-Systeme verlassen sich auf ["Sticky Sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- sie cachen Benutzer-Session-Daten im RAM des App-Prozesses und erwarten, dass künftige Requests desselben Benutzers zum selben Prozess geschickt werden. Sticky Sessions sind eine Verletzung der zwölf Faktoren und eine guter Kandidat für einen Datenspeicher, der ein zeitabhängiges Löschen anbietet, wie [Memcached](http://memcached.org/) oder [Redis](http://redis.io/). diff --git a/content/de/toc.md b/content/de/toc.md new file mode 100644 index 000000000..94e8a1f55 --- /dev/null +++ b/content/de/toc.md @@ -0,0 +1,38 @@ +Die zwölf Faktoren +================== + +## [I. Codebase](./codebase) +### Eine im Versionsmanagementsystem verwaltete Codebase, viele Deployments + +## [II. Abhängigkeiten](./dependencies) +### Abhängigkeiten explizit deklarieren und isolieren + +## [III. Konfiguration](./config) +### Die Konfiguration in Umgebungsvariablen ablegen + +## [IV. Unterstützende Dienste](./backing-services) +### Unterstützende Dienste als angehängte Ressourcen behandeln + +## [V. Build, release, run](./build-release-run) +### Build- und Run-Phase strikt trennen + +## [VI. Prozesse](./processes) +### Die App als einen oder mehrere Prozesse ausführen + +## [VII. Bindung an Ports](./port-binding) +### Dienste durch das Binden von Ports exportieren + +## [VIII. Nebenläufigkeit](./concurrency) +### Mit dem Prozess-Modell skalieren + +## [IX. Einweggebrauch](./disposability) +### Robuster mit schnellem Start und problemlosen Stopp + +## [X. Dev-Prod-Vergleichbarkeit ](./dev-prod-parity) +### Entwicklung, Staging und Produktion so ähnlich wie möglich halten + +## [XI. Logs](./logs) +### Logs als Strom von Ereignissen behandeln + +## [XII. Admin-Prozesse](./admin-processes) +### Admin/Management-Aufgaben als einmalige Vorgänge behandeln diff --git a/content/de/who.md b/content/de/who.md new file mode 100644 index 000000000..b25d5aeb4 --- /dev/null +++ b/content/de/who.md @@ -0,0 +1,4 @@ +Wer sollte dieses Dokument lesen? +============================== + +Jeder Entwickler der Apps baut, die als Dienst laufen. Administratoren, die solche Apps managen oder deployen. diff --git a/content/el/admin-processes.md b/content/el/admin-processes.md new file mode 100644 index 000000000..0d57dae7a --- /dev/null +++ b/content/el/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Διεργασίες διαχείρισης +### Εκτέλεση εργασιών διαχείρισης ως διεργασίες μια και έξω + +Ο [σχηματισμός διεργασιών (process formation)](./concurrency) είναι η συστοιχία των διεργασιών που κάνουν τη συνήθη εργασία της εφαρμογής (όπως να χειρίζονται αιτήσεις ιστού) καθώς τρέχει. Ξεχωριστά, οι προγραμματιστές θα θέλουν συχνά να κάνουν διαχειριστικές εργασίες ή εργασίες συντήρησης μια και έξω, όπως: + +* Να τρέξουν αλλαγές στη βάση δεδομένων (database migrations) (π.χ. `manage.py migrate` στο Django, `rake db:migrate` στο Rails). +* Να τρέξουν μια κονσόλα (επίσης γνωστή ως κέλυφος [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop)) για να εκτελέσουν οποιοδήποτε κώδικα ή να επιθεωρήσουν τα μοντέλα της εφαρμογής σε σχέση με μια ζωντανή βάση δεδομένων. Οι περισσότερες γλώσσες προγραμματισμού προσφέρουν ένα REPL μέσω της εκτέλεσης του διερμηνέα χωρίς άλλα ορίσματα (π.χ. `python` ή `perl`) ή σε ορισμένες περιπτώσεις έχουν μια ξεχωριστή εντολή (π.χ. `irb` για τη Ruby, `rails console` για το Rails). +* Να τρέξουν σενάρια εντολών μια και έξω τα οποία είναι εισηγμένα στο αποθετήριο της εφαρμογής (π.χ. `php scripts/fix_bad_records.php`). + +Οι διεργασίες διαχείρισης μια και έξω θα πρέπει να εκτελούνται σε ένα πανομοιότυπο περιβάλλον όπως το κανονικό περιβάλλον των [διεργασιών μακράς διάρκειας](./processes) της εφαρμογής. Εκτελούνται πάνω σε μια [έκδοση (release)](./build-release-run), χρησιμοποιώντας την ίδια [βάση κώδικα (codebase)](./codebase) και [παραμέτρους (config)](./config) όπως κάθε διεργασία που εκτελείται με βάση την ίδια έκδοση της εφαρμογής. Ο κώδικας διαχείρισης πρέπει να εξάγεται μαζί με τον κώδικα της εφαρμογής για να αποφευχθούν ζητήματα συγχρονισμού. + +Οι ίδιες τεχνικές [απομόνωσης εξαρτήσεων](./dependencies) θα πρέπει να χρησιμοποιούνται σε όλους τους τύπους διεργασιών. Για παράδειγμα, εάν η διεργασία ιστού της Ruby χρησιμοποιεί την εντολή `bundle exec thin start`, τότε μια αλλαγή της βάσης δεδομένων (database migration) θα πρέπει να χρησιμοποιήσει τη `bundle exec rake db:migrate`. Παρομοίως, ένα πρόγραμμα Python που χρησιμοποιεί το Virtualenv θα πρέπει να χρησιμοποιήσει το προμηθευμένο (vendored) `bin/python` για να τρέξει και τον εξυπηρετητή ιστού Tornado και οποιαδήποτε διεργασία διαχείρισης τύπου `manage.py`. + +ΟΙ δώδεκα παράγοντες έχουν ισχυρή προτίμηση στις γλώσσες προγραμματισμού που προσφέρουν ένα κέλυφος REPL έτοιμο για χρήση, και το οποίο καθιστά εύκολο να τρέξουν σενάρια εντολών μια και έξω. Σε μια τοπική ανάπτυξη (local deploy), οι προγραμματιστές καλούν τις διεργασίες διαχείρισης μια και έξω μέσω μιας εντολής απευθείας στο κέλυφος εντολών (shell) μέσα στο φάκελο του αποθετηρίου της εφαρμογής. Σε μια ανάπτυξη παραγωγής (production deploy), οι προγραμματιστές μπορούν να χρησιμοποιήσουν το ssh ή άλλο μηχανισμό απομακρυσμένης εκτέλεσης εντολών ο οποίος παρέχεται από το περιβάλλον εκτέλεσης για να τρέξουν μια τέτοια διεργασία. diff --git a/content/el/background.md b/content/el/background.md new file mode 100644 index 000000000..e690a2d4e --- /dev/null +++ b/content/el/background.md @@ -0,0 +1,9 @@ +Πλαίσιο +======= + +Οι συγγραφείς αυτού του κειμένου έχουν άμεσα εμπλακεί στην υλοποίηση και ανάπτυξη εκατοντάδων εφαρμογών, και έχουν έμμεσα γίνει μάρτυρες της υλοποίησης, λειτουργίας, και κλιμάκωσης εκατοντάδων χιλιάδων εφαρμογών μέσω της εργασίας τους στη πλατφόρμα Heroku. + +Αυτό το κείμενο συνθέτει όλη την εμπειρία μας και τις παρατηρήσεις μας σε μια ευρεία ποικιλία απο εφαρμογές λογισμικού-ως-υπηρεσίας εκεί έξω. Είναι μια τριγωνοποίηση σε ιδανικές πρακτικές για υλοποίηση εφαρμογών, δίνωντας ιδιαίτερη προσοχή στην δυναμική της οργανικής ανάπτυξης μιας εφαρμογής στο χρόνο, της δυναμικής της συνεργασίας μεταξύ προγραμματιστών που δουλέυουν πάνω στη βάση κώδικα της εφαρμογής, και της αποφυγής του κόστους διάβρωσης του λογισμικού. + +Το κίνητρό μας είναι να αυξήσουμε τη συνειδητότητα για μερικά συστημικά προβλήματα που έχουμε δει στην υλοποίηση μοντέρνων εφαρμογών, να παρέχουμε ένα κοινό λεξιλόγιο για να συζητήσουμε αυτά τα προβλήματα, και να προσφέρουμε ένα σύνολο από ευρείς εννοιολογικές λύσεις μαζί με την συνάδουσα ορολογία. Η μορφή είναι εμπνευσμένη απο τα βιβλία του Martin Fowler *Patterns of Enterprise Application Architecture* και *Refactoring*. + diff --git a/content/el/backing-services.md b/content/el/backing-services.md new file mode 100644 index 000000000..4761a1cdc --- /dev/null +++ b/content/el/backing-services.md @@ -0,0 +1,14 @@ +## IV. Υπηρεσίες υποστήριξης +### Υπηρεσίες υποστήριξης ως επισυναπτόμενοι πόροι + +Μία *υπηρεσία υποστήριξης* (*backing service*) είναι οποιαδήποτε υπηρεσία την οποία η εφαρμογή καταναλώνει μέσω του δικτύου ως μέρος της κανονικής λειτουργίας της. Παραδείγματα περιλαμβάνουν τις αποθήκες δεδομένων (datastores) (όπως η [MySQL](http://dev.mysql.com/) ή η [CouchDB](http://couchdb.apache.org/)), τα συστήματα μηνυμάτων/ουρών (messaging/queueing systems) (όπως το [RabbitMQ](http://www.rabbitmq.com/) ή το [Beanstalkd](https://beanstalkd.github.io)), τις υπηρεσίες SMTP για εξερχόμενη ηλεκτρονική αλληλογραφία (όπως το [Postfix](http://www.postfix.org/)), και συστήματα προσωρινής μνήμης (caching systems) (όπως το [Memcached](http://memcached.org/)). + +Υπηρεσίες υποστήριξης όπως η βάση δεδομένων παραδοσιακά διαχειρίζονται από τους ίδιους διαχειριστές συστημάτων που εγκαθιστούν την εφαρμογή. Πρόσθετα σε αυτές τις τοπικά διαχειριζόμενες υπηρεσίες, η εφαρμογή μπορεί επίσης να έχει και υπηρεσίες που προσφέρονται και διαχειρίζονται από τρίτους. Παραδείγματα περιλαμβάνουν υπηρεσίες SMTP (όπως το [Postmark](http://postmarkapp.com/)), υπηρεσίες στατιστικών εφαρμογής (όπως το [New Relic](http://newrelic.com/) ή το [Loggly](http://www.loggly.com/)), υπηρεσίες δυαδικών επισυναπτόμενων αρχείων (binary asset services) (όπως το [Amazon S3](http://aws.amazon.com/s3/)), και ακόμα καταναλωτικές υπηρεσίες προσβάσιμες μέσω API (όπως το [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), ή το [Last.fm](http://www.last.fm/api)). + +**Ο κώδικας μιας εφαρμογής δώδεκα παραγόντων δεν κάνει καμία διάκριση μεταξύ τοπικών υπηρεσιών και υπηρεσιών τρίτων.** Για την εφαρμογή, και οι δύο είναι επισυναπτόμενοι πόροι, προσβάσιμοι μέσω ενός URL ή μέσω άλλων εντοπιστών/διαπιστευτηρίων που αποθηκέυονται ως [παράμετροι (config)](./config). Μία [ανάπτυξη](./codebase) της εφαρμογής δώδεκα παραγόντων θα πρέπει να είναι ικανή να αντικαταστήσει μια τοπική βάση δεδομένων MySQL με μία άλλη διαχειριζόμενη από τρίτους (όπως η [Amazon RDS](http://aws.amazon.com/rds/)) χωρίς καμία αλλαγή στον κώδικα της εφαρμογής. Παρομοίως, ένας τοπικός εξυπηρετητής SMTP μπορεί να αντικατασταθεί από μία υπηρεσία SMTP από τρίτους (όπως το Postmark) χωρίς αλλαγές στον κώδικα. Και στις δύο περιπτώσεις, μόνο το αναγνωριστικό του πόρου (resource handle) στις παραμέτρους πρέπει να αλλάξει. + +Κάθε διακριτή υπηρεσία υποστήριξης είναι ένας *πόρος* (*resource*). Για παράδειγμα, μία βάση δεδομένων MySQL είναι ένας πόρος, δύο βάσεις δεδομένων MySQL (που χρησιμοποιούνται για κομμάτιασμα στο επίπεδο εφαρμογής) είναι δύο διακριτοί πόροι. Η εφαρμογή δώδεκα παραγόντων φέρεται σε αυτές τις βάσεις δεδομένων σαν να είναι *επισυναπτόμενοι πόροι* (*attached resources*), το οποίο σηματοδοτεί την χαλαρή σύνδεση (loose coupling) με την ανάπτυξη της εφαρμογής (deploy) στην οποία επισυνάπτονται. + +Μια ανάπτυξη παραγωγής στην οποία επισυνάπτονται τέσσερις υπηρεσίες υποστήριξης. + +Οι πόροι μπορεί να προστεθούν και να καταργηθούν από μία ανάπτυξη της εφαρμογής κατά βούληση. Για παράδειγμα, εάν η βάση δεδομένων της εφαρμογής λανθάνει λόγω αστοχίας του υλικού (hardware issue), ο διαχειριστής της εφαρμογής μπορεί να σηκώσει ένα νέο εξυπηρετητή βάσης δεδομένων από ένα πρόσφατο αντίγραφο ασφαλείας. Η τρέχουσα βάση δεδομένων της παραγωγής μπορεί να καταργηθεί, και η νέα βάση δεδομένων να προστεθεί -- όλα χωρίς καμία αλλαγή στον κώδικα. diff --git a/content/el/build-release-run.md b/content/el/build-release-run.md new file mode 100644 index 000000000..b9ab494e5 --- /dev/null +++ b/content/el/build-release-run.md @@ -0,0 +1,19 @@ +## V. Κατασκευή, έκδοση, εκτέλεση +### Αυστηρός διαχωρισμός μεταξύ των σταδίων μεταγλώττισης/κατασκευής και εκτέλεσης + +Μια [βάση κώδικα](./codebase) μετασχηματίζεται σε μια ανάπτυξη εφαρμογής (deploy) (όχι για υλοποίηση) μέσω τριών σταδίων: + +* Το *στάδιο κατασκευής* (*build stage*) είναι ένας μετασχηματισμός που μετατρέπει ένα αποθετήριο κώδικα σε μία εκτελέσιμη δέσμη γνωστή ως *κατασκευή* (*build*). Χρησιμοποιώντας μια έκδοση του κώδικα σε κάποιο σημείο δοσμένο απο τη διεργασία ανάπτυξης, το στάδιο κατασκευής μαζέυει τις όποιες [εξαρτήσεις](./dependencies) που πρέπει να προμηθευθούν στην εφαρμογή και μεταγλωττίζει και συνενώνει τα δυαδικά αρχεια και άλλα πρόσθετα. +* Το *στάδιο έκδοσης* (*release stage*) παίρνει το αποτέλεσμα του σταδίου κατασκευής και το συνδυάζει με τις τρέχουσες [παραμέτρους](./config) της ανάπτυξης της εφαρμογής. Η τελική *έκδοση* (*release*) περιέχει την κατασκευή και τις παραμέτρους και είναι έτοιμη για άμεση εκτέλεση στο περιβάλλον εκτέλεσης. +* Το *στάδιο εκτέλεσης* (*run stage*) (επίσης γνωστό ως "εκτελέσιμο", "runtime") τρέχει την εφαρμογή στο περιβάλλον εκτέλεσης, ξεκινώντας ένα σύνολο απο τις [διεργασίες](./processes) της εφαρμογής με βάση μια επιλεγμένη έκδοση της εφαρμογής. + +![Ο κώδικας γίνεται κατασκευή, η οποία συνδυάζεται με παραμέτρους για να δημιουργήσει μια έκδοση της εφαρμογής.](/images/release.png) + +**Η εφαρμογή δώδεκα παραγόντων διαχωρίζει αυστηρά τα στάδια κατασκευής, έκδοσης και εκτέλεσης.** Για παράδειγμα, είναι αδύνατο να πραγματοποιηθούν αλλαγές στον κώδικα κατά την εκτέλεση, καθώς δεν υπάρχει τρόπος να περάσουν αυτές οι αλλαγές πίσω στο στάδιο κατασκευής. + +Τα εργαλεία ανάπτυξης εφαρμογών (deployment tools) τυπικά προσφέρουν εργαλεία διαχείρισης εκδόσεων (release management tools), κυρίως την ικανότητα να γυρίσουν πίσω σε μία προηγούμενη έκδοση της εφαρμογής. Για παράδειγμα, το εργαλείο [Capistrano](https://github.com/capistrano/capistrano/wiki) αποθηκέυει τις εκδόσεις σε ένα υποφάκελο με όνομα `releases`, όπου η τρέχουσα έκδοση είναι ένας συμβολικός σύνδεσμος στο φάκελο της τρέχουσας έκδοσης. Με την εντολή του `rollback` έυκολα και γρήγορα γυρίζει πίσω σε μία προηγούμενη έκδοση της εφαρμογής. + +Κάθε έκδοση της εφαρμογής θα πρέπει πάντα να φέρει ένα μοναδικό αναγνωριστικό έκδοσης (release ID), όπως μια χρονοσφραγίδα της έκδοσης (όπως το `2011-04-06-20:32:17`) ή έναν άυξοντα αριθμό (όπως το `v100`). Οι εκδόσεις της εφαρμογής είναι σαν ένα λογιστικό βιβλίο όπου μόνο προσθέσεις μπορούν να γίνουν και μία έκδοση δεν μπορεί να μεταβληθεί αφού έχει δημιουργηθεί. Κάθε μεταβολή πρέπει να δημιουργήσει μια νέα έκδοση της εφαρμογής. + +Οι κατασκευές (builds) ξεκινούν απο τους προγραμματιστές της εφαρμογής όποια στιγμή καινούργιος κώδικας αναπτύσσεται (deployed). Η εκτέλεση, αντιθέτως, μπορεί να συμβεί αυτόματα σε περιπτώσεις όπως επανεκκίνηση εξυπηρετητή (server restart), ή όταν μια διεργασία που έχει καταρρέυσει επανεκκινείται από τον διαχειριστή διεργασιών (process manager). Επομένως, το στάδιο εκτέλεσης θα πρέπει να έχει όσο πιο λίγα κινούμενα μέρη γίνεται, καθώς προβλήματα που μπορεί να εμποδίσουν μία εφαρμογή απο το να τρέξει μπορεί να την κάνουν να καταρρέυσει εν τω μέσω της νυκτός όπου δεν θα υπάρχει κανένας προγραμματιστής διαθέσιμος. Το στάδιο κατασκευής μπορεί να είναι πιο περίπλοκο, καθώς τα σφάλματα είναι πάντα στο προσκήνιο για ένα προγραμματιστή που καθοδηγεί την ανάπτυξη της εφαρμογής (deploy). + diff --git a/content/el/codebase.md b/content/el/codebase.md new file mode 100644 index 000000000..05a738785 --- /dev/null +++ b/content/el/codebase.md @@ -0,0 +1,18 @@ +## I. Βάση Κώδικα +### Μία βάση κώδικα με έλεγχο εκδόσεων, πολλές αναπτύξεις + +Μια εφαρμογή δώδεκα παραγόντων είναι πάντα διαχειριζόμενη από ένα σύστημα ελέγχου εκδόσεων κώδικα (version control system), όπως το [Git](http://git-scm.com/), το [Mercurial](https://www.mercurial-scm.org/), ή το [Subversion](http://subversion.apache.org/). Ένα αντίγραφο της βάσης αλλαγών του συστήματος είναι γνωστό ως *αποθετήριο κώδικα* (*code repository*), συχνά συντομευμένο σε *αποθετήριο* (*code repo* ή *repo*). + +Μια *βάση κώδικα* (*codebase*) είναι είτε ένα οποιοδήποτε αποθετήριο (σε ένα κεντρικά διαχειριζόμενο σύστημα όπως το Subversion), είτε ένα οποιοδήποτε σύνολο από αποθετήρια τα οποία μοιράζονται μία κοινή ρίζα εισαγωγής κώδικα (σε ένα αποκεντρωμένο σύστημα διαχείρισης όπως το Git). + +![Μία βάση κώδικα αναλογεί σε πολλές αναπτύξεις της εφαρμογής](/images/codebase-deploys.png) + +Υπάρχει πάντα μια σχέση ένα-προς-ένα μεταξύ της βάσης κώδικα και της εφαρμογής: + +* Αν υπάρχουν πολλαπλές βάσεις κώδικα, δεν είναι εφαρμογή -- είναι ενα κατανεμημένο σύστημα. Κάθε μέρος του κατανεμημένου συστήματος είναι εφαρμογή, και το καθένα ξεχωριστά μπορεί να συνάδει με τους δώδεκα παράγοντες. +* Πολλαπλές εφαρμογές οι οποίες μοιράζονται τον ίδιο κώδικα συνιστά παράβαση των δώδεκα παραγόντων. Η λύση εδώ είναι να παραγοντοποιηθεί ο κοινός κώδικας σε βιβλιοθήκες οι οποίες μπορούν να εισαχθούν μέσω του [διαχειριστή εξαρτήσεων](./dependencies). + +Υπάρχει μόνο μία βάση κώδικα ανά εφαρμογή, αλλά θα υπάρξουν πολλές αναπτύξεις της εφαρμογής. Μια *ανάπτυξη* (*deploy*) της εφαρμογής, είναι μία εκτελούμενη ενσάρκωση της εφαρμογής. Αυτό τυπικά είναι μία τοποθεσία παραγωγής (production site), και μία ή περισσότερες τοποθεσίες ελέγχου (staging sites). Επιπλέον, κάθε προγραμματιστής έχει ένα αντίγραφο της εφαρμογής εκτελούμενο τοπικά στο περιβάλλον του, το οποίο επίσης συνιστά μια ανάπτυξη. + +Η βάση κώδικα είναι η ίδια για όλες τις αναπτύξεις, παρόλαυτά διαφορετικές εκδόσεις κώδικα μπορεί να είναι ενεργές ανά ανάπτυξη. Για παράδειγμα, ο προγραμματιστής έχει κάποιες αλλαγές που δεν έχουν ακόμα κατατεθεί στην τοποθεσία ελέγχου, η τοποθεσία ελέγχου έχει κάποιες αλλαγές που δεν έχουν ακόμα κατατεθεί στην παραγωγή. Αλλά όλα μοιράζονται την ίδια βάση κώδικα, έτσι μπορούν να ταυτοποιηθούν ως διαφορετικές αναπτύξεις της ίδιας εφαρμογής. + diff --git a/content/el/concurrency.md b/content/el/concurrency.md new file mode 100644 index 000000000..372ed8a2f --- /dev/null +++ b/content/el/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Παραλληλία +### Κλιμάκωση προς τα έξω μέσω του μοντέλου διεργασιών + +Κάθε πρόγραμμα υπολογιστή, όταν εκτελείται, αντιπροσωπεύεται από μία ή περισσότερες διεργασίες. Οι εφαρμογές ιστου (web apps) έχουν λάβει μία ποικιλία μορφών εκτέλεσης διεργασιών. Για παράδειγμα, οι διεργασίες PHP τρέχουν ως διεργασίες απόγονοι (child processes) του Apache, που εκκινούνται κατά ανάγκη του όγκου αιτημάτων. Οι διεργασίες Java χρησιμοποιούν την αντίθετη προσέγγιση, με τη JVM να παρέχει μια μαζική υπερδιεργασία που δεσμέυει ένα μεγάλο κομμάτι των πόρων συστήματος (CPU και μνήμη) κατά την εκκίνηση, με την παραλληλία να διαχειρίζεται εσωτερικά μέσω ινών εκτέλεσης (threads). Και στις δυο περιπτώσεις, οι εκτελούμενες διεργασίες είναι μόνο ελάχιστα ορατές στους προγραμματιστές της εφαρμογής. + +![Η κλιμάκωση εκφράζεται από εκτελούμενες διεργασίες, η διαφοροποίηση του φόρτου εργασίας εκφράζεται από τύπους διεργασιών.](/images/process-types.png) + +**Στην εφαρμογή δώδεκα παραγόντων, οι διεργασίες είναι πολίτες πρώτης τάξης.** Οι διεργασίες στην εφαρμογή δώδεκα παραγόντων προσιδιάζουν σε αρκετά στοιχεία το [μοντέλο διεργασιών του unix (unix process model) για την εκτέλεση δαιμόνων διαχείρισης (service daemons)](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Χρησιμοποιώντας αυτό το μοντέλο, ο προγραμματιστής μπορεί να δομήσει την εφαρμογή έτσι ώστε να διαχειριστεί μια ποικιλία φόρτου εργασίας με το να αναθέτει κάθε τύπο εργασίας σε ένα *τύπο διεργασίας* (*process type*). Για παράδειγμα, τις αιτήσεις HTTP μπορεί να τις χειριστεί μια διεργασία ιστού (web process), και τις μακρά εκτελούμενες εργασίες παρασκηνίου μπορεί να τις χειριστεί μια διεργασία εργάτη (worker process). + +Αυτό δεν αποκλείει μεμονωμένες διεργασίες από το να διαχειριστούν την δική τους εσωτερική πολυπλεξία, μέσω ινών εκτέλεσης (threads) μέσα στην εκτελούμενη VM, είτε μέσω του μοντέλου async/evented όπως βρίσκεται σε εργαλεία όπως το [EventMachine](https://github.com/eventmachine/eventmachine), το [Twisted](http://twistedmatrix.com/trac/), ή το [Node.js](http://nodejs.org/). Αλλά μια μεμονωμένη VM μπορεί να κλιμακωθεί μόνο τόσο (κάθετη κλιμάκωση, vertical scale), οπότε η εφαρμογή πρέπει επίσης να μπορεί να εξαπλωθεί σε περισσότερες διεργασίες εκτελούμενες σε πολλαπλά φυσικά μηχανήματα. + +Το μοντέλο διεργασιών (process model) πραγματικά λάμπει όταν είναι η ώρα για κλιμάκωση προς τα έξω (scale out). Η [φύση των διεργασιών δώδεκα παραγόντων όπου είναι οριζόντια διαχωρίσιμες και δεν μοιράζονται τίποτα](./processes) σημαίνει ότι η αύξηση παραλληλίας είναι μια απλή και αξιόπιστη διαδικασία. Η συστοιχία των τύπων διεργασιών και του αριθμού διεργασιών κάθε τύπου είναι γνωστή ως *σχηματισμός διεργασιών* (*process formation*). + +Οι διεργασίες της εφαρμογής δώδεκα παραγόντων [δεν πρέπει ποτέ να συμπεριφέρονται σαν δαίμονες (daemonize)](http://dustin.github.com/2010/02/28/running-processes.html) ή να γράφουν αρχεία PID (PID files). Αντίθετα, βασίζονται στον διαχειριστή διεργασιών του λειτουργικού συστήματος (operating system's process manager) (όπως το [systemd](https://www.freedesktop.org/wiki/Software/systemd/), σε ένα κατανεμημένο διαχειριστή διεργασιών σε μια πλατφόρμα υπολογιστικού νέφους, ή σε ένα εργαλείο όπως το [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) κατά την υλοποίηση) για να διαχειριστούν [ροές εξόδου (output streams)](./logs), να διαχειριστούν διεργασίες που κατέρρευσαν, και να διαχειριστούν επανεκκινήσεις και τερματισμούς από το χρήστη. diff --git a/content/el/config.md b/content/el/config.md new file mode 100644 index 000000000..fbcbdf769 --- /dev/null +++ b/content/el/config.md @@ -0,0 +1,22 @@ +## III. Παραμετροποίηση +### Αποθήκευση παραμέτρων στο περιβάλλον + +Οι *παράμετροι* (*config*) μιας εφαρμογής είναι όλα εκείνα που είναι πιθανό να αλλάζουν ανά [ανάπτυξη της εφαρμογής](./codebase) (έλεγχος, παραγωγή, περιβάλλον προγραμματιστή, κλπ). Αυτό περιλαμβάνει: + +* Αναγνωριστικά πόρων (resource handles) στη βάση δεδομένων, στο Memcached, και άλλες [υπηρεσίες υποστήριξης](./backing-services) +* Διαπιστευτήρια (credentials) για εξωτερικές υπηρεσίες όπως το Amazon S3 ή το Twitter +* Τιμές σχετικές με μια συγκεκριμένη ανάπτυξη όπως το κανονικό όνομα φιλοξενητή (canonical hostname) της ανάπτυξης + +Οι εφαρμογές μερικές φορές αποθηκέυουν τις παραμέτρους ως σταθερές στον κώδικα. Αυτό αποτελεί παραβίαση των δώδεκα παραγόντων, το οποίο απαιτεί **αυστηρό διαχωρισμό παραμέτρων από τον κώδικα**. Οι παράμετροι διαφοροποιούνται σημαντικά μεταξύ αναπτύξεων, ο κώδικας όχι. + +Ένα τέστ litmus για το αν μία εφαρμογή έχει αφήσει έξω την παραμετροποίηση με σωστό τρόπο είναι εάν η βάση κώδικα μπορει να γίνει ανοιχτού κώδικα ανά πάσα στιγμή, χωρίς να γίνει γνωστό κανένα διαπιστευτήριο. + +Σημειώστε ότι αυτός ο ορισμός της παραμετροποίησης **δεν** συμπεριλαμβάνει την εσωτερική παραμετροποίηση της εφαρμογής, όπως το `config/routes.rb` στο Rails, ή πως [συνδέονται τα μέρη του κώδικα](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) στο [Spring](http://spring.io/). Αυτός ο τύπος παραμετροποίησης δεν μεταβάλλεται μεταξύ αναπτύξεων, οπότε είναι καλύτερα να γίνεται στον κώδικα. + +Μια άλλη προσέγγιση στην παραμετροποίηση είναι η χρήση αρχείων παραμέτρων (config files) τα οποία δεν περιλαμβάνονται στο αποθετήριο της εφαρμογής, όπως το `config/database.yml` στο Rails. Αυτό αποτελεί μια μεγάλη βελτίωση από το να χρησιμοποιούνται σταθερές στον κώδικα, αλλά ακόμα έχει αδυναμίες: είναι έυκολο κατά λάθος να συμπεριληφθεί το αρχείο στο αποθετήριο, υπάρχει μία τάση τα αρχεία παραμέτρων να είναι διασκορπισμένα σε διάφορα μέρη και σε διαφορετικές μορφές, καθιστώντας έτσι δύσκολο να δει και να διαχειριστεί κάποιος όλες τις παραμέτρους σε ένα μέρος. Επιπλέον, αυτές οι μορφές τείνουν να είναι συγκεκριμένες ως προς τη γλώσσα προγραμματισμού ή το πλάισιο ανάπτυξης της εφαρμογής. + +**Η εφαρμογή δώδεκα παραγόντων αποθηκέυει την παραμετροποίηση σε *μεταβλητές περιβάλλοντος* (*environment variables*, *env vars*, *env*)**. Οι μεταβλητές περιβάλλοντος αλλάζουν έυκολα μεταξύ αναπτύξεων της εφαρμογής χωρίς να αλλάξει ο κώδικας, σε σχέση με τα αρχεία παραμέτρων, υπάρχει μικρή πιθανότητα κατά λάθος να εισαχθούν στο αποθετήριο του κώδικα, και επίσης πάλι σε σχέση με τα αρχεία παραμέτρων, ή άλλους μηχανισμούς παραμετροποίησης όπως τα Java System Properties, αποτελούν ένα πρότυπο ανεξάρτητο από τη γλώσσα προγραμματισμού και το λειτουργικό σύτημα. + +Μια άλλη πλευρά της διαχείρισης παραμέτρων είναι η ομαδοποίηση. Μερικές φορές οι εφαρμογές στοιβάζουν παραμέτρους σε ονομαστικές ομάδες (συχνά καλούνται "περιβάλλοντα") που παίρνουν το όνομά τους απο συγκεκριμένες αναπτύξεις, όπως τα περιβάλλοντα `development` (`υλοποίηση`), `test` (`τέστ`), και `production` (`παραγωγή`) στο Rails. Αυτή η μέθοδος δεν κλιμακώνεται καθαρά: καθώς περισσότερες αναπτύξεις της εφαρμογής δημιουργούνται, νέα ονόματα περιβαλλόντων γίνονται απαραίτητα, όπως `staging` (`έλεγχος`) ή `qa`. Καθώς το έργο επεκτείνεται περαιτέρω, οι προγραμματιστές μπορει να προσθέσουν τα δικά τους ειδικά περιβάλλοντα όπως `joes-staging`, συνεπαγόμενα μια συνδυαστική έκρηξη από παραμετροποιήσεις που κάνουν την διαχείριση αναπτύξεων της εφαρμογής πολύ εύθραυστη. + +Σε μια εφαρμογή δώδεκα παραγόντων, οι μεταβλητές περιβάλλοντος αποτελούν στοιχεία λεπτοφυούς ελέγχου, το καθένα πλήρως ορθογώνιο σε άλλες μεταβλητές περιβάλλοντος. Ποτέ δεν ομαδοποιούνται μαζί ως "περιβάλλοντα", αντιθέτως διαχειρίζονται ανεξάρτητα για κάθε ανάπτυξη της εφαρμογής. Αυτό είναι ένα μοντέλο που κλιμακώνεται ομαλά προς τα πάνω καθώς η εφαρμογή φυσικά διευρύνεται σε περισσότερες αναπτύξεις κατά της διάρκεια της ζωής της. diff --git a/content/el/dependencies.md b/content/el/dependencies.md new file mode 100644 index 000000000..0a922190e --- /dev/null +++ b/content/el/dependencies.md @@ -0,0 +1,12 @@ +## II. Εξαρτήσεις +### Εξαρτήσεις εκπεφρασμένα δηλωμένες και απομονωμένες + +Οι περισσότερες γλώσσες προγραμματισμού προσφέρουν ένα σύστημα πακεταρίσματος για διανομή των βιβλιοθηκών υποστήριξης, όπως το [CPAN](http://www.cpan.org/) για την Perl ή το [Rubygems](http://rubygems.org/) για τη Ruby. Οι βιβλιοθήκες που εγκαθιστούνται μέσω του συστήματος πακεταρίσματος μπορουν να εγκατασταθούν είτε για όλο το σύστημα (γνωστές ως "καθολικά πακέτα", "site packages") είτε τοπικά μέσα στο φάκελο που περιέχει την εφαρμογή (γνωστές ως "προμηθευμένες", "vendoring" ή ως "δέσμες", "bundling"). + +**Μία εφαρμογή δώδεκα παραγόντων ποτέ δεν εξαρτάται απο την υπόρρητη ύπαρξη καθολικών πακέτων.** Δηλώνει όλες τις εξαρτήσεις, ολοκληρωτικά και ακριβώς, μέσω ενός δηλωτικού αρχείου *δήλωσης εξαρτήσεων* (*dependency declaration* manifest). Επιπλέον, χρησιμοποιεί ένα εργαλείο *απομόνωσης εξαρτήσεων* (*dependency isolation*) κατά την διάρκεια της εκτέλεσης ώστε να εξασφαλίσει ότι καμία υπόρρητη εξάρτηση δεν θα "διαρρέυσει" απο το περιβάλλον σύστημα. Η πλήρης και εκπεφρασμένη δήλωση εξαρτήσεων εφαρμόζεται το ίδιο και στο περιβάλλον παραγωγής και στο περιβάλλον υλοποίησης (του προγραμματιστή). + +Για παράδειγμα, το [Bundler](https://bundler.io/) για τη Ruby προσφέρει τη δομή δηλωτικού `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/) για δήλωση εξαρτήσεων, και η στατική διασύνδεση μπορεί να προσφέρει απομόνωση εξαρτήσεων. Όποια και αν είναι η αλυσίδα εργαλείων, η δήλωση εξαρτήσεων και η απομόνωση πρέπει πάντα να χρησιμοποιούνται μαζί -- μόνο η μία ή η άλλη δεν είναι ικανό για τους δώδεκα παράγοντες. + +Ένα πλεονέκτημα της εκπεφρασμένης δήλωσης εξαρτήσεων είναι ότι απλοποιεί το στήσιμο της εφαρμογής για προγραμματιστές οι οποίοι είναι καινούργιοι στην εφαρμογή. Ο νέος προγραμματιστής μπορεί να κατεβάσει τη βάση κώδικα της εφαρμογής στο δικό του υπολογιστή, απαιτώντας να εγκατασταθούν μόνο το εκτελέσιμο της γλώσσας προγραμματισμού (language runtime) και ο διαχειριστής εξαρτήσεων (dependency manager) ως προαπαιτούμενα. Αυτά θα είναι ικανά να στήσουν οτιδήποτε χρειάζεται ώστε να τρέξει η εφαρμογή μέσω μιάς ντετερμινιστικής *εντολής κατασκευής* (*build command*). Για παράδειγμα, η εντολή κατασκευής για το Ruby/Bundler είναι `bundle install`, ενώ για την Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) είναι `lein deps`. + +Οι εφαρμογές δώδεκα παραγόντων επίσης δεν εξαρτώνται από την υπόρρητη ύπαρξη οποιουδήποτε εργαλείου συστήματος. Μερικά παραδείγματα είναι το ImageMagick ή το `curl`. Μπορεί αυτά τα εργαλεία να υπάρχουν σε πολλά ή στα περισσότερα συστήματα, αλλά κανείς δεν εγγυάται ότι θα υπάρχουν σε όλα τα συστήματα που θα τρέξουν την εφαρμογή στο μέλλον, ή ότι η έκδοση που θα υπάρχει θα είναι συμβατή με την εφαρμογή. Εάν η εφαρμογή χρειάζεται κάποιο τέτοιο εργαλείο συστήματος, αυτό το εργαλείο πρέπει να γίνει προμηθέυσιμο (vendored) μέσα στην εφαρμογή. diff --git a/content/el/dev-prod-parity.md b/content/el/dev-prod-parity.md new file mode 100644 index 000000000..338303b01 --- /dev/null +++ b/content/el/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Ισοτιμία dev/prod +### Κράτησε τα περιβάλλοντα υλοποίησης, ελέγχου και παραγωγής όσο πιο όμοια γίνεται + +Ιστορικά, έχουν υπάρξει μεγάλα χάσματα μεταξύ υλοποίησης (development) (ο προγραμματιστής να κάνει αλλαγές σε πραγματικό χρόνο σε μία τοπική [ανάπτυξη](./codebase) της εφαρμογής) και της παραγωγής (production) (μία εκτελούμενη ανάπτυξη της εφαρμογής προσβάσιμη μόνο από τελικούς χρήστες). Αυτά τα χάσματα εκδηλώνονται σε τρία σημεία: + +* **Το χρονικό χάσμα**: Ένας προγραμματιστής μπορεί να δουλέυει σε ένα κώδικα που παίρνει μέρες, εβδομάδες, ή ακόμα και μήνες να φτάσει στην παραγωγή. +* **Το χάσμα προσωπικού**: Οι προγραμματιστές (developers) γράφουν κώδικα, οι επιχειρησιακοί μηχανικοί (ops engineers) τον αναπτύσσουν. +* **Το εργαλειακό χάσμα**: Οι προγραμματιστές μπορεί να χρησιμοποιούν εργαλεία όπως το Nginx, την SQLite, και το OS X, αλλά η αναπτύξη της παραγωγής χρησιμοποιεί το Apache, τη MySQL, και το Linux. + +**Η εφαρμογή δώδεκα παραγόντων είναι σχεδιασμένη για [συνεχή αναπτύξη (continuous deployment)](http://avc.com/2011/02/continuous-deployment/) με το να κρατάει το χάσμα μεταξύ υλοποίησης (development) και παραγωγής (production) μικρό.** Κοιτώντας τα τρία χάσματα που περιγράψαμε παραπάνω: + +* Μείωσε το χρονικό χάσμα: ένας προγραμματιστής μπορεί να γράψει κώδικα και να τον αναπτύξει μερικές ώρες ή ακόμα και μερικά λεπτά αργότερα. +* Μείωσε το χάσμα προσωπικού: οι προγραμματιστές που έγραψαν τον κώδικα ασχολούνται στενά με την ανάπτυξή του και παρακολουθούν την συμπεριφορά του στην παραγωγή. +* Μείωσε το εργαλειακό χάσμα: κράτησε τα περιβάλλοντα υλοποίησης (development) και παραγωγής (production) όσο πιο όμοια γίνεται. + +Συνοψίζοντας τα παραπάνω σε ένα πίνακα: + + + + + + + + + + + + + + + + + + + + + + +
Παραδοσιακή εφαρμογήΕφαρμογή δώδεκα παραγόντων
Χρόνος μεταξύ αναπτύξεωνΕβδομάδεςΏρες
Συγγραφείς κώδικα ή αναπτυκτές του κώδικαΔιαφορετικοί άνθρωποιΊδιοι άνθρωποι
Περιβάλλοντα υλοποίησης (dev) ή παραγωγής (production)ΑποκλίνονταΌσο πιο όμοια γίνεται
+ +Οι [υπηρεσίες υποστήριξης](./backing-services), όπως η βάση δεδομένων (database) της εφαρμογής, το σύστημα ουρών (queueing system), ή η προσωρινή μνήμη (cache), είναι ένας τόπος όπου η ισοτιμία dev/prod είναι σημαντική. Πολλές γλώσσες προγραμματισμού προσφέρουν βιβλιοθήκες οι οποίες απλοποιούν την πρόσβαση στην υπηρεσία υποστήριξης, συμπεριλαμβανομένων *προσαρμογέων* (*adapters*) για διάφορους τύπους υπηρεσιών. Μερικά παραδείγματα περιέχονται στον παρακάτω πίνακα. + + + + + + + + + + + + + + + + + + + + + + + + + + +
ΤύποςΓλώσσα ΠρογραμματισμούΒιβλιοθήκηΠροσαρμογείς
Βάση δεδομένωνRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
Ουρά εργασιώνPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
Προσωρινή μνήμηRuby/RailsActiveSupport::CacheMemory, filesystem, Memcached
+ +Οι προγραμματιστές μερικές φορές βρίσκουν πολύ ελκυστικό να χρησιμοποιήσουν μια ελαφρά υπηρεσία υποστήριξης στο τοπικό περιβάλλον ανάπτυξής τους, ενώ μια πιο στιβαρή και εύρωστη υπηρεσία υποστήριξης θα χρησιμοποιηθεί στην παραγωγή. Για παράδειγμα, χρησιμοποιώντας την SQLite τοπικά και την PostgreSQL στην παραγωγή, ή την τοπική μνήμη διεργασίας για προσωρινή μνήμη κατά την υλοποίηση και το Memcached στην παραγωγή. + +**Ο προγραμματιστής δώδεκα παραγόντων αντιστέκεται στην ορμή να χρησιμοποιήσει διαφορετικές υπηρεσίες υποστήριξης μεταξύ υλοποίησης και παραγωγής**, ακόμα και όταν οι προσαρμογείς θεωρητικά μπορούν να αφαιρέσουν τις επιμέρους διαφορές στις υπηρεσίες υποστήριξης. Οι διαφορές μεταξύ υπηρεσιών υποστήριξης σημαίνουν ότι μικρές ασυμβατότητες ανακύπτουν, που προκαλούν τον κώδικα που λειτουργούσε και πέρναγε τα τεστ στην υλοποίηση ή στον έλεγχο να αποτυγχάνει στην παραγωγή. Αυτού του είδους τα σφάλματα δημιουργούν τριβή η οποία είναι αντικίνητρο στην συνεχή ανάπτυξη (continuous deployment). Το κόστος αυτής της τριβής και της επακόλουθης μείωσης της συνεχούς ανάπτυξης είναι εξαιρετικά υψηλό όταν ληφθεί υπόψη η συσσώρευσή του κατά την διάρκεια του χρόνου ζωής της εφαρμογής. + +Οι ελαφρές τοπικές υπηρεσίες είναι λιγότερο ελκυστικές από ότι ήταν κάποτε. Οι μοντέρνες υπηρεσίες υποστήριξης όπως το Memcached, η PostgreSQL, και το RabbitMQ δεν είναι δύσκολο να εγκατασταθούν και να τρέξουν χάριν στα μοντέρνα συστήματα πακεταρίσματος (modern packaging systems), όπως το [Homebrew](http://mxcl.github.com/homebrew/) και το [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Εναλλακτικά, τα εργαλεία δηλωμένων παροχών (declarative provisioning tools) όπως το [Chef](http://www.opscode.com/chef/) και το [Puppet](http://docs.puppetlabs.com/) συνδυασμένα με ελαφρά εικονικά περιβάλλοντα (light-weight virtual environments) όπως το [Docker](https://www.docker.com/) και το [Vagrant](http://vagrantup.com/) επιτρέπουν στους προγραμματιστές να τρέξουν τοπικά περιβάλλοντα τα οποία προσομοιάζουν κατά πολύ τα περιβάλλοντα παραγωγής. Το κόστος εγκατάστασης και χρήσης αυτών των συστημάτων είναι χαμηλό συγκρινόμενο με το πλεονέκτημα της ισοτιμίας dev/prod και της συνεχούς αναπτύξεως. + +Οι προσαρμογείς στις διαφορετικές υπηρεσίες υποστήριξης είναι ακόμα χρήσιμοι, επειδή η μετάβαση σε νέες υπηρεσίες υποστήριξης γίνεται σχετικά αβασάνιστα. Αλλά όλες οι αναπτύξεις (deploys) της εφαρμογής (περιβάλλοντα υλοποίησης, ελέγχου, παραγωγής) θα πρέπει να χρησιμοποιούν τον ίδιο τύπο και έκδοση για κάθε μια από τις υπηρεσίες υποστήριξης. diff --git a/content/el/disposability.md b/content/el/disposability.md new file mode 100644 index 000000000..efa75e25c --- /dev/null +++ b/content/el/disposability.md @@ -0,0 +1,14 @@ +## IX. Απορριψιμότητα +### Μεγιστοποίηση ευρωστίας της εφαρμογής μέσω γρήγορης εκκίνησης και κομψού τερματισμού + +**Οι [διεργασίες](./processes) της εφαρμογής δώδεκα παραγόντων είναι *απορρίψιμες* (*disposable*), δηλαδή μπορούν να εκκινηθούν και να τερματιστούν μέσα σε μια στιγμή.** Αυτο διευκολύνει τη γρήγορη ελαστική κλιμάκωση, τη γοργή ανάπτυξη του [κώδικα της εφαρμογής](./codebase) ή τις αλλαγές στις [παραμέτρους](./config), και την ευρωστία των αναπτύξεων της εφαρμογής στην παραγωγή. + +Οι διεργασίες θα πρέπει να προσπαθούν να **ελαχιστοποιούν τον χρόνο εκκίνησης**. Ιδανικά, μια διεργασία παίρνει μερικά δευτερόλεπτα απο τη στιγμή της εντολής εκκίνησης μέχρι τη στιγμή που είναι σηκωμένη και έτοιμη να λάβει αιτήσεις ή εργασίες. Ο σύντομος χρόνος εκκίνησης παρέχει περισσότερη ευκινησία στην διαδικασία [έκδοσης](./build-release-run) και κλιμάκωσης προς τα πάνω, και βοηθά την ευρωστία, επειδή ο διαχειριστής διεργασιών μπορεί πιο εύκολα να μετακινήσει διεργασίες σε νέα φυσικά μηχανήματα όταν χρειαστεί. + +Οι διεργασίες **τερματίζουν κομψά όταν λάβουν το σήμα [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** από τον διαχειριστή διεργασιών. Για μια διεργασία ιστού (web process), ο κομψός τερματισμός επιτυγχάνεται με το να πάυει να ακούει τη θύρα εξυπηρέτησης (αρνούμενη έτσι νέες αιτήσεις), επιτρέποντας σε τρέχουσες αιτήσεις να ολοκληρωθούν, και έπειτα να κάνει έξοδο. Σε αυτό το μοντέλο εννοείται πως οι αιτήσεις HTTP είναι σύντομες (όχι παραπάνω από μερικά δευτερόλεπτα), ή στην περίπτωση μακράς δειγματοληψίας (long polling), ο πελάτης (client) θα πρέπει να προσπαθήσει απρόσκοπτα να επανασυνδεθεί όταν η σύνδεση χαθεί. + +Για μια διεργασία εργάτη (worker process), ο κομψός τερματισμός επιτυγχάνεται με το να επιστρέφει την τρέχουσα εργασία πίσω στην ουρά εργασιών. Για παράδειγμα, στο [RabbitMQ](http://www.rabbitmq.com/) ο εργάτης μπορεί να στείλει ένα [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack), στο [Beanstalkd](https://beanstalkd.github.io), η εργασία επιστρέφεται στην ουρά αυτόματα όποτε ένας εργάτης αποσυνδέεται. Συστήματα βασισμένα σε κλείδωμα (lock-based systems) όπως το [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) πρέπει να σιγουρευτούν ότι απελευθέρωσαν το κλείδωμα από την εγγραφή της εργασίας. Σε αυτό το μοντέλο εννοείται πως όλες οι εργασίες είναι [επανεισδόχιμες (reentrant)](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), το οποίο τυπικά επιτυγχάνεται με το να περιέχονται τα αποτελέσματα της εργασίας σε μια συναλλαγή (transaction), ή να είναι η λειτουργία [ταυτοδύναμη (idempotent)](http://en.wikipedia.org/wiki/Idempotence). + +Οι διεργασίες θα πρέπει επίσης να είναι **εύρωστες απέναντι στον ξαφνικό θάνατο**, στην περίπτωση αστοχίας του υποκείμενου υλικού. Καθόσον αυτό είναι ένα πολύ πιο σπάνιο φαινόμενο από ένα κομψό τερματισμό μέσω `SIGTERM`, μπορεί παρολαυτά να συμβεί. Η συνιστώμενη προσέγγιση είναι η χρήση ενός εύρωστου διαχειριστή ουρών, όπως το Beanstalkd, ο οποίος επιστρέφει τις εργασίες πίσω στην ουρά όταν οι πελάτες αποσυνδεθούν ή λήξει ο χρόνος τους. Σε κάθε περίπτωση, μια εφαρμογή δώδεκα παραγόντων είναι δομημένη έτσι ώστε να διαχειρίζεται απρόβλεπτους, μη κομψούς τερματισμούς. Η [σχεδίαση Crash-only](http://lwn.net/Articles/191059/) πάει αυτή την έννοια στην [λογική της κατάληξη](http://docs.couchdb.org/en/latest/intro/overview.html). + + diff --git a/content/el/intro.md b/content/el/intro.md new file mode 100644 index 000000000..ffe0c79f4 --- /dev/null +++ b/content/el/intro.md @@ -0,0 +1,12 @@ +Εισαγωγή +======== + +Στη μοντέρνα εποχή, το λογισμικό συνήθως παρέχεται ως υπηρεσία: καλούμενο *εφαρμογές ιστού* (*web apps*), ή *λογισμικό-ως-υπηρεσία* (*software-as-a-service*). Η εφαρμογή δώδεκα παραγόντων είναι μια μεθοδολογία κατασκευής εφαρμογών λογισμικού-ως-υπηρεσίας όπου: + +* Χρησιμοποιεί **δηλωτικές** μορφές (**declarative** formats) για να στήσει τον αυτοματισμό, να ελαχιστοποιήσει το χρόνο και το κόστος για νέους προγραμματιστές να συμμετέχουν στο έργο, +* Έχει ένα **καθαρό συμβόλαιο** (**clean contract**) με το υποκείμενο λειτουργικό σύστημα, προσφέροντας **μέγιστη φορητότητα** (**maximum portability**) μεταξύ περιβαλλόντων εκτέλεσης, +* Είναι κατάλληλη για **ανάπτυξη** (**deployment**) σε μοντέρνες πλατφόρμες υπολογιστικού νέφους (**cloud platforms**), καθιστώντας περιττή την ανάγκη για εξυπηρετητές και διαχείριση συστημάτων, +* **Ελαχιστοποιεί την απόκλιση** μεταξύ υλοποίησης (development) και παραγωγής (production), διευκολύνοντας την **συνεχή ανάπτυξη** (**continuous deployment**) για μέγιστη ευκινησία (maximum agility), +* Και μπορεί να **κλιμακωθεί προς τα πάνω** (**scale up**) χωρίς σημαντικές αλλαγές στα εργαλεία, στην αρχιτεκτονική, ή στις πρακτικές υλοποίησης. + +Η μεθοδολογία δώδεκα παραγόντων μπορεί να εφαρμοστεί σε εφαρμογές οι οποίες είναι γραμμένες σε οποιαδήποτε γλώσσα προγραμματισμού, και οι οποίες χρησιμοποιούν οποιοδήποτε συνδυασμό από υπηρεσίες υποστήριξης (βάση δεδομένων, ουρά εργασιών, προσωρινή μνήμη, κλπ). diff --git a/content/el/logs.md b/content/el/logs.md new file mode 100644 index 000000000..8e3c3d012 --- /dev/null +++ b/content/el/logs.md @@ -0,0 +1,16 @@ +## XI. Αρχεία συμβάντων +### Τα αρχεία συμβάντων ως ροές συμβάντων + +Τα *αρχεία συμβάντων* (*logs*) παρέχουν ορατότητα στη συμπεριφορά της εκτελούμενης εφαρμογής. Σε περιβάλλοντα εξυπηρετητή (server-based environments) συνήθως γράφονται σε ένα αρχείο στο δίσκο (ένα "logfile"), αλλά αυτό είναι μόνο μια μορφή εξόδου (output format). + +Τα αρχεία συμβάντων είναι η [ροή (stream)](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) των συσσωρευμένων, χρονικά διατεταγμένων συμβάντων που συλλέγονται από τις ροές εξόδου (output streams) όλων των εκτελούμενων διεργασιών και υπηρεσιών υποστήριξης. Τα αρχεία συμβάντων στην ακατέργαστη μορφή τους είναι τυπικά μια μορφή κειμένου με ένα συμβάν ανά γραμμή (ωστόσο τα ίχνη εκτέλεσης ή backtraces από σφάλματα μπορεί να επεκτείνονται σε πολλαπλές γραμμές). Τα αρχεία συμβάντων δεν έχουν δεδομένη αρχή ή τέλος, αλλά ρέουν συνεχόμενα όσο η εφαρμογή λειτουργεί. + +**Μια εφαρμογή δώδεκα παραγόντων ποτέ δεν ασχολείται με τη δρομολόγηση ή την αποθήκευση της ροής εξόδου (output stream) της.** Δεν πρέπει να επιχειρεί να γράψει ή να διαχειριστεί logfiles. Αντίθετα, κάθε εκτέλούμενη διεργασία γράφει τη ροή συμβάντων της , χωρίς προσωρινή αποθήκευση και συσσώρευση (unbuffered), στο `stdout` (τυπική έξοδο). Κατά την υλοποίηση τοπικά, ο προγραμματιστής θα δεί αυτή τη ροή στο προσκήνιο του τερματικού του για να παρατηρήσει την συμπεριφορά της εφαρμογής. + +Στις αναπτύξεις ελέγχου ή παραγωγής (staging or production deploys), η ροή κάθε διεργασίας θα συλλεγεί από το περιβάλλον εκτέλεσης, θα συνδεθεί μαζί με όλες τις άλλες ροές από την εφαρμογή, και θα δρομολογηθεί σε ένα ή περισσότερους τελικούς προορισμούς για εξέταση και αποθήκευση μακράς διάρκειας. Αυτοί οι προορισμοί δεν είναι ούτε ορατοί ούτε παραμετροποιήσιμοι από την εφαρμογή, και αντιθέτως είναι τελείως διαχειριζόμενοι από το περιβάλλον εκτέλεσης. Δρομολογητές συμβάντων ανοικτού κώδικα (όπως το [Logplex](https://github.com/heroku/logplex) και το [Fluentd](https://github.com/fluent/fluentd)) είναι διαθέσιμοι για αυτό το σκοπό. + +Η ροή συμβάντων μιας εφαρμογής μπορεί να δρομολογηθεί σε ένα αρχείο, ή να παρακολουθηθεί σε πραγματικό χρόνο μέσω tail σε ένα τερματικό. Το σημαντικότερο, η ροή μπορεί να σταλθεί σε ένα σύστημα ανάλυσης και αρχειοθέτησης συμβάντων (log indexing and analysis system) όπως το [Splunk](http://www.splunk.com/), ή σε ένα γενικού σκοπού σύστημα ανάλυσης δεδομένων (data warehousing system) όπως το [Hadoop/Hive](http://hive.apache.org/). Αυτά τα συστήματα επιτρέπουν μεγαλή ισχύ και ευελιξία στην ενδοσκόπηση της συμπεριφοράς της εφαρμογής σε σχέση με το χρόνο, συμπεριλαμβανομένων: + +* Εύρεση συγκεκριμένων συμβάντων στο παρελθόν. +* Γραφήματα τάσεων μεγάλης κλίμακας (όπως αιτήσεις ανά λεπτό). +* Ενεργή ειδοποίηση (active alerting) σύμφωνα με ευρετικά κριτήρια δοσμένα από το χρήστη (user-defined heuristics) (όπως μια ειδοποίηση όταν η ποσότητα σφαλμάτων ανά λεπτό υπερβαίνει ένα συγκεκριμένο όριο). diff --git a/content/el/port-binding.md b/content/el/port-binding.md new file mode 100644 index 000000000..edf9e0bb6 --- /dev/null +++ b/content/el/port-binding.md @@ -0,0 +1,14 @@ +## VII. Πρόσδεση θυρών +### Εξαγωγή υπηρεσιών μέσω πρόσδεσης θυρών + +Οι εφαρμογές (παγκόσμιου) ιστού (web apps) μερικές φορές εκτελούνται μέσα σε ένα εξυπηρετητή ιστού (webserver container). Για παράδειγμα, εφαρμογές PHP μπορεί να τρέχουν ως ένα κομμάτι μέσα στο [Apache HTTPD](http://httpd.apache.org/), ή εφαρμογές Java μπορεί να τρέχουν μέσα στο [Tomcat](http://tomcat.apache.org/). + +**Η εφαρμογή δώδεκα παραγόντων είναι εντελώς αυτοτελής (self-contained)** και δεν βασίζεται στην εισδοχή ενός εξυπηρετηή ιστού (webserver) κατά την εκτέλεση από το περιβάλλον εκτέλεσης για να δημιουργήσει μια υπηρεσία ιστού (web-facing service). Η εφαρμογή ιστου (web app) **εξάγει το HTTP ως υπηρεσία μέσω πρόσδεσης σε μια θύρα (binding to a port)**, και αναμένοντας αιτήσεις εξυπηρέτησης που έρχονται από αυτή τη θύρα. + +Σε ένα τοπικό περιβάλλον υλοποίησης, ο προγραμματιστής επισκέπτεται ένα URL υπηρεσίας όπως το `http://localhost:5000/` για να έχει πρόσβαση στην υπηρεσία που εξάγεται απο την εφαρμογή του. Στην παραγωγή, ένα επίπεδο δρομολόγησης χειρίζεται τις αιτήσεις δρομολόγησης από ένα δημόσιο φιλοξενητή πρός τις διεργασίες ιστού προσδεδεμένες σε θύρα (port-bound web processes). + +Αυτό τυπικά υλοποιείται χρησιμοποιώντας [δήλωση εξαρτήσεων](./dependencies) για να προστεθεί μια βιβλιοθήκη εξυπηρετητή ιστου (webserver library) στην εφαρμογή, όπως το [Tornado](http://www.tornadoweb.org/) για τη Python, το [Thin](http://code.macournoyer.com/thin/) για τη Ruby, ή το [Jetty](http://www.eclipse.org/jetty/) για τη Java και άλλες γλώσσες που βασίζονται στη JVM. Αυτό συμβαίνει εξ' ολοκλήρου στο *χώρο χρήστη* (*user space*), δηλαδή, μέσα στον κώδικα της εφαρμογής. Το συμβόλαιο (contract) με το περιβάλλον εκτέλεσης είναι η πρόσδεση σε μια θύρα για να εξυπηρετηθούν αιτήσεις. + +Το HTTP δεν είναι η μόνη υπηρεσία που μπορεί να εξαχθεί μέσω πρόσδεσης θυρών (port binding). Σχεδόν κάθε είδος λογισμικού εξυπηρετητή (server software) μπορέι να τρέξει μέσω μιας διεργασίας που προσδένεται σε θύρα και αναμένει εισερχόμενα αιτήματα εξυπηρέτησης. Παραδείγματα περιλαμβάνουν το [ejabberd](http://www.ejabberd.im/) (που μιλάει [XMPP](http://xmpp.org/)), και το [Redis](http://redis.io/) (που μιλάει το [πρωτόκολλο Redis](http://redis.io/topics/protocol)). + +Σημειώστε επίσης ότι η προσέγγιση της πρόσδεσης θυρών σημαίνει ότι μία εφαρμογή μπορεί να γίνει [υπηρεσία υποστήριξης](./backing-services) για μια άλλη εφαρμογή, παρέχοντας το URL της εφαρμογής υποστήριξης ως ένα αναγνωριστικό πόρου (resource handle) στις [παραμέτρους (config)](./config) της εφαρμογής που θα την καταναλώσει. diff --git a/content/el/processes.md b/content/el/processes.md new file mode 100644 index 000000000..3f0669129 --- /dev/null +++ b/content/el/processes.md @@ -0,0 +1,14 @@ +## VI. Διεργασίες +### Εκτέλεση εφαρμογής ως μία ή περισσότερες διεργασίες χωρίς κατάσταση + +Η εφαρμογή εκτελείται στο περιβάλλον εκτέλεσης ως μία ή περισσότερες *διεργασίες* (*processes*). + +Στην απλούστερη των περιπτώσεων, ο κώδικας είναι ένα αυτόνομο σενάριο εντολών (script), το περιβάλλον εκτέλεσης είναι ο φορητός υπολογιστής του προγραμματιστή με εγκατεστημένο ένα εκτελέσιμο της γλώσσας προγραμματισμού, και η διεργασία κινείται μέσω της γραμμής εντολών (command line) (για παράδειγμα, `python my_script.py`). Στην άλλη πλευρά του φάσματος, μια ανάπτυξη εφαρμογής για παραγωγή μιας σύνθετης εφαρμογής μπορεί να χρησιμοποιήσει πολλούς [τύπους διεργασιών, ενσαρκωμένων σε μερικές διεργασίες](./concurrency). + +**Οι διεργασίες δώδεκα παραγόντων είναι χωρίς κατάσταση (stateless) και [δεν μοιράζονται τίποτα](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Οποιαδήποτε δεδομένα πρέπει να παραμείνουν πρέπει να aποθηκευθούν σε μία [υπηρεσία υποστήριξης](./backing-services) με κατάσταση (stateful), τυπικά μια βάση δεδομένων. + +Ο χώρος μνήμης ή το σύστημα αρχείων μιας διεργασίας μπορούν να χρησιμοποιηθούν ως μία σύντομη, μια και έξω προσωρινή μνήμη. Για παράδειγμα, να κατεβάσει ένα μεγάλο αρχείο, να δράσει πάνω σε αυτό, και να αποθηκέυσει τα αποτελέσματα στη βάση δεδομένων. Η εφαρμογή δώδεκα παραγόντων ποτέ δεν θεωρεί ως δεδομένο πως οτιδήποτε αποθηκέυτηκε προσωρινά στη μνήμη της ή στο δίσκο θα είναι διαθέσιμο και σε μια μελλοντική αίτηση για εξυπηρέτηση ή εργασία -- με πολλές διεργασίες κάθε τύπου να τρέχουν, οι πιθανότητες είναι υψηλές πως μια μελλοντική αίτηση για εξυπηρέτηση θα εξυπηρετηθεί από μια άλλη διεργασία. Ακόμα και εάν τρέχει μόνο μία διεργασία, μια επανεκκίνηση (πυροδοτημένη απο μια ανάπτυξη κώδικα, αλλαγή παραμέτρων, ή από το περιβάλλον εκτέλεσης που αλλάζει τη φυσική τοποθεσία της διεργασίας) συνήθως θα σβήσει όλη την τοπική (π.χ, μνήμη και σύστημα αρχείων) κατάσταση (state). + +Οι συσκευαστές περιουσιακών στοιχείων της εφαρμογής (asset packagers) όπως το [django-assetpackager](http://code.google.com/p/django-assetpackager/) χρησιμοποιούν το σύστημα αρχείων σαν προσωρινή μνήμη για μεταγλωττισμένα στοιχεία (compiled assets). Μια εφαρμογή δώδεκα παραγόντων προτιμά να κάνει αυτή τη μεταγλώττιση κατά το [στάδιο κατασκευής (build stage)](./build-release-run). Μερικοί συσκευαστές όπως το [Jammit](http://documentcloud.github.com/jammit/) και το [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html) μπορούν να ρυθμιστούν ώστε να συσκευάσουν τα assets κατά το στάδιο κατασκευής. + +Μερικά συστήματα ιστού (web systems) βασίζονται σε ["επίμονες συνεδρίες" ("sticky sessions")](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- δηλαδή, αποθηκέυουν προσωρινά τη συνεδρία χρήστη στη μνήμη της διεργασίας της εφαρμογής και θεωρούν πως οι μελλοντικές αιτήσεις για εξυπηρέτηση απο τον ίδιο χρήστη θα δρομολογηθούν στην ίδια διεργασία. Οι επίμονες συνεδρίες συνιστούν παράβαση των δώδεκα παραγόντων και δεν θα πρέπει ποτέ να χρησιμοποιούνται ή η εφαρμογή να βασίζεται σε αυτές. Τα δεδομένα κατάστασης συνεδρίας είναι καλύτερα να αποθηκευτούν σε μια αποθήκη δεδομένων (datastore) που διαθέτει χρόνο λήξης, όπως το [Memcached](http://memcached.org/) ή το [Redis](http://redis.io/). diff --git a/content/el/toc.md b/content/el/toc.md new file mode 100644 index 000000000..fa7580110 --- /dev/null +++ b/content/el/toc.md @@ -0,0 +1,38 @@ +Οι Δώδεκα Παράγοντες +==================== + +## [I. Βάση Κώδικα](./codebase) +### Μία βάση κώδικα με έλεγχο εκδόσεων, πολλές αναπτύξεις + +## [II. Εξαρτήσεις](./dependencies) +### Εξαρτήσεις εκπεφρασμένα δηλωμένες και απομονωμένες + +## [III. Παραμετροποίηση](./config) +### Αποθήκευση παραμέτρων στο περιβάλλον + +## [IV. Υπηρεσίες υποστήριξης](./backing-services) +### Υπηρεσίες υποστήριξης ως επισυναπτόμενοι πόροι + +## [V. Κατασκευή, έκδοση, εκτέλεση](./build-release-run) +### Αυστηρός διαχωρισμός μεταξύ των σταδίων μεταγλώττισης/κατασκευής και εκτέλεσης + +## [VI. Διεργασίες](./processes) +### Εκτέλεση εφαρμογής ως μία ή περισσότερες διεργασίες χωρίς κατάσταση + +## [VII. Πρόσδεση θυρών](./port-binding) +### Εξαγωγή υπηρεσιών μέσω πρόσδεσης θυρών + +## [VIII. Παραλληλία](./concurrency) +### Κλιμάκωση προς τα έξω μέσω του μοντέλου διεργασιών + +## [IX. Απορριψιμότητα](./disposability) +### Μεγιστοποίηση ευρωστίας της εφαρμογής μέσω γρήγορης εκκίνησης και κομψού τερματισμού + +## [X. Ισοτιμία dev/prod](./dev-prod-parity) +### Κράτησε τα περιβάλλοντα υλοποίησης, ελέγχου και παραγωγής όσο πιο όμοια γίνεται + +## [XI. Αρχεία συμβάντων](./logs) +### Τα αρχεία συμβάντων ως ροές συμβάντων + +## [XII. Διεργασίες διαχείρισης](./admin-processes) +### Εκτέλεση εργασιών διαχείρισης ως διεργασίες μια και έξω diff --git a/content/el/who.md b/content/el/who.md new file mode 100644 index 000000000..2e5c93854 --- /dev/null +++ b/content/el/who.md @@ -0,0 +1,4 @@ +Ποιός πρέπει να διαβάσει αυτό το κείμενο; +========================================= + +Κάθε προγραμματιστής που αναπτύσσει εφαρμογές που τρέχουν σαν υπηρεσίες. Μηχανικοί διαχείρισης συστημάτων οι οποίοι εγκαθιστούν ή διαχειρίζονται τέτοιες εφαρμογές. diff --git a/content/en/admin-processes.md b/content/en/admin-processes.md new file mode 100644 index 000000000..870a56096 --- /dev/null +++ b/content/en/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Admin processes +### Run admin/management tasks as one-off processes + +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: + +* Running database migrations (e.g. `manage.py migrate` in Django, `rake db:migrate` in Rails). +* 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). +* Running one-time scripts committed into the app's repo (e.g. `php scripts/fix_bad_records.php`). + +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. + +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. + +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. diff --git a/content/en/background.md b/content/en/background.md new file mode 100644 index 000000000..9be3f1677 --- /dev/null +++ b/content/en/background.md @@ -0,0 +1,9 @@ +Background +========== + +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. + +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. + +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*. + diff --git a/content/en/backing-services.md b/content/en/backing-services.md new file mode 100644 index 000000000..c8f59945e --- /dev/null +++ b/content/en/backing-services.md @@ -0,0 +1,14 @@ +## IV. Backing services +### Treat backing services as attached resources + +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](https://beanstalkd.github.io)), SMTP services for outbound email (such as [Postfix](http://www.postfix.org/)), and caching systems (such as [Memcached](http://memcached.org/)). + +Backing services like the database are traditionally managed by the same systems administrators who deploy the app's runtime. 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](https://developers.google.com/maps/), or [Last.fm](http://www.last.fm/api)). + +**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. + +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. + +A production deploy attached to four backing services. + +Resources can be attached to and detached from 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. diff --git a/content/build-release-run.md b/content/en/build-release-run.md similarity index 82% rename from content/build-release-run.md rename to content/en/build-release-run.md index b0ed3ed90..83525c1ec 100644 --- a/content/build-release-run.md +++ b/content/en/build-release-run.md @@ -1,11 +1,11 @@ ## V. Build, release, run ### Strictly separate build and run stages -A [codebase](/codebase) is transformed into a (non-development) deploy through three stages: +A [codebase](./codebase) is transformed into a (non-development) deploy through three stages: -* 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 and vendors [dependencies](/dependencies) and compiles binaries and assets. -* 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. -* 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. +* 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. +* 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. +* 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. ![Code becomes a build, which is combined with config to create a release.](/images/release.png) diff --git a/content/codebase.md b/content/en/codebase.md similarity index 81% rename from content/codebase.md rename to content/en/codebase.md index a194c98b9..234ad6725 100644 --- a/content/codebase.md +++ b/content/en/codebase.md @@ -1,7 +1,7 @@ ## I. Codebase ### One codebase tracked in revision control, many deploys -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*. +A twelve-factor app is always tracked in a version control system, such as [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), 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*. 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). @@ -10,7 +10,7 @@ A *codebase* is any single repo (in a centralized revision control system like S There is always a one-to-one correlation between the codebase and the app: * 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. -* 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). +* 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). 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. diff --git a/content/concurrency.md b/content/en/concurrency.md similarity index 52% rename from content/concurrency.md rename to content/en/concurrency.md index 8d84064ec..9e7426fcf 100644 --- a/content/concurrency.md +++ b/content/en/concurrency.md @@ -5,10 +5,10 @@ Any computer program, once run, is represented by one or more processes. Web ap ![Scale is expressed as running processes, workload diversity is expressed as process types.](/images/process-types.png) -**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](http://adam.heroku.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. +**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. -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. +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](https://github.com/eventmachine/eventmachine), [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. -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*. +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*. -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. +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 [systemd](https://www.freedesktop.org/wiki/Software/systemd/), 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. diff --git a/content/config.md b/content/en/config.md similarity index 86% rename from content/config.md rename to content/en/config.md index c32d6a22c..0bc603b82 100644 --- a/content/config.md +++ b/content/en/config.md @@ -1,9 +1,9 @@ ## III. Config ### Store config in the environment -An app's *config* is everything that is likely to vary between [deploys](/codebase) (staging, production, developer environments, etc). This includes: +An app's *config* is everything that is likely to vary between [deploys](./codebase) (staging, production, developer environments, etc). This includes: -* Resource handles to the database, Memcached, and other [backing services](/backing-services) +* Resource handles to the database, Memcached, and other [backing services](./backing-services) * Credentials to external services such as Amazon S3 or Twitter * Per-deploy values such as the canonical hostname for the deploy @@ -11,7 +11,7 @@ Apps sometimes store config as constants in the code. This is a violation of tw 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. -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://static.springsource.org/spring/docs/2.5.x/reference/beans.html) in [Spring](http://www.springsource.org/). This type of config does not vary between deploys, and so is best done in the code. +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. 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. @@ -19,5 +19,4 @@ Another approach to config is the use of config files which are not checked into 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. -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. - +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. diff --git a/content/dependencies.md b/content/en/dependencies.md similarity index 73% rename from content/dependencies.md rename to content/en/dependencies.md index b5bcb0343..d53fd4cd8 100644 --- a/content/dependencies.md +++ b/content/en/dependencies.md @@ -5,7 +5,7 @@ Most programming languages offer a packaging system for distributing support lib **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. -For example, [Gem Bundler](http://gembundler.com/) 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. +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. 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`. diff --git a/content/dev-prod-parity.md b/content/en/dev-prod-parity.md similarity index 77% rename from content/dev-prod-parity.md rename to content/en/dev-prod-parity.md index bfea489f7..e771d163c 100644 --- a/content/dev-prod-parity.md +++ b/content/en/dev-prod-parity.md @@ -1,13 +1,13 @@ ## X. Dev/prod parity ### Keep development, staging, and production as similar as possible -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: +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: -* **The time gap:** A developer may work on code that takes days, weeks, or even months to go into production. +* **The time gap**: A developer may work on code that takes days, weeks, or even months to go into production. * **The personnel gap**: Developers write code, ops engineers deploy it. * **The tools gap**: Developers may be using a stack like Nginx, SQLite, and OS X, while the production deploy uses Apache, MySQL, and Linux. -**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: +**The twelve-factor app is designed for [continuous deployment](http://avc.com/2011/02/continuous-deployment/) by keeping the gap between development and production small.** Looking at the three gaps described above: * Make the time gap small: a developer may write code and have it deployed hours or even just minutes later. * Make the personnel gap small: developers who wrote code are closely involved in deploying it and watching its behavior in production. @@ -38,7 +38,7 @@ Summarizing the above into a table: -[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. +[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. @@ -71,6 +71,6 @@ Developers sometimes find great appeal in using a lightweight backing service in **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. -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. +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 [Docker](https://www.docker.com/) and [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. 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. diff --git a/content/disposability.md b/content/en/disposability.md similarity index 59% rename from content/disposability.md rename to content/en/disposability.md index cacbeb0ec..4725ef581 100644 --- a/content/disposability.md +++ b/content/en/disposability.md @@ -1,14 +1,14 @@ ## IX. Disposability ### Maximize robustness with fast startup and graceful shutdown -**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. +**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. -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. +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. 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. -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). +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](https://beanstalkd.github.io), 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). -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://couchdb.apache.org/docs/overview.html). +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). diff --git a/content/intro.md b/content/en/intro.md similarity index 100% rename from content/intro.md rename to content/en/intro.md diff --git a/content/logs.md b/content/en/logs.md similarity index 76% rename from content/logs.md rename to content/en/logs.md index 231a28c27..22e3404e7 100644 --- a/content/logs.md +++ b/content/en/logs.md @@ -3,11 +3,11 @@ *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. -Logs are the [stream](http://adam.heroku.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 continously as long as the app is operating. +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. **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. -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. +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 [Fluentd](https://github.com/fluent/fluentd)) are available for this purpose. 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: diff --git a/content/port-binding.md b/content/en/port-binding.md similarity index 69% rename from content/port-binding.md rename to content/en/port-binding.md index ed1a4b1b2..b12de8b15 100644 --- a/content/port-binding.md +++ b/content/en/port-binding.md @@ -7,8 +7,8 @@ Web apps are sometimes executed inside a webserver container. For example, PHP 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. -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. +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://www.eclipse.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. 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)). -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. +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. diff --git a/content/processes.md b/content/en/processes.md similarity index 78% rename from content/processes.md rename to content/en/processes.md index 2477d6080..f63957def 100644 --- a/content/processes.md +++ b/content/en/processes.md @@ -3,13 +3,12 @@ The app is executed in the execution environment as one or more *processes*. -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). +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). -**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. +**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. 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. -Asset packagers (such as [Jammit](http://documentcloud.github.com/jammit/) or [django-assetpackager](http://code.google.com/p/django-assetpackager/)) 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://ryanbigg.com/guides/asset_pipeline.html), rather than at runtime. +Asset packagers like [django-assetpackager](http://code.google.com/p/django-assetpackager/) 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). Asset packagers such as [Jammit](http://documentcloud.github.com/jammit/) and the [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html) can be configured to package assets during the build stage. 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/). - diff --git a/content/toc.md b/content/en/toc.md similarity index 58% rename from content/toc.md rename to content/en/toc.md index fc2ede4bb..d8fbe2c5e 100644 --- a/content/toc.md +++ b/content/en/toc.md @@ -1,38 +1,38 @@ The Twelve Factors ================== -## [I. Codebase](/codebase) +## [I. Codebase](./codebase) ### One codebase tracked in revision control, many deploys -## [II. Dependencies](/dependencies) +## [II. Dependencies](./dependencies) ### Explicitly declare and isolate dependencies -## [III. Config](/config) +## [III. Config](./config) ### Store config in the environment -## [IV. Backing Services](/backing-services) +## [IV. Backing services](./backing-services) ### Treat backing services as attached resources -## [V. Build, release, run](/build-release-run) +## [V. Build, release, run](./build-release-run) ### Strictly separate build and run stages -## [VI. Processes](/processes) +## [VI. Processes](./processes) ### Execute the app as one or more stateless processes -## [VII. Port binding](/port-binding) +## [VII. Port binding](./port-binding) ### Export services via port binding -## [VIII. Concurrency](/concurrency) +## [VIII. Concurrency](./concurrency) ### Scale out via the process model -## [IX. Disposability](/disposability) +## [IX. Disposability](./disposability) ### Maximize robustness with fast startup and graceful shutdown -## [X. Dev/prod parity](/dev-prod-parity) +## [X. Dev/prod parity](./dev-prod-parity) ### Keep development, staging, and production as similar as possible -## [XI. Logs](/logs) +## [XI. Logs](./logs) ### Treat logs as event streams -## [XII. Admin processes](/admin-processes) +## [XII. Admin processes](./admin-processes) ### Run admin/management tasks as one-off processes diff --git a/content/who.md b/content/en/who.md similarity index 100% rename from content/who.md rename to content/en/who.md diff --git a/content/es/admin-processes.md b/content/es/admin-processes.md new file mode 100644 index 000000000..b731703d5 --- /dev/null +++ b/content/es/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Administración de procesos +### Ejecutar las tareas de gestión/administración como procesos que solo se ejecutan una vez + +El [juego de procesos](./concurrency) es el conjunto de procesos que se usa para hacer las tareas habituales de la aplicación (como procesar las peticiones web). Por otro lado, es frecuente que los desarrolladores quieran ejecutar procesos de administración o mantenimiento una sola vez, como por ejemplo: + +* Ejecutar migraciones de las bases de datos (e.g. `manage.py migrate` de Django, `rake db:migrate` de Rails). +* Ejecutar una consola (también conocidas como [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop)) para ejecutar código arbitrario o inspeccionar los modelos de la aplicación en una base de datos con datos reales. La mayoría de los lenguajes proporcionan un interprete del tipo REPL si se ejecuta el mismo mandato sin ningún argumento (e.g. `python` o `perl`) pero en algunos casos tienen un mandato distinto (e.g. `irb` en Ruby, `rails console` en Rails). +* Ejecutar scripts incluidos en el repositorio de la aplicación (e.g. `php scripts/fix_bad_records.php`). + +Los procesos de este tipo deberían ejecutarse en un entorno idéntico al que se usa normalmente en los [procesos](./processes) habituales de la aplicación. Estos procesos se ejecutan en una [distribución](./build-release-run) concreta, usando el mismo [código base](./codebase) y la misma [configuración](./config) que cualquier otro proceso que ejecuta esa distribución. El código de administración se debe enviar con el código de la aplicación para evitar problemas de sincronización. + +Se deberían usar las mismas técnicas de [aislamiento de dependencias](./dependencies) en todos los tipos de procesos. Por ejemplo, si un proceso web Ruby usa el mandato `bundle exec thin start`, entonces una migración de la base de datos debería usar `bundle exec rake db:migrate`. De la misma manera, un programa Python que usa Virtualenv debería usar `bin/python` para ejecutar tanto el servidor web Tornado como cualquier proceso de administración `manage.py`. + +"Twelve-factor" recomienda encarecidamente lenguajes que proporcionan una consola del tipo REPL, ya que facilitan las tareas relacionadas con la ejecución de scripts que solo han de usarse una vez. En un despliegue local, se invocarán los procesos de administración con un mandato directo en la consola dentro del directorio de la aplicación. En un despliegue de producción, se puede usar ssh u otro mecanismo de ejecución de mandatos remoto proporcionado por el entorno de ejecución del despliegue para ejecutar dichos procesos. diff --git a/content/es/background.md b/content/es/background.md new file mode 100644 index 000000000..ff9934f31 --- /dev/null +++ b/content/es/background.md @@ -0,0 +1,8 @@ +Contexto +======== + +Los colaboradores de este documento han estado involucrados directamente en el desarrollo y despliegue de cientos de aplicaciones, y han sido testigos indirectos del desarrollo, las operaciones y el escalado de cientos de miles de aplicaciones mediante nuestro trabajo en la plataforma [Heroku](http://www.heroku.com/). + +Este documento sintetiza toda nuestra experiencia y observaciones en una amplia variedad de aplicaciones SaaS. Es la triangulación entre practicas ideales para el desarrollo de aplicaciones, prestando especial atención a las dinámicas del crecimiento natural de una aplicación a lo largo del tiempo, las dinámicas de colaboración entre desarrolladores que trabajan en el código base de las aplicaciones y [evitando el coste de la entropía del software](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Nuestra motivación es mejorar la concienciación sobre algunos problemas sistémicos que hemos observado en el desarrollo de las aplicaciones modernas, aportar un vocabulario común que sirva para discutir sobre estos problemas, y ofrecer un conjunto de soluciones conceptualmente robustas para esos problemas acompañados de su correspondiente terminología. El formato está inspirado en los libros de Martin Fowler *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* y *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. diff --git a/content/es/backing-services.md b/content/es/backing-services.md new file mode 100644 index 000000000..ab5c94da0 --- /dev/null +++ b/content/es/backing-services.md @@ -0,0 +1,14 @@ +## IV. Backing services +### Tratar a los "backing services" como recursos conectables + +Un *backing service* es cualquier recurso que la aplicación puede consumir a través de la red como parte de su funcionamiento habitual. Entre otros ejemplos, podemos encontrar bases de datos (como [MySQL](http://dev.mysql.com/) o [CouchDB](http://couchdb.apache.org/)), los sistemas de mensajería y de colas (como [RabbitMQ](http://www.rabbitmq.com/) o [Beanstalkd](https://beanstalkd.github.io)), los servicios SMTP de email (como [Postfix](http://www.postfix.org/)), y los sistemas de cache (como [Memcached](http://memcached.org/)). + +Tradicionalmente, los "backing services" (como las bases de datos) han sido gestionadas por los mismos administradores de sistemas que despliegan la aplicacion en producción. Además de esos servicios gestionados localmente, las aplicaciones también pueden usar servicios proporcionados y gestionados por terceros, como por ejemplo los servicios SMTP ([Postmark](http://postmarkapp.com/)), los servicios de recopilación de métricas (como [New Relic](http://newrelic.com/) o [Loggly](http://www.loggly.com/)), los servicios de activos binarios (como [Amazon S3](http://aws.amazon.com/s3/)), e incluso servicios que se consumen accediendo a ellos mediante un API (como [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), o [Last.fm](http://www.last.fm/api)). + +**El código de una aplicación "twelve-factor" no hace distinciones entre servicios locales y de terceros.** Para la aplicación, ambos son recursos conectados, accedidos mediante una URL u otro localizador o credencial almacenado en la [config](./config). Un [despliegue](./codebase) de una aplicación "twelve-factor" debería ser capaz de reemplazar una base de datos local MySQL por una gestionada por un tercero (como [Amazon RDS](http://aws.amazon.com/rds/)) sin ningún cambio en el código de la aplicación. Igualmente, un servidor SMTP local se podría cambiar por un servicio de terceros (como Postmark) sin modificaciones en el código. En ambos casos, solo el manejador del recurso necesita cambiar en la configuración. + +Cada "backing service" distinto es un *recurso*. Por ejemplo, una base de datos MySQL es un recurso; dos bases de datos MySQL (usadas para "sharding" en la capa de aplicación) les convierte en dos recursos distintos. Una aplicación "twelve factor" trata esas bases de datos como *recursos conectados*, lo que demuestra su bajo acoplamiento al despliegue al que se unen. + +Un despliegue en producción conectado a cuatro backing services. + +Los recursos se pueden conectar y desconectar a voluntad. Por ejemplo, si la base de datos funciona mal debido a un problema en el hardware, el administrador de la aplicación puede cambiar a un nuevo servidor de bases de datos que haya sido restaurado de un backup reciente. La base de datos actual de producción se puede desconectar, y conectar una nueva base de datos sin tener que cambiar nada en el código. diff --git a/content/es/build-release-run.md b/content/es/build-release-run.md new file mode 100644 index 000000000..c37f0adee --- /dev/null +++ b/content/es/build-release-run.md @@ -0,0 +1,18 @@ +## V. Construir, distribuir, ejecutar +### Separar completamente la etapa de construcción de la etapa de ejecución + +El [código base](./codebase) se transforma en un despliegue (que no es de desarrollo) al completar las siguientes tres etapas: + +* La *etapa de construcción* es una transformación que convierte un repositorio de código en un paquete ejecutable llamado *construcción* (una "build"). En la etapa de construcción se traen todas las [dependencias](./dependencies) y se compilan los binarios y las herramientas usando una versión concreta del código correspondiente a un commit especificado por el proceso de despliegue. +* En la *fase de distribución* se usa la construcción creada en la fase de construcción y se combina con la [configuración](./config) del despliegue actual. Por tanto, la *distribución* resultante contiene tanto la construcción como la configuración y está lista para ejecutarse inmediatamente en el entorno de ejecución. +* La *fase de ejecución* (también conocida como "runtime") ejecuta la aplicación en el entorno de ejecución, lanzando un conjunto de [procesos](./processes) de una distribución concreta de la aplicación. + +![El código se convierte en una construcción, que se combina con la configuración para crear una distribución.](/images/release.png) + +**Las aplicaciones "twelve-factor" hacen una separación completa de las fases de construcción, de distribución y de ejecución.** Por ejemplo, es imposible hacer cambios en el código en la fase de ejecución, porque no hay una manera de propagar dichos cambios a la fase de construcción. + +Las herramientas de despliegue ofrecen, normalmente, herramientas de gestión de distribuciones (releases). La capacidad de volver a una versión anterior es especialmente útil. Por ejemplo, la herramienta de despliegues [Capistrano](https://github.com/capistrano/capistrano/wiki) almacena distribuciones en un subdirectorio llamado `releases`, donde la distribución actual es un enlace simbólico al directorio de la distribución actual. Su mandato `rollback` hace fácil y rápidamente el trabajo de volver a la versión anterior. + +Cada distribución debería tener siempre un identificador único de distribución, como por ejemplo una marca de tiempo (timestamp) de la distribución (`2011-04-06-20:32:17`) o un número incremental (como `v100`). Las distribuciones son como un libro de contabilidad, al que solo se le pueden agregar registros y no pueden ser modificados una vez son creados. Cualquier cambio debe crear una nueva distribución. + +Cada vez que un desarrollador despliega código nuevo se crea una construcción nueva de la aplicación. La fase de ejecución, en cambio, puede suceder automáticamente, por ejemplo, cuando se reinicia un servidor, o cuando un proceso termina inesperadamente siendo reiniciado por el gestor de procesos. Por tanto, la fase de ejecución debería mantenerse lo más estática posible, ya que evita que una aplicación en ejecución pueda causar una interrupción inesperada, en mitad de la noche, cuando no hay desarrolladores a mano. La fase de construcción puede ser más compleja, ya que los errores siempre están en la mente de un desarrollador que dirige un despliegue. diff --git a/content/es/codebase.md b/content/es/codebase.md new file mode 100644 index 000000000..7a34788ed --- /dev/null +++ b/content/es/codebase.md @@ -0,0 +1,17 @@ +## I. Código base (Codebase) +### Un código base sobre el que hacer el control de versiones y multiples despliegues + +Una aplicación "twelve-factor" se gestiona siempre con un sistema de control de versiones, como [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), o [Subversion](http://subversion.apache.org/). A la copia de la base de datos de seguimiento de versiones se le conoce como un *repositorio de código*, a menudo abreviado como *repo de código* o simplemente *repo*. + +El *código base* es cualquier repositorio (en un sistema de control de versiones centralizado como Subversion), o cualquier conjunto de repositorios que comparten un commit raíz (en un sistema de control de versiones descentralizado como Git). + +![El código base se usa en muchos despliegues](/images/codebase-deploys.png) + +Siempre hay una relación uno a uno entre el código base y la aplicación: + +* Si hay multiples códigos base, no es una aplicación -- es un sistema distribuido. Cada componente en un sistema distribuido es una aplicación, y cada uno, individualmente, puede cumplir los requisitos de una aplicación "twelve-factor". +* Compartir código en varias aplicaciones se considera una violación de la metodología "twelve factor". La solución en este caso es separar el código compartido en librerías que pueden estar enlazadas mediante un [gestor de dependencias](./dependencies). + +El código base de la aplicación es único, sin embargo, puede haber tantos despliegues de la aplicación como sean necesarios. Un *despliegue* es una instancia de la aplicación que está en ejecución. Normalmente, se ejecuta en un entorno de producción, y uno o varios entornos de pruebas. Además, cada desarrollador tiene una instancia en su propio entorno de desarrollo, los cuales se consideran también como despliegues. + +El código base es el mismo en todos los despliegues, aunque pueden ser diferentes versiones en cada despliegue. Por ejemplo, un desarrollador tiene algunos commits sin desplegar en preproducción; preproducción tiene algunos commits que no están desplegados en producción. Pero todos ellos comparten el mismo código base, de este modo todos son identificables como diferentes despliegues de la misma aplicación. diff --git a/content/es/concurrency.md b/content/es/concurrency.md new file mode 100644 index 000000000..f19ac8080 --- /dev/null +++ b/content/es/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Concurrencia +### Escalar mediante el modelo de procesos + +Todo programa de ordenador, al ejecutarse, se encuentra representado en memoria por uno o más procesos. Las aplicaciones web se pueden ejecutar de diferentes formas desde el punto de vista del modelo de procesos que usan. Por ejemplo, los procesos PHP se ejecutan como procesos pesados (o simplemente procesos), hijos del proceso Apache, creándolos bajo demanda a causa de la cantidad de peticiones si es necesario. Los procesos Java funcionan de forma distinta, la Máquina Virtual de Java (JVM) proporciona un conjunto de procesos que reservan al principio una gran cantidad de recursos del sistema (CPU y memoria), gestionando la concurrencia internamente mediante procesos ligeros (threads). En ambos casos, los procesos en ejecución son prácticamente transparentes para los desarrolladores de la aplicación. + +![La escalabilidad está representada por el número de procesos en ejecución, mientras que la diversidad de carga de trabajo lo está por los tipos de procesos.](/images/process-types.png) + +**En las aplicaciones "twelve-factor", los procesos son ciudadanos de primera clase.** Los procesos de las aplicaciones "twelve-factor" se inspiran en [el modelo de procesos de unix para ejecutar demonios](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Usando este modelo, el desarrollador puede distribuir la ejecución de su aplicación para gestionar diversas cargas de trabajo asignando cada tipo de trabajo a un *tipo de proceso*. Por ejemplo, las peticiones HTTP se pueden procesar con un proceso y las tareas con mucha carga de trabajo con hilos. + +Esto no exime a los procesos de gestionar su propia división interna mediante threads en la ejecución de la máquina virtual o mediante un modelo asíncrono o por eventos con herramientas como [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), o [Node.js](http://nodejs.org/). No obstante, una máquina virtual aislada tiene una capacidad de crecimiento limitada, así que la aplicación debe ser capaz de dividirse en multiples procesos que se puedan ejecutar en múltiples máquinas físicas. + +El modelo de procesos muestra todo su potencial cuando llega el momento de escalar. La [naturaleza "share-nothing", divide horizontalmente los procesos de las aplicaciones "twelve-factor"](./processes) y se traduce en un aumento de la concurrencia como una operación simple y fiable. El conjunto de tipos de procesos y el número de procesos de cada tipo es conocido como *juego de procesos*. + +Los procesos de las aplicaciones "twelve-factor" [nunca deberían ser demonios](http://dustin.github.com/2010/02/28/running-processes.html) ni escribir ficheros de tipo PID. En su lugar, se debería confiar en un gestor de procesos del sistema operativo (como [systemd](https://www.freedesktop.org/wiki/Software/systemd/), un gestor de procesos distribuido en una plataforma en la nube, o una herramienta como [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) en desarrollo) para gestionar [los historiales](./logs), responder a procesos que terminen inesperadamente, y gestionar los reinicios y apagados provocados por los usuarios. diff --git a/content/es/config.md b/content/es/config.md new file mode 100644 index 000000000..9849720b3 --- /dev/null +++ b/content/es/config.md @@ -0,0 +1,22 @@ +## III. Configuración +### Guardar la configuración en el entorno + +La configuración de una aplicación es todo lo que puede variar entre [despliegues](./codebase) (entornos de preproducción, producción, desarrollo, etc), lo cual incluye: + +* Recursos que manejan la base de datos, Memcached, y otros ["backing services"](./backing-services) +* Credenciales para servicios externos tales como Amazon S3 o Twitter +* Valores de despliegue como por ejemplo el nombre canónico del equipo para el despliegue + +A veces las aplicaciones guardan configuraciones como constantes en el código, lo que conduce a una violación de la metodología "twelve-factor", que requiere una **estricta separación de la configuración y el código**. La configuración varía sustancialmente en cada despliegue, el código no. + +La prueba de fuego para saber si una aplicación tiene toda su configuración correctamente separada del código es comprobar que el código base puede convertirse en código abierto en cualquier momento, sin comprometer las credenciales. + +Hay que resaltar que la definición de "configuración" **no** incluye las configuraciones internas de la aplicación, como `config/routes.rb` en Rails, o como [se conectan los módulos](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) en [Spring](http://spring.io/). Este tipo de configuraciones no varían entre despliegues, y es por eso que están mejor en el código. + +Otra estrategia de configuración es el uso de ficheros de configuración que no se guardan en el control de versiones, como ocurre con el `config/database.yml` de Rails. Esto supone una gran mejora con respecto a las constantes que se guardan en el repositorio, aunque todavía tiene ciertas debilidades: es fácil guardar un fichero de configuración en el repo por error; se tiende a desperdigar los ficheros de configuración en diferentes sitios y con distintos formatos, siendo más difícil la tarea de ver y gestionar toda la configuración en un solo sitio. Además, el formato tiende a ser específico del lenguaje o del framework. + +**Las aplicaciones "twelve-factor" almacenan la configuración en *variables de entorno*** (abreviadas normalmente como *env vars* o *env*). Las variables de entorno se modifican fácilmente entre despliegues sin realizar cambios en el código; a diferencia de los ficheros de configuración, en los que existe una pequeña posibilidad de que se guarden en el repositorio de código accidentalmente; y a diferencia de los ficheros de configuración personalizados u otros mecanismos de configuración, como los System Properties de Java, son un estándar independiente del lenguaje y del sistema operativo. + +Otro aspecto de la gestión de la configuración es la clasificación. A veces, las aplicaciones clasifican las configuraciones en grupos identificados (a menudo llamados "entornos" o "environments") identificando después despliegues específicos, como ocurre en Rails con los entornos `development`, `test`, y `production`. Este método no escala de una manera limpia: según se van creando despliegues de la aplicación, se van necesitando nuevos entornos, tales como `staging` o `qa`. Según va creciendo el proyecto, los desarrolladores van añadiendo sus propios entornos especiales como `joes-staging`, resultando en una explosión de combinaciones de configuraciones que hacen muy frágil la gestión de despliegues de la aplicación. + +En una aplicación "twelve-factor", las variables de entorno son controles granulares, cada una de ellas completamente ortogonales a las otras. Nunca se agrupan juntas como "entornos", pero en su lugar se gestionan independientemente para cada despliegue. Este es un modelo que escala con facilidad según la aplicación se amplía, naturalmente, en más despliegues a lo largo de su vida. diff --git a/content/es/dependencies.md b/content/es/dependencies.md new file mode 100644 index 000000000..43bc11ca5 --- /dev/null +++ b/content/es/dependencies.md @@ -0,0 +1,12 @@ +## II. Dependencias +### Declarar y aislar explícitamente las dependencias + +La mayoría de los lenguajes de programación tienen un sistema de gestión de paquetes para distribuir sus librerías, como [CPAN](http://www.cpan.org/) en Perl o [Rubygems](http://rubygems.org/) en Ruby. Las librerías instaladas a través de estos sistemas se pueden instalar en el sistema (también conocido como "site packages") o limitarse al directorio que contiene la aplicación (también conocido como "vendoring" o "bundling"). + +**Una aplicación "twelve-factor" no depende nunca de la existencia explícita de paquetes instalados en el sistema.** Declara todas sus dependencias, completamente y explícitamente, mediante un manifiesto de *declaración de dependencias*. Además, usa herramientas de *aislamiento de dependencias* durante la ejecución para asegurar que las dependencias, implícitamente, no afectan al resto del sistema. La especificación de dependencias completa y explícita se aplica de la misma manera tanto en producción como en desarrollo. + +Por ejemplo, la [Bundler](https://bundler.io/) de Ruby tiene el formato de su manifiesto `Gemfile` para declarar sus dependencias y `bundle exec` para aislar sus dependencias. En Python existen dos herramientas independientes para estas tareas -- [Pip](http://www.pip-installer.org/en/latest/) se usa para la declaración de dependencias y [Virtualenv](http://www.virtualenv.org/en/latest/) para el aislamiento. Incluso C tiene [Autoconf](http://www.gnu.org/s/autoconf/) para la declaración de sus dependencias, y el enlace estático proporciona aislamiento de sus dependencias. No importa qué conjunto de herramientas se use, la declaración y el aislamiento de dependencias se deben usar siempre juntas, usar solo una o la otra no es suficiente para satisfacer las condiciones de "twelve-factor". + +Uno de los beneficios de la declaración explícita de dependencias es que simplifica la configuración para los nuevos desarrolladores de la aplicación. Cualquier desarrollador que se incorpore al equipo debe poder probar el código base de la aplicación en su máquina de desarrollo. Tan solo debe tener instalados el entorno de ejecución del lenguaje y el gestor de dependencias como prerequisitos. Lo cual permitirá configurar todo lo necesario para ejecutar el código de la aplicación con un *mandato para construir*. Por ejemplo, el mandato para construir en Ruby/Bundler es `bundle install`, mientras que en Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) es `lein deps`. + +Las aplicaciones "Twelve-factor" tampoco dependen de la existencia de ninguna herramienta en el sistema. Por ejemplo, ejecutar mandatos como `ImageMagick` o `curl`. Aunque estas herramientas pueden existir en muchos, o incluso en la mayoría de los sistemas, no existen garantías de que vayan a existir en todos los sistemas donde la aplicación pueda ser ejecutada en un futuro, ni de que las versiones futuras de un sistema vayan a ser compatibles con la aplicación. Si la aplicación necesita ejecutar una herramienta del sistema, dicha herramienta debería estar incluida dentro de la aplicación. diff --git a/content/es/dev-prod-parity.md b/content/es/dev-prod-parity.md new file mode 100644 index 000000000..c1216f579 --- /dev/null +++ b/content/es/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Igualdad entre desarrollo y producción +### Mantener desarrollo, preproducción y producción tan parecidos como sea posible + +Históricamente, han existido dos tipos de entorno muy diferenciados: desarrollo (donde un desarrollador puede editar en vivo en un [despliegue](./codebase) local de la aplicación) y producción (un despliegue en el que la aplicación está en ejecución disponible para que lo usen los usuarios). Estas diferencias se pueden clasificar en tres tipos: + +* **Diferencias de tiempo**: Un desarrollador puede estar trabajando en un código durante días, semanas o incluso meses antes de que llegue a producción. +* **Diferencias de personal**: Los desarrolladores escriben el código y los ingenieros de operaciones lo despliegan. +* **Diferencias de herramientas**: Los desarrolladores pueden usar una pila como Nginx, SQLite y OS X, mientras que en producción se usa Apache, MySQL y Linux. + +** Las aplicaciones "twelve-factor" están diseñadas para hacer [despliegues continuos](http://avc.com/2011/02/continuous-deployment/) que reducen las diferencias entre los entornos de desarrollo y producción.** Teniendo en cuenta las tres diferencias descritas anteriormente: + +* Reducir las diferencias de tiempo: Un desarrollador puede escribir código y tenerlo desplegado en tan solo unas horas, o incluso, minutos más tarde. +* Reducir las diferencias de personal: Los desarrolladores que escriben el código están muy involucrados en el despliegue y observan su comportamiento en producción. +* Reducir las diferencias de herramientas: tratar de hacer que desarrollo y producción sean tan parecidos como sea posible. + +Resumiendo lo anterior en una tabla: + +
+ + + + + + + + + + + + + + + + + + + + +
Aplicaciones tradicionalesAplicaciones "twelve-factor"
Tiempo entre desplieguesSemanasHoras
Desarrolladores vs Ingenieros de operacionesDiferentes personasMismas personas
Entorno de desarrollo vs entorno de producciónDivergentesLo más parecidos posibles
+ +Los ["backing services"](./backing-services), como la base de datos de la aplicación, el sistema de colas, o la caché, es donde la igualdad en los entornos de desarrollo y producción es importante. Muchos lenguajes ofrecen librerías en las que se simplifica el acceso a los servicios de respaldo, incluidos *adaptadores* para diferentes tipos de servicios. Se pueden observar algunos ejemplos en la siguiente tabla. + + + + + + + + + + + + + + + + + + + + + + + + + + +
TipoLenguajeLibreríaAdaptador
Base de datosRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
ColasPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CachéRuby/RailsActiveSupport::CacheMemoria, sistema de ficheros, Memcached
+ +Los desarrolladores, a veces, caen en la tentación de usar "backing services" ligeros en sus entornos de desarrollo, mientras que en producción se usan los más serios y robustos. Por ejemplo, se usa SQLite en desarrollo y PostgreSQL en producción; o memoria local para la caché en desarrollo y Memcached en producción. + +**Un desarrollador "twelve-factor" no cae en la tentación de usar diferentes "backing services" en desarrollo y producción**, incluso cuando los adaptadores teóricamente abstractos están lejos de cualquier diferencia en "backing services". Las diferencias entre los servicios de respaldo tienen que ver con las pequeñas incompatibilidades que surgen de la nada, causando que el código que funciona y pasa los tests en desarrollo o en preproducción, falle en producción. Este tipo de errores provocan conflictos que desincentivan la filosofía del despliegue continuo. El coste de estos conflictos y el enfriamiento subsiguiente del despliegue continuo es extremadamente alto cuando se hace balance del total de tiempo de vida de una aplicación. + +Los servicios ligeros locales son menos atractivos que antes. Los "backing services" modernos como Memcached, PostgreSQL, y RabbitMQ no son difíciles de instalar y ejecutar gracias a los sistemas de gestión de paquetes modernos, como [Homebrew](http://mxcl.github.com/homebrew/) y [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Al mismo tiempo, las herramientas de gestión de la configuración como [Chef](http://www.opscode.com/chef/) y [Puppet](http://docs.puppetlabs.com/) combinadas con entornos virtuales ligeros como [Docker](https://www.docker.com/) o [Vagrant](http://vagrantup.com/) permiten a los desarrolladores ejecutar entornos locales que son muy parecidos a los entornos de producción. El coste de instalar y usar estos sistemas es bajo comparado con el beneficio que se puede obtener de la paridad entre desarrollo y producción y del despliegue continuo. + +Los adaptadores de los "backing services" todavía son de gran utilidad, porque hacen que cambiar de unos a otros sea un trámite relativamente poco doloroso. No obstante, todos los despliegues de una aplicación (en entornos de desarrollo, preproducción y producción) deberían usar el mismo tipo y versión de cada uno de los "backing services". diff --git a/content/es/disposability.md b/content/es/disposability.md new file mode 100644 index 000000000..d010e39c4 --- /dev/null +++ b/content/es/disposability.md @@ -0,0 +1,12 @@ +## IX. Desechabilidad +### Hacer el sistema más robusto intentando conseguir inicios rápidos y finalizaciones seguras + +**Los [procesos](./processes) de las aplicaciones "twelve-factor" son *desechables*, lo que significa que pueden iniciarse o finalizarse en el momento que sea necesario.** Esto permite un escalado rápido y flexible, un despliegue rápido del [código](./codebase) y de los cambios de las [configuraciones](./config), y despliegues más robustos en producción. + +Los procesos deberían intentar conseguir **minimizar el tiempo de arranque**. En el mejor de los casos, un proceso necesita unos pocos segundos desde que se ejecuta el mandato hasta que arranca y está preparado para recibir peticiones o trabajos. Mejorar el tiempo de arranque proporciona mayor agilidad en el proceso de [distribución](./build-release-run) y escalado; y lo hace más robusto, porque el gestor de procesos puede mover procesos de forma segura entre máquinas físicas más fácilmente. + +Los procesos **se paran de manera segura cuando reciben una señal [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** desde el gestor de procesos. Un proceso web para de manera segura cuando deja de escuchar el puerto asociado al servicio (así rechaza cualquier nueva petición), permitiendo que cualquier petición termine de procesarse y pueda finalizar sin problemas. Implícitamente, según este modelo, las peticiones HTTP son breves (no duran más de unos pocos segundos) y, en el caso de un sondeo largo, el cliente debería intentar reconectar una y otra vez cuando se pierda la conexión. + +Para finalizar de manera segura, un trabajador (o "worker") debe devolver el trabajo actual a una cola de trabajos. Por ejemplo, en [RabbitMQ](http://www.rabbitmq.com/) un trabajador puede mandar un [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); en [Beanstalkd](https://beanstalkd.github.io), el trabajo se devuelve a una cola automáticamente en el momento en el que el trabajador finaliza. Los sistemas de exclusión mutua como [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) necesitan estar seguros para liberar su candado en el registro de trabajos. Implícitamente, según este modelo, todos los trabajos son [reentrantes](https://es.wikipedia.org/wiki/Reentrancia_%28inform%C3%A1tica%29), lo que se consigue normalmente generando los resultados de manera transaccional, o convirtiendo la operación en [idempotente](http://es.wikipedia.org/wiki/Idempotencia). + +Los procesos deberían estar **preparados contra finalizaciones inesperadas**, como en el caso de un fallo a nivel hardware. Aunque es un caso más raro que una finalización mediante la señal `SIGTERM`, se puede dar el caso. Lo recomendable es usar un sistema de colas robusto, como Beanstalkd, que devuelve los trabajos a su cola cuando los clientes se desconectan o expira su tiempo de espera ("timeout"). En cualquier caso, una aplicación "twelve-factor" es una arquitectura que trata finalizaciones inesperadas y peligrosas. El [diseño Crash-only](http://lwn.net/Articles/191059/) lleva este concepto a su [conclusión lógica](http://docs.couchdb.org/en/latest/intro/overview.html). diff --git a/content/es/intro.md b/content/es/intro.md new file mode 100644 index 000000000..4d18d31d2 --- /dev/null +++ b/content/es/intro.md @@ -0,0 +1,12 @@ +Introducción +============ + +En estos tiempos, el software se está distribuyendo como un servicio: se le denomina *web apps*, o *software as a service* (SaaS). "The twelve-factor app" es una metodología para construir aplicaciones SaaS que: + +* Usan formatos **declarativos** para la automatización de la configuración, para minimizar el tiempo y el coste que supone que nuevos desarrolladores se unan al proyecto; +* Tienen un **contrato claro** con el sistema operativo sobre el que trabajan, ofreciendo la **máxima portabilidad** entre los diferentes entornos de ejecución; +* Son apropiadas para **desplegarse** en modernas **plataformas en la nube**, obviando la necesidad de servidores y administración de sistemas; +* **Minimizan las diferencias** entre los entornos de desarrollo y producción, posibilitando un **despliegue continuo** para conseguir la máxima agilidad; +* Y pueden **escalar** sin cambios significativos para las herramientas, la arquitectura o las prácticas de desarrollo. + +La metodología "twelve-factor" puede ser aplicada a aplicaciones escritas en cualquier lenguaje de programación, y cualquier combinación de 'backing services' (bases de datos, colas, memoria cache, etc). diff --git a/content/es/logs.md b/content/es/logs.md new file mode 100644 index 000000000..e5e9f451f --- /dev/null +++ b/content/es/logs.md @@ -0,0 +1,16 @@ +## XI. Historiales +### Tratar los historiales como una transmisión de eventos + +Los *historiales* permiten observar el comportamiento de la aplicación durante su ejecución. En entornos basados en servidores es muy común escribir un fichero en disco (un "fichero de histórico") pero este, es tan solo un posible formato de salida. + +Los historiales son la [transmisión](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) de un conjunto de eventos ordenados y capturados de la salida de todos los procesos en ejecución y de los "backing services". En bruto, los historiales suelen estar en formato texto y tienen un evento por línea (aunque las trazas de excepciones suelen estar en varias líneas). Los historiales no tienen un principio y un final fijo, sino que fluyen continuamente mientras la aplicación está en funcionamiento. + +**Una aplicación "twelve-factor" nunca se preocupa del direccionamiento o el almacenamiento de sus transmisiones de salida.** No debería intentar escribir o gestionar ficheros de historial. En su lugar, cada proceso en ejecución escribe sus eventos a la `salida estándar` (o `stdout`). Durante el desarrollo, los desarrolladores verán el flujo en su terminal para observar el comportamiento de la aplicación. + +En despliegues de preproducción y producción, cada transmisión del proceso será capturada por el entorno de ejecución, siendo capturadas junto con todos los otros flujos de la aplicación, y redirigidas a uno o más destinos finales para ser revisadas y archivadas. Estos destinos donde se archivan no son visibles o configurables por la aplicación, se gestionan totalmente por el entorno de ejecución. Las herramientas de código abierto que capturan y almacenan los historiales (como [Logplex](https://github.com/heroku/logplex) y [Fluentd](https://github.com/fluent/fluentd)) se usan con este objetivo. + +Las transmisiones de eventos para una aplicación pueden ser redirigidas a un fichero u observadas en tiempo real mediante un "tail" en un terminal. Cabe destacar que la transmisión se puede enviar a un sistema de análisis e indexado como [Splunk](http://www.splunk.com/), o a un sistema de almacenamiendo de datos de propósito general como [Hadoop/Hive](http://hive.apache.org/). Estos sistemas se tienen en cuenta por el gran poder y la flexibilidad para inspeccionar el comportamiento de la aplicación a lo largo del tiempo, incluyendo: + +* Encontrar eventos específicos del pasado. +* Gráficas de tendencia a gran escala (como las peticiones por minuto). +* Activación de alertas de acuerdo con heurísticas definidas por el usuario (como una alerta cuando la cantidad de errores por minuto sobrepasa un cierto límite). diff --git a/content/es/port-binding.md b/content/es/port-binding.md new file mode 100644 index 000000000..5f0e22e69 --- /dev/null +++ b/content/es/port-binding.md @@ -0,0 +1,14 @@ +## VII. Asignación de puertos +### Publicar servicios mediante asignación de puertos + +Las aplicaciones web se ejecutan a menudo mediante contenedores web. Por ejemplo, las aplicaciones de PHP se suelen ejecutar como módulos del [HTTPD de Apache](http://httpd.apache.org/), y las aplicaciones Java en [Tomcat](http://tomcat.apache.org/). + +**Las aplicaciones "twelve factor" son completamente auto-contenidas** y no dependen de un servidor web en ejecución para crear un servicio web público. Una aplicación web **usa HTTP como un servicio al que se le asigna un puerto**, y escucha las peticiones que recibe por dicho puerto. + +En los entornos de desarrollo, los desarrolladores usan una URL del servicio (por ejemplo `http://localhost:5000/`), para acceder al servicio que ofrece la aplicación. En la fase de despliegue, existe una capa de enrutamiento que se encarga de que las peticiones que llegan a una dirección pública se redirijan hacia el proceso web que tiene asignado su puerto correspondiente. + +Esto se implementa, normalmente, usando una [declaración de dependencias](./dependencies) donde se incluyen librerías de las aplicaciones web, como [Tornado](http://www.tornadoweb.org/) para Python, [Thin](http://code.macournoyer.com/thin/) para Ruby, o [Jetty](http://www.eclipse.org/jetty/) para Java y otros lenguajes basados en la Máquina Virtual de Java (JVM). Esto ocurre totalmente en el *entorno del usuario*, es decir, dentro del código de la aplicación. El contrato con el entorno de ejecución obliga al puerto a servir las peticiones. + +HTTP no es el único servicio que usa asignación de puertos. La verdad, es que cualquier servicio puede ejecutarse mediante un proceso al que se le asigna un puerto y queda a la espera de peticiones. Entre otros ejemplos podemos encontrar [ejabberd](http://www.ejabberd.im/) (que usa [XMPP](http://xmpp.org/)), y [Redis](http://redis.io/) (que usa [el protocolo Redis](http://redis.io/topics/protocol)). + +También es cierto que la aproximación de asignación de puertos ofrece la posibilidad de que una aplicación pueda llegar a ser un ["backing service"](./backing-services) para otra aplicación, usando la URL de la aplicación correspondiente como un recurso declarado en la [configuración](./config) de la aplicación que consume este "backing service". diff --git a/content/es/processes.md b/content/es/processes.md new file mode 100644 index 000000000..94add15b2 --- /dev/null +++ b/content/es/processes.md @@ -0,0 +1,14 @@ +## VI. Procesos +### Ejecutar la aplicación como uno o más procesos sin estado + +La aplicación se ejecuta como uno o más *procesos* en el entorno de ejecución. + +El caso más sencillo que podemos plantear es que el código es un script independiente, el entorno de ejecución es un portátil de un desarrollador, el compilador o interprete correspondiente del lenguaje está instalado, y el proceso se lanza mediante la linea de mandatos (por ejemplo, `python my_script.py`). Por otro lado podemos encontrar el caso de un despliegue en producción de una aplicación compleja que puede usar muchos [tipos de procesos, instanciados como cero o más procesos en ejecución](./concurrency). + +**Los procesos "twelve-factor" no tienen estado y son "[share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture)".** Cualquier información que necesite persistencia se debe almacenar en un ['backing service'](./backing-services) con estado, habitualmente una base de datos. + +Tanto el espacio de memoria de un proceso como el sistema de ficheros se pueden usar como si fueran una cache temporal para hacer transacciones. Por ejemplo, descargar un fichero de gran tamaño, realizar alguna operación sobre él, y almacenar sus resultados en una base de datos. Las aplicaciones "twelve-factor" nunca dan por hecho que cualquier cosa cacheada en memoria o en el disco vaya a estar disponible al realizar una petición al ejecutar diferentes procesos. Con muchos procesos de cada tipo ejecutándose al mismo tiempo, existe una gran probabilidad de que otro proceso distinto sirva una petición en el futuro. Incluso cuando solo está corriendo un solo proceso, un reinicio (provocado por el despliegue de código, un cambio de configuración o un cambio de contexto del proceso) normalmente elimina todo el estado local (e.g. memoria y sistema de ficheros). + +Los compresores de estáticos (como [Jammit](http://documentcloud.github.com/jammit/) o [django-compressor](http://django-compressor.readthedocs.org/)) usan el sistema de ficheros como una cache para ficheros compilados. En las aplicaciones "twelve-factor" es preferible realizar esta compilación durante la [fase de construcción](./build-release-run), como con el [asset pipeline de Rails](http://guides.rubyonrails.org/asset_pipeline.html), en lugar de hacerlo en tiempo de ejecución. + +Algunos sistemas webs dependen de ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence), esto quiere decir que cachean la información de la sesión de usuario en la memoria del proceso de la aplicación y esperan peticiones futuras del mismo visitante para redirigirle al mismo proceso. Las "sticky sessions" son una violación de "twelve-factor" y no deberían usarse nunca ni depender de ellas. La información del estado de la sesión es un candidato perfecto para almacenes de información que ofrecen mecanismos de tiempo de expiración, como [Memcached](http://memcached.org/) o [Redis](http://redis.io/). diff --git a/content/es/toc.md b/content/es/toc.md new file mode 100644 index 000000000..a175f0660 --- /dev/null +++ b/content/es/toc.md @@ -0,0 +1,38 @@ +Twelve Factors +============== + +## [I. Código base (Codebase)](./codebase) +### Un código base sobre el que hacer el control de versiones y multiples despliegues + +## [II. Dependencias](./dependencies) +### Declarar y aislar explícitamente las dependencias + +## [III. Configuraciones](./config) +### Guardar la configuración en el entorno + +## [IV. Backing services](./backing-services) +### Tratar a los "backing services" como recursos conectables + +## [V. Construir, desplegar, ejecutar](./build-release-run) +### Separar completamente la etapa de construcción de la etapa de ejecución + +## [VI. Procesos](./processes) +### Ejecutar la aplicación como uno o más procesos sin estado + +## [VII. Asignación de puertos](./port-binding) +### Publicar servicios mediante asignación de puertos + +## [VIII. Concurrencia](./concurrency) +### Escalar mediante el modelo de procesos + +## [IX. Desechabilidad](./disposability) +### Hacer el sistema más robusto intentando conseguir inicios rápidos y finalizaciones seguras + +## [X. Paridad en desarrollo y producción](./dev-prod-parity) +### Mantener desarrollo, preproducción y producción tan parecidos como sea posible + +## [XI. Historiales](./logs) +### Tratar los historiales como una transmisión de eventos + +## [XII. Administración de procesos](./admin-processes) +### Ejecutar las tareas de gestión/administración como procesos que solo se ejecutan una vez diff --git a/content/es/who.md b/content/es/who.md new file mode 100644 index 000000000..a6391a916 --- /dev/null +++ b/content/es/who.md @@ -0,0 +1,4 @@ +¿Quién debería leer este documento? +=================================== + +Cualquier desarrollador que construya aplicaciones y las ejecute como un servicio. Ingenieros de operaciones que desplieguen y gestionen dichas aplicaciones. diff --git a/content/fr/admin-processes.md b/content/fr/admin-processes.md new file mode 100644 index 000000000..dd57d955a --- /dev/null +++ b/content/fr/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Processus d'administration +### Lancez les processus d'administration et de maintenance comme des one-off-processes + +La [formation de processus](./concurrency) est la liste des processus qui sont utilisés pour le fonctionnement normal de l'application (comme gérer les requêtes web) lorsqu'elle tourne. Les développeurs vont souvent vouloir effectuer des tâches occasionnelles d'administration ou de maintenance, comme : + +* Lancer les migrations de base de données (par ex. `manage.py migrate` avec Django, `rake db:migrate` avec Rails). +* Lancer une console (également appelée terminal [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop)) pour exécuter du code arbitraire ou inspecter les modèles de l'application dans la base de données. La plupart des langages fournissent un terminal REPL en lançant l'interpréteur sans arguments (par exemple `python` ou `perl`), ou dans certains cas à l'aide d'une commande dédiée (par ex. `irb` pour Ruby, `rails console` pour Rails). +* Exécuter des scripts ponctuels inclus dans le dépôt de code (par ex. `php scripts/fix_bad_records.php`). + +Les processus ponctuels d'administration devraient être lancés dans un environnement identique à ceux des [processus standards](./processes) de l'application. Ils s'exécutent sur une [release](./build-release-run), en utilisant la même [base de code](./codebase) et [configuration](./config) que tout processus qui tourne pour cette release. Le code d'administration doit être livré avec le code de l'application afin d'éviter les problèmes de synchronisation. + +La même technique d'[isolation de dépendances](./dependencies) doit être utilisée sur tous les types de processus. Par exemple, si le processus web de Ruby utilise la commande `bundle exec thin start`, alors une migration de base de données devrait être faite via `bundle exec rake db:migrate`. De la même manière, un programme Python qui utilise Virtualenv devrait utiliser la commande incluse `bin/python` pour lancer à la fois le serveur web Tornado et tout processus administrateur `manage.py`. + +Les applications 12 facteurs préfèrent les langages qui fournissent un terminal REPL prêt à l'emploi, et qui facilitent l'exécution de scripts ponctuels. Dans un déploiement local, les développeurs invoquent les processus ponctuels d'administration depuis le terminal, par une commande directement dans le répertoire où se trouve l'application. Dans un déploiement de production, les développeurs peuvent utiliser ssh ou d'autres mécanismes d'exécution de commandes fournis par l'environnement d'exécution de ce déploiement pour exécuter un tel processus. diff --git a/content/fr/background.md b/content/fr/background.md new file mode 100644 index 000000000..d5a179a0e --- /dev/null +++ b/content/fr/background.md @@ -0,0 +1,9 @@ +Contexte +========== + +Les contributeurs de ce document ont été directement impliqués dans le développement et le déploiement de centaines d'applications, et ont vu, indirectement, le développement, la gestion et le grossissement de centaines de milliers d'applications via le travail fait sur la plateforme [Heroku](http://www.heroku.com/). + +Ce document fait la synthèse de toutes nos expériences et observations sur une large variété d'applications software-as-a-service. C'est la triangulation de pratiques idéales pour le développement d'applications, en portant un soin tout particulier aux dynamiques de la croissance organique d'une application au cours du temps, les dynamiques de la collaboration entre les développeurs qui travaillent sur le code de l'application, en [évitant le coût de la lente détérioration du logiciel dans un environnement qui évolue (en)](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Notre motivation est de faire prendre conscience de certains problèmes systémiques que nous avons rencontrés dans le développement d'applications modernes, afin de fournir un vocabulaire partagé pour discuter ces problèmes, et pour offrir un ensemble de solutions conceptuelles générales à ces problèmes, ainsi que la terminologie correspondante. Le format est inspiré par celui des livres de Martin Fowler *[Patterns of Enterprise Application Architecture (en)](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* et *[Refactoring (en)](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. + diff --git a/content/fr/backing-services.md b/content/fr/backing-services.md new file mode 100644 index 000000000..e5e67d897 --- /dev/null +++ b/content/fr/backing-services.md @@ -0,0 +1,14 @@ +## IV. Services externes +### Traitez les services externes comme des ressources attachées + +Un *service externe* (backing service) correspond à tout service que l'application utilise à travers le réseau pour son fonctionnement nominal. Cela concerne par exemple les bases de données (tel que [MySQL](http://dev.mysql.com/) ou [CouchDB](http://couchdb.apache.org/)), les systèmes de messages/files (tel que [RabbitMQ](http://www.rabbitmq.com/) ou [Beanstalkd](https://beanstalkd.github.io)), les services SMTP pour l'envoi d'email (comme [Postfix](http://www.postfix.org/)), ainsi que les systèmes de cache (comme [Memcached](http://memcached.org/)). + +Les *services externes* comme la base de données sont le plus souvent gérés par les mêmes administrateurs réseau que ceux qui gèrent l'application de production. En plus de ces services gérés localement, l'application peut également avoir besoin de services gérés par des tiers. Cela concerne par exemple les services SMTP (comme [Postmark](http://postmarkapp.com/)), les services de gestion de métriques (comme [New Relic](http://newrelic.com/) ou [Loggly](http://www.loggly.com/)), les services de ressources binaires (comme [Amazon S3](http://aws.amazon.com/s3/)), et même les services que l'on peut consommer à travers une API (comme [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), ou [Last.fm](http://www.last.fm/api)). + +**Le code d'une application 12 facteurs ne fait pas de distinction entre les services locaux et les services tiers**. Pour l'application, ce sont tous les deux des ressources attachées, accessibles via une URL ou un autre système de localisation et d'authentification stockée dans la [configuration](./config). Un [déploiement](./codebase) d'une application 12 facteurs doit pouvoir remplacer une base de données MySQL locale par une autre gérée par des tiers ([Amazon RDS](http://aws.amazon.com/rds/), par exemple) sans le moindre changement dans le code de l'application. De la même manière, un serveur SMTP local doit pouvoir être remplacé par un service tiers (Postmark, par exemple) sans changements dans le code. Dans les deux cas, seules les informations de configurations doivent changer. + +Chaque service externe est une *ressource*. Par exemple, une base de données MySQL est une ressource. Deux bases de données MySQL (utilisées pour faire du sharding dans la couche applicative) correspondent à deux ressources distinctes. L'application 12 facteurs traite ces bases de données comme des ressources attachées, ce qui indique leur couplage faible au déploiement auquel elles sont rattachées. + +Un déploiement de production lié à quatre services externes. + +Les ressources peuvent être attachées et détachées à volonté à des déploiements. Par exemple, si la base de données de l'application pose problème pour des raisons matérielles, l'administrateur de l'application peut vouloir lancer un nouveau serveur de base de données restauré à partir d'une sauvegarde récente. L'application courante pourrait être détachée de l'ancienne, puis rattachée à la nouvelle — le tout sans changement dans le code. diff --git a/content/fr/build-release-run.md b/content/fr/build-release-run.md new file mode 100644 index 000000000..ae76a3b19 --- /dev/null +++ b/content/fr/build-release-run.md @@ -0,0 +1,19 @@ +## V. Assemblez, publiez, exécutez +### Séparez strictement les étapes d'assemblage et d'exécution + +Une [base de code](./codebase) est transformée en un déploiement (non-développement) à travers les étapes suivantes : + +* L'*étape d'assemblage* (ou "build") est une transformation qui convertit un dépôt de code en un paquet autonome exécutable appelé l'assemblage (ou "build"). En utilisant une version du code référencée par un commit spécifié lors du processus de déploiement, l'étape d'assemblage va chercher toutes les [dépendances externes](./dependencies) et compile les fichiers binaires et les ressources. +* L'*étape de publication * (ou "release") prend l'assemblage produit à l'étape précédente et le combine avec la [configuration](./config) de déploiement courante. La release résultante contient à la fois l'assemblage et la configuration, et elle est prête pour une exécution immédiate dans l'environnement d'exécution. +* L'*étape d'exécution* (ou "runtime") fait fonctionner l'application dans l'environnement d'exécution, en lançant un ensemble de [processus](./processes) de l'application associée à la release considérée. + +![Le code devient un assemblage, qui est combiné à la configuration pour créer une release](/images/release.png) + +**Les applications 12 facteurs ont une séparation stricte entre les étapes d'assemblage, de publication et d'exécution.** Par exemple, il est impossible de faire des changements dans le code au moment de son exécution, car il n'y a pas moyen de propager ces changements vers l'étape de build. + +Les outils de déploiement offrent généralement des outils de gestion de release, permettant notamment de revenir à une release antérieure. Par exemple, l'outil de déploiement [Capistrano](https://github.com/capistrano/capistrano/wiki) stocke les releases dans un sous-répertoire appelé `releases`, où la release courante est un lien symbolique vers le répertoire de release courante. Sa commande `rollback` permet de facilement revenir à une release précédente. + +Chaque release devrait toujours avoir un identifiant unique, comme un horodatage (timestamp) de la release (tel que `2011-04-06-20:32:17`) ou un nombre incrémental (tel que `v100`). La liste des releases est accessible en écriture incrémentale uniquement, et il n'est pas possible de modifier une release une fois qu'elle a été réalisée. Tout changement doit créer une nouvelle release. + +Les assemblages sont initiés par le développeur de l'application dès que du nouveau code est déployé. Son exécution, au contraire, peut avoir lieu automatiquement en cas d'un reboot du serveur, ou du crash d'un processus qui est relancé par le gestionnaire de processus. De ce fait, l'étape d'exécution doit se limiter à un nombre minimal de parties mobiles, car les problèmes qui empêchent une application de fonctionner peuvent entraîner des dysfonctionnements au milieu de la nuit alors qu'aucun développeur ne sera là pour les corriger. L'étape d'assemblage peut être plus complexe, car les erreurs pourront toujours être résolues par le développeur qui réalise le déploiement. + diff --git a/content/fr/codebase.md b/content/fr/codebase.md new file mode 100644 index 000000000..e50c048c9 --- /dev/null +++ b/content/fr/codebase.md @@ -0,0 +1,18 @@ +## I. Base de code +### Une base de code suivie avec un système de contrôle de version, plusieurs déploiements + +Une application 12 facteurs est toujours suivie dans un système de contrôle de version, tel que [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), ou [Subversion](http://subversion.apache.org/). Une copie de la base de données de suivi des révisions est appelée *dépôt de code*, souvent raccourci en *dépôt*. Le terme anglais *code repository*, raccourci en *repository* et *repo* est également utilisé. + +Une *base de code* correspond à chaque dépôt (dans un système de contrôle de version centralisé tel que Subversion), ou tout ensemble de dépôts qui partage un commit racine (dans un système de contrôle de version décentralisé comme Git). + +![Une base de code est associée à plusieurs déploiements](/images/codebase-deploys.png) + +Il y a toujours un rapport direct entre la base de code et l'application : + +* S'il y a plusieurs bases de code, ce n'est pas une application, c'est un système distribué. Chaque composant du système distribué est une application, et chacun peut individuellement respecter la méthodologie 12 facteurs. +* Plusieurs applications partageant le même code est une violation des 12 facteurs. La solution dans ce cas est de factoriser le code partagé dans des bibliothèques qui peuvent être intégrées via un [gestionnaire de dépendances](./dependencies). + +Il y a seulement une base de code par application, mais il y aura plusieurs déploiements de l'application. Un *déploiement* est une instance en fonctionnement de l'application. C'est, par exemple, le site en production, ou bien un ou plusieurs sites de validation. En plus de cela, chaque développeur a une copie de l'application qui fonctionne dans son environnement local de développement, ce qui compte également comme un déploiement. + +La base de code est la même à travers tous les déploiements, bien que différentes versions puissent être actives dans chaque déploiement. Par exemple, un développeur a des commits qui ne sont pas encore déployés dans l'environnement de validation. L'environnement de validation a des commits qui ne sont pas encore déployés en production. Par contre, ils partagent tous la même base de code, ce qui les identifie comme étant des déploiements différents d'une même application. + diff --git a/content/fr/concurrency.md b/content/fr/concurrency.md new file mode 100644 index 000000000..f3ff239ba --- /dev/null +++ b/content/fr/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Concurrence +### Grossissez à l'aide du modèle de processus + +Tout programme informatique, lorsqu'il s'exécute, est représenté par un ou plusieurs processus. Les applications web ont adopté différentes approches d'exécution de processus. Par exemple, les processus PHP s'exécutent comme des processus fils d'Apache, démarrés à la demande lorsque c'est requis par le volume de requêtes. Les processus Java ont adopté l'approche inverse, avec une machine virtuelle qui fournit un super-processus massif qui réserve un gros bloc de ressources système (processeur et mémoire) au démarrage, et la concurrence est gérée en interne à l'aide de threads. Dans les deux cas, les processus qui tournent sont à peine visibles aux développeurs de l'application. + +![La scalabilité est exprimée par des processus qui s'exécutent, la diversité de la charge de travail est exprimée par les types de processus](/images/process-types.png) + +**Dans une application 12 facteurs, les processus sont des élèves modèles**. Les processus dans une application 12 facteurs s'inspirent fortement du [modèle de processus unix pour faire fonctionner les daemon (en)](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). En utilisant ce modèle, les développeurs peuvent structurer l'application pour gérer différents types de charge en assignant chaque type de travail à un *type de processus*. Par exemple, les requêtes HTTP peuvent être gérées par un processus web, et les tâches d'arrière-plan ayant une longue durée d'exécution peuvent être des processus dits "worker". + +Chaque processus peut malgré tout et individuellement, gérer son propre multiplexage interne, avec des threads à l'intérieur de la machine virtuelle d'exécution, ou à l'aide du modèle d'évènements asynchrones que l'on retrouve dans des outils comme [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), ou [Node.js](http://nodejs.org/). Mais une machine virtuelle a individuellement une taille limitée (grandissement vertical), donc l'application doit également pouvoir déclencher plusieurs processus qui tournent sur plusieurs machines physiques. + +Le modèle de processus prend de l'envergure dès qu'il est question de grossir. La [nature sans partage, avec une partition horizontale des processus des applications 12 facteurs](./processes) signifie qu'ajouter plus de concurrence est une opération simple et fiable. La liste des types de processus et du nombre de processus de chaque type est appelée *formation de processus*. + +Les processus des applications 12 facteurs ne devraient [jamais être des daemons (en)](http://dustin.github.com/2010/02/28/running-processes.html) ou écrire des fichiers PID. À la place, utilisez le gestionnaire de processus du système d'exploitation (tel que [systemd](https://www.freedesktop.org/wiki/Software/systemd/), un gestionnaire de processus distribué sur une plateforme cloud, ou un outil comme [Foreman (en)](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) durant le développement) pour gérer les [flux de sortie](./logs), répondre à un processus qui plante, et gérer les redémarrages et les arrêts initiés par les utilisateurs. diff --git a/content/fr/config.md b/content/fr/config.md new file mode 100644 index 000000000..396519b4c --- /dev/null +++ b/content/fr/config.md @@ -0,0 +1,22 @@ +## III. Configuration +### Stockez la configuration dans l'environnement + +La *configuration* d'une application est tout ce qui est susceptible de varier entre des [déploiements](./codebase) (validation, production, environnement de développement, etc.). Cela inclut : + +* Les ressources gérées par la base de données, Memcached, ou tout autre [service de stockage](./backing-services) +* Les identifiants pour des services externes, tel qu'Amazon S3 ou Twitter +* Les valeurs spécifiques au déploiement, tel que son nom d'hôte canonique + +Les applications stockent parfois la configuration avec des constantes dans le code. C'est une violation des 12 facteurs, qui requiert une **stricte séparation de la configuration et du code**. La configuration peut varier substantiellement à travers les déploiements, alors que ce n'est pas le cas du code. + +Un bon moyen de tester si une application a correctement séparé son code, c'est de se demander si l'application pourrait être rendue open-source à tout instant, sans compromettre d'identifiants. + +Notez que cette définition de "configuration" n'inclut **pas** la configuration interne de l'application, tel que `config/routes.rb` avec Rails, ou comment [les modules du noyau sont connectés (en)](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) dans [Spring](http://spring.io/). Ce type de configuration ne varie pas à travers les déploiements, et est ainsi mieux réalisé dans le code. + +Une autre approche de la configuration, c'est d'utiliser des fichiers de configuration qui ne sont pas inclus dans le système de contrôle de version, par exemple `config/database.yml` de Rails. C'est une amélioration considérable par rapport à l'utilisation de constantes qui sont versionnées dans le dépôt de code, mais a toujours des faiblesses : il est facile d'ajouter par inadvertance un fichier de configuration dans le dépôt. Il y a une tendance à ce que les fichiers de configuration soient dispersés à différents endroits et dans différents formats, rendant ainsi difficile de voir et gérer la configuration à un unique endroit. De plus, ces formats ont tendance à être spécifiques à un langage ou un framework. + +**Les applications 12 facteurs stockent la configuration dans des *variables d'environnement*** (souvent raccourcies en *variables d'env*, ou *env*). Les variables d'environnement sont faciles à changer entre des déploiements sans changer le moindre code ; contrairement aux fichiers de configuration, il y a peu de chance pour qu'elles soient ajoutées au dépôt de code accidentellement ; et contrairement aux fichiers de configuration personnalisés, ou tout autre mécanisme de configuration comme les propriétés système Java, ce sont des standards agnostiques du langage ou du système d'exploitation. + +Un autre aspect de la gestion de configuration est le groupage. Parfois, les applications regroupent la configuration dans des groupes nommés (souvent appelés les "environnements"), nommés ainsi d'après des déploiements spécifiques, comme les environnements `development`, `test`, et `production` de Rails. Cette méthode ne permet pas de grossir proprement : lorsque l'on ajoute de nouveaux déploiement à l'application, de nouveaux noms d'environnement sont nécessaires, comme `validation` ou `qa`. Quand le projet grossit encore plus, les développeurs vont avoir tendance à ajouter leurs propres environnements particuliers, comme `joes-validation`, ce qui entraîne une explosion combinatoire de la configuration qui rend la gestion des déploiements de l'application très fragile. + +Dans une application 12 facteurs, les variables d'environnement permettent un contrôle granulaire, chacune complètement orthogonale aux autres variables d'environnement. Elles ne sont jamais groupées ensemble en "environnements", mais sont plutôt gérées indépendamment pour chaque déploiement. C'est un modèle qui permet de grossir verticalement en souplesse, lorsque l'application grossit naturellement en un plus grand nombre de déploiements au cours de sa vie. diff --git a/content/fr/dependencies.md b/content/fr/dependencies.md new file mode 100644 index 000000000..146c066d1 --- /dev/null +++ b/content/fr/dependencies.md @@ -0,0 +1,12 @@ +## II. Dépendances +### Déclarez explicitement et isolez les dépendances + +La plupart des langages de programmation offrent des systèmes pour créer des paquets à partir de bibliothèques afin de les distribuer, tel que [CPAN](http://www.cpan.org/) pour Perl ou [Rubygems](http://rubygems.org/) pour Ruby. Les bibliothèques installées à travers un système de packaging peuvent être installées à travers tout le système, ou bien limitées au répertoire contenant l'application (que l'on appelle les "vendor" ou "bundles"). + +**Une application 12 facteurs ne dépend jamais de l'existence implicite de packages au niveau du système**. Elle déclare toutes ses dépendances, complètement et exactement, à travers un manifeste de *déclaration de dépendances*. De plus, elle utilise un outil d'isolation des dépendances durant l'exécution afin d'assurer qu'aucune dépendance implicite ne s'introduise depuis le système environnant. Les spécifications complètes et explicites sont appliquées uniformément en développement comme en production. + +Par exemple, [Bundler](https://bundler.io/) pour Ruby fournit le format de manifeste `Gemfile` pour la déclaration des dépendances, ainsi que la commande `bundle exec` pour l'isolation des dépendances. En python, il y a deux outils séparés pour ces étapes -- [Pip](http://www.pip-installer.org/en/latest/) est utilisé pour la déclaration et [Virtualenv](http://www.virtualenv.org/en/latest/) pour l'isolation. Même le C dispose d'[Autoconf](http://www.gnu.org/s/autoconf/) pour les déclarations de dépendances, et la liaison statique peut fournir l'isolation des dépendances. Peu importe la chaîne d'outils, la déclaration et l'isolation des dépendances doivent toujours être utilisées ensemble -- seulement l'un ou l'autre ne suffit pas à satisfaire les 12 facteurs. + +Un des bénéfices de la déclaration explicite des dépendances est que cela simplifie la mise en place pour les développeurs qui découvrent l'application. Les nouveaux développeurs peuvent jeter un œil à la base de code de l'application sur leur machine de développement, en ayant besoin uniquement d'avoir de quoi exécuter le langage ainsi que le gestionnaire de dépendances installé en pré-requis. Ils pourront mettre en place tout ce qui est nécessaire pour faire fonctionner le code de l'application de manière déterministe grâce à une *commande d'assemblage* (commande de build). Par exemple, la commande d'assemblage pour Ruby/Bundler est `bundle install`, alors que pour Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) c'est `lein deps`. + +Les applications 12 facteurs ne s'appuient pas sur l'existence implicite d'outils système, par exemple ImageMagick ou `curl`. Bien que ces outils puissent exister sur beaucoup voire la plupart des systèmes d'exploitation, il n'y a pas de garantie qu'ils existeront sur tous les systèmes où l'application sera exécutée à l'avenir, ou si la version disponible sur un système futur sera compatible avec l'application. Si l'application dépend d'un outil système, cet outil doit être distribué avec l'application. diff --git a/content/fr/dev-prod-parity.md b/content/fr/dev-prod-parity.md new file mode 100644 index 000000000..1cd06c0b4 --- /dev/null +++ b/content/fr/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Parité dev/prod +### Gardez le développement, la validation et la production aussi proches que possible + +Historiquement, il y a eu un fossé conséquent entre le développement (un développeur qui fait des modifications sur un [déploiement](./codebase) local de l'application) et la production (un déploiement de l'application accessible aux utilisateurs finaux). Ce fossé se manifeste de trois manières : + +* **Le fossé temporel** : un développeur peut travailler sur du code qui peut prendre des jours, des semaines ou des mois avant d'aller en production +* **Le fossé des personnes** : les développeurs écrivent le code, et d'autres personnes le déploient. +* **Le fossé des outils** : les développeurs peuvent utiliser une pile comme Nginx, SQLite, et OS X, alors que le déploiement de production utilise Apache, MySQL, et Linux. + +**Les applications 12 facteurs sont conçues pour le [déploiement continu (en)](http://avc.com/2011/02/continuous-deployment/) en gardant un fossé étroit entre le développement et la production.** Si l'on regarde les trois fossés décrits plus haut : + +* Réduire le fossé temporel : un développeur peut écrire du code et le déployer quelques heures ou même juste quelques minutes plus tard. +* Réduire le fossé des personnes : les personnes qui écrivent le code sont impliquées dans son déploiement et pour surveiller son comportement en production. +* Réduire le fossé des outils : réduire, autant que possible, les différences entre le développement et la production. + +Si l'on résume cela en un tableau : + + + + + + + + + + + + + + + + + + + + + + +
Application traditionnelleApplication 12 facteurs
Temps entre les déploiementsSemainesHeures
Auteurs du code et ceux qui le déploientDes personnes différentesLes mêmes personnes
L'environnement de développement et celui de productionDivergentsAussi similaires que possible
+ +[Les services externes](./backing-services), tels que la base de données, la file de messages, ou le cache sont des éléments importants de la parité développement/production. La plupart des langages fournissent des bibliothèques qui simplifient l'accès à ces services externes, en fournissant des adaptateurs pour différents types de services. Voici quelques exemples dans le tableau ci-dessous. + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeLangageLibrairieAdaptateurs
Base de donnéesRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
File de messagesPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CacheMémoire, système de fichiers, Memcached
+ +Les développeurs trouvent parfois agréable d'utiliser des services externes légers dans leur environnement local, alors qu'un service externe plus sérieux et robuste est utilisé en production. Par exemple, utiliser SQLite en local, et PostgreSQL en production; ou bien, durant le développement, mettre les données en cache dans la mémoire des processus locaux, et utiliser Memcached en production. + +**Les développeurs des applications 12 facteurs résistent au besoin d'utiliser des services externes différents entre le développement local et la production**, même lorsque les adaptateurs permettent d'abstraire en théorie beaucoup de différences entre les services externes. Les différences entre les services externes signifient que de petites incompatibilités surviennent, ce qui va faire que du code qui fonctionnait et qui passait les tests durant le développement ou la validation ne fonctionnera pas en production. Ce type d'erreurs crée de la friction en défaveur du déploiement continu. Le coût de cette friction et son impact négatif sur le déploiement continu est extrêmement élevé lorsqu'il est cumulé sur toute la vie de l'application. + +Les services locaux légers sont moins attirants aujourd'hui qu'ils ne l'étaient autrefois. Les services externes modernes tels que Memcached, PostgreSQL, et RabbitMQ ne sont pas difficiles à installer et à faire fonctionner grâce aux systèmes de paquets modernes comme [Homebrew](http://mxcl.github.com/homebrew/) et [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Autre possibilité, des outils de provisionnement comme [Chef](http://www.opscode.com/chef/) et [Puppet](http://docs.puppetlabs.com/), combinés à des environnements virtuels légers comme [Docker](https://www.docker.com/) et [Vagrant](http://vagrantup.com/) permettent aux développeurs de faire fonctionner des environnements locaux qui reproduisent de très près les environnements de production. Le coût d'installation et d'utilisation de ces systèmes est faible comparé aux bénéfices d'une bonne parité développement/production et du déploiement continu. + +Les adaptateurs à ces différents systèmes externes sont malgré tout utiles, car ils rendent le portage vers de nouveaux services externes relativement indolores. Mais tous les déploiements de l'application (environnement de développement, validation, production) devraient utiliser le même type et la même version de chacun de ces services externes. diff --git a/content/fr/disposability.md b/content/fr/disposability.md new file mode 100644 index 000000000..61afcdfdd --- /dev/null +++ b/content/fr/disposability.md @@ -0,0 +1,14 @@ +## IX. Jetable +### Maximisez la robustesse avec des démarrages rapides et des arrêts gracieux + +**Les [processus](./processes) des applications 12 facteurs sont *jetables*, c'est-à-dire qu'ils peuvent être démarrés ou stoppés en un instant.** Cela simplifie un rapide grossissement vertical, le déploiement rapide du [code](./codebase) ou de changements dans la [configuration](./config), ainsi que la robustesse des déploiements de production. + +Les processus doivent viser à **minimiser le temps de démarrage**. Idéalement, un processus prend quelques secondes entre le moment où une commande le lance et celui où il est en marche et prêt à recevoir des requêtes ou du travail. Un court temps de démarrage rend les processus de [release](./build-release-run) et de scalabilité verticale plus agiles; il aide également à la robustesse, car les gestionnaires de processus peuvent plus facilement déplacer des processus vers de nouvelles machines physiques lorsque c'est nécessaire. + +Les processus **s'éteignent gracieusement lorsqu'ils reçoivent un signal [SIGTERM (fr)](https://fr.wikipedia.org/wiki/SIGTERM)** du gestionnaire de processus. Pour un processus web, s'éteindre en douceur se fait en arrêtant d'écouter sur le port de service (refusant, par la même occasion, toute nouvelle requête), en permettant à la requête courante de se terminer, et en quittant ensuite. Ce qui est implicite dans ce modèle, c'est que les requêtes sont courtes (pas plus de quelques secondes), ou dans le cas de longues requêtes, les clients doivent pouvoir tenter de se reconnecter sans problème lorsque la connection est perdue. + +Pour un processus de worker, s'éteindre gracieusement est réalisé en renvoyant le travail en cours dans la file de travaux. Par exemple, avec [RabbitMQ](http://www.rabbitmq.com/) le worker peut envoyer un message [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); avec [Beanstalkd](https://beanstalkd.github.io), le travail est renvoyé dans la file automatiquement dès qu'un worker se déconnecte. Les systèmes basés sur des verrous, comme [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) doivent s'assurer de supprimer le verrou de leur travail en cours. Il est implicite dans ce modèle que toutes les tâches sont [réentrantes (fr)](http://fr.wikipedia.org/wiki/R%C3%A9entrance), ce qui est réalisé en englobant les résultats dans une transaction, ou en rendant l'opération [idempotente (fr)](http://fr.wikipedia.org/wiki/Idempotence). + +Les processus doivent également être **robustes face aux morts subites**, dans le cas d'une panne du hardware sous-jacent. Bien que ce soit bien moins courant qu'un arrêt gracieux avec `SIGTERM`, cela peut arriver malgré tout. L'approche recommandée est l'utilisation d'un backend robuste de files de messages, tel que Beanstalkd, capable de renvoyer les tâches dans la file lorsqu'un client se déconnecte ou ne répond plus. Dans les deux cas, une application 12 facteurs est structurée pour gérer des fins inattendues et non-gracieuses. Le [design crash-only (en)](http://lwn.net/Articles/191059/) amène ce concept à sa [conclusion logique (en)](http://docs.couchdb.org/en/latest/intro/overview.html). + + diff --git a/content/fr/intro.md b/content/fr/intro.md new file mode 100644 index 000000000..d7d220cf4 --- /dev/null +++ b/content/fr/intro.md @@ -0,0 +1,12 @@ +Introduction +============ + +À l'époque actuelle, les logiciels sont régulièrement délivrés en tant que services : on les appelle des *applications web* (web apps), ou *logiciels en tant que service* (*software-as-a-service*). L'application 12 facteurs est une méthodologie pour concevoir des logiciels en tant que service qui : + +* Utilisent des formats **déclaratifs** pour mettre en oeuvre l'automatisation, pour minimiser le temps et les coûts pour que de nouveaux développeurs rejoignent le projet; +* Ont un **contrat propre** avec le système d'exploitation sous-jacent, offrant une **portabilité maximum** entre les environnements d'exécution; +* Sont adaptés à des **déploiements** sur des **plateformes cloud** modernes, rendant inutile le besoin de serveurs et de l'administration de systèmes; +* **Minimisent la divergence** entre le développement et la production, ce qui permet le **déploiement continu** pour une agilité maximum; +* et peuvent **grossir verticalement** sans changement significatif dans les outils, l'architecture ou les pratiques de développement; + +La méthodologie 12 facteurs peut être appliquée à des applications écrites dans tout langage de programmation, et qui utilisent tout type de services externes (base de données, file, cache mémoire, etc.) diff --git a/content/fr/logs.md b/content/fr/logs.md new file mode 100644 index 000000000..ec5d26ea2 --- /dev/null +++ b/content/fr/logs.md @@ -0,0 +1,16 @@ +## XI. Logs +### Traitez les logs comme des flux d'évènements + +Les *logs* fournissent de la visibilité au comportement de l'application qui s'exécute. Dans des environnements de type serveur, ils sont généralement écrits dans un fichier, sur le disque (dans un fichier de log). Mais c'est simplement un format de sortie. + +Les logs sont des [flux (en)](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) d'agrégats d'évènements, ordonnés dans le temps, collectés à travers les flux de sortie de tous les processus et services externes qui tournent. Les logs, dans leur forme brute, sont au format texte avec un événement par ligne (bien que les traces d'exécutions puissent s'étaler sur plusieurs lignes). Les logs n'ont pas de début ou de fin fixe, mais se remplissent en continu tant que l'application est en marche. + +**Une application 12 facteurs ne s'inquiète jamais du routage ou du stockage de ses flux de sortie.** Elle ne devrait pas tenter d'écrire ou de gérer les fichiers de logs. À la place, chaque processus qui tourne écrit ses flux d'événements, sans tampon, vers `stdout`, la sortie standard ; en phase de développement local, les développeurs pourront voir ce flux dans leur terminal et observer le comportement de l'application. + +Dans les déploiements de validation ou de production, les flux de chaque processus seront capturés par leur environnement d'exécution, assemblés avec les autres flux de l'application, et routés vers une ou plusieurs destinations pour un visionnage et un archivage de longue durée. Le lieu d'archivage n'est pas visible et ne peut être configuré par l'application : ils sont complètements gérés par l'environnement d'exécution. Des routeurs opensource de logs, (tel que [Logplex](https://github.com/heroku/logplex) et [Fluentd](https://github.com/fluent/fluentd)) existent pour cela. + +Le flux d'événements d'une application peut être routé dans un fichier, ou surveillé en temps réel (avec tail) dans un terminal. Plus pertinent, les flux peuvent être envoyés vers un outil d'indexation et d'archivage des logs tel que [Splunk](http://www.splunk.com/), ou bien dans un entrepôt de données générique comme [Hadoop/Hive](http://hive.apache.org/). Ces systèmes sont très puissants et flexibles pour inspecter le comportement de l'application au cours du temps, ce qui inclut : + +* Trouver un événement spécifique dans le passé +* Faire des graphiques à grande échelle des tendances (comme le nombre de requêtes par minutes) +* Lever des alertes, à partir d'heuristiques définies par l'utilisateur (comme alerter dès que la quantité d'erreurs par minutes dépasse un certain seuil) diff --git a/content/fr/port-binding.md b/content/fr/port-binding.md new file mode 100644 index 000000000..09036e959 --- /dev/null +++ b/content/fr/port-binding.md @@ -0,0 +1,14 @@ +## VII. Associations de ports +### Exportez les services via des associations de ports + +Les applications web sont parfois exécutées à l'intérieur d'un container de serveur web. Par exemple, les applications PHP peuvent fonctionner comme un module à l'intérieur de [HTTPD, d'Apache](http://httpd.apache.org/), ou bien les applications Java peuvent fonctionner à l'intérieur de [Tomcat](http://tomcat.apache.org/). + +**Les applications 12 facteurs sont complètement auto-contenues** et ne se basent pas sur l'injection au moment de l'exécution d'un serveur web dans l'environnement d'exécution pour créer les services exposés au web. L'application web **expose HTTP comme un service en l'associant à un port** et écoute les requêtes qui arrivent sur ce port. + +Dans un environnement de développement local, le développeur visite l'URL d'un service tel que `http://localhost:5000/` pour accéder au service exporté par leur application. Durant le déploiement, une couche de routage gère le routage des requêtes depuis un nom d'hôte qui s'expose au public, vers les processus sur lequel est associé le port. + +Ceci est typiquement implémenté en utilisant [la déclaration de dépendances](./dependencies) pour ajouter une bibliothèque de serveur web, tel que [Tornado](http://www.tornadoweb.org/) pour Python, [Thin](http://code.macournoyer.com/thin/) pour Ruby, ou [Jetty](http://www.eclipse.org/jetty/) pour Java et autres langages basés sur la JVM. Cela se déroule entièrement dans l'espace utilisateur, c'est-à-dire, dans le code de l'application. Le contrat avec l'environnement d'exécution, c'est l'association de port pour servir les requêtes. + +HTTP n'est pas le seul service qui peut être exporté à l'aide d'association de ports. Presque tout type de serveur peut fonctionner à travers l'association à un port et l'écoute des requêtes entrantes. Il y a par exemple [ejabberd](http://www.ejabberd.im/) (qui parle [XMPP](http://xmpp.org/)), et [Redis](http://redis.io/) (qui parle le [protocole Redis](http://redis.io/topics/protocol)). + +Notez également que l'approche par association de port signifie qu'une application peut devenir le [service externe](./backing-services) d'une autre application, en fournissant l'URL de l'application externe dans la configuration de l'application qui la consomme. diff --git a/content/fr/processes.md b/content/fr/processes.md new file mode 100644 index 000000000..7b0d56459 --- /dev/null +++ b/content/fr/processes.md @@ -0,0 +1,16 @@ +## VI. Processus +### Exécutez l'application comme un ou plusieurs processus sans état + +L'application est exécutée dans l'environnement d'exécution comme un ou plusieurs *processus*. + +Dans la situation la plus simple, le code est un script indépendant, l'environnement d'exécution est l'ordinateur portable du développeur sur lequel est installé de quoi exécuter le langage, et le processus est lancé depuis la ligne de commande. (par exemple, `python mon_script.py`). De l'autre côté du spectre, un déploiement de production d'une application sophistiquée peut utiliser plusieurs [types de processus, instanciés dans zéro ou plus processus en fonctionnement](./concurrency). + +**Les processus 12 facteurs sont sans état et ne partagent [rien (en)](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Toute donnée qui doit être persistée doit être stockée dans un [service externe](./backing-services) stateful, typiquement une base de données. + +L'espace mémoire ou le système de fichier du processus peut être utilisé comme cache momentané pour des transactions uniques. Par exemple, télécharger un gros fichier, effectuer une opération dessus, puis stocker le résultat de l'opération dans la base de données. Les applications 12 facteurs ne supposent jamais que quelque chose ayant été mis en cache en mémoire ou sur le disque sera disponible dans une future requête ou job — avec plusieurs processus de chaque type qui s'exécutent, il y a de grandes chances qu'une future requête soit effectuée par un processus différent. Même lorsque l'on fait tourner seulement un processus, un redémarrage (déclenché par le déploiement du code, un changement de configuration, ou l'environnement d'exécution qui déplace le processus vers un lieu physique différent) va généralement balayer toutes les modifications locales (c'est-à-dire en mémoire et sur le disque). + +Des outils de création de paquets de ressources (ou "asset packagers") (tel que [Jammit](http://documentcloud.github.com/jammit/) ou [django-compressor](http://django-compressor.readthedocs.org/)) utilisent le système de fichier comme cache pour les ressources compilées. Une application 12 facteurs préfère faire cette compilation durant l'[étape d'assemblage](./build-release-run), comme avec le [pipeline des ressources de Rails](http://guides.rubyonrails.org/asset_pipeline.html), plutôt que durant l'exécution. + +Certains systèmes web s'appuient sur des ["sessions persistantes" (en)](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- c'est-à-dire, mettre en cache les données de session utilisateur dans le processus de l'application et attendre que les requêtes futures du même visiteur seront routées dans le même processus. Les sessions persistantes sont une violation des 12 facteurs, qu'il ne faudrait jamais utiliser. +Les états de session sont de bons candidats pour un datastore qui offre des dates d'expiration, comme [Memcached](http://memcached.org/) ou [Redis](http://redis.io/). + diff --git a/content/fr/toc.md b/content/fr/toc.md new file mode 100644 index 000000000..c67e46eb9 --- /dev/null +++ b/content/fr/toc.md @@ -0,0 +1,38 @@ +Les 12 facteurs +================== + +## [I. Base de code](./codebase) +### Une base de code suivie avec un système de contrôle de version, plusieurs déploiements + +## [II. Dépendances](./dependencies) +### Déclarez explicitement et isolez les dépendances + +## [III. Configuration](./config) +### Stockez la configuration dans l'environnement + +## [IV. Services externes](./backing-services) +### Traitez les services externes comme des ressources attachées + +## [V. Assemblez, publiez, exécutez](./build-release-run) +### Séparez strictement les étapes d'assemblage et d'exécution + +## [VI. Processus](./processes) +### Exécutez l'application comme un ou plusieurs processus sans état + +## [VII. Associations de ports](./port-binding) +### Exportez les services via des associations de ports + +## [VIII. Concurrence](./concurrency) +### Grossissez à l'aide du modèle de processus + +## [IX. Jetable](./disposability) +### Maximisez la robustesse avec des démarrages rapides et des arrêts gracieux + +## [X. Parité dev/prod](./dev-prod-parity) +### Gardez le développement, la validation et la production aussi proches que possible + +## [XI. Logs](./logs) +### Traitez les logs comme des flux d'évènements + +## [XII. Processus d'administration](./admin-processes) +### Lancez les processus d'administration et de maintenance comme des one-off-processes diff --git a/content/fr/who.md b/content/fr/who.md new file mode 100644 index 000000000..3396c7aec --- /dev/null +++ b/content/fr/who.md @@ -0,0 +1,4 @@ +Qui devrait lire ce document ? +============================== + +Tout développeur qui construit des applications qui fonctionnent en tant que service, ainsi que les personnes qui déploient et gèrent de telles applications. diff --git a/content/it/admin-processes.md b/content/it/admin-processes.md new file mode 100644 index 000000000..327282d0a --- /dev/null +++ b/content/it/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Processi di Amministrazione +### Esegui i task di amministrazione come processi una tantum + +La "[process formation](./concurrency)" è l'array dei processi che vengono usati durante le normali operazioni dell'applicazione (per esempio, la gestione delle richieste web). Non è tutto, però: ci sono dei task che lo sviluppatore può voler eseguire, una volta ogni tanto. Per esempio: + +* Esecuzione delle migration del database (esempi: `manage.py migrate` in Django, `rake db:migrate` in Rails). +* Esecuzione di una console (una [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) in modo tale da avviare del codice arbitrariamente o analizzare alcuni aspetti dell'applicazione specifici. Molti linguaggi prevedono una REPL, in genere avviando l'interprete senza opzioni e argomenti aggiuntivi (esempi: `python` o `perl`) o in alcuni casi eseguibile con un comando separato (esempi: `irb` per Ruby, `rails console` per Rails). +* Esecuzione one-time di alcuni script specifici (esempio: `php scripts/fix_bad_records.php`). + +Tali processi dovrebbero essere avviati in un ambiente identico a quello in cui [lavorano gli altri](./processes) nel contesto dell'applicazione. Dovrebbero essere eseguiti quindi su una specifica [release](./build-release-run), partendo dalla stessa [codebase](./codebase) e impostazioni di [configurazione](./config). Il codice per l'amministrazione dovrebbe inoltre essere incluso nel codice dell'applicazione, in modo tale da evitare qualsiasi problema di sincronizzazione. + +La stessa tecnica di [isolamento delle dipendenze](./dependencies) dovrebbe poter essere usata allo stesso modo su tutti i processi. Per esempio, se il processo web di Ruby può usare il comando `bundle exec thin start`, una migration del database dovrebbe poter usare `bundle exec rake db:migrate` senza problemi. Allo stesso modo, un programma Python che usa Virtualenv dovrebbe usare il `bin/python` per eseguire sia i server Tornado che processi di amministrazione. + +La metodologia twelve-factor favorisce molto tutti quei linguaggi che offrono una shell REPL out of the box, rendendo quindi semplice l'esecuzione di script una tantum. In un deployment locale, gli sviluppatori possono invocare questi processi speciali tramite un semplice comando diretto. In un ambiente di produzione, invece, gli sviluppatori possono raggiungere lo stesso obiettivo tramite SSH o un qualsiasi altro sistema di esecuzione di comandi remoto. diff --git a/content/it/background.md b/content/it/background.md new file mode 100644 index 000000000..7552707aa --- /dev/null +++ b/content/it/background.md @@ -0,0 +1,8 @@ +Background +========== + +Chi ha scritto questo documento è stato coinvolto direttamente nella realizzazione e nel deployment di centinaia di applicazioni, e ha indirettamente assistito allo sviluppo, le operazioni e lo scaling di centinaia (o migliaia) di app tramite il proprio lavoro sulla piattaforma [Heroku](http://www.heroku.com/). + +Questo documento riassume tutta quella che è stata la nostra esperienza, basata sull'osservazione di un grande numero di applicazioni SaaS. Si tratta di una "triangolazione" di pratiche di sviluppo ideali (con una particolare attenzione alla crescita organica dell'app nel tempo), la collaborazione dinamica nel corso del tempo tra gli sviluppatori sulla codebase e la necessità di evitare i costi di [software erosion](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +La nostra motivazione è di far crescere la consapevolezza intorno ad alcuni problemi sistemici che abbiamo scoperto nello sviluppo di applicazioni moderne, cercando di fornire un vocabolario condiviso per la discussione di tali problemi. Oltre, ovviamente, a offrire delle soluzioni concettuali a queste situazioni (senza però tralasciare il fattore tecnologia). Questo format si rifà ai libri di Martin Fowler *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* e *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. diff --git a/content/it/backing-services.md b/content/it/backing-services.md new file mode 100644 index 000000000..781901b9a --- /dev/null +++ b/content/it/backing-services.md @@ -0,0 +1,14 @@ +## IV. Backing Service +### Tratta i backing service come "risorse" + +Un "backing service" è un qualsiasi servizio che l'applicazione consuma attraverso la rete durante la sua esecuzione. Alcuni esempi includono i database (come [MySQL](http://dev.mysql.com/) o [CouchDB](http://couchdb.apache.org/)), servizi di messaging/code (come [RabbitMQ](http://www.rabbitmq.com/) oppure [Beanstalkd](https://beanstalkd.github.io)), servizi SMTP per la posta (come [Postfix](http://www.postfix.org/)) e sistemi di cache (come [Memcached](http://memcached.org/)). + +Un backing service (prendiamo ad esempio un database) è tradizionalmente gestito dallo stesso amministratore di sistema, al deployment dell'applicazione. In aggiunta a questi servizi gestiti in locale potrebbero esserne presenti altri, forniti da terze parti. Parliamo di servizi SMTP (come [Postmark](http://postmarkapp.com/)), servizi di raccolta metriche (come [New Relic](http://newrelic.com/) o [Loggly](http://www.loggly.com/)), servizi per asset (come [Amazon S3](http://aws.amazon.com/s3/)), e anche servizi accessibili via API (come [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), o [Last.fm](http://www.last.fm/api)). + +**Il codice di un'app twelve-factor non fa distinzioni tra servizi in locale o third party**. Per l'applicazione, entrambi sono risorse connesse, accessibili via URL (o tramite un altro locator) e credenziali memorizzate nell'opportuno file di [configurazione](./config). A un qualsiasi [deployment](./codebase) di un'applicazione twelve-factor si deve poter permettere di passare velocemente da un database MySQL locale a uno third party (come [Amazon RDS](http://aws.amazon.com/rds/)) senza alcuna modifica al codice. Allo stesso modo, un server SMTP locale dovrebbe poter essere cambiato con uno third party (come Postmark). In entrambi i casi, a cambiare dovrebbero essere **solo** i file di configurazione necessari. + +Ogni backing service è quindi definibile come una "risorsa connessa". Un Database MySQL è una risorsa. Due database MySQL (utilizzati per lo sharding a livello di applicazione) saranno visti come due distinte risorse. Un'app twelve-factor vede questi database come *risorse* anche per sottolineare la separazione dal deployment a cui fanno riferimento. + +Un deployment di produzione collegato a quattro backing service. + +Le risorse possono essere collegate e scollegate da un deployment a piacimento. Per esempio, supponiamo che il database dell'applicazione si comporti in modo anomalo per problemi hardware. L'amministratore potrebbe decidere di voler configurare un altro server di database ripreso da un recente backup. Il vecchio database verrebbe scollegato, quello nuovo connesso -- senza modifiche al codice. diff --git a/content/it/build-release-run.md b/content/it/build-release-run.md new file mode 100644 index 000000000..96927e3b1 --- /dev/null +++ b/content/it/build-release-run.md @@ -0,0 +1,18 @@ +## V. Build, release, esecuzione +### Separare in modo netto lo stadio di build dall'esecuzione + +Una [codebase](./codebase) viene "trasformata" in deployment attraverso tre fasi: + +* la fase di *build*, che converte il codice del repo in una build "eseguibile". Usando una certa versione del codice, a una specifica commit, nella fase di build vengono compilati i binari con gli asset appropriati includendo anche le eventuali dipendenze; +* la fase di *release* prende la build prodotta nella fase precedente e la combina con l'attuale insieme di impostazioni di configurazione del deployment specifico. La *release* risultante contiene sia la build che le impostazioni; +* la fase di *esecuzione* (conosciuta anche come "runtime") vede l'applicazione in esecuzione nell'ambiente di destinazione, attraverso l'avvio di processi della release scelta; + +![Il codice diventa build, che combinata con le impostazioni diventa release.](/images/release.png) + +**Un'app twelve-factor definisce una separazione netta tra build, release ed esecuzione.** Per esempio, è impossibile effettuare dei cambiamenti del codice a runtime, dato che non c'è modo di propagare queste modifiche all'"indietro", verso la fase di build. + +I tool di deployment offrono tipicamente dei tool di gestione delle release, in particolare alcuni dedicati a un rollback verso una release precedente. Per esempio, [Capistrano](https://github.com/capistrano/capistrano/wiki) memorizza le varie release in una sotto-directory chiamata `releases`, in cui la release attuale non è che un symlink verso la directory della release attuale. Il comando di rollback permette di tornare indietro a una certa release velocemente. + +Ogni release dovrebbe inoltre possedere un ID univoco di rilascio, come per esempio un timestamp (es. `2011-04-06-20:32:17`) o un numero incrementale (es. `v100`). In un certo senso, la creazione di una release è una procedura "a senso unico" e una certa release non può essere modificata dopo la sua creazione. Qualsiasi cambiamento deve quindi prevedere una nuova release. + +Una fase di build è sempre avviata da uno sviluppatore, non appena il codice viene modificato. Al contrario, l'esecuzione può essere anche gestita in modo automatico (si pensi al riavvio del server oppure a un crash con successivo riavvio del processo). A ogni modo, una volta in esecuzione, la regola aurea è di evitare il più possibile (se non del tutto) modifiche che potrebbero rompere qualche equilibrio. Magari nel bel mezzo della notte, quando non c'è nessuno disponibile. La fase di build può essere sicuramente più "faticosa", comunque, visto che possono verificarsi degli errori da risolvere prima di proseguire. diff --git a/content/it/codebase.md b/content/it/codebase.md new file mode 100644 index 000000000..e7669a05c --- /dev/null +++ b/content/it/codebase.md @@ -0,0 +1,17 @@ +## I. Codebase +### Una sola codebase sotto controllo di versione, tanti deploy + +Un'app conforme alla metodologia twelve-factor è sempre sotto un sistema di controllo di versione, sia essa [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), o [Subversion](http://subversion.apache.org/). Una copia della codebase è detta *code repository*, oppure più in breve *code repo* o *repo*. + +Una *codebase* è quindi un singolo repository (in un sistema centralizzato come Subversion), oppure un set di repo che condividono una root commit (in un sistema di controllo decentralizzato come Git). + +![Una codebase, N deployment](/images/codebase-deploys.png) + +C'è sempre una relazione uno-ad-uno tra codebase e applicazione: + +* Se ci sono più codebase, non si parla più di applicazione ma di sistema distribuito. Ogni componente in un sistema distribuito è un'applicazione, e ognuna di queste applicazioni può individualmente aderire alla metodologia twelve-factor. +* Se più applicazioni condividono lo stesso codice si ha una violazione del twelve-factor. La soluzione è, ovviamente, quella di sistemare il codice in modo adeguato, in modo tale da essere incluso eventualmente dove necessario tramite un [dependency manager](./dependencies). + +Quindi: una sola codebase per applicazione, ma ci saranno comunque tanti deployment della stessa app. Per *deploy* si intende un'istanza dell'applicazione. Può essere il software in produzione, oppure una delle varie istanze in staging. Ancora, un deploy può essere la copia posseduta dal singolo sviluppatore nel suo ambiente locale. + +La codebase rimane comunque sempre la stessa su tutti i deployment, anche se potrebbero essere attive diverse versioni nello stesso istante. Si pensi per esempio a uno sviluppatore che possiede dei commit in più che non ha ancora mandato in staging. Nonostante questo, comunque, rimane la condivisione della stessa codebase, nonostante la possibilità di avere più deploy della stessa app. diff --git a/content/it/concurrency.md b/content/it/concurrency.md new file mode 100644 index 000000000..1ea240065 --- /dev/null +++ b/content/it/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Concorrenza +### Scalare attraverso il process model + +Ogni software, una volta avviato, è rappresentato da uno o più processi. Le web application in particolare hanno assunto nel tempo una gran varietà di forme e di tipologie di esecuzione, in tal senso. Per esempio, i processi PHP vengono eseguiti come sotto-processi figli di Apache, avviati su richiesta quando necessari in base al volume di richieste. Java invece gestisce le cose nella maniera opposta, tramite un superprocesso unico che usa una grande quantità di risorse sul server (CPU e memoria) dall'avvio, con una concorrenza gestita "internamente" tramite i threads. In entrambi i casi, comunque, i processi non sono esplicitamente visibili allo sviluppatore. + +![Il fattore di scale è espresso con un numero di processi dello stesso tipo avviati, la diversità del carico di lavoro, invece, come le varie tipologie di processo.](/images/process-types.png) + +**In un'applicazione twelve-factor, i processi sono "first class citizen"**. La visione del concetto di processo prende spunto dal [concetto, in unix, dedicato all'esecuzione di demoni di servizi](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Attraverso l'uso di questo modello, lo sviluppatore può realizzare la propria applicazione in modo tale da farle gestire senza problemi diversi livelli di carico di lavoro, assegnando ogni tipo di lavoro a un tipo di processo ben definito. Per esempio, le richieste HTTP possono essere gestite da un web process, mentre dei compiti più lunghi (in background) possono essere gestiti da un altro processo separato. + +Questo non esclude che un certo processo, individualmente, possa gestire in modo autonomo e interno il multiplexing, tramite threading, all'interno della VM in esecuzione, o magari un modello asincrono o basato su eventi come quello di [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), o [Node.js](http://nodejs.org/). Tuttavia, tutto questo può non bastare: l'applicazione deve essere anche adatta all'esecuzione su più macchine fisiche. + +Il modello di processo così come presentato rende il massimo quando arriva il momento di scalare. La [natura orizzontalmente partizionabile (e non soggetta a condivisioni) di un "processo twelve-factor"](./processes) permette di gestire la concorrenza in modo semplice e affidabile. L'array dei tipi di processo e il numero di processi presenti per ogni tipo è conosciuto come *process formation* (formazione di processi). + +I processi di un'app twelve-factor non dovrebbero [essere soggetti a daemonizing](http://dustin.github.com/2010/02/28/running-processes.html), o scrivere file PID. Al contrario, facendo affidamento sul process manager del sistema operativo (come [systemd](https://www.freedesktop.org/wiki/Software/systemd/), un process manager distribuito su piattaforma cloud, o tool come [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) durante lo sviluppo) per gestire [gli stream in output](./logs), rispondere adeguatamente a crash di processi e gestire riavvii e shutdown. diff --git a/content/it/config.md b/content/it/config.md new file mode 100644 index 000000000..656dca8e2 --- /dev/null +++ b/content/it/config.md @@ -0,0 +1,22 @@ +## III. Configurazione +### Memorizza le informazioni di configurazione nell'ambiente + +La "configurazione" di un'applicazione è tutto quello che può variare da un [deployment](./codebase) all'altro (staging, production, ambienti di sviluppo). Ad esempio: + +* Valori da usare per connettersi a un database, Memcached, oppure altri [backing service](./backing-services); +* Credenziali per servizi esterni, come Amazon S3 o Twitter; +* Valori eventualmente definiti per i singoli deployment, come l'hostname; + +Molto spesso, queste informazioni vengono memorizzate come costanti nel codice: la cosa viola la metodologia twelve-factor, che richiede una **separazione ben definita delle impostazioni di configurazione dal codice**. Le impostazioni possono infatti variare da un deployment all'altro: il codice, invece, no. + +Il codice dell'applicazione, infatti, potrebbe essere reso open-source in ogni momento: un buon motivo per separare le due cose. + +Nota che comunque la definizione di "configurazione" **non** include eventuali configurazione interne dell'applicazione, come `config/routes.rb` in Rails, o come [i moduli di codice sono connessi](http://static.springsource.org/spring/docs/2.5.x/reference/beans.html) in [Spring](http://www.springsource.org/). Questo tipo di configurazione non varia da deployment a deployment: come giusto che sia, quindi, rimane nel codice. + +Un ottimo approccio al "rispetto" di questo principio consiste nell'usare dei file di configurazione non coinvolti dal version control, come per esempio `config/database.yml` in Rails. Stiamo parlando di un miglioramento enorme rispetto all'uso di costanti nel codice, ma c'è da dire la cosa ha il suo lato negativo: basta poco per sbagliarsi e includere nel repo il file di configurazione che, invece, non dovrebbe essere lì. C'è una certa tendenza, infatti, a non avere tutti i file di configurazione necessari nello stesso posto. Inoltre, i vari formati tendono a essere collegati a un certo linguaggio/framework. + +**L'applicazione che rispetta la metodologia twelve-factor memorizza tutte le impostazioni in *variabili d'ambiente*** (spesso dette *env vars* o *env*). Le variabili d'ambiente sono molto semplici da cambiare di deployment in deployment senza dover toccare il codice direttamente. Inoltre, a differenza dei file di configurazione classici, c'è una probabilità molto bassa di venire inclusi nel repo. Infine, questi file sono indipendenti sia dal linguaggio che dal sistema operativo utilizzato. + +Un altro aspetto del config management è il raggruppamento. A volte, infatti, alcune applicazioni prevedono la memorizzazione delle impostazioni in gruppi (chiamati spesso "ambienti") dal nome ben preciso: "development", "test" e "production", per esempio. Questo metodo non scala correttamente, se ci pensi: potrebbero essere necessari nuovi ambienti, come "staging" e "qa". Oppure, i vari sviluppatori potrebbero aver bisogno di creare i propri ambienti "speciali", come "joes-staging" e così via. Il risultato? Una quantità di combinazioni ingestibile e disordinata. + +In una buona twelve-factor app, le variabili di ambiente sono controllate in modo più "granulare", in modo totalmente ortogonale alle altre. Non sono mai raggruppate e classificate sotto "ambienti" specifici, ma vengono gestite in modo totalmente indipendente per ogni deployment. Il prodotto finale ne risente positivamente in termini di scalabilità. \ No newline at end of file diff --git a/content/it/dependencies.md b/content/it/dependencies.md new file mode 100644 index 000000000..cfc7408ee --- /dev/null +++ b/content/it/dependencies.md @@ -0,0 +1,12 @@ +## II. Dipendenze +### Dipendenze dichiarate e isolate + +Molti linguaggi di programmazione offrono dei sistemi di packaging per la distribuzione delle proprie librerie, come [CPAN](http://www.cpan.org/) per Perl o [Rubygems](http://rubygems.org/) per Ruby. Le librerie installate attraverso questi sistemi, inoltre, possono essere identificate come "system-wide" (attive a livello di sistema), oppure posizionate nella directory della singola applicazione (in questo caso si parla di "vendoring" o "bundling"). + +**Un'applicazione che aderisce alla twelve-factor non si basa mai sull'esistenza implicita di librerie system-wide**. Le dipendenze vengono tutte dichiarate, tramite un manifest dedicato. Inoltre, viene contemplato anche l'uso di un tool di *isolamento delle dipendenze* durante l'esecuzione, in modo tale da assicurarsi che non ci siano delle "dipendenze implicite" che creino interferenze nel sistema in cui ci si trova. La specifica completa ed esplicita delle dipendenze si applica in modo uniforme: sia in production che in sviluppo. + +Per esempio, [Bundler](https://bundler.io/) per Ruby offre il supporto di un file-manifesto `Gemfile` da usare per la dichiarazione delle dipendenze e `bundle exec` per il loro isolamento. In Python invece troviamo altri due tool per questi scopi -- [Pip](http://www.pip-installer.org/en/latest/) viene usato per la dichiarazione e [Virtualenv](http://www.virtualenv.org/en/latest/) per l'isolamento. Anche C ha [Autoconf](http://www.gnu.org/s/autoconf/) per la dichiarazione di dipendenze, mentre lo static linking si occupa dell'isolamento. Non importa quale sia il toolchain usato, le operazioni di dichiarazione e isolamento vanno sempre effettuate. In caso contrario, l'applicazione non aderisce più alla metodologia. + +Un altro importante beneficio di una dichiarazione esplicita delle dipendenze sta nel fatto che semplifica di molto la configurazione iniziale per gli sviluppatori appena entrati a lavorare al progetto. Il nuovo arrivato non dovrà fare altro che effettuare un check out della codebase nella propria macchina di sviluppo, occupandosi di dover installare solo ed esclusivamente le dipendenze, appunto, dichiarate. Molto spesso è inoltre presente un *build command* che permette di automatizzare il processo. Per Ruby/Bundler si usa `bundle install`, mentre per Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) c'è `lein deps`. + +Ogni applicazione che aderisce alla metodologia twelve-factor, inoltre, non si basa mai sull'esistenza di un qualsiasi tool di sistema. Alcuni esempi sono *ImageMagick* o *curl*. Nonostante questi software esistano già su buona parte dei sistemi in circolazione, non è comunque detto che siano presenti su tutti quelli su cui girerà l'applicazione in futuro. Se l'app non può fare a meno di questo tool, si dovrebbe prendere in considerazione l'idea di "vendorizzarlo" nell'applicazione stessa. diff --git a/content/it/dev-prod-parity.md b/content/it/dev-prod-parity.md new file mode 100644 index 000000000..77e6cedc4 --- /dev/null +++ b/content/it/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Parità tra Sviluppo e Produzione +### Mantieni lo sviluppo, staging e produzione simili il più possibile + +Storicamente, ci sono sempre state differenze sostanziali tra gli ambienti di sviluppo (lo sviluppatore che effettua delle modifiche live a un [deployment](./codebase) in locale) e quello di produzione (un deployment in esecuzione raggiungibile dagli utenti finali). Differenze (o gap) che si possono raggruppare in tre categorie: + +* **Tempo:** uno sviluppatore può lavorare sul codice per giorni, settimane o mesi prima di poter andare in produzione; +* **Personale**: gli sviluppatori scrivono il codice, gli ops effettuano il deployment; +* **Strumenti**: gli sviluppatori potrebbero usare uno stack quale Nginx, SQLite e OS X, mentre in produzione per il deployment verrebbero installati Apache, MySQL e Linux. + +**Un'applicazione twelve-factor è progettata per il [rilascio continuo](http://avc.com/2011/02/continuous-deployment/), tenendo così queste differenze al minimo possibile.** A proposito di queste tre tipologie di differenze appena viste: + +* Rendi la differenze temporali minime: cerca di scrivere (o far scrivere) del codice da rilasciare nel giro di poche ore, se non minuti; +* Rendi le differenze a livello di personale minime: fai in modo che gli sviluppatori siano coinvolti anche nella fase di deploy, per permettere loro di osservare il comportamento di ciò che hanno scritto anche in produzione; +* Rendi le differenze a livello di strumenti minime: mantieni gli ambienti di lavoro il più simile possibile; + +Riassumendo tutto in una tabella: + + + + + + + + + + + + + + + + + + + + + + +
App TradizionaleApp Twelve-factor
Tempo tra i DeploymentSettimaneOre
Sviluppatori e OpsSono diversiSono gli stessi
Sviluppo e ProduzioneDivergentiIl più simili possibile
+ +I [backing service](./backing-services), come il database dell'applicazione o la cache, sono una delle aree in cui la parità degli ambienti è molto importante. Molti linguaggi offrono delle librerie che facilitano l'accesso a questi servizi, tra cui anche degli adattatori per questi tipi di servizi. Eccone alcuni: + + + + + + + + + + + + + + + + + + + + + + + + + + +
TipologiaLinguaggioLibreriaAdattatore
DatabaseRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
CodePython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CacheMemory, filesystem, Memcached
+ +Gli sviluppatori, inoltre, trovano utile usare dei servizi "leggeri" in fase di sviluppo, passando quindi a qualcosa di più serio e robusto in produzione. Per esempio, usando SQLite localmente e PostgreSQL in produzione. Ancora, un sistema di cache in locale in fase di sviluppo e Memcached in produzione. + +**Lo sviluppatore twelve-factor "resiste" a questa necessità**, anche se gli adapter ci sono e funzionano in modo tale da astrarre in modo sufficiente tutte le differenze nella gestione. Nulla impedisce, infatti, a qualche altra incompatibilità di uscire allo scoperto quando meno ce lo si aspetta, soprattutto se in ambiente di sviluppo funziona tutto e poi, magari, in produzione i test non vengono superati. Il costo di questa differenza può risultare abbastanza alto, soprattutto in situazioni in cui si effettua il rilascio continuo. + +Rispetto al passato, usare dei sistemi "light" in locale è una prassi poco convincente. Si pensi al fatto che alcuni servizi moderni come Memcached o PostgreSQL si possono installare e usare senza difficoltà tramite alcuni sistemi di packaging come [Homebrew](http://mxcl.github.com/homebrew/) e [apt-get](https://help.ubuntu.com/community/AptGet/Howto). In alternativa, esistono anche alcuni tool di provisioning come [Chef](http://www.opscode.com/chef/) e [Puppet](http://docs.puppetlabs.com/), che combinati con sistemi di ambienti virtuali come [Vagrant](http://vagrantup.com/) permettono agli sviluppatori di riprodurre in locale delle macchine molto simili, se non identiche, a quelle in produzione. Ne risente quindi positivamente il costo di deployment. + +Tutto questo, sia chiaro, non rende gli adapter meno utili: grazie ad essi infatti il porting verso nuovi servizi, in un secondo momento, rimane un processo indolore. Nonostante questo, comunque, rimane scontato che sarebbe buona norma usare uno stesso backing service su tutti i deployment di un'applicazione. diff --git a/content/it/disposability.md b/content/it/disposability.md new file mode 100644 index 000000000..355806714 --- /dev/null +++ b/content/it/disposability.md @@ -0,0 +1,12 @@ +## IX. Rilasciabilità +### Massimizzare la robustezza con avvii veloci e shutdown graduali + +**I [processi](./processes) di un'applicazione twelve-factor sono *rilasciabili*, cioè possono essere avviati o fermati senza problemi al momento del bisogno.** Questa caratteristica ovviamente facilita le procedure di scaling, deploy rapido della [codebase](./codebase) o cambi dei file di [configurazione](./config). + +I processi dovrebbero inoltre ambire a **minimizzare i tempi di avvio**. Idealmente, un processo impiega pochi secondi dal tempo di lancio al momento in cui tutto è pronto per ricevere nuove richieste. Dei tempi brevi di avvio inoltre forniscono una maggiore agilità in fase di [release](./build-release-run); il tutto a vantaggio della robustezza dell'applicazione, dato che il process manager può così muoversi agevolmente verso un'altra macchina fisica, se necessario. + +I processi dovrebbero inoltre **terminare in modo tutt'altro che brusco, quindi graduale, in caso di ricezione di un segnale [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** dal process manager. Per un'applicazione web, la giusta terminazione di un processo viene ottenuta quando si cessa innanzitutto di ascoltare sulla porta dedicata del servizio (evitando quindi di ricevere altre richieste), permettendo poi di terminare le richieste esistenti e infine di concludere la fase di terminazione in modo definitivo. + +Per un processo worker, invece, la fase di terminazione più adatta vede il ritorno del job corrente alla coda. Per esempio, su [RabbitMQ](http://www.rabbitmq.com/) il worker può inviare un [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); su [Beanstalkd](https://beanstalkd.github.io), il job viene automaticamente rimandato in coda nel caso in cui il worker si disconnette. I sistemi basati su lock come [Delayed + +リソースは自由にデプロイにアタッチしたり、デプロイからデタッチしたりできる。例えば、ハードウェアの問題によってアプリケーションのデータベースの動作がおかしい場合、アプリケーションの管理者は最新のバックアップから新しいデータベースサーバーを立ち上げる。そして現在の本番データベースをデタッチし、新しいデータベースをアタッチする -- コードを一切変更せずに。 + diff --git a/content/ja/build-release-run.md b/content/ja/build-release-run.md new file mode 100644 index 000000000..19cdd5406 --- /dev/null +++ b/content/ja/build-release-run.md @@ -0,0 +1,18 @@ +## V. ビルド、リリース、実行 +### ビルド、リリース、実行の3つのステージを厳密に分離する + +[コードベース](./codebase)は3つのステージを経て、(開発環境ではない)デプロイへと変換される。 + +* *ビルドステージ* は、コードリポジトリを *ビルド* と呼ばれる実行可能な塊へと変える変換である。デプロイプロセスで指定したコミットのコードで指定されたバージョンを使って、ビルドステージは[依存関係](./dependencies)を取得してローカル環境に配置し、バイナリやアセットファイルをコンパイルする。 +* *リリースステージ* は、ビルドステージで生成されたビルドを受け取り、それをデプロイの現在の[設定](./config)と結合する。出来上がる *リリース* にはビルドと設定の両方が含まれ、実行環境の中ですぐにでも実行できるよう準備が整う。 +* *実行ステージ* (ランタイムとも呼ばれる)は、選択されたリリースに対して、アプリケーションのいくつかの[プロセス](./processes)を起動することで、アプリケーションを実行環境の中で実行する。 + +![コードがビルドになり、ビルドと設定が結合されてリリースが作られる。](/images/release.png) + +**Twelve-Factor Appは、ビルド、リリース、実行の3つのステージを厳密に分離する。** 例えば、実行ステージにあるコードを変更してもその変更をビルドステージに伝える方法がないため、コードを実行中に変更することはあり得ない。 + +デプロイツールは通常、リリース管理ツールを提供する。中でも注目すべきは、以前のリリースにロールバックする機能である。例えばデプロイツールの[Capistrano](https://github.com/capistrano/capistrano/wiki)は、リリースを`releases`という名前のサブディレクトリに格納し、現在のリリースは現在のリリースのディレクトリへのシンボリックリンクとなる。Capistranoの`rollback`コマンドを使うと、簡単かつ即座に以前のリリースにロールバックできる。 + +すべてのリリースは常に一意のリリースIDを持つべきである。リリースIDの例としては、リリースのタイムスタンプ(例:`2011-04-06-20:32:17`)や連番(例:`v100`)がある。リリースは追記専用の台帳であり、一度作られたリリースは変更することができない。変更する場合は新しいリリースを作らなければならない。 + +ビルドステージは、新しいコードがデプロイされるときに必ずアプリケーションの開発者によって開始される。一方実行ステージは、サーバーの再起動時や、クラッシュしたプロセスがプロセスマネージャーによって再起動された時に自動で開始される。このため、実行ステージはできるだけ可変部分を持たないようにするべきである。なぜなら、アプリケーションの実行を妨げるような問題が起きると、開発者が待機していない真夜中にアプリケーションが壊れる結果になるためである。ビルドステージはもっと複雑でも構わない。なぜなら、ビルドステージのエラーは常にデプロイを実行している開発者の目の前で発生するためである。 diff --git a/content/ja/codebase.md b/content/ja/codebase.md new file mode 100644 index 000000000..75fc9d961 --- /dev/null +++ b/content/ja/codebase.md @@ -0,0 +1,17 @@ +## I. コードベース +### バージョン管理されている1つのコードベースと複数のデプロイ + +Twelve-Factor Appは[Git](http://git-scm.com/)や[Mercurial](https://www.mercurial-scm.org/)、[Subversion](http://subversion.apache.org/)などのバージョン管理システムで常に変更を追跡している。リビジョン追跡データベースのコピーは *コードリポジトリ* と言われ、単に *リポジトリ* とも言われる。 + +*コードベース* は、単一のリポジトリ(Subversionのような集中バージョン管理システムの場合)またはルートコミットを共有する複数のリポジトリ(Gitのような分散バージョン管理システムの場合)である。 + +![1つのコードベースは複数のデプロイにマッピングされる](/images/codebase-deploys.png) + +コードベースとアプリケーションの間には、常に1対1の関係がある。 + +* もし複数のコードベースがある場合、それはアプリケーションではない -- それは分散システムである。分散システムのそれぞれのコンポーネントがアプリケーションであり、個別にTwelve-Factorに適合することができる。 +* 同じコードを共有する複数のアプリケーションは、Twelve-Factorに違反している。その場合の解決策は、共通のコードをライブラリに分解し、そのライブラリを[依存関係管理ツール](./dependencies)で組み込むようにすることである。 + +アプリケーションごとにただ1つのコードベースが存在するが、アプリケーションのデプロイは複数存在する。 *デプロイ* はアプリケーションの実行中のインスタンスである。これは通常1つの本番サイトと、1つ以上のステージングサイトである。さらにすべての開発者はローカル開発環境で動作するアプリケーションのコピーを持っており、それらもデプロイと見なせる。 + +デプロイごとに異なるバージョンがアクティブであるかもしれないが、コードベースはすべてのデプロイを通して同一である。例えば、開発者はステージング環境にまだデプロイされていないコミットを抱えているし、ステージング環境には本番環境にデプロイされていないコミットが含まれている。しかし、これらのデプロイはすべて同一のコードベースを共有しているため、同一のアプリケーションの異なるデプロイであると認識できる。 diff --git a/content/ja/concurrency.md b/content/ja/concurrency.md new file mode 100644 index 000000000..864b47e9c --- /dev/null +++ b/content/ja/concurrency.md @@ -0,0 +1,14 @@ +## VIII. 並行性 +### プロセスモデルによってスケールアウトする + +すべてのコンピュータープログラムは、一度実行されると、1つ以上のプロセスとして表される。Webアプリケーションでは様々なプロセス実行形態がとられてきた。例えば、PHPのプロセスはApacheの子プロセスとして実行され、リクエスト量に応じて起動される。Javaプロセスは反対の方法をとる。JVMが1つの巨大な親プロセスを提供し、起動時にシステムリソース(CPUやメモリ)の大きなブロックを確保し、スレッドを使って内部的に並行性を管理する。どちらの場合でも、実行されるプロセスはアプリケーションの開発者にはほとんど見えない。 + +![スケールは実行されるプロセスの数として表現され、ワークロードの種類はプロセスタイプとして表現される。](/images/process-types.png) + +**Twelve-Factor Appではプロセスは第一級市民である。** Twelve-Factor Appにおけるプロセスの考え方は、[サービスのデーモンを実行するためのUnixプロセスモデル](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/)から大きなヒントを得ている。このモデルを使い、個々のワークロードの種類を *プロセスタイプ* に割り当てることで、開発者はアプリケーションが多様なワークロードを扱えるように設計することができる。例えば、HTTPリクエストはWebプロセスによって処理し、時間のかかるバックグラウンドタスクはワーカープロセスによって処理することができる。 + +このモデルは、ランタイムVM内のスレッドや、[EventMachine](https://github.com/eventmachine/eventmachine)、[Twisted](http://twistedmatrix.com/trac/)、[Node.js](http://nodejs.org/)などの非同期イベントモデルによって、個々のプロセスがプロセス内部で多重化することを禁止するわけではない。しかし個々のVMはそれほど大きくなる(垂直にスケールする)ことができないため、アプリケーションは複数の物理マシンで動作する複数のプロセスへと拡大できなければならない。 + +このプロセスモデルが真価を発揮するのは、スケールアウトが必要になったときである。[シェアードナッシングで水平分割可能なTwelve-Factor Appプロセスの性質](./processes)は、並行性を高める操作が単純かつ確実なものであることを意味する。プロセスタイプとそれぞれのタイプのプロセス数の配列は、 *プロセスフォーメーション* と言われる。 + +Twelve-Factor Appのプロセスは[決してデーモン化するべきではないし](http://dustin.github.com/2010/02/28/running-processes.html)、PIDファイルを書き出すべきではない。その代わりに、OSのプロセスマネージャー(例:[systemd](https://www.freedesktop.org/wiki/Software/systemd/)、クラウドプラットフォームの分散プロセスマネージャー、あるいは開発環境における[Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html)のようなツール)を頼ることで、[出力ストリーム](./logs)を管理し、プロセスのクラッシュに対応し、ユーザーによる再起動やシャットダウンを処理すべきである。 diff --git a/content/ja/config.md b/content/ja/config.md new file mode 100644 index 000000000..6c8e43c32 --- /dev/null +++ b/content/ja/config.md @@ -0,0 +1,22 @@ +## III. 設定 +### 設定を環境変数に格納する + +アプリケーションの *設定* は、[デプロイ](./codebase)(ステージング、本番、開発環境など)の間で異なり得る唯一のものである。設定には以下のものが含まれる。 + +* データベース、Memcached、他の[バックエンドサービス](./backing-services)などのリソースへのハンドル +* Amazon S3やTwitterなどの外部サービスの認証情報 +* デプロイされたホストの正規化されたホスト名など、デプロイごとの値 + +アプリケーションは時に設定を定数としてコード内に格納する。これはTwelve-Factorに違反している。Twelve-Factorは **設定をコードから厳密に分離すること** を要求する。設定はデプロイごとに大きく異なるが、コードはそうではない。 + +アプリケーションがすべての設定をコードの外部に正しく分離できているかどうかの簡単なテストは、認証情報を漏洩させることなく、コードベースを今すぐにでもオープンソースにすることができるかどうかである。 + +なお、この“設定”の定義には、アプリケーション内部の設定は **含まない** ことに注意する。内部の設定とは、Railsにおける`config/routes.rb`や、[Spring](http://spring.io/)において[コードモジュールがどう接続されるか](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html)などの設定を指す。この種の設定はデプロイの間で変わらないため、コードの内部で行うべきである。 + +設定に対するもう1つのアプローチは、バージョン管理システムにチェックインされない設定ファイルを使う方法である。例として、Railsにおける`config/database.yml`がある。この方法は、リポジトリにチェックインされる定数を使うことに比べると非常に大きな進歩であるが、まだ弱点がある。設定ファイルが誤ってリポジトリにチェックインされやすいことと、設定ファイルが異なる場所に異なるフォーマットで散乱し、すべての設定を一つの場所で見たり管理したりすることが難しくなりがちであることである。その上、これらのフォーマットは言語やフレームワークに固有のものになりがちである。 + +**Twelve-Factor Appは設定を *環境変数* に格納する。** 環境変数は、コードを変更することなくデプロイごとに簡単に変更できる。設定ファイルとは異なり、誤ってリポジトリにチェックインされる可能性はほとんどない。また、独自形式の設定ファイルやJava System Propertiesなど他の設定の仕組みとは異なり、環境変数は言語やOSに依存しない標準である。 + +設定管理のもう1つの側面はグルーピングである。アプリケーションは設定を名前付きのグループ(しばしば“環境”と呼ばれる)にまとめることがある。グループは、Railsにおける`development`、`test`、`production`環境のように、デプロイの名前を取って名付けられる。この方法はうまくスケールしない。アプリケーションのデプロイが増えるにつれて、新しい環境名(`staging`や`qa`)が必要になる。さらにプロジェクトが拡大すると、開発者は`joes-staging`のような自分用の環境を追加する。結果として設定が組み合わせ的に爆発し、アプリケーションのデプロイの管理が非常に不安定になる。 + +Twelve-Factor Appの場合、環境変数は粒度の細かい管理であり、それぞれの環境変数は互いに直交している。環境変数は“環境”としてまとめられることはないが、代わりにデプロイごとに独立して管理される。これは、アプリケーションのライフサイクルに渡って、アプリケーションが多くのデプロイへと自然に拡大していくにつれて、スムーズにスケールアップするモデルである。 diff --git a/content/ja/dependencies.md b/content/ja/dependencies.md new file mode 100644 index 000000000..724105d0a --- /dev/null +++ b/content/ja/dependencies.md @@ -0,0 +1,12 @@ +## II. 依存関係 +### 依存関係を明示的に宣言し分離する + +ほとんどのプログラミング言語は、サポートライブラリを配布するためのパッケージ管理システムを提供している。例えば、Perlにおける[CPAN](http://www.cpan.org/)やRubyにおける[Rubygems](http://rubygems.org/)などである。パッケージ管理システムでインストールされるライブラリは、システム全体(“site packages”と言われる)にインストールされる場合と、アプリケーションを含むディレクトリのスコープ(“vendoring”または“bundling”と言われる)にインストールされる場合がある。 + +**Twelve-Factor Appは、システム全体にインストールされるパッケージが暗黙的に存在することに決して依存しない。** すべての依存関係を *依存関係宣言* マニフェストで完全かつ厳密に宣言する。さらに、実行時には *依存関係分離* ツールを使って、取り囲んでいるシステムから暗黙の依存関係が“漏れ出ない”ことを保証する。完全かつ明示的な依存関係の指定は、本番環境と開発環境の両方に対して同様に適用される。 + +例えば、Rubyで使われる[Bundler](https://bundler.io/) は、依存関係宣言のためのマニフェストのフォーマットである`Gemfile`と依存関係分離のための`bundle exec`を提供している。Pythonではこれらのステップで2つの別々のツールが使われる -- [Pip](http://www.pip-installer.org/en/latest/)が宣言のために使われ、[Virtualenv](http://www.virtualenv.org/en/latest/)が分離のために使われる。C言語でも[Autoconf](http://www.gnu.org/s/autoconf/)で依存関係を宣言し、静的リンクで依存関係を分離することができる。ツールが何であれ、依存関係の宣言と分離は常に一緒に使わなければならない -- どちらか片方だけではTwelve-Factorを満足するのに不十分である。 + +明示的に依存関係を宣言する利点の1つは、アプリケーションに新しい開発者が加わった際のセットアップを単純化できることである。新しい開発者は、言語のランタイムと依存関係管理ツールさえインストールされていれば、アプリケーションのコードベースを自分の開発マシンにチェックアウトすることができる。開発者は決められた *ビルドコマンド* で、アプリケーションのコードを実行するために必要なすべてのものをセットアップできる。例えば、Ruby/Bundlerのビルドコマンドは`bundle install`であり、Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme)では`lein deps`である。 + +また、Twelve-Factor Appは、いかなるシステムツールの暗黙的な存在にも依存しない。例として、アプリケーションからImageMagickや`curl`を使う場合がある。これらのツールはほとんどのシステムに存在するだろうが、アプリケーションが将来に渡って実行され得るすべてのシステムに存在するかどうか、あるいは将来のシステムでこのアプリケーションと互換性のあるバージョンが見つかるかどうかについては何の保証もない。アプリケーションがシステムツールを必要とするならば、そのツールをアプリケーションに組み込むべきである。 diff --git a/content/ja/dev-prod-parity.md b/content/ja/dev-prod-parity.md new file mode 100644 index 000000000..cb92cd03c --- /dev/null +++ b/content/ja/dev-prod-parity.md @@ -0,0 +1,78 @@ +## X. 開発/本番一致 +### 開発、ステージング、本番環境をできるだけ一致させた状態を保つ + +歴史的に、開発環境(開発者が直接変更するアプリケーションのローカル[デプロイ](./codebase))と本番環境(エンドユーザーからアクセスされるアプリケーションの実行中デプロイ)の間には大きなギャップがあった。これらのギャップは3つの領域で現れる。 + +* **時間のギャップ**: 開発者が編集したコードが本番に反映されるまで数日、数週間、時には数ヶ月かかることがある。 +* **人材のギャップ**: 開発者が書いたコードを、インフラエンジニアがデプロイする。 +* **ツールのギャップ**: 本番デプロイではApache、MySQL、Linuxを使うのに、開発者がNginx、SQLite、OS Xのようなスタックを使うことがある。 + +**Twelve-Factor Appでは、[継続的デプロイ](http://avc.com/2011/02/continuous-deployment/)しやすいよう開発環境と本番環境のギャップを小さく保つ。** 上で述べた3つのギャップを見る。 + +* 時間のギャップを小さくする: 開発者が書いたコードは数時間後、さらには数分後にはデプロイされる。 +* 人材のギャップを小さくする: コードを書いた開発者はそのコードのデプロイに深く関わり、そのコードの本番環境での挙動をモニタリングする。 +* ツールのギャップを小さくする: 開発環境と本番環境をできるだけ一致させた状態を保つ。 + +上で述べたことを表にまとめる。 + + + + + + + + + + + + + + + + + + + + + + +
伝統的なアプリケーションTwelve-Factor App
デプロイの間隔数週間数時間
コードを書く人とデプロイする人異なる人同じ人
開発環境と本番環境異なるできるだけ一致
+ + +[バックエンドサービス](./backing-services)(アプリケーションのデータベース、キューイングシステム、キャッシュなど)は、開発/本番一致が重要になる領域の一つである。多くの言語は、異なる種類のサービスへの *アダプター* を含め、バックエンド・サービスへのアクセスを単純化するライブラリを提供している。以下の表にいくつかの例を示す。 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
種類言語ライブラリアダプター
データベースRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
キューPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
キャッシュRuby/RailsActiveSupport::Cacheメモリ, ファイルシステム, Memcached
+ +本番環境ではより本格的で堅牢なバックエンドサービスが使われるにもかかわらず、開発者は自身のローカル開発環境で軽量なバックエンドサービスを使いたくなることがある。例えば、開発環境ではSQLiteを使い、本番ではPostgreSQLを使ったり、開発環境ではローカルプロセスのメモリをキャッシュに使い、本番ではMemcachedを使ったりするなどである。 + +たとえ理論的にはアダプターがバックエンドサービスの違いをすべて抽象化してくれるとしても、 **Twelve-Factorの開発者は、開発と本番の間で異なるバックエンドサービスを使いたくなる衝動に抵抗する。** バックエンドサービスの違いは、わずかな非互換性が顕在化し、開発環境やステージング環境では正常に動作してテストも通過するコードが本番環境でエラーを起こす事態を招くことを意味する。この種のエラーは継続的デプロイを妨げる摩擦を生む。この摩擦とそれに伴って継続的デプロイが妨げられることのコストは、アプリケーションのライフサイクルに渡ってトータルで考えると非常に高くつく。 + +軽量なローカルサービスは、以前ほど魅力的なものではなくなっている。Memcached、PostgreSQLやRabbitMQなどのモダンなバックエンドサービスは、[Homebrew](http://mxcl.github.com/homebrew/) や [apt-get](https://help.ubuntu.com/community/AptGet/Howto) などのモダンなパッケージングシステムのおかげで、簡単にインストールして実行できる。あるいは [Chef](http://www.opscode.com/chef/) や [Puppet](http://docs.puppetlabs.com/) などの宣言的なプロビジョニングツールと、[Vagrant](http://vagrantup.com/) などの軽量な仮想環境を組み合わせることで、開発者は本番環境に限りなく近いローカル環境を作ることができる。開発/本番一致と継続的デプロイの利益に比べると、これらのシステムをインストールして利用するコストは低い。 + +異なるバックエンドサービスへのアダプターは依然有用である。これらのアダプターは、新しいバックエンドサービスに移植するときの苦痛を比較的和らげてくれるためである。しかし、アプリケーションのすべてのデプロイ(開発、ステージング、本番環境)は同じ種類かつ同じバージョンのバックエンドサービスを利用するべきである。 diff --git a/content/ja/disposability.md b/content/ja/disposability.md new file mode 100644 index 000000000..77726d055 --- /dev/null +++ b/content/ja/disposability.md @@ -0,0 +1,12 @@ +## IX. 廃棄容易性 +### 高速な起動とグレースフルシャットダウンで堅牢性を最大化する + +**Twelve-Factor Appの [プロセス](./processes) は *廃棄容易* である、すなわち即座に起動・終了することができる。** この性質が、素早く柔軟なスケールと、[コード](./codebase) や [設定](./config) に対する変更の素早いデプロイを容易にし、本番デプロイの堅牢性を高める。 + +プロセスは、 **起動時間を最小化する** よう努力するべきである。理想的には、1つのプロセスは、起動コマンドが実行されてから数秒間でリクエストやジョブを受け取れるようになるべきである。起動時間が短いと、[リリース](./build-release-run)作業やスケールアップのアジリティが高くなる。さらに、プロセスマネージャーが必要に応じてプロセスを新しい物理マシンに簡単に移動できるようになるため、堅牢性も高くなる。 + +プロセスは、プロセスマネージャーから **[SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)シグナルを受け取ったときに、グレースフルにシャットダウンする。** Webプロセスの場合、グレースフルシャットダウンは、サービスポートのリッスンを中止し(従って新しいリクエストを拒み)、処理中のリクエストが終了するまで待ち、シャットダウンすることで実現される。このモデルでは暗黙的にHTTPリクエストが短い(せいぜい数秒)ことを仮定している。ロングポーリングの場合、クライアントはコネクションが失われたときに途切れなく再接続を試みるべきである。 + +ワーカープロセスの場合、グレースフルシャットダウンは、処理中のジョブをワーカーキューに戻すことで実現される。例えば、[RabbitMQ](http://www.rabbitmq.com/)ではワーカーは[`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack)を送ることができる。[Beanstalkd](https://beanstalkd.github.io)では、ワーカーの接続が失われるとジョブは自動的にキューに戻る。[Delayed Job](https://github.com/collectiveidea/delayed_job#readme)などのロックをベースにしたシステムでは、ジョブレコードのロックを確実に解放する必要がある。このモデルでは、暗黙的にすべてのジョブが[再入可能](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29)であることを仮定している。再入可能性は一般的に、結果をトランザクションで包んだり、処理を[べき等](http://en.wikipedia.org/wiki/Idempotence)にすることで実現される。 + +また、下層のハードウェアの障害に関して言えば、プロセスは **突然の死に対して堅牢** であるべきである。このような事態が起こることは、`SIGTERM`によるグレースフルシャットダウンに比べればずっと少ないが、それでも起こりうる。この対策として推奨される方法は、Beanstalkdなどの堅牢なキューイングバックエンドを使い、クライアントの接続が切断されたり、タイムアウトしたときにジョブをキューに戻せるようにすることである。どちらにしても、Twelve-Factor Appは予期しないグレースフルでない停止をうまく処理できるよう設計される。[「クラッシュオンリー」設計](http://lwn.net/Articles/191059/)はこのコンセプトをその[論理的帰結](http://docs.couchdb.org/en/latest/intro/overview.html)に導く。 diff --git a/content/ja/intro.md b/content/ja/intro.md new file mode 100644 index 000000000..dd62a6656 --- /dev/null +++ b/content/ja/intro.md @@ -0,0 +1,12 @@ +はじめに +============ + +現代では、ソフトウェアは一般にサービスとして提供され、*Webアプリケーション* や *Software as a Service* と呼ばれる。Twelve-Factor Appは、次のようなSoftware as a Serviceを作り上げるための方法論である。 + +* セットアップ自動化のために **宣言的な** フォーマットを使い、プロジェクトに新しく加わった開発者が要する時間とコストを最小化する。 +* 下層のOSへの **依存関係を明確化** し、実行環境間での **移植性を最大化** する。 +* モダンな **クラウドプラットフォーム** 上への **デプロイ** に適しており、サーバー管理やシステム管理を不要なものにする。 +* 開発環境と本番環境の **差異を最小限** にし、アジリティを最大化する **継続的デプロイ** を可能にする。 +* ツール、アーキテクチャ、開発プラクティスを大幅に変更することなく **スケールアップ** できる。 + +Twelve-Factorの方法論は、どのようなプログラミング言語で書かれたアプリケーションにでも適用できる。また、どのようなバックエンドサービス(データベース、メッセージキュー、メモリキャッシュなど)の組み合わせを使っていても適用できる。 diff --git a/content/ja/logs.md b/content/ja/logs.md new file mode 100644 index 000000000..b8aa706ea --- /dev/null +++ b/content/ja/logs.md @@ -0,0 +1,16 @@ +## XI. ログ +### ログをイベントストリームとして扱う + +*ログ* は実行中のアプリケーションの挙動を可視化する。サーバーベースの環境では、ログは一般的にディスク上のファイル(“ログファイル”)に書き込まれる。しかしこれは出力フォーマットの一つに過ぎない。 + +ログは、すべての実行中のプロセスとバックエンドサービスの出力ストリームから収集されたイベントが、集約されて時刻順に並べられた[ストリーム](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/)である。生の状態のログは、通常1行が1つのイベントを表すテキストフォーマットである(例外のバックトレースは複数行に渡る場合もあるが)。ログには固定の始まりと終わりはなく、アプリケーションが稼動している限り流れ続ける。 + +**Twelve-Factor Appはアプリケーションの出力ストリームの送り先やストレージについて一切関知しない。** アプリケーションはログファイルに書き込んだり管理しようとするべきではない。代わりに、それぞれの実行中のプロセスはイベントストリームを`stdout`(標準出力)にバッファリングせずに書きだす。ローカルでの開発中、開発者はこのストリームをターミナルのフォアグラウンドで見ることで、アプリケーションの挙動を観察する。 + +ステージングや本番のデプロイでは、それぞれのプロセスのストリームは実行環境に捕らえられ、アプリケーションからの他のすべてのストリームと一緒に並べられ、表示や長期アーカイブのために1つもしくは複数の最終目的地に送られる。これらの保存のための目的地は、アプリケーションからは見ることも設定することもできず、代わりに実行環境によって完全に管理される。[Logplex](https://github.com/heroku/logplex) や [Fluentd](https://github.com/fluent/fluentd) などのオープンソースのログルーターがこの目的に利用できる。 + +アプリケーションのイベントストリームは、ファイルに送られたり、ターミナルでtailを使ってリアルタイムに見られたりする。最も重要な用途として、ストリームは、[Splunk](http://www.splunk.com/)などのログインデックス・解析システムや、[Hadoop/Hive](http://hive.apache.org/)などの汎用データウェアハウスシステムに送られることもある。これらのシステムは、長期に渡ってアプリケーションの挙動を確認するための大きな力と柔軟性をもたらし、次のようなことができるようになる。 + +* 過去の特定のイベントを見つける。 +* 大きなスケールの傾向をグラフ化する。(1分あたりのリクエスト数など) +* ユーザー定義のヒューリスティクスに基づいて素早くアラートを出す。(1分あたりのエラー数がある閾値を超えた場合にアラートを出すなど) diff --git a/content/ja/port-binding.md b/content/ja/port-binding.md new file mode 100644 index 000000000..18b20ae40 --- /dev/null +++ b/content/ja/port-binding.md @@ -0,0 +1,14 @@ +## VII. ポートバインディング +### ポートバインディングを通してサービスを公開する + +WebアプリケーションはWebサーバーコンテナの内部で実行されることがある。例えば、PHPアプリケーションは[Apache HTTPD](http://httpd.apache.org/)内部のモジュールとして実行されるかもしれないし、Javaアプリケーションは[Tomcat](http://tomcat.apache.org/)の内部で実行されるかもしれない。 + +**Twelve-Factor Appは完全に自己完結** し、Webに公開されるサービスを作成するために、コンテナが実行環境にWebサーバーランタイムを注入することを頼りにしない。Webアプリケーションは **ポートにバインドすることでHTTPをサービスとして公開し、** そのポートにリクエストが来るのを待つ。 + +ローカルの開発環境では、開発者はアプリケーションによって公開されたサービスにアクセスするために、`http://localhost:5000/`のようなサービスのURLにアクセスする。本番環境ではルーティング層が、外向きのホスト名からポートにバインドされたWebプロセスへとリクエストをルーティングする。 + +これは一般に、[依存関係宣言](./dependencies)を使ってWebサーバーライブラリをアプリケーションに追加することで実装される。Webサーバーライブラリの例として、Pythonにおける[Tornado](http://www.tornadoweb.org/)、Rubyにおける[Thin](http://code.macournoyer.com/thin/)、Javaやその他のJVMベースの言語における[Jetty](http://www.eclipse.org/jetty/)などがある。これは *ユーザー空間* すなわちアプリケーションのコード内で完結する。リクエストを処理するための実行環境との契約は、ポートをバインドすることである。 + +ポートバインディングによって公開されるサービスはHTTPだけではない。ほぼすべてのサーバーソフトウェアは、ポートをバインドするプロセスを用いて動作し、リクエストが来るのを待つ。例として、[ejabberd](http://www.ejabberd.im/)([XMPP](http://xmpp.org/)を話す)や [Redis](http://redis.io/)([Redisプロトコル](http://redis.io/topics/protocol)を話す)などがある。 + +ここで注目すべきは、ポートバインディングの方法によって、あるアプリケーションが他のアプリケーションにとっての[バックエンドサービス](./backing-services)になれる点である。バックエンドアプリケーションへのURLを提供し、利用するアプリケーションの[設定](./config)にリソースハンドルとして格納すればよい。 diff --git a/content/ja/processes.md b/content/ja/processes.md new file mode 100644 index 000000000..1b2db2e36 --- /dev/null +++ b/content/ja/processes.md @@ -0,0 +1,14 @@ +## VI. プロセス +### アプリケーションを1つもしくは複数のステートレスなプロセスとして実行する + +アプリケーションは、実行環境の中で1つもしくは複数の *プロセス* として実行される。 + +最も単純な場合では、コードは単体のスクリプトであり、実行環境は言語ランタイムがインストールされた開発者のローカルノートPCであり、プロセスはコマンドラインから実行される(例:`python my_script.py`)。対極にあるのは、[複数の実行プロセスとしてインスタンス化される多くのプロセスタイプ](./concurrency)を使う洗練されたアプリケーションの本番デプロイである。 + +**Twelve-Factorのプロセスはステートレスかつ[シェアードナッシング](http://en.wikipedia.org/wiki/Shared_nothing_architecture)** である。永続化する必要のあるすべてのデータは、ステートフルな[バックエンドサービス](./backing-services)(典型的にはデータベース)に格納しなければならない。 + +プロセスのメモリ空間やファイルシステムは、短い単一のトランザクション内でのキャッシュとして利用してもよい。例えば、大きなファイルをダウンロードし、そのファイルを処理し、結果をデータベースに格納するという一連の処理において、ファイルシステムをキャッシュとして利用できる。Twelve-Factor Appは、メモリやディスクにキャッシュされたものが将来のリクエストやジョブにおいて利用できることを決して仮定しない -- それぞれのプロセスタイプのプロセスが多く実行されている場合、将来のリクエストやジョブが別のプロセスで処理される可能性が高い。1つのプロセスしか実行されていない場合であっても、プロセスが再起動すると、すべての局所的な状態(メモリやファイルシステムなど)が消えてしまうことがある。プロセスの再起動の要因としては、コードのデプロイ、設定の変更、プロセスを別の物理位置に再配置する実行環境などがある。 + +アセットパッケージャー(例:[Jammit](http://documentcloud.github.com/jammit/) や [django-compressor](http://django-compressor.readthedocs.org/))は、コンパイルされたアセットをキャッシュするためにファイルシステムを利用する。Twelve-Factor Appは、このコンパイル処理を実行時に行うよりも、[Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html)のように[ビルドステージ](./build-release-run)で行うほうが、望ましいと考えている。 + +Webシステムの中には、[“スティッキーセッション”](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence)に頼るものがある -- これはユーザーのセッションデータをアプリケーションプロセスのメモリにキャッシュし、同じ訪問者からの将来のリクエストが同じプロセスに送られることを期待するものである。スティッキーセッションはTwelve-Factorに違反しており、決して使ったり頼ったりしてはならない。セッション状態のデータは、有効期限を持つデータストア(例:[Memcached](http://memcached.org/) や [Redis](http://redis.io/))に格納すべきである。 diff --git a/content/ja/toc.md b/content/ja/toc.md new file mode 100644 index 000000000..2de323df1 --- /dev/null +++ b/content/ja/toc.md @@ -0,0 +1,38 @@ +The Twelve Factors +================== + +## [I. コードベース](./codebase) +### バージョン管理されている1つのコードベースと複数のデプロイ + +## [II. 依存関係](./dependencies) +### 依存関係を明示的に宣言し分離する + +## [III. 設定](./config) +### 設定を環境変数に格納する + +## [IV. バックエンドサービス](./backing-services) +### バックエンドサービスをアタッチされたリソースとして扱う + +## [V. ビルド、リリース、実行](./build-release-run) +### ビルド、リリース、実行の3つのステージを厳密に分離する + +## [VI. プロセス](./processes) +### アプリケーションを1つもしくは複数のステートレスなプロセスとして実行する + +## [VII. ポートバインディング](./port-binding) +### ポートバインディングを通してサービスを公開する + +## [VIII. 並行性](./concurrency) +### プロセスモデルによってスケールアウトする + +## [IX. 廃棄容易性](./disposability) +### 高速な起動とグレースフルシャットダウンで堅牢性を最大化する + +## [X. 開発/本番一致](./dev-prod-parity) +### 開発、ステージング、本番環境をできるだけ一致させた状態を保つ + +## [XI. ログ](./logs) +### ログをイベントストリームとして扱う + +## [XII. 管理プロセス](./admin-processes) +### 管理タスクを1回限りのプロセスとして実行する diff --git a/content/ja/who.md b/content/ja/who.md new file mode 100644 index 000000000..7633f0e65 --- /dev/null +++ b/content/ja/who.md @@ -0,0 +1,4 @@ +このドキュメントの対象者 +============================== + +サービスとして動くアプリケーションを開発しているすべての開発者。およびそのようなアプリケーションをデプロイまたは管理しているインフラエンジニア。 diff --git a/content/ko/admin-processes.md b/content/ko/admin-processes.md new file mode 100644 index 000000000..1a237e9cb --- /dev/null +++ b/content/ko/admin-processes.md @@ -0,0 +1,15 @@ +## XII. Admin 프로세스 +### admin/maintenance 작업을 일회성 프로세스로 실행 + +[프로세스 포메이션](./concurrency)은 애플리케이션의 일반적인 기능들(예: Web request의 처리)을 처리하기 위한 프로세스들의 집합 입니다. 이와는 별도로, 개발자들은 종종 일회성 관리나 유지 보수 작업이 필요합니다. 그 예는 아래와 같습니다. + +* 데이터베이스 마이그레이션을 실행합니다. (예: Django에서 `manage.py migrate`, Rail에서 `rake db:migrate`) +* 임의의 코드를 실행하거나 라이브 데이터베이스에서 앱의 모델을 조사하기 위해 콘솔([REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) Shell로도 알려져 있는)을 실행합니다. 대부분의 언어에서는 인터프리터를 아무런 인자 없이 실행하거나(예: python, perl) 별도의 명령어로 실행(예: ruby의 irb, rails의 rails console)할 수 있는 REPL를 제공합니다. +* 애플리케이션 저장소에 커밋된 일회성 스크립트의 실행 (예: php scripts/fix_bad_records.php) + +일회성 admin 프로세스는 애플리케이션의 일반적인 [오래 실행되는 프로세스](./processes)들과 동일한 환경에서 실행되어야 합니다. 일회성 admin 프로세스들은 릴리즈를 기반으로 실행되며, 해당 릴리즈를 기반으로 돌아가는 모든 프로세스처럼 같은 [코드베이스](./codebase)와 [설정](./config)를 사용해야 합니다. admin 코드는 동기화 문제를 피하기 위해 애플리케이션 코드와 함께 배포되어야 합니다. + +모든 프로세스 타입들에는 동일한 [종속성 분리](./dependencies) 기술이 사용되어야 합니다. 예를 들어, +루비 웹 프로세스가 `bundle exec thin start` 명령어를 사용한다면, 데이터베이스 마이그레이션은 `bundle exec rake db:migrate`를 사용해야합니다. 마찬가지로, virtualenv를 사용하는 파이썬 프로그램은 tornado 웹 서버와 모든 `manage.py` admin 프로세스가 같은 virtualenv에서의 `bin/python`을 사용해야 합니다. + +Twelve-Factor는 별도의 설치나 구성없이 REPL shell을 제공하는 언어를 강하게 선호합니다. 이러한 점은 일회성 스크립트를 실행하기 쉽게 만들어주기 때문입니다. 로컬 배포에서, 개발자는 앱을 체크아웃한 디렉토리에서 일회성 admin 프로세스를 shell 명령어로 바로 실행시킵니다. production 배포에서, 개발자는 ssh나 배포의 실행 환경에서 제공하는 다른 원격 명령어 실행 메커니즘을 사용하여 admin 프로세스를 실행할 수 있습니다. \ No newline at end of file diff --git a/content/ko/background.md b/content/ko/background.md new file mode 100644 index 000000000..be72db553 --- /dev/null +++ b/content/ko/background.md @@ -0,0 +1,8 @@ +배경 +========== + +이 문서에 기여한 사람들은 수백개 앱의 개발과 배포에 직접 참여했으며, [Heroku](http://www.heroku.com/) 플랫폼을 통해서 방대한 앱의 개발, 운영, 확장을 간접적으로 관찰했다. + +이 문서는 실제로 쓰이는 다양한 SaaS 앱에 대한 경험과 관찰을 종합한 결과물이다. 특히 시간이 지나면서 앱이 유기적으로 성장하는 부분, 앱 코드베이스에서 작업하는 개발자들 간의 협업, [시간이 지나면서 망가지는 소프트웨어 유지비용을 줄이는 법](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/)에 집중하여 이상적인 앱 개발 방법을 찾고자 했다. + +이 문서는 우리가 최신 애플리케이션 개발에서 만났던 몇가지 시스템적인 문제에 대한 인지도를 높이고, 이 문제들을 가지고 논의 하는데 필요한 공통의 어휘를 제공하며, 이 문제들에 대한 넓은 개념의 해결책과 용어를 제공하기 위해 작성 했다. 형식은 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)*에서 영감을 받았다. \ No newline at end of file diff --git a/content/ko/backing-services.md b/content/ko/backing-services.md new file mode 100644 index 000000000..4e276ace2 --- /dev/null +++ b/content/ko/backing-services.md @@ -0,0 +1,15 @@ +## IV. 백엔드 서비스 +### 백엔드 서비스를 연결된 리소스로 취급 + +*백엔드 서비스*는 애플리케이션 정상 동작 중 네트워크를 통해 이용하는 모든 서비스입니다. 예를 들어, 데이터 저장소(예: [MySQL](http://dev.mysql.com/), [CouchDB](http://couchdb.apache.org/)), 메시지 큐잉 시스템(예: [RabbitMQ](http://www.rabbitmq.com/), [Beanstalkd](https://beanstalkd.github.io)), 메일을 보내기 위한 SMTP 서비스 (예: [Postfix](http://www.postfix.org/)), 캐시 시스템(예: [Memcached](http://memcached.org/)) 등이 있습니다. + +데이터베이스와 같은 백엔드 서비스들은 통상적으로 배포된 애플리케이션과 같은 시스템 관리자에 의해서 관리되고 있었습니다. 애플리케이션은 이런 로컬에서 관리하는 서비스 대신, 서드파티에 의해서 제공되고 관리되는 서비스를 이용할 수 있습니다. 예를 들어, SMTP 서비스 (예: [Postmark](http://postmarkapp.com/)), 지표 수집 서비스 (예: [New Relic](http://newrelic.com/), [Loggly](http://www.loggly.com/)), 스토리지 서비스 (예: [Amazon S3](http://aws.amazon.com/s3/)), API로 접근 가능한 소비자 서비스 (예: [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), [Last.fm](http://www.last.fm/api))등이 있습니다. + +**Twelve-Factor App의 코드는 로컬 서비스와 서드파티 서비스를 구별하지 않습니다.** 애플리케이션에게는 양 쪽 모두 연결된 리소스이며, [설정](./config)에 있는 URL 혹은 다른 로케이터와 인증 정보를 사용해서 접근 됩니다. Twelve-Factor App의 [배포](./codebase)는 애플리케이션 코드를 수정하지 않고 로컬에서 관리되는 MySQL DB를 서드파티에서 관리되는 DB(예: [Amazon RDS](http://aws.amazon.com/rds/))로 전환할 수 있어야 합니다. 마찬가지로, 로컬 SMTP 서버는 서드파티 SMTP 서비스(예: Postmark)로 코드 수정 없이 전환이 가능해야 합니다. 두 경우 모두 설정에 있는 리소스 핸들만 변경하면 됩니다. + +각각의 다른 백엔드 서비스는 *리소스*입니다. 예를 들어, 하나의 MySQL DB는 하나의 리소스입니다. 애플리케이션 레이어에서 샤딩을 하는 두 개의 MySQL 데이터베이스는 두 개의 서로 다른 리소스라고 볼 수 있습니다. Twelve-Factor App은 이러한 데이터베이스들을 *첨부된(Attached) 리소스*으로 다룹니다. 이는 서로 느슨하게 결합된다는 점을 암시합니다. + + +4개의 백엔드 서비스가 연결된 production 배포. + +리소스는 자유롭게 배포에 연결되거나 분리될 수 있습니다. 예를 들어, 애플리케이션의 데이터베이스가 하드웨어 이슈로 작용이 이상한 경우, 애플리케이션의 관리자는 최신 백업에서 새로운 데이터베이스 서버를 시작시킬 것입니다. 그리고 코드를 전혀 수정하지 않고 현재 운영에 사용하고 있는 데이터베이스를 분리하고 새로운 데이터베이스를 연결할 수 있습니다. diff --git a/content/ko/build-release-run.md b/content/ko/build-release-run.md new file mode 100644 index 000000000..00ff6aee9 --- /dev/null +++ b/content/ko/build-release-run.md @@ -0,0 +1,19 @@ +## V. 빌드, 릴리즈, 실행 +### 철저하게 분리된 빌드와 실행 단계 + +[코드베이스](./codebase)는 3 단계를 거쳐 (개발용이 아닌) 배포로 변환됩니다. + +* *빌드 단계*는 코드 저장소를 *빌드*라는 실행 가능한 번들로 변환시키는 단계입니다. 빌드 단계에서는 커밋된 코드 중 배포 프로세스에서 지정된 버전을 사용하며, [종속성](./dependencies)을 가져와 바이너리와 에셋들을 컴파일합니다. +* *릴리즈 단계*에서는 빌드 단계에서 만들어진 빌드와 배포의 현재 [설정](./config)을 결합 합니다. 완성된 *릴리즈*는 빌드와 설정을 모두 포함하며 실행 환경에서 바로 실행될 수 있도록 준비됩니다. +* *실행 단계*(런타임이라고도 하는)에서는 선택된 릴리즈에 대한 애플리케이션 [프로세스](./processes)의 집합을 시작하여, 애플리케이션을 실행 환경에서 돌아가도록 합니다. + + +![코드 베이스는 빌드가 되고, 빌드는 설정과 조합되어 릴리즈가 됩니다.](/images/release.png) + +**Twelve-Factor App은 빌드, 릴리즈, 실행 단계를 엄격하게 서로 분리합니다.** 예를 들어, 실행 단계에서 코드를 변경할 수는 없습니다. 변경을 실행 단계보다 앞에 있는 빌드 단계로 전달할 수 있는 방법이 없기 때문입니다. + +배포 도구는 일반적으로 릴리즈 관리 도구를 제공합니다. 특히 주목할만한 점은 이전 릴리즈로 되돌릴 수 있는 롤백 기능입니다. 예를 들어, [Capistrano](https://github.com/capistrano/capistrano/wiki)는 배포 툴은 릴리즈를 `releases`라는 하위 디렉토리에 저장시키고, 현재 릴리즈는 현재 릴리즈 디렉토리로 심볼릭 링크로 연결합니다. 이 툴의 `rollback` 명령어는 이전 버전으로 쉽고 빠르게 이전 릴리즈로 롤백할 수 있도록 해줍니다. + +모든 릴리즈는 항상 유니크한 릴리즈 아이디를 지녀야 합니다. 예를 들어, 릴리즈의 타임 스템프(예: 2011-04-06-20:32:17)나 증가하는 번호(예: v100, v101)가 있습니다. 릴리즈는 추가만 될 수 있으며, 한번 만들어진 릴리즈는 변경될 수 없습니다. 모든 변경은 새로운 릴리즈를 만들어야 합니다. + +빌드는 새로운 코드가 배포 될 때마다 개발자에 의해 시작됩니다. 반면, 실행 단계는 서버가 재부팅되거나 충돌이 발생한 프로세스가 프로세스 매니저에 의해 재시작 되었을 때 자동으로 실행될 수 있습니다. 따라서 대응할 수 있는 개발자가 없는 한밤중에 문제가 발생하는 것을 방지하기 위해, 실행 단계는 최대한 변화가 적어야합니다. 빌드 단계는 좀 더 복잡해져도 괜찮습니다. 항상 배포를 진행하고 있는 개발자의 눈 앞에서 에러가 발생하기 때문입니다. diff --git a/content/ko/codebase.md b/content/ko/codebase.md new file mode 100644 index 000000000..28d54f827 --- /dev/null +++ b/content/ko/codebase.md @@ -0,0 +1,17 @@ +## I. 코드베이스 +### 버전 관리되는 하나의 코드베이스와 다양한 배포 + +Twelve-Factor 앱은 항상 [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), [Subversion](http://subversion.apache.org/) 같은 버전 컨트롤 시스템을 사용하여 변화를 추적하며, 버전 추적 데이터베이스의 사본을 *코드 저장소*, 줄여서 *저장소*라고 부릅니다. + +*코드베이스*는 단일 저장소(Subversion 같은 중앙 집중식 버전 관리 시스템의 경우) 일수도 있고, 루트 커밋을 공유하는 여러 저장소(Git 같은 분산 버전 관리 시스템)일수도 있습니다. + +![하나의 코드베스는 여러 배포로 매핑됩니다.](/images/codebase-deploys.png) + +코드베이스와 앱 사이에는 항상 1대1 관계가 성립됩니다. + +* 코드베이스가 여러개 있는 경우, 앱이 아니라 분산 시스템으로 봐야합니다. 분산 시스템의 개별 구성요소가 앱이 되며, 개별 앱이 Twelve-Factor를 따릅니다. +* 여러개 앱이 동일한 코드를 공유한다면 Twelve-Factor를 위반하는것입니다. 이를 해결하려면 공유하는 코드를 라이브러리화 시키고, 해당 라이브러리를 [종속성 매니저](./dependencies)로 관리해야합니다. + +앱의 코드베이스는 한개여야 하지만, 앱 배포는 여러개가 될수 있습니다. *배포*는 실행중인 앱의 인스턴스를 가리킵니다. 보통 운영 사이트와 여러 스테이징 사이트가 여기에 해당합니다. 모든 개발자는 자신의 로컬 개발 환경에 실행되는 앱을 가지고 있는데, 이것 역시 하나의 배포로 볼 수 있습니다. + +배포마다 다른 버전이 활성화 될수 있지만, 코드베이스 자체는 모든 배포에 대해 동일합니다. 예를 들어, 개발자는 아직 스테이징 환경에 배포하지 않은 커밋이 있을 수 있으며, 스테이징 환경에는 아직 운영 환경에 배포되지 않은 커밋이 있을 수 있습니다. 하지만 이 모든 것들이 같은 코드베이스를 공유하고, 같은 앱의 다른 배포라고 할 수 있습니다. \ No newline at end of file diff --git a/content/ko/concurrency.md b/content/ko/concurrency.md new file mode 100644 index 000000000..b388c6a4c --- /dev/null +++ b/content/ko/concurrency.md @@ -0,0 +1,14 @@ +## VIII. 동시성(Concurrency) +### 프로세스 모델을 통한 확장 + +모든 컴퓨터 프로그램은 실행되면 하나 이상의 프로세스로 표현됩니다. 웹 애플리케이션은 다양한 프로세스 실행 형태를 취해왔습니다. 예를 들어, PHP 프로세스는 Apache의 자식 프로세스로 실행되며, request의 양에 따라 필요한 만큼 시작됩니다. 자바 프로세스들은 반대 방향에서의 접근법을 취합니다. JVM은, 시작될 때 큰 시스템 리소스(CPU와 메모리) 블록을 예약하는 하나의 거대한 부모 프로세스를 제공하고, 내부 쓰레드를 통해 동시성(concurrency)을 관리합니다. 두 경우 모두 실행되는 프로세스는 애플리케이션 개발자에게 최소한으로 노출됩니다. + +![Scale는 실행되는 프로세스의 갯수로 표현되고, Workload Diversity는 프로세스의 타입으로 표현됩니다. ](/images/process-types.png) + +**Twelve-Factor App에서 프로세스들은 일급 시민입니다.** Twelve-Factor App에서의 프로세스는 [서비스 데몬들을 실행하기 위한 유닉스 프로세스 모델](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/)에서 큰 힌트를 얻었습니다. 이 모델을 사용하면 개발자는 애플리케이션의 작업을 적절한 *프로세스 타입*에 할당함으로서 다양한 작업 부하를 처리할 수 있도록 설계할 수 있습니다. 예를 들어, HTTP 요청은 웹 프로세스가 처리하며, 시간이 오래 걸리는 백그라운드 작업은 worker 프로세스가 처리하도록 할 수 있습니다. + +이는 런타임 VM 내부의 쓰레드나 [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), [Node.js](http://nodejs.org/)에서 구성된 것 처럼 async/evented 모델처럼 개별 프로세스가 내부적으로 동시에 처리하는 것을 금지하는 것은 아닙니다. 하지만 개별 VM이 너무 커질 수 있습니다.(수직 확장) 따라서 애플리케이션은 여러개의 물리적인 머신에서 돌아가는 여러개의 프로세스로 넓게 퍼질 수 있어야만 합니다. + +프로세스 모델이 진정으로 빛나는 것은 수평적으로 확장하는 경우입니다. [아무것도 공유하지 않고, 수평으로 분할할 수 있는 Twelve-Factor App 프로세스의 성질](./processes)은 동시성을 높이는 것은 간단하고 안정적인 작업이라는 것을 의미 합니다. 프로세스의 타입과 각 타입별 프로세스의 갯수의 배치를 *프로세스 포메이션*이라고 합니다. + +Twelve-Factor App 프로세스는 [절대 데몬화해서는 안되며](http://dustin.github.com/2010/02/28/running-processes.html) PID 파일을 작성해서는 안됩니다. 대신, OS의 프로세스 관리자(예: [systemd](https://www.freedesktop.org/wiki/Software/systemd/))나 클라우드 플랫폼의 분산 프로세스 매니저, 혹은 [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) 같은 툴에 의존하여 [아웃풋 스트림](./logs)을 관리하고, 충돌이 발생한 프로세스에 대응하고, 재시작과 종료를 처리해야 합니다. diff --git a/content/ko/config.md b/content/ko/config.md new file mode 100644 index 000000000..c1f033277 --- /dev/null +++ b/content/ko/config.md @@ -0,0 +1,22 @@ +## III. 설정 +### 환경(environment)에 저장된 설정 + +애플리케이션의 *설정*은 [배포](./codebase) (스테이징, 프로덕션, 개발 환경 등) 마다 달라질 수 있는 모든 것들입니다. 설정에는 다음이 포함됩니다. + +* 데이터베이스, memcached 등 [백엔드 서비스](./backing-services)들의 리소스 핸들 +* Amazon S3 이나 트위터 등의 외부 서비스 인증 정보 +* 배포된 호스트의 정규화된 호스트 이름(canonical hostname)처럼 각 배포마다 달라지는 값 + +애플리케이션은 종종 설정을 상수로 코드에 저장합니다. 이것은 Twelve-Factor를 위반하며, Twelve-Factor는 **설정을 코드에서 엄격하게 분리하는 것**을 요구합니다. 설정은 배치마다 크게 다르지만, 코드는 그렇지 않습니다. + +애플리케이션의 모든 설정이 정상적으로 코드 바깥으로 분리되어 있는지 확인할 수 있는 간단한 테스트는 어떠한 인증정보도 유출시키지 않고 코드베이스가 지금 당장 오픈 소스가 될 수 있는지 확인하는 것입니다. + +이 "설정"의 정의는 애플리케이션 내부 설정을 *포함하지 않는다는 점*에 유의해야 합니다. Rails의 `config/routes.rb`이나 [Spring](http://spring.io/)의 ["어떻게 코드 모듈이 연결되는 가](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html)과 같은 설정들은 배치 사이에서 변하지 않기 때문에 코드의 내부에 있는 것이 가장 좋습니다. + +설정에 대한 또 다른 접근방식은 Rails의 `config/database.yaml`처럼 버전 관리 시스템에 등록되지 않은 설정 파일을 이용하는 것입니다. 이 방법은 코드 저장소에 등록된 상수를 사용하는 것에 비하면 매우 큰 발전이지만, 설정 파일이 여러 위치에 여러 포맷으로 흝어지고 모든 설정을 한 곳에서 확인하고 관리하기 어렵게 만드는 경향이 있습니다. 게다가, 이러한 형식들은 언어와 프레임워크을 따라가는 경향이 있습니다. + +**Twelve-Factor App은 설정을 *환경 변수*** (envvars나 env라고도 불림)에 저장합니다. 환경 변수는 코드 변경 없이 쉽게 배포 때마다 쉽게 변경할 수 있습니다. 설정 파일과 달리, 잘못해서 코드 저장소에 올라갈 가능성도 낮습니다. 또한, 커스텀 설정 파일이나 Java System Property와 같은 다른 설정 매커니즘과 달리 언어나 OS에 의존하지 않는 표준입니다. + +설정 관리의 다른 측면은 그룹핑입니다. 종종 애플리케이션은 설정을 명명된 그룹("environments"라고도 함)으로 구성하기도 합니다. 해당 그룹은 Rails의 'development', 'test', 'production' environments처럼, 배포의 이름을 따서 명명됩니다. 이 방법은 깔끔하게 확장하기 어렵습니다. 응용 프로그램의 배포가 증가함에 따라, 'staging'이라던가 'qa'같은 새로운 그룹의 이름이 필요하게 됩니다. 프로젝트가 성장함에 따라, 개발자은 자기 자신의 그룹를 추가하게 됩니다. 결과적으로 설정이 각 그룹의 조합으로 폭발하게 되고, 애플리케이션의 배포를 불안정하게 만듭니다. + +Twelve-Factor App에서 환경 변수는 매우 정교한 관리이며, 각각의 환경변수는 서로 직교합니다. 환경 변수는 "environments"로 절대 그룹으로 묶이지 않지만, 대신 각 배포마다 독립적으로 관리됩니다. 이 모델은 애플리케이션의 수명주기를 거치는 동안 더 많은 배포로 원활하게 확장해 나갈 수 있습니다. diff --git a/content/ko/dependencies.md b/content/ko/dependencies.md new file mode 100644 index 000000000..99a2e7f74 --- /dev/null +++ b/content/ko/dependencies.md @@ -0,0 +1,12 @@ +## II. 종속성 +### 명시적으로 선언되고 분리된 종속성 + +대부분의 프로그래밍 언어는 라이브러리 배포를 위한 패키징 시스템을 제공하고 있습니다. Perl의 [CPAN](http://www.cpan.org/) 이나 Ruby의 [Rubygems](http://rubygems.org/)가 그 예입니다. 라이브러리는 패키징 시스템을 통해 시스템 전체(site pakages)나 애플리케이션을 포함한 디렉토리(vendoring 혹은 bundling)에 설치될 수 있습니다. + +**Twelve-Factor App은 전체 시스템에 특정 패키지가 암묵적으로 존재하는 것에 절대 의존하지 않습니다.** *종속선 선언* mainifest를 이용하여 모든 종속성을 완전하고 엄격하게 선언합니다. 더나아가, *종속성 분리* 툴을 사용하여 실행되는 동안 둘러싼 시스템으로 암묵적인 종속성 "유출"이 발생하지 않는 것을 보장합니다. 이런 완전하고 명시적인 종속성의 명시는 개발과 서비스 모두에게 동일하게 적용됩니다. + +예를 들어, 루비에서 사용되는 [Bundler](https://bundler.io/)는 종속성 선언을 위해 `Gemfile` manifest 포맷을 지원하며, 종속성 분리를 위해 `bundle exec`를 지원합니다. 파이썬에는 이를 지원하기 위한 2가지 도구가 있습니다. [Pip](http://www.pip-installer.org/en/latest/)은 종속성 선언을 위해 사용되며, [Virtualenv](http://www.virtualenv.org/en/latest/)는 종속성 분리를 위해 사용됩니다. 심지어 C언어에도 종속성 분리를 위해 [Autoconf](http://www.gnu.org/s/autoconf/)가 있으며, static link를 활용해 종속성 분리도 가능합니다. 어떤 툴체인을 사용하든, 종속성 선언과 분리는 항상 같이 사용되어야 합니다. 하나만 사용하는 것은 Twelve-Factor에 만족하는 데 불충분합니다. + +명시적인 종속성 선언의 장점 중 하나는 애플리케이션 개발에 새로 참가하게 된 개발자가 설치를 간단하게 할 수 있다는 점입니다. 새로 참가한 개발자는 애플리케이션의 코드베이스를 개발 머신에 체크아웃 하고, 언어의 런타임과 종속성 매니저만 미리 설치하면 됩니다. 개발자는 정해져있는 *빌드 명령어*만 입력하면 응용 프로그램의 코드를 실행하는 데 필요한 모든 것을 설치할 수 있습니다. 예를 들어, Ruby의 빌드 명령어는 `bundle install`이며, Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme)에서는 `lein deps`입니다. + +Twelve-Factor App은 어떠한 시스템 도구에도 암시적으로 의존하지 않습니다. 예를 들어, ImageMagick이나 `curl`을 사용하는 경우가 있습니다. 이러한 툴들은 대부분의 시스템에 존재하지만, 모든 시스템에 존재하는 것이 보장되는 것은 아닙니다. 미래의 시스템에서는 존재하지 않을 수 있으며, 호환되는 버전이 있으라는 보장도 없습니다. 애플리케이션에게 시스템 도구가 필요하다면, 그 도구를 애플리케이션과 통합해야 합니다. diff --git a/content/ko/dev-prod-parity.md b/content/ko/dev-prod-parity.md new file mode 100644 index 000000000..eb90cdd47 --- /dev/null +++ b/content/ko/dev-prod-parity.md @@ -0,0 +1,77 @@ +## X. dev/prod 일치 +### development, staging, production 환경을 최대한 비슷하게 유지 + +역사적으로, 개발 환경(애플리케이션의 개발자가 직접 수정하는 로컬의 [배포](./codebase))과 production 환경(최종 사용자가 접근하게 되는 실행 중인 배포) 사이에는 큰 차이가 있었습니다. 이러한 차이는 3가지 영역에 걸처 나타납니다. + +* **시간의 차이**: 개발자가 작업한 코드는 production에 반영되기까지 며칠, 몇주, 때로는 몇개월이 걸릴 수 있습니다. +* **담당자의 차이**: 개발자가 작성한 코드를 시스템 엔지니어가 배포합니다. +* **툴의 차이**: production 배포는 아파치, MySQL, 리눅스를 사용하는데, 개발자는 Nginx, SQLite, OS X를 사용할 수 있습니다. + +**Twelve Factor App은 개발 환경과 production 환경의 차이를 작게 유지하여 [지속적인 배포](http://avc.com/2011/02/continuous-deployment/)가 가능하도록 디자인 되었습니다.** 위에서 언급한 3가지 차이에 대한 대응책은 아래와 같습니다. + +* 시간의 차이를 최소화: 개발자가 작성한 코드는 몇 시간, 심지어 몇 분 후에 배포됩니다. +* 담당자의 차이를 최소화: 코드를 작성한 개발자들이 배포와 production에서의 모니터링에 깊게 관여합니다. +* 툴의 차이를 최소화: 개발과 production 환경을 최대한 비슷하게 유지합니다. + +위의 내용을 표로 요약하면 아래와 같습니다. + + + + + + + + + + + + + + + + + + + + + + +
전통적인 애플리케이션Twelve-Factor App
배포 간의 간격몇 주몇 시간
코드 작성자와 코드 배포자다른 사람같은 사람
개발 환경과 production 환경불일치함최대한 유사함
+ + +데이터베이스, 큐잉 시스템, 캐시와 같은 [백엔드 서비스](./backing-services)는 dev/prod 일치가 중요한 영역 중 하나 입니다. 많은 언어들은 다른 종류의 서비스에 대한 *어댑터*를 포함하고 간단하게 백엔드 서비스에 접근할 수 있는 라이브러리들을 제공합니다. 아래의 표에 몇가지 예가 나와있습니다. + + + + + + + + + + + + + + + + + + + + + + + + + + +
종류언어라이브러리어댑터
데이터 베이스Ruby/RailsActiveRecordMySQL, PostgreSQL, SQLite
큐(Queue)Python/DjangoCeleryRabbitMQ, Beanstalkd, Redis
캐쉬Ruby/RailsActiveSupport::Cache메모리, 파일시스템, Memcached
+ +production 환경에서는 더 본격적이고 강력한 백엔드 서비스가 사용됨에도 불구하고, 개발자는 자신의 로컬 개발 환경에서는 가벼운 백엔드 서비스를 사용하는 것에 큰 매력을 느낄 수도 있습니다. 예를 들어, 로컬에서는 SQLite를 사용하고 production에서는 PostgreSQL을 사용한다던가, 개발 중에는 로컬 프로세스의 메모리를 캐싱용으로 사용하고 production에서는 Memcached를 사용하는 경우가 있습니다. + +**Twelve-Factor 개발자는 개발 환경과 production 환경에서 다른 백엔드 서비스를 쓰고 싶은 충동에 저항합니다.** 이론적으로는 어댑터가 백엔드 서비스 간의 차이를 추상화해준다고 해도, 백엔드 서비스 간의 약간의 불일치가 개발 환경과 스테이징 환경에서는 동작하고 테스트에 통과된 코드가 production 환경에서 오류를 일으킬 수 있기 때문입니다. 이런 종류의 오류는 지속적인 배포를 방해합니다. 애플리케이션의 생명 주기 전체를 보았을 때, 이러한 방해와 지속적인 배포의 둔화가 발생시키는 손해는 엄청나게 큽니다. + +가벼운 로컬 서비스는 예전처럼 필수적인 것은 아닙니다. Memcache, PostgreSQL, RabbitMQ와 같은 현대적인 백엔드 서비스들은 [Homebrew](http://mxcl.github.com/homebrew/)나 [apt-get](https://help.ubuntu.com/community/AptGet/Howto)와 같은 현대적인 패키징 시스템 덕분에 설치하고 실행하는데 아무런 어려움도 없습니다. 혹은 [Chef](http://www.opscode.com/chef/) and [Puppet](http://docs.puppetlabs.com/)와 같은 선언적 provisioning 툴과 [Vagrant](http://vagrantup.com/)등의 가벼운 가상 환경을 결합하여 로컬 환경을 production 환경과 매우 유사하게 구성할 수 있습니다. dev/prod 일치와 지속적인 배포의 이점에 비하면 이러한 시스템을 설치하고 사용하는 비용은 낮습니다. + +여러 백엔드 서비스에 접근할 수 있는 어댑터는 여전히 유용합니다. 새로운 백엔드 서비스를 사용하도록 포팅하는 작업의 고통을 낮춰주기 때문입니다. 하지만, 모든 애플리케이션의 배포들(개발자 환경, 스테이징, production)은 같은 종류, 같은 버전의 백엔드 서비스를 이용해야합니다. diff --git a/content/ko/disposability.md b/content/ko/disposability.md new file mode 100644 index 000000000..f9201b38e --- /dev/null +++ b/content/ko/disposability.md @@ -0,0 +1,12 @@ +## IX. 폐기 가능(Disposability) +### 빠른 시작과 그레이스풀 셧다운(graceful shutdown)을 통한 안정성 극대화 + +**Twelve-Factor App의 [프로세스](./processes)는 *간단하게 폐기 가능*합니다. 즉, 프로세스는 바로 시작하거나 종료될 수 있습니다.** 이러한 속성은 신축성 있는 확장과 [코드](./codebase)나 [설정](./config)의 변화를 빠르게 배포하는 것을 쉽게 하며, production 배포를 안정성 있게 해줍니다. + +프로세스는 **시작 시간을 최소화**하도록 노력해야합니다. 이상적으로, 프로세스는 실행 커맨드가 실행된 뒤 몇 초만에 요청이나 작업을 받을 수 있도록 준비 됩니다. 짧은 실행 시간은 [릴리즈](./build-release-run) 작업과 확장(scale up)이 더 민첩하게 이루어질 수 있게 합니다. 또한 프로세스 매니저가 필요에 따라 쉽게 프로세스를 새로운 머신으로 프로세스를 옮길 수 있기 때문에 안정성도 높아집니다. + +프로세스는 프로세스 매니저로부터 **[SIGTERM](http://en.wikipedia.org/wiki/SIGTERM) 신호를 받았을 때 그레이스풀 셧다운(graceful shutdown)을 합니다.** 웹프로세스의 그레이스풀 셧다운 과정에서는 서비스 포트의 수신을 중지하고(그럼으로써 새로운 요청을 거절함), 현재 처리 중인 요청이 끝나길 기다린 뒤에 프로세스가 종료 되게 됩니다. 이 모델은 암묵적으로 HTTP 요청이 짧다는 가정(기껏해야 몇 초)을 깔고 있습니다. long polling의 경우에는 클라이언트가 연결이 끊긴 시점에 바로 다시 연결을 시도해야 합니다. + +worker 프로세스의 경우, 그레이스풀 셧다운은 현재 처리중인 작업을 작업 큐로 되돌리는 방법으로 구현됩니다. 예를 들어, [RabbitMQ](http://www.rabbitmq.com/)에서는 worker는 [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack)을 메시지큐로 보낼 수 있습니다. [Beanstalkd](https://beanstalkd.github.io)에서는 woker와의 연결이 끊기면 때 자동으로 작업을 큐로 되돌립니다. [Delayed Job](https://github.com/collectiveidea/delayed_job#readme)와 같은 Lock-based 시스템들은 작업 레코드에 걸어놨던 lock을 확실하게 풀어놓을 필요가 있습니다. 이 모델은 암묵적으로 모든 작업은 [재입력 가능(reentrant)](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29)하다고 가정합니다. 이는 보통, 결과를 트랜잭션으로 감싸거나 요청을 [멱등(idempotent)](http://en.wikipedia.org/wiki/Idempotence)하게 함으로써 구현될 수 있습니다. + +프로세스는 하드웨어 에러에 의한 **갑작스러운 죽음에도 견고해야합니다.** 이러한 사태는 `SIGTERM`에 의한 그레이스풀 셧다운에 비하면 드문 일이지만, 그럼에도 발생할 수 있습니다. 이런 일에 대한 대책으로 Beanstalkd와 같은 견고한 큐잉 백엔드를 사용하는 것을 권장합니다. 이러한 백엔드는 클라이언트가 접속이 끊기거나, 타임 아웃이 발생했을 때, 작업을 큐로 되돌립니다. Twelve-Factor App은 예기치 못한, 우아하지 않은 종료도 처리할 수 있도록 설계됩니다. [Crash-only design](http://lwn.net/Articles/191059/)에서는 [논리적인 결론](http://docs.couchdb.org/en/latest/intro/overview.html)으로 이러한 컨셉을 가져왔습니다. diff --git a/content/ko/intro.md b/content/ko/intro.md new file mode 100644 index 000000000..0914b5aac --- /dev/null +++ b/content/ko/intro.md @@ -0,0 +1,12 @@ +머리말 +============ + +최근 소프트웨어를 서비스 형태로 제공하는게 일반화 되면서, 웹앱 혹은 SaaS(Software As A Service)라고 부르게 되었다. Twelve-Factor app은 아래 특징을 가진 SaaS 앱을 만들기 위한 방법론이다. + +* 설정 자동화를 위한 **절차(declarative)** 를 체계화 하여 새로운 개발자가 프로젝트에 참여하는데 드는 시간과 비용을 최소화한다. +* OS에 따라 **달라지는 부분을 명확히**하고, 실행 환경 사이의 **이식성을 극대화** 한다. +* 최근 등장한 **클라우드 플랫폼** **배포에** 적합하고, 서버와 시스템의 관리가 필요없게 된다. +* 개발 환경과 운영 환경의 **차이를 최소화**하고 민첩성을 극대화하기 위해 **지속적인 배포**가 가능하다. +* 툴, 아키텍처, 개발 방식을 크게 바꾸지 않고 **확장(scale up)** 할 수 있다. + +Twelve-Factor 방법론은 어떤 프로그래밍 언어로 작성된 앱에도 적용할 수 있고 백엔드 서비스(데이터베이스, 큐, 메모리 캐시 등)와 다양한 조합으로 사용할 수 있다. \ No newline at end of file diff --git a/content/ko/logs.md b/content/ko/logs.md new file mode 100644 index 000000000..1886334fa --- /dev/null +++ b/content/ko/logs.md @@ -0,0 +1,16 @@ +## XI. 로그 +### 로그를 이벤트 스트림으로 취급 + +*로그*는 실행 중인 app의 동작을 확인할 수 있는 수단입니다. 서버 기반 환경에서 로그는 보통 디스크에 파일(로그 파일)로 저장됩니다. 하지만, 이것은 출력 포맷 중 하나에 불과합니다. + +로그는 모든 실행중인 프로세스와 백그라운드 서비스의 아웃풋 스트림으로부터 수집된 이벤트가 시간 순서로 정렬된 [스트림](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/)입니다. 가공되지 않는 로그는 보통, 하나의 이벤트가 하나의 라인으로 기록된 텍스트 포맷입니다.(예외(exception)에 의한 backtrace는 여러 라인에 걸쳐 있을 수도 있습니다.) 로그는 고정된 시작과 끝이 있는 것이 아니라, app이 실행되는 동안 계속 흐르는 흐름입니다. + +**Twelve-Factor App은 아웃풋 스트림의 전달이나 저장에 절대 관여하지 않습니다.** app은 로그 파일을 작성하거나, 관리하려고 해서는 안됩니다. 대신, 각 프로세스는 이벤트 스트림을 버퍼링 없이 `stdout`에 출력합니다. 로컬 개발환경에서 작업 중인 개발자는 app의 동작을 관찰하기 원하면 각자의 터미널에 출력되는 이 스트림을 볼 수 있습니다. + +스테이징이나 production 배포에서는 각 프로세스의 스트림은 실행 환경에 의해서 수집된 후, 앱의 다른 모든 스트림과 병합되어 열람하거나 보관하기 위한 하나 이상의 최종 목적지로 전달됩니다. 이러한 목적지들은 앱이 열람하거나 설정할 수 없지만, 대신 실행 환경에 의해서 완벽하게 관리됩니다. 이를 위해 오픈 소스 로그 라우터를 사용할 수 있습니다.(예: ([Logplex](https://github.com/heroku/logplex), [Fluentd](https://github.com/fluent/fluentd))) + +앱의 이벤트 스트림은 파일로 보내지거나 터미널에서 실시간으로 보여질 수 있습니다. 가장 중요한 점은 스트림은 [Splunk](http://www.splunk.com/)같은 로그 분석 시스템과 [Hadoop/Hive](http://hive.apache.org/)같은 범용 데이터 보관소에 보내질 수 있다는 점입니다. 이러한 시스템은 장기간에 걸쳐 앱의 동작을 조사할 수 있는 강력함과 유연성을 가지게 됩니다. + +* 과거의 특정 이벤트를 찾기 +* 트렌드에 대한 거대한 규모의 그래프 (예: 분당 요청 수) +* 유저가 정의한 휴리스틱에 따른 알림 (예: 분당 오류 수가 임계 값을 넘는 경우 알림을 발생시킴) diff --git a/content/ko/port-binding.md b/content/ko/port-binding.md new file mode 100644 index 000000000..b3293d4b8 --- /dev/null +++ b/content/ko/port-binding.md @@ -0,0 +1,14 @@ +## VII. 포트 바인딩 +### 포트 바인딩을 사용해서 서비스를 공개함 + +웹앱은 웹서버 컨테이너 내부에서 실행되기도 합니다. 예를 들어, PHP 앱은 [Apache HTTPD](http://httpd.apache.org/)의 모듈로 실행될 수도 있고, Java 앱은 [Tomcat](http://tomcat.apache.org/) 내부에서 실행될 수도 있습니다. + +**Twelve-Factor 앱은 완전히 독립적**이며 웹서버가 웹 서비스를 만들기 위해 처리하는 실행환경에 대한 런타임 인젝션에 의존하지 않습니다. Twelve-Factor 웹 앱은 **포트를 바인딩하여 HTTP 서비스로 공개되며** 그 포트로 들어오는 요청을 기다립니다. + +로컬 개발 환경에서는 `http://localhost:5000`과 같은 주소를 통해 개발자가 애플리케이션 서비스에 접근할 수 있습니다. 배포에서는 라우팅 레이어가 외부에 공개된 호스트명으로 들어온 요청을 포트에 바인딩된 웹 프로세스에 전달 합니다. + +이는 일반적으로 [종속선 선언](./dependencies)에 웹서버 라이브러리를 추가함으로써 구현됩니다. 예를 들어, 파이썬의 [Tornado](http://www.tornadoweb.org/)나 루비의 [Thin](http://code.macournoyer.com/thin/)이나 자바와 JVM 기반 언어들을 위한 [Jetty](http://www.eclipse.org/jetty/)가 있습니다. 이것들은 전적으로 *유저 스페이스* 즉, 애플리케이션의 코드 내에서 처리됩니다. 실행 환경과의 규약은 요청을 처리하기 위해 포트를 바인딩하는 것입니다. + +포트 바인딩에 의해 공개되는 서비스는 HTTP 뿐만이 아닙니다. 거의 모든 종류의 서버 소프트웨어는 포트를 바인딩하고 요청이 들어오길 기다리는 프로세스를 통해 실행될 수 있습니다. 예를 들면, [ejabberd](http://www.ejabberd.im/) ([XMPP](http://xmpp.org/)을 따름)나 [Redis](http://redis.io/) ([Redis protocol](http://redis.io/topics/protocol)을 따름) 등이 있습니다. + +포트 바인딩을 사용한다는 것은 하나의 앱이 다른 앱을 위한 백엔드 서비스가 될 수 있다는 것을 의미한다는 점에 주목합시다. 백엔드 앱의 URL을 사용할 앱의 [설정](./config)의 리소스 핸들로 추가하는 방식으로 앱이 다른 앱을 백엔드 서비스로 사용할 수 있습니다. diff --git a/content/ko/processes.md b/content/ko/processes.md new file mode 100644 index 000000000..19a9e63cd --- /dev/null +++ b/content/ko/processes.md @@ -0,0 +1,14 @@ +## VI. 프로세스 +### 애플리케이션을 하나 혹은 여러개의 무상태(stateless) 프로세스로 실행 + +실행 환경에서 앱은 하나 이상의 *프로세스*로 실행됩니다. + +가장 간단한 케이스는 코드가 stand-alone 스크립트인 경우입니다. 이 경우, 실행 환경은 개발자의 언어 런타임이 설치된 로컬 노트북이며, 프로세스는 커맨드 라인 명령어에 의해서 실행됩니다.(예: `python my_script.py`) 복잡한 케이스로는 많은 [프로세스 타입별로 여러개의 프로세스](./concurrency)가 사용되는 복잡한 애플리케이션이 있습니다. + +**Twelve-Factor 프로세스는 무상태(stateless)이며, [아무 것도 공유하지 않습니다](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** 유지될 필요가 있는 모든 데이터는 데이터베이스 같은 안정된 [백엔드 서비스](./backing-services)에 저장되어야 합니다. + +짧은 단일 트랙잭션 내에서 캐시로 프로세스의 메모리 공간이나 파일시스템을 사용해도 됩니다. 예를 들자면 큰 파일을 받고, 해당 파일을 처리하고, 그 결과를 데이터베이스에 저장하는 경우가 있습니다. Twelve-Factor 앱에서 절대로 메모리나 디스크에 캐시된 내용이 미래의 요청이나 작업에서도 유효할 것이라고 가정해서는 안됩니다. 각 프로세스 타입의 프로세스가 여러개 돌아가고 있는 경우, 미래의 요청은 다른 프로세스에 의해서 처리될 가능성이 높습니다. 하나의 프로세스만 돌고 있는 경우에도 여러 요인(코드 배포, 설정 변경, 프로세스를 다른 물리적 장소에 재배치 등)에 의해서 발생하는 재실행은 보통 모든 로컬의 상태(메모리와 파일 시스템 등)를 없애버립니다. + +에셋 패키징 도구 (예: [Jammit](http://documentcloud.github.com/jammit/), [django-assetpackager](http://code.google.com/p/django-assetpackager/))는 컴파일된 에셋을 저장할 캐시로 파일 시스템을 사용합니다. Twelve-Factor App은 이러한 컴파일을 런타임에 진행하기보다는, [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html)처럼 [빌드 단계](./build-release-run)에서 수행하는 것을 권장합니다. + +웹 시스템 중에서는 ["Sticky Session"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence)에 의존하는 것도 있습니다. 이는 유저의 세션 데이터를 앱의 프로세스 메모리에 캐싱하고, 같은 유저의 이후 요청도 같은 프로세스로 전달될 것을 가정하는 것입니다. Sticky Session은 Twelve-Factor에 위반되며, 절대로 사용하거나 의존해서는 안됩니다. 세션 상태 데이터는 [Memcached](http://memcached.org/)나 [Redis](http://redis.io/)처럼 유효기간을 제공하는 데이터 저장소에 저장하는 것이 적합합니다. \ No newline at end of file diff --git a/content/ko/toc.md b/content/ko/toc.md new file mode 100644 index 000000000..bac6c0e15 --- /dev/null +++ b/content/ko/toc.md @@ -0,0 +1,38 @@ +The Twelve Factors +================== + +## [I. 코드베이스](./codebase) +### 버전 관리되는 하나의 코드베이스와 다양한 배포 + +## [II. 종속성](./dependencies) +### 명시적으로 선언되고 분리된 종속성 + +## [III. 설정](./config) +### 환경(environment)에 저장된 설정 + +## [IV. 백엔드 서비스](./backing-services) +### 백엔드 서비스를 연결된 리소스로 취급 + +## [V. 빌드, 릴리즈, 실행](./build-release-run) +### 철저하게 분리된 빌드와 실행 단계 + +## [VI. 프로세스](./processes) +### 애플리케이션을 하나 혹은 여러개의 무상태(stateless) 프로세스로 실행 + +## [VII. 포트 바인딩](./port-binding) +### 포트 바인딩을 사용해서 서비스를 공개함 + +## [VIII. 동시성(Concurrency)](./concurrency) +### 프로세스 모델을 사용한 확장 + +## [IX. 폐기 가능(Disposability)](./disposability) +### 빠른 시작과 그레이스풀 셧다운(graceful shutdown)을 통한 안정성 극대화 + +## [X. 개발/프로덕션환경 일치](./dev-prod-parity) +### 개발, 스테이징, 프로덕션 환경을 최대한 비슷하게 유지 + +## [XI. 로그](./logs) +### 로그를 이벤트 스트림으로 취급 + +## [XII. Admin 프로세스](./admin-processes) +### admin/maintenance 작업을 일회성 프로세스로 실행 diff --git a/content/ko/who.md b/content/ko/who.md new file mode 100644 index 000000000..55674e684 --- /dev/null +++ b/content/ko/who.md @@ -0,0 +1,4 @@ +이 문서의 대상 +============================== + +서비스로 동작하는 애플리케이션을 개발하는 모든 개발자. 그런 애플리케이션을 배포하고 관리하는 인프라 엔지니어. diff --git a/content/pl/admin-processes.md b/content/pl/admin-processes.md new file mode 100644 index 000000000..c0273dbfa --- /dev/null +++ b/content/pl/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Zarządzanie aplikacją +### Uruchamiaj zadania administracyjne jako jednorazowe procesy + +[Formacja](./concurrency) jest zestawem procesów używanych przez aplikację podczas jej działania (np. obsługi zapytań z sieci). Do często wykonywanych zadań administracyjnych należą: + +* Wykonanie migracji bazy danych (np. `manage.py migrate` w Django, `rake db:migrate` w Railsach). +* Uruchomienie konsoli (znanej również jako powłoka [REPL](http://pl.wikipedia.org/wiki/REPL)) by wykonać fragment kodu lub podejrzeć modele działającej bazy danych. Większość środowisk języków programowania udostępnia REPL poprzez wywołanie interpretera bez dodatkowych argumentów (np. `python` lub `perl`). W innych przypadkach przeznaczone są do tego osobne polecenia (np. `irb` w Ruby, `rails console` w Railsach). +* Wykonywanie pojedynczych skryptów znajdujących się w repozytorium kodu aplikacji (np. `php scripts/fix_bad_records.php`). + +Pojedyncze zadania powinny być uruchamiane w identycznym środowisku jak [długoterminowe procesy](./processes) aplikacji. Działają w ramach tego samego [wdrożenia](./build-release-run), używając tego samego [kodu](./codebase) i [konfiguracji](./config) jak każdy inny działający proces. Kod zadania administracyjnego musi zostać dołączony do kodu aplikacji by uniknąć problemów z synchronizacją. + +Te same techniki [izolacji zależności](./dependencies) powinny być używane dla wszystkich typów procesów. Dla przykładu, jeśli proces sieciowy Ruby używa polecenia `bundle exec thin start`, wtedy do migracji bazy danych powinno się użyć `bundle exec rake db:migrate`. Podobnie program napisany w Pythonie używający Virtualenv powinien używać dołączonego `bin/python` by uruchomić zarówno webserver Tornado lub `manage.py` do procesów zarządzania. + +Aplikacja 12factor zaleca używanie języków programowania, które udostępniają powłokę REPL oraz takich w których można łatwo uruchomić pojedynczy skrypt. W środowisku lokalnym developerzy uruchamiają zadania zarządzające aplikacją poprzez bezpośrednie wywołanie polecenia w konsoli w katalogu roboczym aplikacji. We wdrożeniu produkcyjnym, developer może użyć ssh lub innego mechanizmu służącego do zdalnego wykonywania poleceń, by uruchomić ten sam proces. diff --git a/content/pl/background.md b/content/pl/background.md new file mode 100644 index 000000000..0a6af3bda --- /dev/null +++ b/content/pl/background.md @@ -0,0 +1,10 @@ +Background +========== + +Kontrybutorzy tego dokumentu byli bezpośrednio zaangażowani w tworzenie i wdrażanie setek aplikacji i pośrednio byli świadkami produkcji, działania i skalowania setek tysięcy aplikacji dzięki naszej pracy na platformie [Heroku](http://www.heroku.com/). + +Ten dokument jest podsumowaniem całego naszego doświadczenia i obserwacji szerokiej gamy aplikacji SaaS. Jest on połączeniem idealnych praktyk developmentu, zwracania szczególnej uwagi na naturalny rozrost aplikacji w czasie, dynamiki współpracy developerów pracujących nad jednym codebase'm, oraz [unikania kosztów gnijącego oprogramowania](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Naszym celem jest podniesienie poziomu świadomości o podstawowych problemach, które dostrzegliśmy przy tworzeniu nowoczesnych aplikacji, zapewnienie wspólnego słownictwa do rozmowy o tych problemach oraz zaoferowanie ogólnych rozwiązań dla tych problemów wraz z towarzyszącą terminologią. Format dokumentu jest inspirowany książkami Martina Fowlera + *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* oraz *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. + diff --git a/content/pl/backing-services.md b/content/pl/backing-services.md new file mode 100644 index 000000000..abab6962d --- /dev/null +++ b/content/pl/backing-services.md @@ -0,0 +1,15 @@ +## IV. Usługi wspierające +### Traktuj usługi wspierające jako przydzielone zasoby + +Usługą wspierającą jest każda, z której aplikacja korzysta przez sieć jako część normalnego działania. Zaliczamy do nich np. magazyny danych (takie jak [MySQL](http://dev.mysql.com/) albo [CouchDB](http://couchdb.apache.org/)), systemy wysyłania/kolejkowania wiadomości (takie jak [RabbitMQ](http://www.rabbitmq.com/) czy [Beanstalkd](https://beanstalkd.github.io)), usługi SMTP do zewnętrznej wysyłki emaili (np. [Postfix](http://www.postfix.org/)) oraz systemy cachowania pamięci (np. [Memcached](http://memcached.org/)). + +Usługa wspierająca taka jak baza danych jest zazwyczaj zarządzana przez tych samych programistów, którzy zajmują się wdrażaniem aplikacji. Dodatkowo aplikacja może również korzystać z usług oferowanych przez osoby trzecie. Do przykładów zaliczają się usługi SMTP ([Postmark](http://postmarkapp.com/)),usługi zbierające metryki ([New Relic](http://newrelic.com/) czy [Loggly](http://www.loggly.com/)), usługi przechowywania danych (takie jak [Amazon S3](http://aws.amazon.com/s3/)), czy również usługi dostępne przez publiczne API (jak np. [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), lub [Last.fm](http://www.last.fm/api)). + +**Aplikacje 12factor nie rozróżniają usług lokalnych od zewnętrznych.** Dla aplikacji wszystkie są załączonymi zasobami, dostepnymi przez adres URL lub inny standard zdefiniowany w [konfiguracji](./config). Przy [wdrożeniu](./codebase) aplikacji nie może być problemów ze zmianą lokalnej bazy MySQL na oferowaną przez zewnętrznego usługodawcę (np. [Amazon RDS](http://aws.amazon.com/rds/)) bez żadnych zmian w kodzie aplikacji. Podobnie lokalny serwer SMTP może być zamieniony na zewnętrzną usługę SMTP (taką jak Postmark) bez zmian kodu. W obu przypadkach zmiana powinna wystąpić jedynie w konfiguracji aplikacji. + +Każda usługa jest traktowana jako *zasób*. Zasobem będzie np. baza MySQL; dwie bazy danych (używane do [shardingu](https://en.wikipedia.org/wiki/Shard_(database_architecture)) w warstwie aplikacji) kwalifikują się jako dwa odrębne zasoby. Aplikacja 12factor traktuje te bazy danych jako *załączone zasoby*, co wskazuje, że nie są z nią trwale powiązane. + +Produkcyjne wdrożenie aplikacji korzystajace z czterech usług wspierających. + +Zasoby mogą być dołączane i odłączane jeśli zajdzie taka potrzeba. W momencie gdy baza danych aplikacji z powodu usterek sprzętowych nie działa poprawnie, administrator może przełączyć bazę danych aplikacji na nowy serwer odtworzoną z ostatniego zapisu przywracania danych. Obecna produkcyjna baza może więc zostać przełączona bez żadnych zmian w kodzie aplikacji. + diff --git a/content/pl/build-release-run.md b/content/pl/build-release-run.md new file mode 100644 index 000000000..30d950da9 --- /dev/null +++ b/content/pl/build-release-run.md @@ -0,0 +1,18 @@ +## V. Buduj, publikuj, uruchamiaj +### Oddzielaj etap budowania od uruchamiania + +[Codebase](./codebase) jest przetwarzany we wdrożenie w trzech etapach (poza lokalnym środowiskiem). + +* Podczas *etapu budowania* kod z repozytorium konwertowany jest do wykonywalnej paczki tzw. *buildu*. Używając wersji kodu zdefiniowanej przez commit w procesie deploymentu, w tym etapie pobiera i dołącza się do projektu [zależności](./dependencies) oraz kompiluje niezbędne zasoby. +* Podczas *etapu publikacji* aplikacji używany jest build stworzony w poprzednim etapie i konfigurowany na podstawie [ustawień](./config) obecnego wdrożenia. Stworzony w ten sposób *release* zawiera zbudowane źródło kodu, jego konfigurację i jest gotowy do uruchomienia w wybranym środowisku. +* *Etap uruchamiania* (znany również jako "runtime") startuje aplikację w środowisku wykonawczym przez uruchomienie zestawu [procesów](./processes) w oparciu o wcześniej przygotowany release. + +![Kod staje się buildem, jeśli zostanie połączony z konfiguracją by stworzyć release](/images/release.png) + +**Aplikacja 12factor ściśle rozgranicza etapy budowy, publikacji i uruchomiania** Kiedy aplikacja została już uruchomiona, nie można zmienić jej kodu w inny sposób niż zbudować ją na nowo na podstawie wcześniej naniesionych zmian. + +Narzędzia do obsługi wdrożeń zazwyczaj oferują moduły do zarządzania releasami, w tym możliwość do powrotu do poprzedniej wersji (rollback). Np. narzędzie [Capistrano](https://github.com/capistrano/capistrano/wiki) przechowuje releasy w podkatalogu `releases`, gdzie obecna wersja opublikowanej aplikacji jest symlinkowana do jednej z wersji przechowywanej w katalogu Capistrano. Komenda `rollback` pozwala na szybką zmianę wersji opublikowanej aplikacji na jedną z poprzednich. + +Każdy release powinien zawsze posiadać unikalny identyfikator, jak np. data publikacji aplikacji (taka jak `2011-04-06-20:32:17`) lub inkrementowany numer (np. `v100`). Do rejestru opublikowanych wersji aplikacji można jedynie dodawać jej nowe wersje, jego zawartość nie może być zmieniana w żaden inny sposób. + +Aplikacja może zostać zbudowana gdy developer zdecyduje o wdrożeniu zmian do kodu. Uruchomienie aplikacji może natomiast nastąpić automatycznie po restarcie serwera lub jednego z procesów aplikacji po błędzie krytycznym. Dlatego też etap uruchamiania aplikacji powinien być jak najbardziej jednolity minimalizując równocześnie ryzyko wystąpienia problemów ze startem aplikacji - mogą one spowodować zaprzestanie działania aplikacji np. w nocy, kiedy to nie ma żadnego developera "pod ręką". Etap budowy aplikacji może być bardziej złożony, ponieważ ewentualne błędy są zawsze widoczne dla developera, który nadzoruje ten proces. diff --git a/content/pl/codebase.md b/content/pl/codebase.md new file mode 100644 index 000000000..a0c59d8a8 --- /dev/null +++ b/content/pl/codebase.md @@ -0,0 +1,17 @@ +## I. Codebase +### Jedno źródło kodu śledzone systemem kontroli wersji, wiele wdrożeń + +Aplikacja 12factor zawsze jest zarządzana w systemie kontroli wersji takim jak [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), czy [Subversion](http://subversion.apache.org/). Miejsce, w którym trzymany i rewizjonowany jest kod nazywane jest *repozytorium kodu źródłowego*, często skracane do samego *code repo*, albo po prostu *repo*. + +*Codebase* (baza kodu) jest więc niczym innym jak pojedynczym repo (w przypadku zcentralizowanego systemu kontroli wersji jak Subversion), albo zestawem repozytoriów, które współdzielą tzw. root commit. (w przypadku zdecentralizowanego systemu jak Git). + +![Jeden codebase, wiele wdrożeń](/images/codebase-deploys.png) + +Aplikacja powinna zawsze odzwierciedlać bazowy kod: + +* Jeśli istnieje wiele źródeł, z których pobierany jest kod, nie można mówić o aplikacji, a systemie rozproszonym. Każdy komponent w systemie rozproszonym będzie wtedy aplikacją i każdy z osobna może spełniać wszystkie zasady 12factor. +* Jeśli wiele aplikacji dzieli ten sam kod, mamy do czynienia z naruszeniem 12factor. Wyjściem z tej sytuacji może być wyizolowanie współdzielonego kodu do bibliotek, które będą dodane do aplikacji przez tzw. [dependency manager](./dependencies). + +Aplikacja może posiadać tylko jeden codebase, jednocześnie mając wiele wdrożeń. *Deploy* (z ang. wdrożenie) jest działającą instancją aplikacji. Zazwyczaj mówi się o wersji produkcyjnej i jednej lub więcej przedprodukcyjnych. Ponadto każdy developer pracujący nad aplikacją posiada jej kopię działającą w swoim lokalnym środowisku developerskim, co również kwalifikuje się jako osobne wdrożenie. + +Codebase jest taki sam dla wszystkich wdrożeń aplikacji, jednak poszczególne wdrożenia aplikacji mogą korzystać z jego różnych wersji. Dla przykładu, developer pracujący nad aplikacją może nanieść zmiany, które nie znajdą się jeszcze w wersji produkcyjnej. Obie wersje dzielą jednak ten sam codebase, przez co kwalifikują się jako osobne wdrożenia tej samej aplikacji. diff --git a/content/pl/concurrency.md b/content/pl/concurrency.md new file mode 100644 index 000000000..37375252f --- /dev/null +++ b/content/pl/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Współbieżność +### Skaluj przez odpowiednio dobrane procesy + +Każdy program komputerowy od momentu uruchomienia jest reprezentowany przez jeden lub więcej procesów. Aplikacje internetowe mogą być uruchamiane w różnorodny sposób. Dla przykładu - procesy PHP uruchamiane są na żądanie (w zależności od potrzeby obsługi odpowiednio dużej liczby zapytań) jako podrzędne procesy Apache'a. W Javie procesy obsługiwane są zupełnie inaczej, z JVM zapewniającym jeden nadrzędny proces, który rezerwuje zasoby systemu (CPU oraz pamięć) na starcie oraz współbieżnością zarządzaną wewnętrznie i opartą na wątkach. Dla developerów aplikacji różnica jednak nie będzie szczególnie odczuwalna. + +![Skala wyrażana jest przez działające procesy, natomiast różnorodność obciążenia wyrażana jest w typach procesów](/images/process-types.png) + +**W aplikacji 12factor, procesy są typem pierwszoklasowym** Zachowanie tych procesów jest mocno wzorowane na [modelu procesów unixowych dla usług działających w wewnątrz systemu operacyjnego](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Używając tego modelu programista może zaprojektować aplikację by radziła sobie z różnorodnym obciążeniem przez przypisywanie każdej czynności do *typu procesu*. Przykłady to m.in obsługa procesów sieciowych przez HTTP oraz długotrwałe działanie zadań w tle opierających się na procesach roboczych. + +Mimo tego procesy wciąż mogą się zwielokrotnić przez wątki w środowisku maszyny wirtualnej lub w asynchronicznym modelu wydarzeń, którego implementację możemy znaleźć wśród narzędzi takich jak [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), albo [Node.js](http://nodejs.org/). Należy pamiętać, że pojedyncza maszyna wirtualna może z czasem wymagać coraz więcej zasobów (skala pionowa), dlatego aplikacja musi być również w stanie pracować w oparciu o wiele procesów działających na wielu fizycznych maszynach. + +Największa zaleta modelu procesów objawia się w momencie skalowania. [Niezależność oraz dzielenie się na podprocesy](./processes) umożliwia proste i bezproblemowe dodawanie wiekszej liczby równolegle działajacych procesów. Tablica typów procesów i liczba procesów nazywana jest ich *formacją*. + +Procesy aplikacji 12factor [nigdy nie powinny być uruchamiane w tle](http://dustin.github.com/2010/02/28/running-processes.html) i nie mogą zapisywać plików PID. Zamiast tego opierają się na narzędziach systemu operacyjnego: do zarządzania procesami (np. [systemd](https://www.freedesktop.org/wiki/Software/systemd/), do zarządzania rozproszonymi procesami w chmurze, lub [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) w developmencie) do zarządzania [stumieniami wyjściowymi](./logs), do obsługi zatrzymanych procesów, restartu i zakończenia działań zainicjowanych przez użytkownika. diff --git a/content/pl/config.md b/content/pl/config.md new file mode 100644 index 000000000..1425579b3 --- /dev/null +++ b/content/pl/config.md @@ -0,0 +1,22 @@ +## III. Konfiguracja +### Przechowuj konfigurację w środowisku + +*Konfiguracja* to jedyny element, który może się różnić pomiędzy [wdrożeniami](./codebase) aplikacji (staging, produkcja, środowisko developerskie, etc). W jej skład wchodzą: + +* Ustawienia połączeń do baz danych, Memcached, i innych [usług wspierających](./backing-services) +* Dane uwierzytelniające zewnętrznych usług takich jak Amazon S3 czy Twitter +* Wartości różne dla każdego wdrożenia, jak np. kanoniczna nazwa hosta + +Aplikacja czasem przechowuje konfigurację jako stałe wartości w kodzie źródłowym. Niestety jest to złamanie zasady 12factor wg której konfiguracja jest **ściśle oddzielona od kodu aplikacji**. + +Dowodem na to, czy aplikacja posiada swoją konfigurację oddzieloną od kodu jest to, czy można ją udostępnić na zasadach open source bez równoczesnego udostępniania np. danych uwierzytelniających. + +Należy pamiętać, że definicja "konfiguracji" **nie** dotyczy wewnętrznych ustawień aplikacji takich jak np. plik `config/routes.rb` w Railsach lub to jak [są połączone moduły kodu](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) w [Springu](http://spring.io/). Konfiguracja tego typu nie zmienia się pomiędzy wdrożeniami co sprawia, że najbardziej odpowiednim miejscem do jej przechowywania jest kod aplikacji. + +Innym podejściem do konfiguacji jest korzystanie z plików, które nie znajdują się w repozytorium i nie są wersjonowane, jak np. `config/database.yml` w Railsach. Jest to duże usprawnienie względem używania stałych wartości, które są zapisywane w repozytorium. Minusem tego rozwiązania jest możliwość przypadkowego umieszczenia pliku konfiguracyjnego w repo. Ponadto można spotkać się z tendencją do rozrzucania takich plików w różnych katalogach i różnych formatach, co czyni je trudnymi do znalezienia i zarządzania z jednego miejsca. + +**Aplikacja 12factor przechowuje konfigurację w *zmiennych środowiskowych*** (czasem nazywane z języka angielskiego *env vars* lub *env*). W tej sytuacji można łatwo modyfikować zmienne środowiskowe pomiędzy wdrożeniami bez zmiany kodu aplikacji. W odróżnieniu do plików konfiguracyjnych istnieje mała szansa by zostały umieszczone przypadkowo w repozytorium. Ich kolejną zaletą jest to, że nie są powiązane z językiem programowania, frameworkiem, jak np. Java System Properties, czy też systemem operacyjnym. + +Kolejnym zagadnieniem zarządzania konfiguracją jest jej grupowanie. Czasem aplikacje gromadzą konfigurację w grupach (czasem nazywane "środowiskami") nazywanych od nazwy wdrożenia, takie jak `development`, `test`, czy `produkcja` w Railsach. Ten sposób organizacji jest niestety nieskalowalny. Im więcej różnych wdrożeń, tym większa potrzeba nazw, jak np. `staging` czy `qa`. Wraz z rozwojem projektu programiści mogą dodawać swoje specjalne konfiguracje, jak `staging-józefa`. Efektem tego mogą być niezliczone kombinacje nazw plików konfiguracyjnych, co utrudniać będzie zarządzanie wdrożonymi aplikacji. + +W aplikacji 12factor zmienne środowiskowe służą do precyzyjnej kontroli poszczególnych ustawień, posiadając różne, nie mylące się ze sobą nazwy. Nigdy nie są zgrupowane w "środowiskach", tylko niezależnie ustawiane dla każdego wdrożenia. Taki model konfiguracji skaluje się bez problemu, nawet jeśli aplikacja będzie potrzebowała w przyszłości więcej zróżnicowanych wdrożeń. diff --git a/content/pl/dependencies.md b/content/pl/dependencies.md new file mode 100644 index 000000000..93cb1ea12 --- /dev/null +++ b/content/pl/dependencies.md @@ -0,0 +1,12 @@ +## II. Dependencies +### Jawnie zadeklaruj i wydziel zależności + +Większość języków programowania oferuje narzędzia do dystrybucji dodatkowych bibliotek, takie jak [CPAN](http://www.cpan.org/) dla Perla lub [Rubygems](http://rubygems.org/) dla języka Ruby. Biblioteki zainstalowane w ten sposób mogą być dostępne dla całego systemu (określane jako "site packages") lub zakres ich działania może być ograniczony dla pojedynczego projektu lub aplikacji (określane jako "vendoring" lub "bundling"). + +**Aplikacja 12factor nigdy nie jest zależna od bibliotek zainstalowanych dla całego systemu.** Wszystkie zależności są dokładnie określone przez dokument zawierający ich kompletną listę (*dependency declaration manifest*). Ponadto taka aplikacja korzysta z narzędzia służącego do izolacji tych zależności podczas działania aplikacji. W ten sposób ma się pewność, że np. jakaś biblioteka nie jest przypadkiem jedną z tych zainstalowanych w zewnętrznym środowisku, w którym działa aplikacja. Inaczej podobna sytuacja mogłaby uniemożliwiać poprawne działanie aplikacji w innym środowisku, gdzie takiej biblioteki by brakowało. Pełna i dokładna specyfikacja bibliotek używanych przez aplikację jest identyczna dla zarówno środowiska developerskiego jak i produkcyjnego. + +Np. [Bundler](https://bundler.io/) dla Ruby'ego używa pliku `Gemfile` dla deklaracji bibliotek z których korzysta aplikacja oraz komendę `bundle exec` do izolacji tych zależności. W Pythonie istnieją dwa oddzielne narzędzia dla tych zadań -- [Pip](http://www.pip-installer.org/en/latest/) jest używany do deklaracji oraz [Virtualenv](http://www.virtualenv.org/en/latest/) do izolacji. Nawet język C posiada narzędzie [Autoconf](http://www.gnu.org/s/autoconf/) do deklaracji zależności, a statyczne wiązania mogą zapewnić izolację zależności. Bez względu na użyte narzędzia, deklaracja i izolacja zależności muszą być zawsze stosowane razem. Użycie tylko jednej z nich nie jest wystarczające by spełnić wymogi 12factor. + +Jedną z niewątpliwych korzyści deklaracji zależności jest uproszczenie początkowej konfiguracji aplikacji dla developera. Nowy programista może pobrać kod źródłowy z repozytorium. Następnie, posiadając wcześniej skonfigurowane środowisko danego języka i narzędzie do zarządzania jego bibliotekami, jest w stanie zainstalować wszystkie moduły i biblioteki potrzebne dla działania aplikacji przy pomocy jednej komendy. Taką komendą np. dla Ruby'ego/Bundlera jest `bundle install`, a dla Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) jest to `lein deps`. + +Aplikacje zgodne z 12factor również nie są zależne od systemowych narzędzi. Wśród przykładów można wymienić ImageMagick czy też `curl`. Pomimo, że narzędzia te mogą być dostępne na wielu lub nawet większości systemów, nie ma gwarancji, że będą istniały na wszystkich środowiskach, w których będzie uruchamiana aplikacja w przyszłości lub że ich wersja będzie kompatybilna. Jeśli aplikacja korzysta z jakiegokolwiek systemowego narzędzia, powinno być ono osobno do niej dołączone. diff --git a/content/pl/dev-prod-parity.md b/content/pl/dev-prod-parity.md new file mode 100644 index 000000000..50e2234f4 --- /dev/null +++ b/content/pl/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Jednolitość środowisk +### Utrzymuj środowisko developerskie, stagingowe i produkcyjne tak podobne jak tylko możliwe + +Z doświadczenia wiadomo, że od zawsze istniały różnice pomiędzy środowiskiem developerskim (developer pracujący nad swoją lokalną wersją [kodu](./codebase) aplikacji) a produkcyjnym (działająca aplikacja dostępna dla użytkowników. Ze względu na ich charakter, możemy wymienić trzy rodzaje różnic: + +* **Różnica czasowa:** Developer może pracować nad kodem przez dni, tygodnie, miesiące zanim ostatecznie pojawi się on w wersji produkcyjnej. +* **Różnica odpowiedzialności**: Developer tworzy kod aplikacji, natomiast kto inny wdraża go do na produkcję. +* **Różnica narzędzi**: Developer może używać narzędzi takich jak Nginx, SQLite i systemu OS X, natomiast wersja produkcyjna będzie opierać się na Apache, MySQL i systemie Linux. + +**Aplikacja 12factor jest zaprojektowana tak by można ją było [bez przerwy wdrażać na produkcję](http://avc.com/2011/02/continuous-deployment/) minimalizując różnice pomiędzy środowiskami.** Mając na uwadze powyższe różnice, można sobie z nimi radzić na różne sposoby: + +* Zmniejsz czas deploymentu: czas wdrożenia kodu napisanego przez developera powinien być mierzony w godzinach, a nawet w minutach. +* Przenieś odpowiedzialność: developer piszący kod powinien być zaangażowany we wdrożenia aplikacji na produkcję. +* Stosuj ten sam zestaw narzędzi: utrzymuj wszystkie środowiska w których działa aplikacja tak podobne jak to możliwe. + +Podsumowując w formie tabeli: + + + + + + + + + + + + + + + + + + + + + + +
Tradycyjna aplikacjaAplikacja 12factor
Czas pomiędzy wdrożeniamiTygodnieGodziny
Tworzenie kodu vs wdrażanie koduRóżne osobyTe same osoby
Środowisko developerskie vs produkcyjneMocno różniące sięJak najbardziej zbliżone
+ +Zachowanie podobieństw między wdrożeniami jest ważne w przypadku [usług wspierających](./backing-services) takich jak baza danych aplikacji, system kolejkowania czy też cache. Wiele języków oferuje biblioteki, które upraszczają korzystanie z usług wspierających w tym *adaptery* do usług różnego typu. Kilka przykładów w tabeli poniżej: + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypJęzykBibliotekaAdaptery
Baza danychRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
KolejkaPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CachePamięć, system plików, Memcached
+ +Czasami zdarza się, że developerzy w swoim lokalnym środowisku wolą korzystać z "lżejszych" wersji różnych usług, na produkcji natomiast używając bardziej zaawansowanych narzędzi. Przykładem takiej sytuacji jest używanie lokalnie SQLite, a PostgreSQL na produkcji. Podobnie wygląda też użycie na środowisku developerskim do cachowania pamięci, zamiast Memcached znajdującego się na produkcji. + +**Developer postępujący zgodnie zasadami 12factor opiera się pokusie używania usług różniących się pomiędzy środowiskami**, nawet wtedy, gdy adaptery teoretycznie ukrywają różnice w implementacji pod warstwą abstrakcji. Z powodu różnic pomiędzy usługami wspierającymi mogą pojawić się niezgodności, powodując, że kod, który działał i był testowany lokalnie lub na stagingu, przestanie funkcjonować na produkcji. Pojawianie się tego typu błędów negatywnie wpływa na proces ciągłego wdrażania aplikacji. Czas stracony na wykrywaniu takich błędów i konsekwentnych awariach podczas wdrażania aplikacji może sporo kosztować, zwłaszcza gdy podobne problemy będą się z czasem gromadzić. + +Lekkie wersje usług w obecnych czasach nie są już tak atrakcyjne jak kiedyś. Nowoczesne usługi takie jak Memcached, PostgreSQL oraz RabbitMQ nie są trudne do instalacji w lokalnym środowisku, dzięki narzędziom jak [Homebrew](http://mxcl.github.com/homebrew/) i [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Innym rozwiązaniem są narzędzia do deklaratywnego [provisioningu](https://en.wikipedia.org/wiki/Provisioning) takie jak [Chef](http://www.opscode.com/chef/) czy [Puppet](http://docs.puppetlabs.com/) połączone z lekkimi środowiskami wirtualnymi jak np. [Vagrant](http://vagrantup.com/). Pozwala ono developerom na uruchamianie lokalnych środowisk, które są bardzo zbliżone do produkcyjnych. Koszt instalacji i używania takich rozwiązań jest stosunkowo niski, biorąc pod uwagę korzyści płynące z utrzymywania jednolitych środowisk i procesu ciągłego wdrażania aplikacji. + +Adaptery dla różnych usług wspierających są wciąż użyteczne, gdyż dzięki nim zmiana usługi jest relatywnie łatwa. Należy jednak pamiętać, że wszystkie wdrożenia aplikacji (środowiska developerskie, stagingowe, produkcyjne) powinny używać tych samych typów i wersji usług wspierających. diff --git a/content/pl/disposability.md b/content/pl/disposability.md new file mode 100644 index 000000000..0ee598b8f --- /dev/null +++ b/content/pl/disposability.md @@ -0,0 +1,14 @@ +## IX. Zbywalność +### Zwiększ elastyczność aplikacji przez szybki start i bezproblemowe zamknięcie + +**[Procesy](./processes) aplikacji 12factor są *jednorazowe*, znaczy to, że mogą być wystartowane lub zatrzymane w dowolnym momencie.** Ułatwia to elastyczne skalowanie i szybkie wdrożenia [kodu](./codebase), zmianę [konfiguracji](./config) oraz zapewnia większą stabilność przy wdrożeniu na produkcję. + +Procesy powinny dążyć do **minimalizowania czasu swojego rozruchu**. W idealnej sytuacji proces powinien potrzebować kilku sekund na to aby wystartować i być gotowym na przyjmowanie zapytań. Dzięki krótkiemu czasowi startu można szybciej wykonywać kolejne [wdrożenia](./build-release-run) oraz łatwiej skalować aplikację. Zwiększa to również zdolności aplikacji do radzenia sobie z problemami, ponieważ `process manager` może bezproblemowo przenieść je na nową maszynę fizyczną, gdy zajdzie taka potrzeba. + +Procesy **zamykają się gdy otrzymają sygnał [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** od managera procesów. Dla procesów sieciowych poprawne zamknięcie polega na zakończeniu nasłuchiwania na porcie usługi (skutkiem czego jest odrzucanie nowych zapytań), zakończenie obecnych, a ostatecznie zaprzestaniu działania. Wynika z tego, że zapytania HTTP są krótkie (trwają nie więcej niż kilka sekund), lub w przypadku `long pollingu` i utraty połączenia klient powinien bezproblemowo spróbować połączyć się ponownie. + +Dla procesów roboczych poprawnym zamknięciem jest zwrot obecnie wykonywanego zadania do kolejki. Dla przykładu w [RabbitMQ](http://www.rabbitmq.com/) działający proces może wysłać wiadomość [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); w [Beanstalkd](https://beanstalkd.github.io), zadanie jest zwracane do kolejki automatycznie, gdy tylko proces się rozłączy. Systemy bazujące na blokadach zasobów jak [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) muszą upewnić się, że odblokowały zajmowany wcześniej zasób. W tym modelu ważne jest to, że wszystkie zadania są [wielobieżne](http://pl.wikipedia.org/wiki/Wielobieżność), co zazwyczaj jest osiągane przez zebranie wyników w transakcję lub uczynienie operacji [idempotentną](http://pl.wikipedia.org/wiki/Idempotentno%C5%9B%C4%87). + +Architektura aplikacji 12factor jest również zaprojektowana by działające procesy zostały poprawnie **zakończone w razie awarii** sprzętu. Podczas gdy taka sytuacja jest o wiele rzadsza niż otrzymanie sygnału `SIGTERM`, wciąż może mieć miejsce. Zalecanym podejściem w takich przypadkach jest stosowanie serwerowego systemu kolejkowania zadań, jak Beanstalkd, który zwróci zadanie do kolejki, gdy klient się rozłączy, bądź minie maksymalny czas obsługi pojedynczego zapytania. Architektura ["crash-only"](http://lwn.net/Articles/191059/) jest więc rozwinięciem takiego [konceptu](http://docs.couchdb.org/en/latest/intro/overview.html). + + diff --git a/content/pl/intro.md b/content/pl/intro.md new file mode 100644 index 000000000..7dc74abf3 --- /dev/null +++ b/content/pl/intro.md @@ -0,0 +1,12 @@ +Wprowadzenie +============ + +We współczesnym świecie oprogramowanie jest powszechnie wytwarzane w formie usługi, nazywane _software-as-service (SaaS)_ lub aplikacjami internetowymi. Dwanaście aspektów aplikacji jest metodologią budowania aplikacji SaaS, które: + +* Używają **deklaratywnego** formatu by zautomatyzować konfigurację aplikacji w celu zmniejszenia czasu i kosztów dołączenia nowych programistów do projektu; +* Mają **czysty kontrakt** z systemem operacyjnym, umożliwiając **jak największą możliwość przenoszenia** pomiędzy środowiskami, w których działają; +* Są dopasowane do **wdrożenia** na nowoczesne **chmury obliczeniowe**, zapobiegając potrzebie użycia serwerów i administracji systemu; +* **Minimalizują rozbieżności** pomiędzy środowiskami developerskimi i produkcyjnymi, umożliwiając **nieustanne wdrażanie aplikacji** by zmaksymalizować prędkość zmian; +* I mogą **skalować się** bez większej zmiany narzędzi, architektury, czy sposobu pracy zespołu. + +Metodologia dwunastu aspektów może być stosowana do aplikacji napisanych w każdym języku programowania i wykorzystujących dowolną kombinację usług wspierających (bazy danych, kolejki, cache pamięci etc). diff --git a/content/pl/logs.md b/content/pl/logs.md new file mode 100644 index 000000000..1a7d29cfc --- /dev/null +++ b/content/pl/logs.md @@ -0,0 +1,16 @@ +## XI. Logi +### Traktuj logi jako strumień zdarzeń + +*Logi* zapewniają wgląd w zachowanie działającej aplikacji. W środowiskach korzystających z serwera zazwyczaj są zapisywane na dysku (plik "logfile"); jednak jest to tylko wybrany format zapisu. + + Logi są listą zaagregowanych i uporządkowanych w czasie [zdarzeń](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) zebranych ze strumieni wyjściowych wszystkich uruchomionych procesów i usług wspierających. Logi w swojej pierwotnej formie występują zazwyczaj w formacie tekstowym, gdzie jedno zdarzenie zajmuje jedną linię w pliku (wyjątkiem jest jednak [backtrace](https://en.wikipedia.org/wiki/Stack_trace), który może zajmować wiele linii). Logi nie mają określonego początku ani końca, napływają nieustannie podczas działania aplikacji. + +**Aplikacja 12factor nie odpowiada za przekierowywanie i zapis swojego strumienia wyjściowego.** Nie powinna też zapisywać czy zarządzać plikami logów. Zamiast tego, każdy działający proces zapisuje swój niebuforowany strumień zdarzeń do `stdout`. Podczas pracy w lokalnym środowisku developer może obserwować zachowanie aplikacji przeglądając strumień w oknie terminala + +We wdrożeniu stagingowym czy produkcyjnym, każdy strumień procesów zostanie przechwycony przez środowisko wykonawcze, dołączony do pozostałych i skierowany do jednego lub wielu miejsc w celu przeglądania i długoterminowego zapisu. Miejsca zapisu nie są widoczne ani konfigurowane przez aplikację - w całości zarządza nimi środowisko wykonawcze. W tym celu można skorzystać z narzędzi do obsługi logów (takich jak [Logplex](https://github.com/heroku/logplex) lub [Fluentd](https://github.com/fluent/fluentd)) dostępnych na licencji open-source. + +Strumień zdarzeń aplikacji może być skierowany do pliku lub obserwowany w czasie rzeczywistym przy pomocy komendy `tail` w terminalu. Przeważnie strumień jest wysyłany do systemu indeksowania i analizowania jak np. [Splunk](http://www.splunk.com/), albo do systemu magazynowania danych jak [Hadoop/Hive](http://hive.apache.org/). Wymienione systemy oferują duże możliwości i elastyczność obserwacji i badania zachowań aplikacji w czasie, w tym: + +* Wyszukiwanie konkretnych zdarzeń z przeszłości. +* Wizualizację masowych statystyk (np. zapytania na minutę). +* Wysyłanie powiadomień na podstawie wcześniej zdefiniowanych heurystyk (np. o tym, że liczba błędów przekroczyła dozwoloną wartość). diff --git a/content/pl/port-binding.md b/content/pl/port-binding.md new file mode 100644 index 000000000..9a5ec8f70 --- /dev/null +++ b/content/pl/port-binding.md @@ -0,0 +1,14 @@ +## VII. Przydzielanie portów +### Udostępniaj usługi przez przydzielanie portów + +Zdarza się, że aplikacje internetowe uruchamiane są w ramach serwera web. Napisane w PHP np. działają jako moduł [Apache HTTPD](http://httpd.apache.org/), natomiast aplikacje w Javie mogą być uruchomiane wewnątrz serwera aplikacji, np. [Tomcat](http://tomcat.apache.org/). + +**Aplikacja 12factor nie posiada zewnętrznych zależności** co czyni ją niezależną wobec innych modułów znajdujących się na serwerze. Aplikacja internetowa **udostępniać będzie np. HTTP w formie usługi przez przydzielenie portu**. Umożliwia jej to obsługę zapytań przychodzących do wybranego portu. + +Aby skorzystać z usługi udostępnionej przez aplikację, developer może otworzyć adres URL jak np. `http://localhost:5000/`. W przypadku aplikacji wdrożonej w środowisku produkcyjnym zapytania do udostępnionej publicznie nazwy hosta są obsługiwane przez warstwę nawigacji. Kierowane są one później do procesu sieciowego udostępnionego na danym porcie. + +Kwestię obsługi takich zapytań można rozwiązać dodając bibliotekę webservera jako kolejną [zewnętrzną zależność](./dependencies), jak np. [Tornado](http://www.tornadoweb.org/) w Pythonie, [Thin](http://code.macournoyer.com/thin/) w Ruby, lub [Jetty](http://www.eclipse.org/jetty/) dla Javy i innych języków opierających się na JVM. Obsługa zapytania jest całkowicie oprogramowana przez kod aplikacji, natomiast kontraktem ze środowiskiem wykonawczym jest przydzielenie portu w celu obsłużenia tego zapytania. + +HTTP nie jest jedyną usługą, którą możną eksportować przez przydzielenie portu. Niemal każdy rodzaj oprogramowania serwerowego może być uruchomiony przez przydzielenie portu na którym jest uruchomiony proces i oczekiwać na przychodzące zapytania. Do przykładów należą [ejabberd](http://www.ejabberd.im/) (komunikujący się przez [XMPP](http://xmpp.org/)), oraz [Redis](http://redis.io/) (komunikujący się przez [Redis protocol](http://redis.io/topics/protocol)). + +Warto również zauważyć, że przez przydzielnie portu aplikacja może pełnić funkcję [usługi wspierającej](./backing-services) dla innej aplikacji przez udostępnienie swojego adresu URL jako adres zasobu w [konfiguracji](./config) tejże aplikacji. diff --git a/content/pl/processes.md b/content/pl/processes.md new file mode 100644 index 000000000..3f0dc2e18 --- /dev/null +++ b/content/pl/processes.md @@ -0,0 +1,15 @@ +## VI. Procesy +### Uruchamiaj aplikację jako jeden lub więcej bezstanowych procesów + +Aplikacja jest uruchamiana w środowisku wykonawczym w postaci jednego lub kilku *procesów*. + +W najprostszym przypadku kod aplikacji jest samodzielnym skryptem, środowiskiem wykonawczym jest laptop developera z wsparciem dla języka programowania, a proces jest uruchamiany za pomocą linii komend (na przykład `python my_script.py`). Innym razem wdrożenie produkcyjne mocno rozwiniętej aplikacji może wymagać wiele [różnych rodzajów procesów](./concurrency). + +**Wg zasad 12factor, procesy są bezstanowe i [nie-współdzielące](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Jakiekolwiek dane wymagające zapisu musza być zmagazynowane w "trwałej" [usłudze wspierającej](./backing-services), najczęściej będącą bazą danych. + +Przestrzeń adresowa lub system plików procesu mogą być używane jako tymczasowy cache dla pojedynczych operacji. Przykładem jest pobieranie dużych plików, działanie na nich, a następnie zapisywanie wyników operacji w bazie danych. Aplikacja dwunastu aspektów nigdy nie zakłada, że jakiś fragment informacji zapisany w pamięci lub dysku będzie dostępny w przyszłości podczas jakiegokolwiek zapytania -- wraz z wieloma aktywnymi procesami rośnie szansa, że przyszłe zapytanie zostanie obsłużone przez zupełnie inny proces. Nawet w przypadku pojedynczego procesu, restart (spowodowany przez deployment kodu, zmianę konfiguracji lub relokacja procesu do innej fizycznej lokalizacji wykonana przez środowisko wykonawcze) zazwyczaj usunie wszystkie dane z lokalnego stanu aplikacji (system plików, pamięć podręczna). + +Narzędzie do pakowania plików, z których korzysta aplikacja (takie jak [Jammit](http://documentcloud.github.com/jammit/) lub [django-compressor](http://django-compressor.readthedocs.org/)) używają systemu plików jako cache dla skompilowanych zasobów. Wg 12factor taka kompilacja powinna mieć miejsce podczas [etapu budowy aplikacji](./build-release-run), jak to się dzieje np. w [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html). + +Niektóre systemy sieciowe polegają na tzw. ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- oznacza to, że sesja użytkownika jest zapisywana tymczasowo w pamięci procesu aplikacji, zakładając, że kolejne zapytania dotyczące użytkownika będą kierowane do tego samego procesu. "Sticky sessions" są złamaniem zasad aplikacji 12factor i nigdy nie powinny być używane jako źródło informacji. Dane sesji nadają się bardziej do zapisu w magazynie oferującym wygasanie danych w czasie, jak np. [Memcached](http://memcached.org/) czy [Redis](http://redis.io/). + diff --git a/content/pl/toc.md b/content/pl/toc.md new file mode 100644 index 000000000..1adc429a1 --- /dev/null +++ b/content/pl/toc.md @@ -0,0 +1,38 @@ +The Twelve Factors +================== + +## [I. Codebase](./codebase) +### Jedno źródło kodu śledzone systemem kontroli wersji, wiele wdrożeń + +## [II. Zależności](./dependencies) +### Jawnie zadeklaruj i wydziel zależności + +## [III. Konfiguracja](./config) +### Przechowuj konfigurację w środowisku + +## [IV. Usługi wspierające](./backing-services) +### Traktuj usługi wspierające jako przydzielone zasoby + +## [V. Buduj, publikuj, uruchamiaj](./build-release-run) +### Oddzielaj etap budowania od uruchamiania + +## [VI. Procesy](./processes) +### Uruchamiaj aplikację jako jeden lub więcej bezstanowych procesów + +## [VII. Przydzielanie portów](./port-binding) +### Udostępniaj usługi przez przydzielanie portów + +## [VIII. Współbieżność](./concurrency) +### Skaluj przez odpowiednio dobrane procesy + +## [IX. Zbywalność](./disposability) +### Zwiększ elastyczność pozwalając na szybkie uruchamianie i zatrzymywanie aplikacji + +## [X. Jednolitość środowisk](./dev-prod-parity) +### Utrzymuj konfigurację środowisk jak najbardziej zbliżoną do siebie + +## [XI. Logi](./logs) +### Traktuj logi jako strumień zdarzeń + +## [XII. Zarządzanie aplikacją](./admin-processes) +### Uruchamiaj zadania administracyjne jako jednorazowe procesy diff --git a/content/pl/who.md b/content/pl/who.md new file mode 100644 index 000000000..08d2c78b0 --- /dev/null +++ b/content/pl/who.md @@ -0,0 +1,4 @@ +Dla kogo przeznaczony jest ten dokument? +============================== + +Dla każdego developera tworzącego aplikacje, które działają jako usługa. Dla każdego Dev-opsa, który wdraża i zarządza takimi aplikacjami. diff --git a/content/pt_br/admin-processes.md b/content/pt_br/admin-processes.md new file mode 100644 index 000000000..06e3b829b --- /dev/null +++ b/content/pt_br/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Processos administrativos +### Rode tarefas de administração/gestão em processos pontuais + +A [formação de processos](./concurrency) é o conjunto de processos que são usados para fazer as negociações regulares da app como ela é executada (tais como manipulação de requisições web). Separadamente, os desenvolvedores, muitas vezes desejam fazer tarefas pontuais de administração ou manutenção para a app, tais como: + +* Executar migrações de base de dados (ex: `manage.py migrate` no Django, `rake db:migrate` no Rails). +* Executar um console (também conhecido como um [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) para rodar código arbitrário ou inspecionar os modelos da app ao vivo no banco de dados. A maioria das linguagens fornece um REPL para rodar o interpretador sem nenhum argumento (ex: `python` or `perl`) ou em alguns casos tem um comando separado (ex: `irb` para Ruby, `rails console` para Rails). +* Executar uma vez os scripts comitados no repositório da app (ex: `php scripts/fix_bad_records.php`). + +Processos administrativos pontuais devem ser executados em um ambiente idêntico, como os [processos regulares de longa execução](./processes) da app. Eles rodam uma [versão](./build-release-run), usando a mesma [base de código](./codebase) e [configuração](./config) como qualquer processo executado com essa versão. Códigos de administração devem ser fornecidos com o código da aplicação para evitar problemas de sincronização. + +A mesma técnica de [isolamento de dependência](./dependencies) deve ser usada em todos tipos de processos. Por exemplo, se o processo web Ruby usa o comando `bundle exec thin start`, então uma migração de base de dados deve usar `bundle exec rake db:migrate`. Da mesma forma, um programa Python usando Virtualenv deve usar `bin/python` fornecido para executar tanto o servidor web Tornado e qualquer processo `manage.py` de administração. + +Doze-fatores favorecem fortemente linguagens que fornecem um shell REPL embutido, e que tornam mais fácil executar scripts pontuais. Em um deploy local, desenvolvedores invocam processos administrativos pontuais por um comando shell direto no diretório de checkout da app. Em um deploy de produção, desenvolvedores podem usar ssh ou outro mecanismo de execução de comandos remoto fornecido por aquele ambiente de execução do deploy para executar tal processo. diff --git a/content/pt_br/background.md b/content/pt_br/background.md new file mode 100644 index 000000000..0b6d12bdc --- /dev/null +++ b/content/pt_br/background.md @@ -0,0 +1,8 @@ +Experiência +=========== + +Os contribuidores deste documento estão diretamente envolvidos no desenvolvimento e implantação de centenas de aplicações, e indiretamente testemunhando o desenvolvimento, operação e escalada de centenas de milhares de aplicações através de seu trabalho na plataforma [Heroku](http://www.heroku.com/). + +Este documento sintetiza toda nossa experiência e observação em uma variedade de aplicações que operam como software-como-serviço. Isto é a triangulação de práticas ideais ao desenvolvimento de software, com uma atenção particular a respeito das dinâmicas de crescimento orgânico de uma aplicação ao longo do tempo, a dinâmica de colaboração entre desenvolvedores trabalhando em uma base de código, e evitando os [custos de erosão de software](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/) + +Nossa motivação é aumentar a consciência de alguns problemas sistêmicos que temos visto no desenvolvimento de aplicações modernas, prover um vocabulário comum para discussão destes, e oferecer um amplo conjunto de soluções conceituais para esses problemas com a terminologia que os acompanha. O formato é inspirado nos livros de Martin Fowler *[Padrões de Arquitetura de Aplicações Enterprise](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* e *[Refatorando](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. diff --git a/content/pt_br/backing-services.md b/content/pt_br/backing-services.md new file mode 100644 index 000000000..64f45456d --- /dev/null +++ b/content/pt_br/backing-services.md @@ -0,0 +1,14 @@ +## IV. Serviços de Apoio +### Trate serviços de apoio como recursos anexados + +Um *serviço de apoio* é qualquer serviço que o app consuma via rede como parte de sua operação normal. Exemplos incluem armazenamentos de dados (como [MySQL](http://dev.mysql.com/) ou [CouchDB](http://couchdb.apache.org/)), sistemas de mensagens/filas (tais como [RabbitMQ](http://www.rabbitmq.com/) ou [Beanstalkd](https://beanstalkd.github.io)), serviços SMTP para emails externos (tais como [Postfix](http://www.postfix.org/)), e sistemas de cache (tais como [Memcached](http://memcached.org/)). + +Serviços de apoio como o banco de dados são tradicionalmente gerenciados pelos mesmos administradores de sistema do servidor de deploy de tempo de execução do app. Adicionalmente à esses serviços localmente gerenciados, o app pode ter serviços providos e gerenciados por terceiros. Exemplos incluem serviços SMTP (tais como [Postmark](http://postmarkapp.com/)), serviços de colheita de métricas (tais como [New Relic](http://newrelic.com/) ou [Loggly](http://www.loggly.com/)), serviços de ativos binários (tais como [Amazon S3](http://aws.amazon.com/s3/)), e até serviços de consumidores acessíveis via API (tais como [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), ou [Last.fm](http://www.last.fm/api)). + +**O código para um app doze-fatores não faz distinção entre serviços locais e de terceiros.** Para o app, ambos são recursos anexados, acessíveis via uma URL ou outro localizador/credenciais na [config](./config). Um [deploy](./codebase) do app doze-fatores deve ser capaz de trocar um banco de dados MySQL por um gerenciado por terceiros (tais como [Amazon RDS](http://aws.amazon.com/rds/)) sem realizar quaisquer mudanças no código do app. Da mesma forma, um servidor local SMTP poderia ser trocado por um serviço de terceiros (tais como Postmark) sem as mudanças em código. Em ambos os casos, apenas o identificador de recurso precisa mudar. + +Cada serviço de apoio distinto é um *recurso*. Por exemplo, um banco MySQL é um recurso; dois bancos MySQL (usados para sharding na camada da aplicação) qualificam como dois recursos distintos. O app doze-fatores trata tais bancos como *recursos anexados*, o que indica seu baixo acoplamento ao deploy que ele está anexado. + +Um deploy de produção anexado a quatro serviços de apoio. + +Recursos podem ser anexados e desanexados a deploys à vontade. Por exemplo, se o banco de dados do app não está funcionando corretamente devido a um problema de hardware, o administrador do app pode subir um novo servidor de banco de dados restaurado de um backup recente. O atual banco de produção pode ser desanexado, e o novo banco anexado -- tudo sem nenhuma mudança no código. diff --git a/content/pt_br/build-release-run.md b/content/pt_br/build-release-run.md new file mode 100644 index 000000000..610ddee68 --- /dev/null +++ b/content/pt_br/build-release-run.md @@ -0,0 +1,18 @@ +## V. Construa, lance, execute +### Separe estritamente os estágios de construção e execução + +Uma [base de código](./codebase) é transformada num deploy (de não-desenvolvimento) através de três estágios: + +* O *estágio de construção* é uma transformação que converte um repositório de código em um pacote executável conhecido como *construção*. Usando uma versão do código de um commit especificado pelo processo de desenvolvimento, o estágio de construção obtém e fornece [dependências](./dependencies) e compila binários e ativos. +* O *estágio de lançamento* pega a construção produzida pelo estágio de construção e a combina com a atual [configuração](./config) do deploy. O *lançamento* resultante contém tanto a construção quanto a configuração e está pronta para execução imediata no ambiente de execução. +* O *estágio de execução* roda o app no ambiente de execução, através do início de alguns dos [processos](./processes) do app com um determinado lançamento. + +![Código vira uma construção, que é combinada com a configuração para se criar um lançamento.](/images/release.png) + +**O app doze-fatores usa separação estrita entre os estágios de construção, lançamento e execução.** Por exemplo, é impossível alterar código em tempo de execução, já que não há meios de se propagar tais mudanças de volta ao estágio de construção. + +Ferramentas para deploy tipicamente oferecem ferramentas de gestão de lançamento, mais notadamente a habilidade de se reverter à um lançamento prévio. Por exemplo, a ferramenta de deploy [Capistrano](https://github.com/capistrano/capistrano/wiki) armazena lançamentos em um subdiretório chamado `releases`, onde o lançamento atual é um link simbólico para o diretório de lançamento atual. Seu comando `rollback` torna fácil reverter para um lançamento prévio. + +Cada lançamento deve sempre ter um identificador de lançamento único, tal qual o timestamp do lançamento (como `2011-04-06-20:32:17`) ou um número incremental (como `v100`). Lançamentos são livro-razões onde apenas se acrescenta informações, ou seja, uma vez criado o lançamento não pode ser alterado. Qualquer mudança deve gerar um novo lançamento. + +Construções são iniciadas pelos desenvolvedores do app sempre que novos códigos entram no deploy. A execução de um executável, todavia, pode acontecer automaticamente em casos como o reinício do servidor, ou um processo travado sendo reiniciado pelo gerenciador de processos. Assim, no estágio de execução deve haver quanto menos partes móveis quanto possível, já que problemas que previnem um app de rodar pode causá-lo a travar no meio da noite quando não há desenvolvedores por perto. O estágio de construção pode ser mais complexo, já que os erros estão sempre à vista do desenvolvedor que está cuidando do deploy. diff --git a/content/pt_br/codebase.md b/content/pt_br/codebase.md new file mode 100644 index 000000000..91d46fcb9 --- /dev/null +++ b/content/pt_br/codebase.md @@ -0,0 +1,17 @@ +## I. Base de Código +### Uma base de código com rastreamento utilizando controle de revisão, muitos deploys + +Uma aplicação 12 fatores é sempre rastreada em um sistema de controle de versão, como [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), ou [Subversion](http://subversion.apache.org/). Uma cópia da base de dados do rastreamento de revisões é conhecido como *repositório de código*, normalmente abreviado como *repositório* ou *repo*. + +Uma *base de código* é um único repo (em um sistema de controle de versão centralizado como Subversion), ou uma série de repositórios que compartilham um registro raiz. + +![Uma base de código para vários deploys](/images/codebase-deploys.png) + +Existe sempre uma correlação um-para-um entre a base de código e a aplicação: + +* Se existem várias bases de código, isto não é uma app -- é um sistema distribuído. Cada componente do sistema é uma app, e cada uma pode individualmente ser compatível com os 12 fatores. +* Múltiplas apps compartilhando uma base de código é uma violação dos 12 fatores. A solução aqui é dividir o código compartilhado entre bibliotecas que podem ser incluídas através do [gerenciador de dependências](/dependencies). + +Existe apenas uma base de código por aplicação, mas existirão vários deploys da mesma. Um *deploy* (ou implantação) é uma instância executando a aplicação. Isto é tipicamente um local de produção, e um ou mais locais de testes. Adicionalmente, todo desenvolvedor tem uma cópia da aplicação rodando em seu ambiente local de desenvolvimento, cada um desses pode ser qualificado como um deploy. + +A base de código é a mesma através de todos os deploys, entretanto diferentes versões podem estar ativas em cada deploy. Por exemplo, um desenvolvedor tem alguns registros ainda não implantados no ambiente de teste, o ambiente de teste ainda tem registros não implantados em produção. Mas todos esses ambientes compartilham a mesma base de código, tornando-os identificáveis ​​como diferentes deploys do mesmo app. diff --git a/content/pt_br/concurrency.md b/content/pt_br/concurrency.md new file mode 100644 index 000000000..0bdca1eac --- /dev/null +++ b/content/pt_br/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Concorrência +### Escale através do processo modelo + +Qualquer programa de computador, uma vez executado, está representado por um ou mais processos. Aplicações web têm tomado uma variedade de formas de processo de execução. Por exemplo, processos PHP rodam como processos filhos do Apache, iniciados sob demanda conforme necessário por volume de requisições. Processos Java tomam o caminho inverso, com a JVM proporcionando um processo uber maciço que reserva um grande bloco de recursos do sistema (CPU e memória) na inicialização, com concorrência gerenciada internamente via threads. Em ambos os casos, o(s) processo(os) em execução são apenas minimamente visível para os desenvolvedores da aplicação. + +![Escala é expressado como processos em execução, a diversidade da carga de trabalho é expressada como tipos de processo.](/images/process-types.png) + +**Na aplicação doze-fatores, processos são cidadãos de primeira classe.** Processos na aplicação doze-fatores utilizam fortes sugestões do modelo de processos UNIX para execução de serviços daemon, o desenvolvedor pode arquitetar a aplicação dele para lidar com diversas cargas de trabalho, atribuindo a cada tipo de trabalho a um *tipo de processo*. Por exemplo, solicitações HTTP podem ser manipuladas para um processo web, e tarefas background de longa duração podem ser manipuladas por um processo trabalhador. + +Isto não exclui processos individuais da manipulação de sua própria multiplexação interna, por threads dentro do runtime da VM, ou o modelo async/evented encontrado em ferramentas como [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), ou [Node.js](http://nodejs.org/). Mas uma VM individual pode aumentar (escala vertical), de modo que a aplicação deve ser capaz de abranger processos em execução em várias máquinas físicas. + +O modelo de processo realmente brilha quando chega a hora de escalar. O [compartilhar-nada, natureza horizontal particionada de um processo da aplicação doze-fatores](./processes) significa que a adição de mais simultaneidade é uma operação simples e de confiança. A matriz de tipos de processo e número de processos de cada tipo é conhecida como o *processo de formação*. + +Processos de uma app doze-fatores [nunca deveriam daemonizar](http://dustin.github.com/2010/02/28/running-processes.html) ou escrever arquivos PID. Em vez disso, confiar no gerente de processo do sistema operacional (como [systemd](https://www.freedesktop.org/wiki/Software/systemd/), um gerenciador de processos distribuídos em uma plataforma de nuvem, ou uma ferramenta como [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) em desenvolvimento) para gerenciar [fluxos de saída](./logs), responder a processos travados, e lidar com reinícios e desligamentos iniciados pelo usuário. diff --git a/content/pt_br/config.md b/content/pt_br/config.md new file mode 100644 index 000000000..e4c11387d --- /dev/null +++ b/content/pt_br/config.md @@ -0,0 +1,22 @@ +## III. Configurações +### Armazene as configurações no ambiente + +A *configuração* de uma aplicação é tudo o que é provável variar entre [deploys](./codebase) (homologação, produção, ambientes de desenvolvimento, etc). Isto inclui: + +* Recursos para a base de dados, Memcached, e outros [serviços de apoio](./backing-services) +* Credenciais para serviços externos como Amazon S3 ou Twitter +* Valores por deploy como o nome canônico do host para o deploy + +Aplicações às vezes armazenam as configurações no código como constantes. Isto é uma violação da doze-fatores, a qual exige uma **estrita separação entre configuração e código**. Configuração varia substancialmente entre deploys, código não. + +A prova de fogo para saber se uma aplicação tem todas as configurações corretamente consignadas fora do código é saber se a base de código poderia ter seu código aberto ao público a qualquer momento, sem comprometer as credenciais. + +Note que esta definição de "configuração" **não** inclui configuração interna da aplicação, como `config/routes.rb` em Rails, ou como [módulos de códigos são conectados](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) em [Spring](http://spring.io/). Este tipo de configuração não varia entre deploys, e por isso é melhor que seja feito no código. + +Outra abordagem para configuração é o uso de arquivos de configuração que não são versionados no controle de versão, como `config/database.yml` em Rails. Isto é uma grande melhoria sobre o uso de constantes que são versionadas no repositório do código, mas ainda tem pontos fracos: é fácil de colocar por engano um arquivo de configuração no repositório; há uma tendência para que os arquivos de configuração sejam espelhados em diferentes lugares e diferentes formatos, tornando-se difícil de ver e gerenciar todas as configurações em um só lugar. Além disso estes formatos tendem a ser específicos da linguagem ou framework. + +**A aplicação doze-fatores armazena configuração em *variáveis de ambiente*** (muitas vezes abreviadas para *env vars* ou *env*). Env vars são fáceis de mudar entre deploys sem alterar qualquer código; ao contrário de arquivos de configuração, há pouca chance de serem colocados acidentalmente no repositório do código; e ao contrário dos arquivos de configuração personalizados, ou outros mecanismos de configuração como Propriedades do Sistema Java, eles são por padrão agnósticos a linguagem e ao SO. + +Outro aspecto do gerenciamento de configuração é o agrupamento. Às vezes, as aplicações incluem a configuração em grupos nomeados (muitas vezes chamados de ambientes) que remetem a deploys específicos, tais como os ambientes `development`, `test`, e `production` em Rails. Este método não escala de forma limpa: quanto mais deploys da aplicação são criados, novos nomes de ambiente são necessários, tais como `staging` ou `qa`. A medida que o projeto cresce ainda mais, desenvolvedores podem adicionar seus próprios ambientes especiais como `joes-staging`, resultando em uma explosão combinatória de configurações que torna o gerenciamento de deploys da aplicação muito frágil. + +Em uma aplicação doze-fatores, env vars são controles granulares, cada um totalmente ortogonal às outras env vars. Elas nunca são agrupadas como "environments", mas em vez disso são gerenciadas independentemente para cada deploy. Este é um modelo que escala sem problemas à medida que o app naturalmente se expande em muitos deploys durante seu ciclo de vida. diff --git a/content/pt_br/dependencies.md b/content/pt_br/dependencies.md new file mode 100644 index 000000000..5eb220463 --- /dev/null +++ b/content/pt_br/dependencies.md @@ -0,0 +1,12 @@ +## II. Dependências +### Declare e isole explicitamente as dependências + +A maioria das linguagens de programação oferecem um sistema de pacotes para a distribuição de bibliotecas de apoio, como o [CPAN](http://www.cpan.org/) para Perl ou [Rubygems](http://rubygems.org/) para Ruby. Bibliotecas instaladas por meio de um sistema de pacotes podem ser instaladas em todo o sistema (conhecidas como "site packages") ou com escopo dentro do diretório contendo a aplicação (conhecidas como "vendoring" ou "building"). + +**Uma aplicação doze-fatores nunca confia na existência implícita de pacotes em todo o sistema.** Ela declara todas as dependências, completa e exatamente, por meio de um manifesto de *declaração de dependência*. Além disso, ela usa uma ferramenta de *isolamento de dependência* durante a execução para garantir que não há dependências implícitas "vazamento" a partir do sistema circundante. A completa e explícita especificação de dependências é aplicada de maneira uniforme tanto para produção quanto para desenvolvimento. + +Por exemplo, [Bundler](https://bundler.io/) para Ruby oferece o formato de manifesto `Gemfile` para declaração de dependência e `bundle exec` para isolamento das mesmas. Em Python existem duas ferramentas separadas para estas etapas -- [Pip](http://www.pip-installer.org/en/latest/) é utilizado para declaração e [Virtualenv](http://www.virtualenv.org/en/latest/) para isolamento. Mesmo C tem [Autoconf](http://www.gnu.org/s/autoconf/) para declaração de dependência, e vinculação estática pode fornecer o isolamento. Não importa qual o conjunto de ferramentas, declaração de dependência e isolamento devem ser sempre usados juntos -- apenas um ou o outro não é suficiente para satisfazer doze-fatores. + +Um dos beneficios da declaração de dependência explícita é que simplifica a configuração da aplicação para novos desenvolvedores. O novo desenvolvedor pode verificar a base de código do aplicativo em sua máquina de desenvolvimento, exigindo apenas runtime da linguagem e gerenciador de dependência instalado como pré-requisitos. Eles serão capazes de configurar tudo o que é necessário para rodar o código da aplicação com um determinístico *comando de build*. Por exemplo, o comando de build para Ruby/Bundler é `bundle install`, enquanto que para Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) é `lein deps`. + +Aplicações doze-fatores também não contam com a existência implícita de todas as ferramentas do sistema. Exemplos incluem executar algum comando externo como do ImageMagick ou `curl`. Embora possam existir essas ferramentas em muitos ou mesmo na maioria dos sistemas, não há garantia de que eles vão existir em todos os sistemas em que a aplicação pode rodar no futuro, ou se a versão encontrada em um futuro sistema será compatível com a aplicação. Se a aplicação precisa executar alguma ferramenta do sistema, essa ferramenta deve ser vendorizada na aplicação. diff --git a/content/pt_br/dev-prod-parity.md b/content/pt_br/dev-prod-parity.md new file mode 100644 index 000000000..e54f5a332 --- /dev/null +++ b/content/pt_br/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Paridade entre desenvolvimento e produção +### Mantenha o desenvolvimento, homologação e produção o mais similares possível + +Historicamente, houveram lacunas substanciais entre desenvolvimento (um desenvolvedor editando código num [deploy](./codebase) local do app) e produção (um deploy acessado pelos usuários finais). Essas lacunas se manifestam em três áreas: + +* **A lacuna do tempo:** Um desenvolvedor pode trabalhar em código que demora dias, semanas ou até meses para ir para produção. +* **A lacuna de pessoal:** Desenvolvedores escrevem código, engenheiros de operação fazem o deploy dele. +* **A lacuna de ferramentas:** Desenvolvedores podem estar usando um conjunto como Nginx, SQLite, e OS X, enquanto o app em produção usa Apache, MySQL, e Linux. + +**O App doze-fatores é projetado para [implantação contínua](http://avc.com/2011/02/continuous-deployment/) deixando a lacuna entre desenvolvimento e produção pequena.** Olhando às três lacunas descritas acima: + +* Diminua a lacuna de tempo: um desenvolvedor pode escrever código e ter o deploy feito em horas ou até mesmo minutos depois. +* Diminua a lacuna de pessoal: desenvolvedores que escrevem código estão proximamente envolvidos em realizar o deploy e acompanhar seu comportamento em produção. +* Diminua a lacuna de ferramentas: mantenha desenvolvimento e produção o mais similares possível. + +Resumindo o acima em uma tabela: + + + + + + + + + + + + + + + + + + + + + + +
App tradicionalApp doze-fatores
Tempo entre deploysSemanasHoras
Autores de código vs deployersPessoas diferentesMesmas pessoas
Ambientes de desenvolvimento vs produçãoDivergenteO mais similar possível
+ +[Serviços de apoio](./backing-services), como o banco de dados do app, sistema de filas, ou cache, são uma área onde paridade entre desenvolvimento e produção é importante. Muitas linguagens oferecem diferentes bibliotecas que simplificam o acesso ao serviço de apoio, incluindo *adaptadores* para os diferentes tipos de serviços. Alguns exemplos na tabela abaixo. + + + + + + + + + + + + + + + + + + + + + + + + + + +
TipoLinguagemBibliotecaAdaptadores
Banco de dadosRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
FilaPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CacheMemory, sistema de arquivos, Memcached
+ +Desenvolvedores as vezes veem uma grande vantagem em usar um serviço de apoio leve em seus ambientes, enquanto um serviço de apoio mais sério e robusto seria usado em produção. Por exemplo, usando SQLite localmente e PostgreSQL em produção; ou memória de processo local para caching em desenvolvimento e Memcached em produção. + +**O desenvolvedor doze-fatores resiste a tentação de usar diferentes serviços de apoio entre desenvolvimento e produção**, mesmo quando adaptadores teoricamente abstraem as diferenças dos serviços de apoio. Diferenças entre serviços de apoio significam que pequenas incompatibilidades aparecerão, fazendo com que código que funcionava e passava em desenvolvimento ou homologação, falhe em produção. Tais tipos de erros criam fricção que desincentivam deploy contínuo. O custo dessa fricção e do subsequente decaimento de deploy contínuo é extremamente alto quando considerado que vai acumular no tempo de vida da aplicação. + +Serviços locais leves são menos tentadores que já foram um dia. Serviços de apoio modernos tais como Memcached, PostgreSQL, e RabbitMQ não são difíceis de instalar e rodam graças a sistemas modernos de empacotamento tais como [Homebrew](http://mxcl.github.com/homebrew/) e [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Alternativamente, ferramentas de provisionamento declarativo tais como [Chef](http://www.opscode.com/chef/) e [Puppet](http://docs.puppetlabs.com/) combinado com ambientes virtuais leves como [Vagrant](http://vagrantup.com/) permitem desenvolvedores rodar ambientes locais que são bem próximos dos ambientes de produção. O custo de instalar e usar esses sistemas é baixo comparado ao benefício de ter a paridade entre desenvolvimento, produção e deploy contínuo. + +Adaptadores para diferentes serviços de apoio ainda são úteis, pois eles fazem a portabilidade para novos serviços de apoio relativamente tranquilas. Mas todos os deploys do app (ambientes de desenvolvimento, homologação, produção) devem usar o mesmo tipo e versão de cada serviço de apoio. diff --git a/content/pt_br/disposability.md b/content/pt_br/disposability.md new file mode 100644 index 000000000..999c5ebc0 --- /dev/null +++ b/content/pt_br/disposability.md @@ -0,0 +1,12 @@ +## IX. Descartabilidade +### Maximize robustez com inicialização rápida e desligamento gracioso + +**Os [processos](./processos) de um app doze-fatores são *descartáveis*, significando que podem ser iniciados ou parados a qualquer momento.** Isso facilita o escalonamento elástico, rápido deploy de [código](./codebase) ou mudanças de [configuração](./config), e robustez de deploys de produção. + +Processos devem empenhar-se em **minimizar o tempo de inicialização**. Idealmente, um processo leva alguns segundos do tempo que o comando de inicialização é executado até o ponto que ele estará pronto para receber requisições ou tarefas. Períodos curtos de inicialização provém mais agilidade para o processo de [release](./build-release-run) e de escalonamento; e ele adiciona robustez, pois o gestor de processos pode mais facilmente mover processos para outras máquinas físicas quando necessário. + +Processos **desligam-se graciosamente quando recebem um sinal [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** do seu gestor de processos. Para um processo web, desligamento gracioso é alcançado quando cessa de escutar à porta de serviço (consequentemente recusando quaisquer requisições novas), permitindo qualquer requisição em andamento terminar, e então desligando. Implícito neste modelo é que as requisições HTTP são curtas (não mais que alguns poucos segundos), ou no caso de um longo _polling_, o cliente deve ser capaz de transparentemente tentar se reconectar quando a conexão for perdida. + +Para um processo de trabalho (worker), desligamento gracioso é alcançado retornando a tarefa atual para fila de trabalho. Por exemplo, no [RabbitMQ](http://www.rabbitmq.com/) o trabalhador pode enviar um [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); no [Beanstalkd](https://beanstalkd.github.io), a tarefa é retornada para a fila automaticamente sempre que um trabalhador se desconecta. Sistemas baseados em trava como o [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) precisam se certificar de soltar a trava no registro da tarefa. Implícito neste modelo é que todas as tarefas são [reentrantes](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), o que tipicamente é atingindo envolvendo os resultados numa transação, ou tornando a operação [idempotente](http://en.wikipedia.org/wiki/Idempotence). + +Processos também devem ser **robustos contra morte súbida**, no caso de uma falha de hardware. Ao passo que isso é muito menos comum que um desligamento via `SIGTERM`, isso ainda pode acontecer. Uma abordagem recomendada é usar um backend de filas robusto, como o Beanstalkd, que retorna tarefas à fila quando clientes desconectam ou esgotam o tempo de resposta. De qualquer forma, um app doze-fatores é arquitetado para lidar com terminações não esperadas e não graciosas. [Crash-only design](http://lwn.net/Articles/191059/) leva este conceito à sua [conclusão lógica](http://docs.couchdb.org/en/latest/intro/overview.html). diff --git a/content/pt_br/intro.md b/content/pt_br/intro.md new file mode 100644 index 000000000..4bba7c229 --- /dev/null +++ b/content/pt_br/intro.md @@ -0,0 +1,12 @@ +Introdução +============ + +Na era moderna, software é comumente entregue como um serviço: denominados *web apps*, ou *software-como-serviço*. A aplicação doze-fatores é uma metodologia para construir softwares-como-serviço que: + +* Usam formatos **declarativos** para automatizar a configuração inicial, minimizar tempo e custo para novos desenvolvedores participarem do projeto; +* Tem um **contrato claro** com o sistema operacional que o suporta, oferecendo **portabilidade máxima** entre ambientes que o executem; +* São adequados para **implantação** em modernas **plataformas em nuvem**, evitando a necessidade por servidores e administração do sistema; +* **Minimizam a divergência** entre desenvolvimento e produção, permitindo a **implantação contínua** para máxima agilidade; +* E podem **escalar** sem significativas mudanças em ferramentas, arquiteturas, ou práticas de desenvolvimento. + +A metodologia doze-fatores pode ser aplicada a aplicações escritas em qualquer linguagem de programação, e que utilizem qualquer combinação de serviços de suportes (banco de dados, filas, cache de memória, etc). \ No newline at end of file diff --git a/content/pt_br/logs.md b/content/pt_br/logs.md new file mode 100644 index 000000000..ec4467c4e --- /dev/null +++ b/content/pt_br/logs.md @@ -0,0 +1,16 @@ +## XI. Logs +### Trate logs como fluxos de eventos + +*Logs* provém visibilidade no comportamento de um app em execução. Em ambientes de servidor eles são comumente escritos num arquivo em disco (um "logfile"); mas este é apenas um formato de saída. + +Logs são o [fluxo](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) de eventos agregados e ordenados por tempo coletados dos fluxos de saída de todos os processos em execução e serviços de apoio. Logs na sua forma crua são tipicamente um formato de texto com um evento por linha (apesar que pilhas de exceção podem ocupar várias linhas). Logs não tem começos ou términos fixos, mas fluem continuamente enquanto o app estiver operante. + +**Um app doze-fatores nunca se preocupa com o roteamento ou armazenagem do seu fluxo de saída.** Ele não deve tentar escrever ou gerir arquivos de logs. No lugar, cada processo em execução escreve seu próprio fluxo de evento, sem buffer, para o `stdout`. Durante o desenvolvimento local, o desenvolvedor verá este fluxo no plano de frente do seu terminal para observar o comportamento do app. + +Em deploys de homologação ou produção, cada fluxo dos processos serão capturados pelo ambiente de execução, colados com todos os demais fluxos do app, e direcionados para um ou mais destinos finais para visualização e arquivamento de longo prazo. Estes destinos de arquivamento não são visíveis ou configuráveis pelo app, e ao invés disso, são completamente geridos pelo ambiente de execução. Roteadores de log open source (tais como [Logplex](https://github.com/heroku/logplex) e [Fluentd](https://github.com/fluent/fluentd)) estão disponíveis para este propósito. + +O fluxo de evento para um app pode ser direcionado para um arquivo, ou visto em tempo real via `tail` num terminal. Mais significativamente, o fluxo pode ser enviado para um sistema indexador e analisador tal como [Splunk](http://www.splunk.com/), ou um sistema mais genérico de _data warehousing_ como o [Hadoop/Hive](http://hive.apache.org/). Estes sistemas permitem grande poder e flexibilidade para observar o comportamento de um app durante o tempo, incluindo: + +* Encontrando eventos específicos no passado. +* Gráficos em larga escala de tendências (como requisições por minuto) +* Notificações ativas de acordo com as heurísticas determinadas pelo usuário (como uma notificação quando a quantidade de erros por minuto exceder um certo limite). diff --git a/content/pt_br/port-binding.md b/content/pt_br/port-binding.md new file mode 100644 index 000000000..f2b291cf5 --- /dev/null +++ b/content/pt_br/port-binding.md @@ -0,0 +1,14 @@ +## VII. Vínculo de Portas +### Exporte serviços via vínculo de portas + +Apps web as vezes são executadas dentro de container de servidor web. Por exemplo, apps PHP podem rodar como um módulo dentro do [Apache HTTPD](http://httpd.apache.org/), ou apps Java podem rodar dentro do [Tomcat](http://tomcat.apache.org/). + +**O aplicativo doze-fatores é completamente auto-contido** e não depende de injeções de tempo de execução de um servidor web em um ambiente de execução para criar um serviço que defronte a web. O app web **exporta o HTTP como um serviço através da vínculação a uma porta**, e escuta as requisições que chegam na mesma. + +Num ambiente de desenvolvimento local, o desenvolvedor visita a URL de um serviço como `http://localhost:5000/` para acessar o serviço exportado pelo seu app. Num deploy, uma camada de roteamento manipula as requisições de rotas vindas de um hostname público para os processos web atrelados às portas. + +Isso é tipicamente implementado usando [declaração de dependências](./dependencies) para adicionar uma biblioteca de servidor ao app, tal como [Tornado](http://www.tornadoweb.org/) para Python, [Thin](http://code.macournoyer.com/thin/) para Ruby, ou [Jetty](http://www.eclipse.org/jetty/) para Java e outra linguagens baseadas na JVM. Isso acontece completamente no *espaço do usuário*, isso é, dentro do código do app. O contrato com o ambiente de execução é vincular a uma porta para servir requisições. + +HTTP não é o único serviço que pode ser exportado via vínculo de portas. Quase todos os tipos de software servidores podem rodar via um processo vinculado a uma porta e aguardar as requisições chegar. Exemplos incluem [ejabberd](http://www.ejabberd.im/) (comunicando via [XMPP](http://xmpp.org/)), e [Redis](http://redis.io/) (comunicando via [protocolo Redis](http://redis.io/topics/protocol)). + +Note que a abordagem de vincular portas significa que um app pode se tornar o [serviço de apoio](./backing-services) para um outro app, provendo a URL do app de apoio como um identificador de recurso na [configuração](./config) para o app consumidor. diff --git a/content/pt_br/processes.md b/content/pt_br/processes.md new file mode 100644 index 000000000..39a472f00 --- /dev/null +++ b/content/pt_br/processes.md @@ -0,0 +1,14 @@ +## VI. Processos +### Execute a aplicação como um ou mais processos que não armazenam estado + +A aplicação é executada em um ambiente de execução como um ou mais *processos*. + +No caso mais simples, o código é um script autônomo, o ambiente de execução é o laptop local de um desenvolvedor com o runtime da linguagem instalado, e o processo é iniciado pela linha de comando (por exemplo, `python my_script`). Na outra extremidade do espectro, o deploy em produção de uma aplicação sofisticada pode utilizar vários [tipos de processos, instanciado em zero ou mais processos em andamento](./concurrency). + +**Processos doze-fatores são stateless(não armazenam estado) e [share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Quaisquer dados que precise persistir deve ser armazenado em um serviço de apoio stateful(que armazena o seu estado), tipicamente uma base de dados. + +O espaço de memória ou sistema de arquivos do processo pode ser usado como um breve, cache de transação única. Por exemplo, o download de um arquivo grande, operando sobre ele, e armazenando os resultados da operação no banco de dados. A aplicação doze-fatores nunca assume que qualquer coisa cacheada na memória ou no disco estará disponível em uma futura solicitação ou job -- com muitos processos de cada tipo rodando, as chances são altas de que uma futura solicitação será servida por um processo diferente. Mesmo quando rodando em apenas um processo, um restart (desencadeado pelo deploy de um código, mudança de configuração, ou o ambiente de execução realocando o processo para uma localização física diferente) geralmente vai acabar com todo o estado local (por exemplo, memória e sistema de arquivos). + +Empacotadores de assets (como [Jammit](http://documentcloud.github.com/jammit/) ou [django-compressor](http://django-compressor.readthedocs.org/)) usa o sistema de arquivos como um cache para assets compilados. Uma aplicação doze-fatores prefere fazer isto compilando durante a [fase de build](./build-release-run), tal como o [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html), do que em tempo de execução. + +Alguns sistemas web dependem de ["sessões persistentes"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- ou seja, fazem cache dos dados da sessão do usuário na memória do processo da aplicação, esperando futuras requisições do mesmo visitante para serem encaminhadas para o mesmo processo. Sessões persistentes são uma violação do doze-fatores e nunca devem ser utilizadas ou invocadas. Dados do estado da sessão são bons candidatos para um datastore que oferece tempo de expiração, tal como [Memcached](http://memcached.org/) ou [Redis](http://redis.io/). diff --git a/content/pt_br/toc.md b/content/pt_br/toc.md new file mode 100644 index 000000000..d57d599c0 --- /dev/null +++ b/content/pt_br/toc.md @@ -0,0 +1,38 @@ +Os Doze Fatores +=============== + +## [I. Base de Código](./codebase) +### Uma base de código com rastreamento utilizando controle de revisão, muitos deploys + +## [II. Dependências](./dependencies) +### Declare e isole as dependências + +## [III. Configurações](./config) +### Armazene as configurações no ambiente + +## [IV. Serviços de Apoio](./backing-services) +### Trate os serviços de apoio, como recursos ligados + +## [V. Construa, lance, execute](./build-release-run) +### Separe estritamente os builds e execute em estágios + +## [VI. Processos](./processes) +### Execute a aplicação como um ou mais processos que não armazenam estado + +## [VII. Vínculo de porta](./port-binding) +### Exporte serviços por ligação de porta + +## [VIII. Concorrência](./concurrency) +### Dimensione por um modelo de processo + +## [IX. Descartabilidade](./disposability) +### Maximizar a robustez com inicialização e desligamento rápido + +## [X. Dev/prod semelhantes](./dev-prod-parity) +### Mantenha o desenvolvimento, teste, produção o mais semelhante possível + +## [XI. Logs](./logs) +### Trate logs como fluxo de eventos + +## [XII. Processos de Admin](./admin-processes) +### Executar tarefas de administração/gerenciamento como processos pontuais diff --git a/content/pt_br/who.md b/content/pt_br/who.md new file mode 100644 index 000000000..4cbf0fe68 --- /dev/null +++ b/content/pt_br/who.md @@ -0,0 +1,4 @@ +Quem deve ler este documento? +============================= + +Qualquer desenvolvedor que esta construindo aplicações que rodam como serviço. Engenheiros de Operações que implantam ou administram tais aplicações. diff --git a/content/ru/admin-processes.md b/content/ru/admin-processes.md new file mode 100644 index 000000000..6e317c094 --- /dev/null +++ b/content/ru/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Задачи администрирования +### Выполняйте задачи администрирования/управления с помощью разовых процессов + +[Формирование процессов](./concurrency) является некоторым набором процессов, которые необходимы для выполнения регулярных задач приложения (таких как обработка веб-запросов), когда оно исполняется. В дополнение к этому, разработчикам периодически необходимо выполнять разовые задачи администрирования и обслуживания приложения, такие как: + +* Запуск миграции базы данных (например `manage.py migrate` в Django, `rake db:migrate` в Rails). +* Запуск консоли (также известной как оболочка [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop)), чтобы запустить произвольный код или проверить модели приложения с действующей базой данных. Большинство языков предоставляют REPL путём запуска интерпретатора без каких-либо аргументов (например, `python` или `perl`), а в некоторых случаях имеют отдельную команду (например `irb` в Ruby, `rails console` в Rails). +* Запуск разовых скриптов, хранящихся в репозитории приложения (например, `php scripts/fix_bad_records.php`). + +Разовые процессы администрирования следует запускать в среде идентичной регулярным [длительным процессам](./processes) приложения. Они запускаются на уровне [релиза](./build-release-run), используя те же [кодовую базу](./codebase) и [конфигурацию](./config), как и любой другой процесс, выполняющий этот релиз. Код администрирования должен поставляться вместе с кодом приложения, чтобы избежать проблем синхронизации. + +Те же самые методы [изоляции зависимостей](./dependencies) должны быть использованы для всех типов процессов. Например, если веб-процесс Ruby использует команду `bundle exec thin start`, то для миграции базы данных следует использовать `bundle exec rake db:migrate`. Аналогичным образом для программы на Python с использованием Virtualenv следует использовать поставляемый `bin/python` как для запуска веб-сервера Tornado, так и для запуска любых `manage.py` процессов администрирования. + +Методология двенадцати факторов отдаёт предпочтение языкам, которые предоставляют REPL оболочки из коробки, и которые позволяют легко выполнять разовые скрипты. В локальном развёртывании разработчики выполняют разовый процесс администрирования с помощью консольной команды внутри каталога с приложением. В рабочем развёртывании разработчики могут использовать ssh или другой механизм выполнения удалённой команды, предоставленный средой выполнения, для запуска такого процесса. diff --git a/content/ru/background.md b/content/ru/background.md new file mode 100644 index 000000000..b6b41cb66 --- /dev/null +++ b/content/ru/background.md @@ -0,0 +1,8 @@ +Предпосылки +========== + +Участники, внёсшие вклад в этот документ, были непосредственно вовлечены в разработку и развёртывание сотен приложений и косвенно были свидетелями разработки, выполнения и масштабирования сотен тысяч приложений во время нашей работы над платформой [Heroku](http://www.heroku.com/). + +В этом документе обобщается весь наш опыт использования и наблюдения за самыми разнообразными SaaS-приложениями в дикой природе. Документ является объединением трёх идеальных подходов к разработке приложений: уделение особого внимания динамике органического роста приложения с течением времени, динамике сотрудничества разработчиков, работающих над кодовой базой приложения, и [устранение последствий эрозии программного обеспечения](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Наша мотивация заключается в повышении осведомлённости о некоторых системных проблемах, которые мы встретили в практике разработки современных приложений, а также для того, чтобы предоставить общие основные понятия для обсуждения этих проблем и предложить набор общих концептуальных решений этих проблем с сопутствующей терминологией. Формат навеян книгами Мартина Фаулера (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)*. diff --git a/content/ru/backing-services.md b/content/ru/backing-services.md new file mode 100644 index 000000000..c6a44e011 --- /dev/null +++ b/content/ru/backing-services.md @@ -0,0 +1,14 @@ +## IV. Сторонние службы (Backing Services) +### Считайте сторонние службы (backing services) подключаемыми ресурсами + +*Сторонняя служба*-- это любая служба, которая доступна приложению по сети и необходима как часть его нормальной работы. Например, хранилища данных (например, [MySQL](http://dev.mysql.com/) и [CouchDB](http://couchdb.apache.org/)), системы очередей сообщений (например, [RabbitMQ](http://www.rabbitmq.com/) и [Beanstalkd](https://beanstalkd.github.io)), службы SMTP для исходящей электронной почты (например, [Postfix](http://www.postfix.org/)) и кэширующие системы (например, [Memcached](http://memcached.org/)). + +Традиционно, сторонние службы, такие как базы данных, поддерживаются тем же самым системным администратором, который разворачивает приложение. Помимо локальных сервисов приложение может использовать сервисы, предоставленные и управляемые третьей стороной. Примеры включают в себя SMTP сервисы (например [Postmark](http://postmarkapp.com/)), сервисы сбора метрик (такие как [New Relic](http://newrelic.com/) и [Loggly](http://www.loggly.com/)), хранилища бинарных данных (например, [Amazon S3](http://aws.amazon.com/s3/)), а также использование API различных сервисов (таких как [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/) и [Last.fm](http://www.last.fm/api)). + +**Код приложения двенадцати факторов не делает различий между локальными и сторонними сервисами.** Для приложения каждый из них является подключаемым ресурсом, доступным по URL-адресу или по другой паре расположение/учётные данные, хранящимися в [конфигурации](./config). Каждое [развёртывание](./codebase) приложения двенадцати факторов должно иметь возможность заменить локальную базу данных MySQL на любую управляемую третьей стороной (например [Amazon RDS](http://aws.amazon.com/rds/)) без каких либо изменений кода приложения. Аналогичным образом, локальный SMTP сервер может быть заменён сторонним (например Postmark) без изменения кода. В обоих случаях необходимо изменить только идентификатор ресурса в конфигурации. + +Каждая различная сторонняя служба является *ресурсом*. Например, база данных MySQL является ресурсом, две базы данных MySQL (используются для фрагментации на уровне приложения) квалифицируются как два отдельных ресурса. Приложение двенадцати факторов считает эти базы данных *подключёнными ресурсами*, что указывает на их слабое связывание с развёртыванием, в котором они подключены. + +Рабочее развёртывание приложения, подключённого к 4 сторонним сервисам. + +Ресурсы можно по необходимости подключать к развёртыванию и отключать от развёртывания. Например, если база данных приложения функционирует некорректно из-за аппаратных проблем, администратор может запустить новый сервер базы данных, восстановленный из последней резервной копии. Текущая рабочая база данных может быть отключена, а новая база данных подключена -- всё это без каких-либо изменений кода. diff --git a/content/ru/build-release-run.md b/content/ru/build-release-run.md new file mode 100644 index 000000000..7e8b4aafd --- /dev/null +++ b/content/ru/build-release-run.md @@ -0,0 +1,18 @@ +## V. Сборка, релиз, выполнение +### Строго разделяйте стадии сборки и выполнения + +[Кодовая база](./codebase) трансформируется в развёртывание (не учитывая развёртывание для разработки) за три этапа: + +* *Этап сборки* -- это трансформация, которая преобразует репозиторий кода в исполняемый пакет, называемый *сборка*. Используя версию кода по указанному процессом развёртывания коммиту, этап сборки загружает сторонние [зависимости](./dependencies) и компилирует двоичные файлы и ресурсы (assets). +* *Этап релиза* принимает сборку, полученную на этапе сборки, и объединяет её с текущей [конфигурацией](./config) развёртывания. Полученный *релиз* содержит сборку и конфигурацию и готов к немедленному запуску в среде выполнения. +* *Этап выполнения* (также известный как "runtime") запускает приложение в среде выполнения путём запуска некоторого набора [процессов](./processes) приложения из определённого релиза. + +![Код становится сборкой, которая объединяется с конфигурацией для создания релиза.](/images/release.png) + +**Приложение двенадцати факторов использует строгое разделение между этапами сборки, релиза и выполнения.** Например, невозможно внести изменения в код во время выполнения, так как нет способа распространить эти изменения обратно на этап сборки. + +Инструменты развёртывания, как правило, представляют собой инструменты управления релизами, и что немаловажно, дают возможность отката к предыдущему релизу. Например инструмент развёртывания [Capistrano](https://github.com/capistrano/capistrano/wiki) сохраняет релизы в подкаталогах каталога с именем `releases`, где текущий релиз является символической ссылкой на каталог текущего релиза. Команда Capistrano `rollback` даёт возможность быстро откатится к предыдущему релизу. + +Каждый релиз должен иметь уникальный идентификатор, такой как отметка времени релиза (например `2015-04-06-15:42:17`) или увеличивающееся число (например `v100`). Релизы могут только добавляться и каждый релиз невозможно изменить после его создания. Любые изменения обязаны создавать новый релиз. + +Сборка инициируется разработчиком приложения всякий раз, когда разворачивается новый код. Запуск этапа выполнения, напротив, может происходить автоматически в таких случаях, как перезагрузка сервера, или перезапуск упавшего процесса менеджером процессов. Таким образом, этап выполнения должен быть как можно более технически простым, так как проблемы, которые могут помешать приложению запуститься могут возникнуть в середине ночи, когда нет доступных разработчиков. Этап сборки может быть более сложным, так как возможные ошибки всегда видимы разработчику, который запустил развёртывание. diff --git a/content/ru/codebase.md b/content/ru/codebase.md new file mode 100644 index 000000000..27c0e1641 --- /dev/null +++ b/content/ru/codebase.md @@ -0,0 +1,17 @@ +## I. Кодовая база +### Одна кодовая база, отслеживаемая в системе контроля версий, -- множество развёртываний + +Приложение двенадцати факторов всегда отслеживается в системе контроля версий, такой как [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/) или [Subversion](http://subversion.apache.org/). Копия базы данных отслеживаемых версий называется *репозиторием кода (code repository)*, что часто сокращается до *code repo* или просто до *репозиторий (repo)* + +*Кодовая база* -- это один репозиторий (в централизованных системах контроля версий, как Subversion) или множество репозиториев, имеющих общие начальные коммиты (в децентрализованных системах контроля версий, как Git). + +![Одна кодовая база -- множество развёртываний](/images/codebase-deploys.png) + +Всегда есть однозначное соответствие между кодовой базой и приложением: + +* Если есть несколько кодовых баз, то это не приложение — это распределённая система. Каждый компонент в распределённой системе является приложением и каждый компонент может индивидуально соответствовать двенадцати факторам. +* Факт того, что несколько приложений совместно используют тот же самый код, является нарушением двенадцати факторов. Решением в данной ситуации является выделение общего кода в библиотеки, которые могут быть подключены через [менеджер зависимостей](./dependencies). + +Существует только одна кодовая база для каждого приложения, но может быть множество развёртываний одного и того же приложения. *Развёрнутым приложением (deploy)* является запущенный экземпляр приложения. Как правило, это рабочее развёртывание сайта и одно или несколько промежуточных развёртываний сайта. Кроме того каждый разработчик имеет копию приложения, запущенного в его локальном окружении разработки, каждая из которых также квалифицируется как развёрнутое приложение (deploy). + +Кодовая база обязана быть единой для всех развёртываний, однако разные версии одной кодовой базы могут выполняться в каждом из развёртываний. Например разработчик может иметь некоторые изменения которые ещё не добавлены в промежуточное развёртывание; промежуточное развёртывание может иметь некоторые изменения, которые ещё не добавлены в рабочее развёртывание. Однако, все эти развёртывания используют одну и ту же кодовую базу, таким образом можно их идентифицировать как разные развёртывания одного и того же приложения. diff --git a/content/ru/concurrency.md b/content/ru/concurrency.md new file mode 100644 index 000000000..1e3b5b5a9 --- /dev/null +++ b/content/ru/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Параллелизм +### Масштабируйте приложение с помощью процессов + +Любая компьютерная программа после запуска представляет собой один или несколько работающих процессов. Исторически веб-приложения принимали различные формы выполнения процессов. К примеру, PHP-процессы выполнятся как дочерние процессы Apache и запускаются по требованию в необходимом для обслуживания поступивших запросов количестве. Java-процессы используют противоположный подход, JVM представляет собой один монолитный мета-процесс, который резервирует большой объём системных ресурсов (процессор и память) при запуске и управляет параллельностью внутри себя с помощью нитей исполнения (threads). В обоих случаях запущенные процессы лишь минимально видны для разработчика приложения. + +![Масштабирование выражается в количестве запущенных процессов, различие рабочей нагрузки выражается в типах процессов.](/images/process-types.png) + +**В приложении двенадцати факторов процессы являются сущностями первого класса.** Процессы в приложении двенадцати факторов взяли сильные стороны из [модели процессов Unix для запуска демонов](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). С помощью этой модели разработчик может спроектировать своё приложение таким образом, что для обработки различной рабочей нагрузки необходимо назначить каждому типу работы свой *типа процесса*. Например, HTTP-запросы могут быть обработаны веб-процессом, а длительные фоновые задачи обработаны воркером, выполняющим их в фоне. + +Это не исключает возможность использования внутреннего мультиплексирования для индивидуальных процессов через потоки выполнения виртуальной машины или асинхронные/событийные модели в инструментах таких, как [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/) и [Node.js](http://nodejs.org/). Но каждая индивидуальная виртуальная машина может масштабироваться только ограниченно (вертикальное масштабирование), поэтому приложение должно иметь возможность быть запущенным как несколько процессов на различных физических машинах. + +Модель, построенная на процессах в полной мере демонстрирует свои преимущества, когда приходит время масштабирования. [Отсутствие разделяемых данных и горизонтальное разделение процессов приложения двенадцати факторов](./processes) означает, что добавление большего параллелизма является простой и надёжной операцией. Массив процессов различного типа и количество процессов каждого типа называются *формированием процессов (process formation)*. + +Процессы приложения двенадцати факторов [никогда не должны демонизироваться](http://dustin.github.com/2010/02/28/running-processes.html) и записывать PID файлы. Вместо этого они должны полагаться на менеджер процессов операционной системы (например, [systemd](https://www.freedesktop.org/wiki/Software/systemd/), распределённый менеджер процессов на облачной платформе, или инструмент как [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) в процессе разработки) для управления [потоком вывода](./logs), реагирования на падения процесса и обработки инициированных пользователем перезагрузки или завершения работы. diff --git a/content/ru/config.md b/content/ru/config.md new file mode 100644 index 000000000..ea216d36f --- /dev/null +++ b/content/ru/config.md @@ -0,0 +1,22 @@ +## III. Конфигурация +### Сохраняйте конфигурацию в среде выполнения + +*Конфигурация* приложения -- это всё, что может меняться между [развёртываниями](./codebase) (среда разработки, промежуточное и рабочее развёртывание). Это включает в себя: + +* Идентификаторы подключения к ресурсам типа базы данных, кэш-памяти и другим [сторонним службам](./backing-services) +* Регистрационные данные для подключения к внешним сервисам, например, к Amazon S3 или Twitter +* Значения зависимые от среды развёртывания такие, как каноническое имя хоста + +Иногда приложения хранят конфигурации как константы в коде. Это нарушение методологии двенадцати факторов, которая требует **строгого разделения конфигурации и кода**. Конфигурация может существенно различаться между развёртываниями, код не должен различаться. + +Лакмусовой бумажкой того, правильно ли разделены конфигурация и код приложения, является факт того, что кодовая база приложения может быть в любой момент открыта в свободный доступ без компрометации каких-либо приватных данных. + +Обратите внимание, что это определение "конфигурации" **не** включает внутренние конфигурации приложения, например такие как 'config/routes.rb' в Rails, или того как [основные модули будут связаны](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) в [Spring](http://spring.io/). Этот тип конфигурации не меняется между развёртываниями и поэтому лучше всего держать его в коде. + +Другим подходом к конфигурации является использование конфигурационных файлов, которые не сохраняются в систему контроля версия, например 'config/database.yml' в Rails. Это огромное улучшение перед использованием констант, которые сохраняются в коде, но по-прежнему и у этого метода есть недостатки: легко по ошибке сохранить конфигурационный файл в репозиторий; существует тенденция когда конфигурационные файлы разбросаны в разных местах и в разных форматах, из за этого становится трудно просматривать и управлять всеми настройками в одном месте. Кроме того форматы этих файлов, как правило, специфичны для конкретного языка или фреймворка. + +**Приложение двенадцати факторов хранит конфигурацию в *переменных окружения*** (часто сокращается до *env vars* или *env*). Переменные окружения легко изменить между развёртываниями, не изменяя код; в отличие от файлов конфигурации, менее вероятно случайно сохранить их в репозиторий кода; и в отличие от пользовательских конфигурационных файлов или других механизмов конфигурации, таких как Java System Properties, они являются независимым от языка и операционной системы стандартом. + +Другим подходом к управлению конфигурациями является группировка. Иногда приложения группируют конфигурации в именованные группы (часто называемые "окружениями") названые по названию конкретного развёртывания, например как `development`, `test` и `production` окружения в Rails. Этот метод не является достаточно масштабируемым: чем больше различных развёртываний приложения создаётся, тем больше новых имён окружений необходимо, например `staging` и `qa`. При дальнейшем росте проекта, разработчики могут добавлять свои собственные специальные окружения, такие как `joes-staging`, в результате происходит комбинаторный взрыв конфигураций, который делает управление развёртываниями приложения очень хрупким. + +В приложении двенадцати факторов переменные окружения являются не связанными между собой средствами управления, где каждая переменная окружения полностью независима от других. Они никогда не группируются вместе в "окружения", а вместо этого управляются независимо для каждого развёртывания. Эта модель которая масштабируется постепенно вместе с естественным появлением большего количества развёртываний приложения за время его жизни. diff --git a/content/ru/dependencies.md b/content/ru/dependencies.md new file mode 100644 index 000000000..caffb63d3 --- /dev/null +++ b/content/ru/dependencies.md @@ -0,0 +1,12 @@ +## II. Зависимости +### Явно объявляйте и изолируйте зависимости + +Большинство языков программирования поставляются вместе с менеджером пакетов для распространения библиотек, таким как [CPAN](http://www.cpan.org/) в Perl или [Rubygems](http://rubygems.org/) в Ruby. Библиотеки, устанавливаемые менеджером пакетов, могут быть установлены доступными для всей системы (так называемые "системные пакеты") или доступными только приложению в директорию содержащую приложение (так называемые "vendoring" и "bundling"). + +**Приложение двенадцати факторов никогда не зависит от неявно существующих, доступных всей системе пакетов.** Приложение объявляет все свои зависимости полностью и точно с помощью манифеста *декларации зависимостей*. Кроме того, оно использует инструмент *изоляции зависимостей* во время выполнения для обеспечения того, что неявные зависимости не "просочились" из окружающей системы. Полная и явная спецификация зависимостей применяется равным образом как при разработке, так и при работе приложения. + +Например, [Bundler](https://bundler.io/) в Ruby использует `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/) для объявления зависимостей, и статическое связывание может обеспечить изоляцию зависимостей. Независимо от того, какой набор инструментов используется, объявление и изоляция зависимостей должны всегда использоваться совместно -- только одного из них недостаточно, чтобы удовлетворить двенадцати факторам. + +Одним из преимуществ явного объявления зависимостей является то, что это упрощает настройку приложения для новых разработчиков. Новый разработчик может скопировать кодовую базу приложения на свою машину, необходимыми требованиями для которой являются только наличие среды выполнения языка и менеджера пакетов. Всё необходимое для запуска кода приложения может быть настроено с помощью определённой *команды настройки*. Например, для Ruby/Bundler командой настройки является `bundle install`, для Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) это `lein deps`. + +Приложение двенадцати факторов также не полагается на неявное существование любых инструментов системы. Примером является запуск программ ImageMagick и `curl`. Хотя эти инструменты могут присутствовать во многих или даже в большинстве систем, нет никакой гарантии, что они будут присутствовать на всех системах, где приложение может работать в будущем, или будет ли версия найденная в другой системе совместима с приложением. Если приложению необходимо запустить инструмент системы, то этот инструмент должен быть включён в приложение. diff --git a/content/ru/dev-prod-parity.md b/content/ru/dev-prod-parity.md new file mode 100644 index 000000000..8dde29b41 --- /dev/null +++ b/content/ru/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Паритет окружений разработки и продуктива (Dev/prod parity) +### Держите окружения разработки, промежуточного развёртывания (staging) и рабочего развёртывания (production) максимально похожими + +Исторически существуют значительные различия между разработкой (разработчик делает живые изменения на локальном [развёртывании](./codebase) приложения) и работой приложения (развёртывание приложения с доступом к нему конечных пользователей). Эти различия проявляются в трёх областях: + +* **Различие во времени:** разработчик может работать с кодом, который попадёт в рабочую версию приложения только через дни, недели или даже месяцы. +* **Различие персонала**: разработчики пишут код, OPS инженеры разворачивают его. +* **Различие инструментов**: разработчики могут использовать стек технологий, такой как Nginx, SQLite, и OS X, в то время как при рабочем развёртывании используются Apache, MySQL и Linux. + +**Приложение двенадцати факторов спроектировано для [непрерывного развёртывания](http://avc.com/2011/02/continuous-deployment/) благодаря минимизации различий между разработкой и работой приложения. Рассмотрим три различия, описанных выше: + +* Сделать различие во времени небольшим: разработчик может написать код, и он будет развёрнут через несколько часов или даже минут. +* Сделать небольшими различия персонала: разработчик который написал код, активно участвует в его развёртывании и наблюдает за его поведением во время работы приложения. +* Сделать различия инструментов небольшими: держать окружение разработки и работы приложения максимально похожими. + +Резюмируя сказанное выше в таблицу: + + + + + + + + + + + + + + + + + + + + + + +
Традиционное приложениеПриложение двенадцати факторов
Время между развёртываниямиНеделиЧасы
Автор кода/тот кто разворачиваетРазные людиТе же люди
Окружение разработки/работы приложенияРазличныеМаксимально похожие
+ +[Сторонние службы](./backing-services), такие как базы данных, системы очередей сообщений и кэш, являются одной из областей, где паритет при разработке и работе приложения имеет важное значение. Многие языки предоставляют библиотеки, которые упрощают доступ к сторонним службам, включая *адаптеры* для доступа к различных типам сервисов. Некоторые примеры, в таблице ниже. + + + + + + + + + + + + + + + + + + + + + + + + + + +
ТипЯзыкБиблиотекаАдаптеры
База данныхRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
Очередь сообщенийPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
КэшRuby/RailsActiveSupport::CacheПамять, файловая система, Memcached
+ +Иногда разработчики находят удобным использовать лёгкие сторонние службы в их локальном окружении, в то время как более серьёзные и надёжные сторонние сервисы будут использованы в рабочем окружении. Например используют SQLite локально и PostgreSQL в рабочем окружении; или память процесса для кэширования при разработке и Memcached в рабочем окружении. + +**Разработчик приложения двенадцати факторов сопротивляется искушению использовать различные сторонние сервисы при разработке и в рабочем окружении**, даже когда адаптеры теоретически абстрагированы от различий в сторонних сервисах. Различия в используемых сторонних сервисах означают, что может возникнуть крошечная несовместимость, которая станет причиной того, что код, который работал и прошёл тесты при разработке и промежуточном развёртывании не работает в рабочем окружении. Такой тип ошибок создаёт помехи, которые нивелируют преимущества непрерывного развёртывания. Стоимость этих помех и последующего восстановления непрерывного развёртывания является чрезвычайно высокой, если рассматривать в совокупности за всё время существования приложения. + +Установка локальных сервисов стала менее непреодолимой задачей, чем она когда-то была. Современные сторонние сервисы, такие как Memcached, PostgreSQL и RabbitMQ не трудно установить и запустить благодаря современным менеджерам пакетов, таким как [Homebrew](http://mxcl.github.com/homebrew/) и [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Кроме того, декларативные инструменты подготовки окружения, такие как [Chef](http://www.opscode.com/chef/) и [Puppet](http://docs.puppetlabs.com/) в сочетании с легковесным виртуальным окружением, таким как [Vagrant](http://vagrantup.com/) позволяют разработчикам запустить локальное окружение которое максимально приближено к рабочему окружению. Стоимость установки и использования этих систем ниже по сравнению с выгодой, получаемой от паритета разработки/работы приложения и непрерывного развёртывания. + +Адаптеры для различных сторонних сервисов по-прежнему полезны, потому что они позволяют портировать приложение для использования новых сторонних сервисов относительно безболезненно. Но все развёртывания приложения (окружение разработчика, промежуточное и рабочее развёртывание) должны использовать тот же тип и ту же версию каждого из сторонних сервисов. diff --git a/content/ru/disposability.md b/content/ru/disposability.md new file mode 100644 index 000000000..aa527b66d --- /dev/null +++ b/content/ru/disposability.md @@ -0,0 +1,12 @@ +## IX. Утилизируемость (Disposability) +### Максимизируйте надёжность с помощью быстрого запуска и корректного завершения работы + +**[Процессы](./processes) приложения двенадцати факторов являются *утилизируемыми*, это означает, что они могут быть запущены и остановлены в любой момент.** Это способствует стабильному и гибкому масштабированию, быстрому развёртыванию изменений [кода](./codebase) и [конфигураций](./config) и надёжности рабочего развёртывания. + +Процессы должны стараться **минимизировать время запуска**. В идеале процесс должен затратить всего несколько секунд от момента времени, когда выполнена команда запуска, и до того момента, когда процесс запущен и готов принимать запросы или задачи. Короткое время запуска предоставляет большую гибкость для [релиза](./build-release-run) и масштабирования. Кроме того, это более надёжно, так как менеджер процессов может свободно перемещать процессы на новые физические машины при необходимости. + +Процессы должны **завершаться корректно, когда они получают [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** сигнал от диспетчера процессов. Для веб-процесса корректное завершение работы достигается путём прекращения прослушивания порта сервиса (таким образом, отказаться от каких-либо новых запросов), что позволяет завершить текущие запросы и затем завершиться. В этой модели подразумевается, что HTTP-запросы короткие (не более чем на несколько секунд), в случае длинных запросов клиент должен плавно попытаться восстановить подключение при потере соединения. + +Для процесса, выполняющего фоновые задачи (worker), корректное завершение работы достигается путём возвращения текущей задачи назад в очередь задач. Например, в [RabbitMQ](http://www.rabbitmq.com/) рабочий процесс может отправлять команду [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); в [Beanstalkd](https://beanstalkd.github.io) задача возвращается в очередь автоматически, когда рабочий процесс отключается. Системы, основанные на блокировках такие, как [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) должны быть уведомлены, чтобы освободить блокировку задачи. В этой модели подразумевается, что все задачи являются [повторно входимыми](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), что обычно достигается путём оборачивания результатов работы в транзакции или путём использования [идемпотентных](http://en.wikipedia.org/wiki/Idempotence) операций. + +Процессы также должны быть **устойчивыми к внезапной смерти** в случае отказа аппаратного обеспечения. Хотя это менее вероятное событие, чем корректное завершение работы сигналом `SIGTERM`, оно всё же может случиться. Рекомендуемым подходом является использование надёжных очередей задач, таких как Beanstalkd, которые возвращают задачу в очередь когда клиент отключается или превышает лимит времени. В любом случае приложение двенадцати факторов должно проектироваться так, чтобы обрабатывать неожиданные и неизящные выключения. [Архитектура только аварийного выключения (Crash-only design)](http://lwn.net/Articles/191059/) доводит эту концепцию до её [логического завершения](http://docs.couchdb.org/en/latest/intro/overview.html). diff --git a/content/ru/intro.md b/content/ru/intro.md new file mode 100644 index 000000000..ea294f3bb --- /dev/null +++ b/content/ru/intro.md @@ -0,0 +1,12 @@ +Введение +============ + +В наши дни программное обеспечение обычно распространяется в виде сервисов, называемых *веб-приложения* (web apps) или *software-as-a-service* (SaaS). Приложение двенадцати факторов — это методология для создания SaaS-приложений, которые: + +* Используют **декларативный** формат для описания процесса установки и настройки, что сводит к минимуму затраты времени и ресурсов для новых разработчиков, подключённых к проекту; +* Имеют **соглашение** с операционной системой, предполагающее **максимальную переносимость** между средами выполнения; +* Подходят для **развёртывания** на современных **облачных платформах**, устраняя необходимость в серверах и системном администрировании; +* **Сводят к минимуму расхождения** между средой разработки и средой выполнения, что позволяет использовать **непрерывное развёртывание** (continuous deployment) для максимальной гибкости; +* И могут **масштабироваться** без существенных изменений в инструментах, архитектуре и практике разработки. + +Методология двенадцати факторов может быть применена для приложений, написанных на любом языке программирования и использующих любые комбинации сторонних служб (backing services) (базы данных, очереди сообщений, кэш-памяти, и т.д.). diff --git a/content/ru/logs.md b/content/ru/logs.md new file mode 100644 index 000000000..bbccbf64f --- /dev/null +++ b/content/ru/logs.md @@ -0,0 +1,16 @@ +## XI. Журналирование (Logs) +### Рассматривайте журнал как поток событий + +*Журналирование* обеспечивает наглядное представление поведения работающего приложения. Обычно в серверной среде журнал записывается в файл на диске ("logfile"), но это только один из форматов вывода. + +Журнал -- это [поток](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) агрегированных, упорядоченных по времени событий, собранных из потоков вывода всех запущенных процессов и вспомогательных сервисов. Журнал в своём сыром виде обычно представлен текстовым форматом с одним событием на строчку (хотя трассировки исключений могут занимать несколько строк). Журнал не имеет фиксированного начала и конца, поток сообщений непрерывен, пока работает приложение. + +**Приложение двенадцати факторов никогда не занимается маршрутизацией и хранением своего потока вывода.** Приложение не должно записывать журнал в файл и управлять файлами журналов. Вместо этого каждый выполняющийся процесс записывает свой поток событий без буферизации в стандартный вывод `stdout`. Во время локальной разработки разработчик имеет возможность просматривать этот поток в терминале, чтобы наблюдать за поведением приложения. + +При промежуточном и рабочем развёртывании поток вывода каждого процесса будет захвачен средой выполнения, собран вместе со всеми другими потоками вывода приложения и перенаправлен к одному или нескольким конечным пунктам назначения для просмотра и долгосрочной архивации. Эти конечные пункты архивации не являются видимыми для приложения и настраиваемыми приложением, вместо этого они полностью управляются средой выполнения. Маршрутизаторы журналов с открытым исходным кодом (например, [Logplex](https://github.com/heroku/logplex) и [Fluentd](https://github.com/fluent/fluentd)) могут быть использованы для этой цели. + +Поток событий приложения может быть перенаправлен в файл или просматриваться в терминале в режиме реального времени. Наиболее значимым является то, что поток событий может быть направлен в систему индексирования и анализа журналов, такую как [Splunk](http://www.splunk.com/), или систему хранения данных общего назначения, такую как [Hadoop/Hive](http://hive.apache.org/). Эти системы обладают большими возможностями и гибкостью для досконального анализа поведения приложение в течении времени, что включает в себя: + +* Поиск конкретных событий в прошлом. +* Крупномасштабные графики трендов (например, запросов в минуту). +* Активные оповещения согласно эвристическим правилам, определяемых пользователем (например, оповещение, когда количество ошибок в минуту превышает определённый порог). diff --git a/content/ru/port-binding.md b/content/ru/port-binding.md new file mode 100644 index 000000000..2bd64d0a3 --- /dev/null +++ b/content/ru/port-binding.md @@ -0,0 +1,14 @@ +## VII. Привязка портов (Port binding) +### Экспортируйте сервисы через привязку портов + +Иногда веб-приложения запускают внутри контейнера веб-сервера. Например, PHP-приложение может быть запущено как модуль внутри [Apache HTTPD](http://httpd.apache.org/), или Java-приложение может быть запущено внутри [Tomcat](http://tomcat.apache.org/). + +**Приложение двенадцати факторов является полностью самодостаточным** и не полагается на инъекцию веб-сервера во время выполнения для того, чтобы создать веб-сервис. Веб-приложение **экспортирует HTTP-сервис путём привязки к порту** и прослушивает запросы, поступающих на этот порт. + +Во время локальной разработки разработчик переходит по URL-адресу вида `http://localhost:5000/`, чтобы получить доступ к сервису, предоставляемым его приложением. При развёртывании слой маршрутизации обрабатывает запросы к общедоступному хосту и перенаправляет их к привязанному к порту веб приложению. + +Это обычно реализуется с помощью [объявления зависимости](./dependencies) для добавления библиотеки веб-сервера к приложению такой, как [Tornado](http://www.tornadoweb.org/) в Python, [Thin](http://code.macournoyer.com/thin/) в Ruby, и [Jetty](http://www.eclipse.org/jetty/) в Java и других языках на основе JVM. Это происходит полностью в *пространстве пользователя*, то есть в коде приложения. Контрактом со средой исполнения является привязка приложения к порту для обработки запросов. + +HTTP -- это не единственный сервис, который может быть экспортирован посредством привязки порта. Почти любой тип серверного ПО может быть запущен как процесс, привязанный к порту и ожидающий входящих запросов. Примеры этого включают [ejabberd](http://www.ejabberd.im/) (предоставляет [XMPP протокол](http://xmpp.org/)) и [Redis](http://redis.io/) (предоставляет [Redis протокол](http://redis.io/topics/protocol)). + +Также обратите внимание, что подход привязки к порту означает, что одно приложение может выступать [сторонней службой](./backing-services) для другого приложения путём предоставления URL-адреса стороннего приложения как идентификатор ресурса в конфигурации потребляющего приложения. diff --git a/content/ru/processes.md b/content/ru/processes.md new file mode 100644 index 000000000..605c79837 --- /dev/null +++ b/content/ru/processes.md @@ -0,0 +1,14 @@ +## VI. Процессы +### Запускайте приложение как один или несколько процессов, не сохраняющих внутреннее состояние (stateless) + +Приложение выполняется в среде выполнения как один или несколько *процессов*. + +В простейшем случае код является независимым скриптом, среда выполнения -- ноутбуком разработчика с установленной средой исполнения языка, а процесс запускается из командной строки (например, как `python my_script.py`). Другой крайний вариант -- это рабочее развёртывание сложного приложения, которое может использовать много [типов процессов, каждый из которых запущен в необходимом количестве экземпляров](./concurrency). + +**Процессы приложения двенадцати факторов не сохраняют внутреннее состояние (stateless) и [не имеют разделяемых данных (share-nothing)](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Любые данные, которые требуется сохранить, должны быть сохранены в хранящей состояние [сторонней службе](./backing-services), обычно, в базе данных. + +Память и файловая система процесса может быть использована в качестве временного кэша для одной транзакции. Например, загрузка, обработка и сохранение большого файла в базе данных. Приложение двенадцати факторов не предполагает, что что-либо закэшированное в памяти или на диске будет доступно следующим запросам или задачам -- с большим количеством разноплановых процессов высока вероятность, что следующий запрос будет обработан другим процессом. Даже с одним запущенным процессом перезапуск (вызванный развёртыванием, изменением конфигураций или переносом процесса на другое физическое устройство) приведёт к уничтожению всех локальных (памяти, файловой системы) состояний. + +Упаковщики ресурсов (asset) (например, [Jammit](http://documentcloud.github.com/jammit/) или [django-compressor](http://django-compressor.readthedocs.org/)) используют файловую систему как кэш для скомпилированных ресурсов. Приложение двенадцати факторов предпочитает делать данную компиляцию во время [этапа сборки](./build-release-run), например, как в [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html), а не во время выполнения. + +Некоторые веб-системы полагаются на ["липкие сессии"] (http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- то есть кэшируют данные пользовательских сессии в памяти процесса приложения и ожидают того, что последующие запросы того же пользователя будут перенаправлены к тому же процессу. Липкие сессии являются нарушением двенадцати факторов и их никогда не следует использовать или полагаться на них. Данные пользовательской сессии являются хорошими кандидатами для хранилища данных, которое предоставляет функцию ограничения времени хранения, например, [Memcached](http://memcached.org/) и [Redis](http://redis.io/). diff --git a/content/ru/toc.md b/content/ru/toc.md new file mode 100644 index 000000000..000928d58 --- /dev/null +++ b/content/ru/toc.md @@ -0,0 +1,38 @@ +Двенадцать факторов +================== + +## [I. Кодовая база](./codebase) +### Одна кодовая база, отслеживаемая в системе контроля версий, -- множество развёртываний + +## [II. Зависимости](./dependencies) +### Явно объявляйте и изолируйте зависимости + +## [III. Конфигурация](./config) +### Сохраняйте конфигурацию в среде выполнения + +## [IV. Сторонние службы (Backing Services)](./backing-services) +### Считайте сторонние службы (backing services) подключаемыми ресурсами + +## [V. Сборка, релиз, выполнение](./build-release-run) +### Строго разделяйте стадии сборки и выполнения + +## [VI. Процессы](./processes) +### Запускайте приложение как один или несколько процессов не сохраняющих внутреннее состояние (stateless) + +## [VII. Привязка портов (Port binding)](./port-binding) +### Экспортируйте сервисы через привязку портов + +## [VIII. Параллелизм](./concurrency) +### Масштабируйте приложение с помощью процессов + +## [IX. Утилизируемость (Disposability)](./disposability) +### Максимизируйте надёжность с помощью быстрого запуска и корректного завершения работы + +## [X. Паритет разработки/работы приложения](./dev-prod-parity) +### Держите окружения разработки, промежуточного развёртывания (staging) и рабочего развёртывания (production) максимально похожими + +## [XI. Журналирование (Logs)](./logs) +### Рассматривайте журнал как поток событий + +## [XII. Задачи администрирования](./admin-processes) +### Выполняйте задачи администрирования/управления с помощью разовых процессов diff --git a/content/ru/who.md b/content/ru/who.md new file mode 100644 index 000000000..a11e3803b --- /dev/null +++ b/content/ru/who.md @@ -0,0 +1,4 @@ +Кому следует читать этот документ? +============================== + +Разработчикам, которые создают SaaS-приложения. Ops инженерам, выполняющим развёртывание и управление такими приложениями. diff --git a/content/sk/admin-processes.md b/content/sk/admin-processes.md new file mode 100644 index 000000000..21339f33e --- /dev/null +++ b/content/sk/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Admin procesy +### Spúštanie administrátorských/správcovských úloh ako jednorazových procesov + +[Process formation](./concurrency) je sada procesov, ktoré tvoria bežnú prevádzku aplikácie (napríklad odpovedanie na požiadavky). Na rozdiel od toho, vývojári často chcú spraviť jednorazové administratívne alebo údržbové úlohy, ako napríklad: + +* Spustenie databázovej migrácie (e.g. `manage.py migrate` v Django, `rake db:migrate` v Rails). +* Spustenie konzoly (alebo tiež [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) aby mohli spúštať ľubovoľný kód alebo skúmať modely aplikácie voči živej databáze. Väčšina jazykov poskytuje REPL spustením interpretra bez argumentov (napr. `python` alebo `perl`) v niektorých prípadoch majú samostatný príkaz (napr. `irb` pre Ruby, `rails console` pre Rails). +* Spustenie jednorazových skriptov uložených v repozitári aplikácie (napr.. `php scripts/fix_bad_records.php`). + +Jednorazové administračné procesy by sa mali spúštať v identickom prostredí ako bežné dlho [bežiace procesy](./processes) aplikácie. Bežia voči [releasu](./build-release-run), použitím rovnakého [kódu](./codebase) a [konfigurácie](./config) ako ostatné procesy bežiace v rámci releasu. Administračný kód sa musí dodať spolu s kódom aplikácie, aby sa zamedzilo synchronizačným problémom. + +Rovnaká technika [izolácie závislostí](./dependencies) by sa mala použiť pre všetky typy procesov. Napríklad, ak Ruby webový proces používa príkaz `bundle exec thin start`, potom databázová migrácia by mala používať `bundle exec rake db:migrate`. A podobne Python program používajúci Virtualenv by mal používať `bin/python` rovnako na spúšťania Tornado webservera aj všetkých `manage.py` administračných procesov. + +Dvanásť faktorová aplikácia silne preferuje jazyky, ktoré poskytujú REPL shell už v základe, a ktoré jednoducho umožňujú spúštanie jednorazových skriptov. Vývojári na lokálnom nasadení spúšťajú jednorazové administračné procesy priamym shell príkazom v priečinku aplikácie. V produkčnom nasadení môžu vývojári použiť ssh alebo iný spôsob vzdialeného spúšťania príkazov, ktorý poskytuje dané exekučné prostredie na spustenie takého procesu. diff --git a/content/sk/background.md b/content/sk/background.md new file mode 100644 index 000000000..9be3f1677 --- /dev/null +++ b/content/sk/background.md @@ -0,0 +1,9 @@ +Background +========== + +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. + +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. + +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*. + diff --git a/content/sk/backing-services.md b/content/sk/backing-services.md new file mode 100644 index 000000000..70acf4144 --- /dev/null +++ b/content/sk/backing-services.md @@ -0,0 +1,14 @@ +## IV. Podporné služby +### Spravovanie podporných služieb ako pripojených zdrojov + +*Podporná služba* je akákoľvek služba, ktorú aplikácia konzumuje cez sieť ako súčasť je normálneho behu. Príklady zahŕňajú databázy (ako napr. [MySQL](http://dev.mysql.com/) alebo [CouchDB](http://couchdb.apache.org/)), messaging/queueing systémy (napr. [RabbitMQ](http://www.rabbitmq.com/) alebo [Beanstalkd](https://beanstalkd.github.io)), SMTP služby pre odchádzajúce emaily (napr. [Postfix](http://www.postfix.org/)), a cachovacie systémy (napr. [Memcached](http://memcached.org/)). + +Podporné služby ako databázy sú tradične spravované tými istými systémovými administrátormi ako nasadenia aplikácie. Popri lokálne spravovaných službách, može mať aplikácia služby spravované tretími stranami. Príklady zahŕňajú SMTP služby (napr. [Postmark](http://postmarkapp.com/)), služby na zbieranie metrík (napr. [New Relic](http://newrelic.com/) alebo [Loggly](http://www.loggly.com/)), úložiskové služby (napr. [Amazon S3](http://aws.amazon.com/s3/)), alebo dokonca služby prístupné cez API (napr. [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), alebo [Last.fm](http://www.last.fm/api)). + +**Kód v dvanásť faktorovej aplikácii nerozlišuje medzi službou lokálnou a od tretej strany.** Pre aplikáciu sú obidve pripojené zdroje, prístupné cez URL alebo iné prístupové/prihlasovacie údaje uložené v [konfigurácii](./config). [Nasadenie](./codebase) dvanásť faktorovej aplikácie by malo byť schopné vymeniť lokálnu MySQL databázu s databázou spravovanou treťou stranou (napr. [Amazon RDS](http://aws.amazon.com/rds/)) bez akýchkoľvek zmien v kóde aplikácie. Podobne, lokálny SMTP server môže by vymenený SMTP službou od tretej strany (napr. Postmark) bez zmeny v kóde. V obidvoch prípado sa zmenia len prístupové a prihlasovacie údaje v konfigurácii. + +Každá podporná služba je osobitným *zdrojom*. Napríklad, MySQL databáza je zdroj; dve MySQL databázy (používané na sharding na úrovni aplikácie) sú dva rôzne zdroje. Dvanásť faktorová aplikácie považuje tieto databázy ako *pripojené zdroje*, čo znamená ich voľné spojenie so súvisiacim nasadením. + +Produkčné nasadenie pripojené ku štyrom podporným službám. + +Zdroje je možné pripájať a odpájať od nasedení podľa ľubovôle. Napríklad, ak je databáza z dôvodu hardvérových problémov nestabilná, správca aplikácie môže rozbehnúť nový databázový server zo zálohy. Aktuálna produkčná databáza môže byť odpojená a nový databáza pripojená -- všetko bez zmien v kóde. diff --git a/content/sk/build-release-run.md b/content/sk/build-release-run.md new file mode 100644 index 000000000..897146c53 --- /dev/null +++ b/content/sk/build-release-run.md @@ -0,0 +1,19 @@ +## V. Build, release, run +### Jasne oddelené fázy build, release a run + +[Kód](./codebase) sa transformuje do (nevývojárskeho) nasadenia troma krokmi: + +* *Krok build* transformuje kód v repozitári na vykonateľný balík nazývaný *build*. Použitím verzie kódu v čase commitu špecifikovaného nasadzovacím procesom, krok build stiahne [závislosti](./dependencies) a skompiluje binárky a assets. +* *Krok release* zoberie build vytvorený predchádzajúcim krokom a skombinuje ho s aktuálnou [konfiguráciou](./config) pre dané nasadenie. Výsledok *release* obsahuje build a konfiguráciu pripravené na okamžité vykonanie v exekučnom prostredí. +* *Krok run* (alebo "runtime") spustí aplikáciu v exekučnom prostredí naštartovaním aplikačných [procesov](./processes) voči danému release. + +![Kód sa stane buildom, ktorý sa skombinuje s konfiguráciou a vytvorí sa release.](/images/release.png) + +**Dvanásť faktorová aplikácia striktne oddeľuje fázy build, release a run.** Napríklad: je nemožné spraviť zmeny v kóde počas jeho behu, keďže neexistuje spôsob, ako by sa tieto zmeny dostali späť do fázy build. + +Nástroje na nasadzovanie zvyčajne ponúkajú spôsoby na správu release, hlavne teda možnosť vrátiť sa na predchádzajúci release. Napríklad [Capistrano](https://github.com/capistrano/capistrano/wiki) si ukladá release v podpriečinku s názvom `releases`, kde je aktuálny release symlink na priečinok s aktuálnym releasom. Tento príkaz `rollback` umožňuje jednoducho a rýchlo vrátiť sa na predchádzajúci release. + +Každý release by mal vždy mať unikátne release ID, ako napríklad timestamp release (napríklad `2019-04-06-20:32:17`) alebo inkrementálne číslo (napr. `v100`). Releasy sú záznamy, ktoré iba pribúdajú a release sa nedá zmeniť potom jeho vytvorení. Každá zmenu musí vytvoriť nový release. + +Buildy inicializujú developeri aplikácie kedykoľvek sa nasadzuje nový kód. Vykonávanie behu sa na rozdiel od buildov vykonáva automaticky v prípade reštartu servera, alebo pri reštarte padnutého procesu správcom procesov. Preto by fáza spustenia mala mať čo najmenej pohyblivých častí, keďže problémy, ktoré so spustením aplikácie môžu nastať v strede noci, keď developeri nie sú k dispozícii. Fáza build môže byť komplexnejšia, keďže chyby sú vždy viditeľné developerom, ktorí spustili nasadenie. + diff --git a/content/sk/codebase.md b/content/sk/codebase.md new file mode 100644 index 000000000..e4e911b35 --- /dev/null +++ b/content/sk/codebase.md @@ -0,0 +1,17 @@ +## I. Zdrojový kód +### Jeden zdrojový kód vo verzionovacom systéme, veľa nasadení + +Dvanásť faktorová aplikácia je vždy uložená vo verzionovacom systéme ako napríklad [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), alebo [Subversion](http://subversion.apache.org/). Kópia databázy verzionovacieho systému sa nazýva *repozitár kódu*, často skrátene *repozitár* alebo len *repo*. + +*Zdrojový kód* je akýkoľvek repozitár (v centralizovanom verzionovacom systéme ako napr. Subversion), alebo akákoľvek skupina repozitárov, ktoré majú spoločný koreňový commit (v decentralizovanm verzionovacom systéme ako napr. Git). + +![Jeden zdrojový kód má viacero nasadení](/images/codebase-deploys.png) + +Vždy existuje korelácia jedna k jednej medzi zdrojovým kódom a aplikáciou: + +* Ak je to viacero zdrojových kódov, nie je to aplikácia -- je to distribuovaný systém. Každý komponent v distribuovanom systéme je aplikácia, a každá môže osobitne spĺňať dvanásť faktorov. +* Viaceré aplikácie zdieľajúce jeden kód je porušenie dvanástich faktorov. Riešenie je oddelenie zdieľaného kódu do knižníc, ktoré sa pripoja pomocou [správy závislostí](./dependencies). + +Každá aplikácia má len jeden zdrojový kód, ale nasadení jednej aplikácie bude viacero. *Nasadenie* je bežiaca inštancia aplikácie. Typicky je to produkčný web a jeden alebo viacero testovacích webov. Navyše, každý developer má kópiu bežiacej aplikácie vo svojom vlastnom vývojovom prostredí, z ktorých každé sa ráta ako nasadenie. + +Zdrojový kód je rovnaký na všetkých nasadeniach, aj keď samozrejvie rôzne verzie môžu byť aktívne na rôznych nasadeniach. Napríklad, developer má niekoľko commitov, ktoré nie sú nasadené na testovacom prostredí a na testovacom prostredí sú commity, ktoré ešte nie sú na produkcii. Ale všetky zdieľajú jeden zdrojový kód a dá sa teda povedať, že sú rôznymi nasadeniami jednej aplikácie. diff --git a/content/sk/concurrency.md b/content/sk/concurrency.md new file mode 100644 index 000000000..d93c854e5 --- /dev/null +++ b/content/sk/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Concurrency +### Škálovanie pomocou modelu procesov + +Každý počítačový program je po spustení reprezentovaný jedným alebo viac procesmi. Webové aplikácie sa objavujú v rôznych formách vykonávania procesov. Napríklad, PHP procesy bežia ako podprocesy Apachu, spustené na požiadanie podľa objemu požiadaviek. Java procesy prevzali opačný prístup, kde JVM poskytuje jeden masívny nadproces, ktorý si vyhradí veľké množstvo systémových prostriedkov (CPU a pamäte) pri spustení a súbežnosť spravuje interne cez vlákna. V obidvoch prípadoch sú bežiace procesy len minimálne viditeľné pre developera aplikácie. + +![Škálovanie je vyjadrené bežiacimi procesmi, rôznorodosť funkcionality je vyjadrená typmi procesov.](/images/process-types.png) + +**V dvanásť faktorovej aplikácii sú procesy prvotriednymi obyvateľmi.** Procesy v dvanásť faktorovej aplikácii preberajú správanie z [modelu unix procesov pre démony služieb](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Použitím tohoto modelu, developer môže navrhnúť svoju aplikáciu tak, aby rôznu prácu vykonávali rôzne *typy procesov*. Napríklad, HTTP požiadavky môže spravovať webový proces, a dlho bežiace úlohy na pozadí môže spravovať worker proces. + +Toto nevylučuje, že si individuálne procesy nemôžu spravovať svoj interný multiplexing cez vlákna vnútri VM alebo interpretra, alebo async/event model v nástrojoch ako [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), alebo [Node.js](http://nodejs.org/). Keďže individuálne VM môže rásť len obmedzene (vertikálne škálovanie), aplikáciu musí byť tiež schopná sa rozšíriť na viacero procesov bežiacich na viacerých fyzických strojoch. + +Procesový model vyniká, keď príde čas rozširovania. [Nezdieľaná, horizontálne particionovateľná podstata procesov dvanásť faktorovej aplikácie](./processes) znamená, že pridanie väčšej súbežnosti je jednoduchá a spoľahlivá operácia. Súhrn typov procesov a počtu procesov každého typu sa nazýva *process formation*. + +Procesty dvanásť faktorovej aplikácie [by sa nikdy nemali démonizovať](http://dustin.github.com/2010/02/28/running-processes.html) alebo zapisovať PID súbory. Namiesto toho by sa mali spoliehať na manažéra procesov operačného systému (ako napr. [systemd](https://www.freedesktop.org/wiki/Software/systemd/), distribuovaného manažéra procesov na cloudovej platforme, alebo nástroji ako [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) počas vývoja) na spravovanie [výstupných streamov](./logs), reakcie na spadnuté procesy, a spravovanie userom iniciovaných reštartov a zastavení. diff --git a/content/sk/config.md b/content/sk/config.md new file mode 100644 index 000000000..02758b2b8 --- /dev/null +++ b/content/sk/config.md @@ -0,0 +1,22 @@ +## III. Konfigurácia +### Konfigurácia uložená v prostredí + +*Konfigurácia* aplikácie je všetko, čo sa líši medzi [nasadeniami](./codebase) (staging, produkcia, vývojárske prostredie, atď). To zahŕňa: + +* Pripojenia k databázam, Memcached a iným [podporným službám](./backing-services) +* Prihlasovacie údaje k externým službám ako Amazon S3 alebo Twitter +* Špeciálne hodnotu Per-nasadenie values such ako napríklad kanonické názvy hostov. + +Aplikácia si niekedy ukladá konštanty v kóde. Toto je porušenie dvanástich faktorov, ktoré vyžaduje **striktné oddelenie konfigurácie od kódu**. Konfigurácia sa medzi nasadeniami podstatne odlišuje, kód nie. + +Litmusovým testom správneho oddelenia konfigurácie, je to či by mohla byť v ktoromkoľvek momente open-sourcovaná bez úniku prihlasovacích údajov. + +Všimnite si, že definícia "konfigurácie" **nezahŕňa** internú konfiguráciu aplikácie, ako napríklad `config/routes.rb` v Rails, alebo [prepojenie modulov](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) v [Spring](http://spring.io/). Tento typ konfigurácie sa medzi nasadeniami nelíši, a preto je najlepšie ho nechať v kóde. + +Ďalšou možnosťou, ako pristupovať ku konfiguráciám je mať konfiguračné súbory, ktoré nie sú uložené v revíznom systéme, ako napríklad `config/database.yml` v Rails. Je to obrovské zlepšenie oproti konštantám uloženým v repozitári, ale stále má slabosť: je veľmi jednoduché omylom tento súbor uložiť do repozitára; je tendencia mať konfiguračné súbory na rôznych miestach a v rôznych formátoch, a preto je ťažké ich spravovať z jedného miesta. Navyše, tieto formáty zvyknú byť špecifické pre jazyk alebo framework. + +**Dvanásť faktorová aplikácia konfiguráciu ukladá v *premenných prostredia*** (často skrátané na *env vars* alebo *env*). Premenné prostredia sa dajú jednoducho meniť pri nasadeniach bez potreby zmeny v kóde; na rozdiel od konfiguračných súborov je minimálna šanca, že ich niekto omylom uloží do repozitára; a narozdiel od rôznych konfiguračných súborov, alebo iných konfiguračných mechanizmov ako napr. Java System Properties, premenné prostredia sú nezávislé na jazyku alebo OS. + +Ďalším pohľadom na správu konfigurácie je zoskupovanie. Niekedy aplikácie zoskupia konfigurácie do pomenovaných skupín (často nazývaných called "prostredia") a sú pomenované podľa jednotlivých typov nasadení, ako napríklad `development`, `test`, a `production` prostredia v Rails. Tento spôsob je náročné škálovať čistým spôsobom: ako pribúdajú ďalšie typy nasadení, je potrebné vytvárať nové názvy prostredí, ako napríklad `staging` alebo `qa`. Ako projekt ďalej rastie, developeri môžu pridávať ďalšie vlastné špeciálne prostredia ako `joes-staging`, a výsledkom je kombinatorická explózia konfiguračných prostredí a tým sa stáva spravovanie nasadení veľmi citlivé. + +V dvanásť faktorovej aplikácii sú premenné prostredia granulárne nastavenia, každé ortogonálne k inej premennej prostredia. Nikdy sa nezoskupujú spolu do pomenovaných "prostredí", ale namiesto toho sú nezávisle spravované pre každé nasadenie. Tento model sa plynule škáluje počas prirodzeného rastu aplikácie ako pribúdajú ďalšie typy nasadení. diff --git a/content/sk/dependencies.md b/content/sk/dependencies.md new file mode 100644 index 000000000..d019b44b0 --- /dev/null +++ b/content/sk/dependencies.md @@ -0,0 +1,12 @@ +## II. Závislosti +### Explicitne deklarované a izolované závislosti + +Väčšina programovacích jazykov poskytuje distribučný systém knižníc, napríklad [CPAN](http://www.cpan.org/) pre Perl alebo [Rubygems](http://rubygems.org/) pre Ruby. Knižnice nainštalované cez balíčkovací systém sa dajú nainštalovať pre celý systém (nazývané "site packages") alebo len v rámci priečinka s aplikáciou (nazýva sa "vendoring" alebo "bundling"). + +**Dvanásť faktorová aplikácia sa nikdy nespolieha na implicitnú existenciou systémových balíčkov.** Svoje závislosti deklaruje úplne a presne, pomocou *deklaráciu závislostí*. Ďalej používa nástroj na *izoláciu závislostí*, pre istotu, aby žiadne implicitné závislosti "nepretiekli" z vonkajšieho systému. Špecifikácia závislostí je úplná a explicitná a používa sa rovnako na produkcii tak aj pri vývoji. + +Napríklad, [Bundler](https://bundler.io/) pre Ruby poskytuje `Gemfile` manifest format na deklaráciu závislostí a `bundle exec` na izoláciu závislostí. V pythone sú na to dva rôzne nástroje -- [Pip](http://www.pip-installer.org/en/latest/) sa používa na deklaráciu a [Virtualenv](http://www.virtualenv.org/en/latest/) na izoláciu. Dokonca aj C má [Autoconf](http://www.gnu.org/s/autoconf/) na deklaráciu závislostí, a statické linkovanie poskytuje izoláciu závislostí. Nezáleží na nástrojoch, deklarácia závislostí a izolácia sa musia vždy používať spolu -- len jedno alebo druhé nestačí na splnenie dvanástich faktorov. + +Jednou z výhod explicitnej deklarácie závislosí je to, že zjednodušuje rozbehanie aplikácie pre nových developerov. Nový developer si len naklonuje repozitár aplikácie do svojho vývojárskeho prostredia a ako prerekvizity mu stačí mať nainštalovaný kompilátor jazyka a manažér závislostí. Všetko potrebné na rozbehanie aplikácie sa dotiahne deterministickým *build príkazom*. Napríklad, build príkaz pre Ruby/Bundler je `bundle install`, pre Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) je to `lein deps`. + +Dvanásť faktorová aplikácia nezávisí na implicitnej existencii akéhokoľvek systémového nástroja. Príkladom môže byť spustenie ImageMagick alebo `curl` cez shell. Napriek tomu, že tieto nástroje môžu existovať na veľa alebo aj väčšine systémov, neexistuje záruka, že budú existovať na všetkých systémoch, na ktorých bude aplikácia bežať v budúcnosti, alebo, že verzia na budúcom systéme bude kompatibilná s aplikáciou. Ak aplikácia potrebuje spúšťať systémový nástroj cez shell, daný nástroj by mal byť zahrnutý do aplikácie. diff --git a/content/sk/dev-prod-parity.md b/content/sk/dev-prod-parity.md new file mode 100644 index 000000000..f460e049d --- /dev/null +++ b/content/sk/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Dev/prod parity +### Vývojové, testovacie a produkčné prostredie sú čo najpodobnejšie ako sa dá + +Historicky bývali podstatné rozdiely medzi vývojovým prostredím (developer upravoval živé lokálne [nasadenie](./codebase)) a produkčným prostredím (bežiace nasadenie aplikácie, na ktoré pristupujú používatelia). Tieto rozdiely sa prejavujú v týchto troch oblastiach: + +* **Časový rozdiel:** Developer môže pracovať na kóde, ktorý trvá dni, týždne alebo dokonca mesiace pred tým ako sa dostane na produkciu. +* **Personálny rozdiel**: Developeri píšu kód, systémový administrátory ho nasadzujú. +* **Nástrojový rozdiel**: Developeri môžu používať Nginx, SQLite, a OS X, pričom na produkcii beží Apache, MySQL, a Linux. + +**Dvanásť faktorová aplikácia je navrhnutá pre [continuous deployment](http://avc.com/2011/02/continuous-deployment/) tak, že udržiava rozdiely medzi vývojom a produkciou.** Keď sa pozrieme na tri rozdiely popísané vyššie: + +* Zmenšite časový rozdiel: developer napíše kód a nasadí ho v priebehu hodín alebo dokonca minút. +* Zmenšite personálny rozdiel: developeri, ktorí kód píšu by mali byť prítomní pri nasadzovaní a sledovaní správania na produkcii. +* Zmenšite nástrojvý rozdiel: udržujte vývojové a produkčné prostredie nakoľko sa dá rovnaké. + +Súhrn vyššie napísaného v tabuľke: + + + + + + + + + + + + + + + + + + + + + + +
Tradičná aplikáciaDvanásť faktorová aplikácia
Čas medzi nasadeniamiTýždneHodiny
Autori kódu vs nasadzovači kóduRôzni ľudiaRovnakí ľudia
Vývojárske vs produkčné prostredieRozdielneČo najpodobnejšie
+ +[Podporné služby](./backing-services) ako napríklad databáza, fronty alebo cache sú oblasťou, kde je zhodnosť vývojárskeho-produkčného prostredia dôležitá. Veľa jazykov poskytuje knižnice, ktoré uľahčujú prístup k podporným službám, vrátane *adaptérov* k rôznym typom služieb. Niektoré príklady sú v tabuľke nižšie. + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypJazykKnižnicaAdapér
DatabázaRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
FrontaPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CachePamäť, súborový systém, Memcached
+ +Developeri niekedy radi používajú odľahčené podporné služby na lokálny vývoj, pričom na produkcii sú robustnejšie podporné služby. Napríklad používajú SQLite lokálne a PostgreSQL na produkcii; alebo pamäť lokálneho procesu počas vývoja a Memcached na produkcii. + +**Dvanásť faktorový vývojár odoláva nutkaniu používať rôzne podporné služby medzi vývojom a produkciou**, aj v prípade, že adaptéry teoreticky abstrahujú rozdiely medzi službami. Rozdiely medzi službami znamenajú, že sa vyskytnú maličné nekompatibility a spôsobia, že kód prejde cez testy pri vývoji alebo testovaní a zlyhá na produkcii. Tieto typy chýb vytvárajú trenie, ktoré spomaľuje priebežné nasadzovanie. Cena tohoto trenia a následné spomalenie priebežného nasadzovania je extrémne vysoká, keď ju sčítame cez celú životnosť aplikácie. + +Odľahčené lokálne služby už nie sú také príťažlivé ako boli. Moderné podporné služby ako Memcached, PostgreSQL a RabbitMQ nie je ťažké nainštalovať a spustiť vďaka moderným balíčkovacím systémom ako [Homebrew](http://mxcl.github.com/homebrew/) a [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Alternatívne deklaratívne nástroje ako [Chef](http://www.opscode.com/chef/) a [Puppet](http://docs.puppetlabs.com/) skombinované s odľahčenými virtuálnymi prostrediami ako [Docker](https://www.docker.com/) a [Vagrant](http://vagrantup.com/) umôžňujú vývojárom vytvoriť lokálne prostredie, ktoré tesne aproximuje produkčné prostredie. Cena inštalácie a používania týchto systémov je nízka v porovnaní s výhodami rovnakého prostredia vývoj/produkcia. + +Adaptéry k rôznym podporným službám sú stále užitočné, pretože umožňujú plynulú migráciu na nové podporné služby. Ale všetky nasadenia aplikácia (vývojárske prostredie, testovacie, produkcia) by mali používať rovnaký typ a verziu každej podpornej služby. diff --git a/content/sk/disposability.md b/content/sk/disposability.md new file mode 100644 index 000000000..d791c3cbc --- /dev/null +++ b/content/sk/disposability.md @@ -0,0 +1,14 @@ +## IX. Zahoditeľnosť +### Maximalizácia robustnosti rýchlym štartom a vhodným vypnutím + +**[Procesy](./processes) dvanásť faktorovej aplikácie sú *zahoditeľné*, čo znamená, že sa kedykoľvek dajú spustiť alebo zastaviť.** Umožňuje to elastické škálovanie, rýchly vývoj [kódu](./codebase) alebo zmeny v [konfigurácii](./config), a robustnosť produkčných nasadení. + +Procesy by sa mali snažiť **minimalizovať čas spustenia**. Ideálne, procesu zaberie len pár sekúnd od spustenia príkazu do kým je proces pripravený prijímať požiadavky alebo úlohy. Krátky čas spustenia poskytuje väčšiu agility pre [release](./build-release-run) proces a škálovanie; a pomáha tiež robustnosti, lebo manažér procesov, môže jednoduchšie presúvať procesy na nové fyzické stroje v prípade potreby. + +Procesy **sa vhodne vypnú po prijatí signálu [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** od správcu procesov. Pre webový proces, vhodné vypnutie znamená, že prestane počúvať na porte (teda začne odmietať nové požiadavky), aktuálne bežiace požiadaviek nechá dobehnúť a vypne sa. V tomto modeli predpokladáme, že HTTP požiadavky sú krátke (nie viac ako pár sekúnd). V prípade dlhotrvajúcich spojení by sa mal klient vedieť po strate spojenia znova pripojiť. + +Pre proces workera, je vhodné vypnutie dosiahnuté vrátením aktuálnej úlohy do pracovnej fronty. For a worker process, graceful shutdown is achieved by returning the current job to the work queue. Napríklad pri [RabbitMQ](http://www.rabbitmq.com/) worker môže poslať [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); pri [Beanstalkd](https://beanstalkd.github.io) sa úloha vrátiť do fronty keď sa worker odpojí. Systéme postavené na zamkýnaní, ako napr. [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) musia uvoľniť zamknutie pre záznam svojej úlohy. V tomto modeli predpokladáme, že všetky úlohy sú [opakovateľné](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), čo sa zvyčajne dosiahne obalením výsledkov do transakcie alebo spravením operácie [idempotentnou](http://en.wikipedia.org/wiki/Idempotence). + +Procesy by mali byť tiež **robustné proti náhlej smrti**, v prípade zlyhanie hardvéru. Aj keď je toto vyskytuje oveľa menej často ako vypnutie signálom `SIGTERM`, môže sa to stať. Odporúčaný prístup je použitie robustnej fronty, ako napr. Beanstalkd, ktorá vracia úlohy do fronty pri odpojení klienta alebo vypršaní časového limitu. V každom prípade, dvanásť faktorová aplikácia je navrhnutá, aby zvládla neočakávané, nevhodné ukončenia. [Crash-only design](http://lwn.net/Articles/191059/) tento koncept vedie k [logickým záverom](http://docs.couchdb.org/en/latest/intro/overview.html). + + diff --git a/content/sk/intro.md b/content/sk/intro.md new file mode 100644 index 000000000..2f0d0c655 --- /dev/null +++ b/content/sk/intro.md @@ -0,0 +1,12 @@ +Úvod +============ + +V modernej dobe sa zvyčajne softvér dodáva ako služba: nazýva sa *webová aplikácia*, alebo *software-as-a-service*. Dvanásť faktorová aplikácia je metodológia na budovanie software-as-a-service aplikácií, ktoré: + +* Používajú **deklaratívne** formáty na automatizáciu nastavení, a minimalizáciu času a nákladov pre nových developerov, ktorí sa začlenia do projektu; +* Obsahuje **jasnú zmluvu** s operačným systémom, nad ktorým bežia, čím umožňujú **maximálnu portabilitu** medzi rôznymi prostrediami; +* Sú vhodné na **nasadenie** na moderné **cloudové platformy**, čím vylučujú potrebu serverov a systémových administrátorov; +* **Minimalizujú rozdiely** medzi vývojom a produkciou, čím umôžňujú **continuous deployment** s maximálnou agilnosťou; +* A sú **škálovateľné** bez významných zmien v nástrojoch, architektúre alebo vývojárskych postupoch. + +Dvanásť faktorová metodológia sa dá použiť na aplikácie písané v akomkoľvek programovacom jazyku, ktoré používajú akúkoľvek kombináciu podporných služieb (databáza, fronta, pamäťová cache, atď). diff --git a/content/sk/logs.md b/content/sk/logs.md new file mode 100644 index 000000000..2d98128d1 --- /dev/null +++ b/content/sk/logs.md @@ -0,0 +1,16 @@ +## XI. Logs +### Logy sú prúdy udalostí + +*Logy* poskytujú náhľad do správania sa bežiacej aplikácie. V prostredí serverov sa zvyčajne zapisujú do súboru na disk (tzv. "logfile"); ale toto je len výstupný formát. + +Logy sú [prúd](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) agregovaných, časovo zoradených udalostí pozbierané z výstupných prúdov všetkých bežiacich procesov a podporných služieb. Logy sú vo svojej surovej forme zvyčajne v textovom formáte s jednou udalosťou na riadok (thougaj keď výpisy výnimiek môžu zaberať viac riadkov). Logy nemajú pevný začiatok ani koniec, ale plynule prúdia počas behu aplikácie. + +**Dvanásť faktorová aplikácia sa nikdy nestará o routovanie alebo ukladanie svojho výstupného prúdu.** Nemala by sa pokúšať zapisovať alebo spravovať logsúbory. Namiesto toho každý bežiaci proces zapisuje svoje udalosti nebufferované do `stdout`. Počas lokálneho vývoja vývojár vidí tento prúd udalostí vo svojom termináli a sleduje správanie aplikácie. + +V testovacom a produkčnom prostredí, sa prúd každého procesu zachytáva exekučné prostredie, spája s ostatnými prúdmi z aplikácie a presmeruje do cieľovej destinácie na prehliadanie a dlhodobejšie uloženie. Tieto destinácie nie sú konfigurovateľné aplikáciou, ale namiesto toho sú kompletne spravované exekučným prostredím. Open-sourcové smerovače logov (ako napr. [Logplex](https://github.com/heroku/logplex) a [Fluentd](https://github.com/fluent/fluentd)) sú vytvorené na tento účel. + +Prúd udalostí z aplikácie sa dá presmerovať do súboru, alebo sledovať priamo v termináli. Čo je ešte dôležitejšie je, že tento prúd sa dá poslať do systému na indexovanie a analýzu logov ako napr. [Splunk](http://www.splunk.com/), alebo univerzálne uložiská ako [Hadoop/Hive](http://hive.apache.org/). Tieto systému sú mocné a flexibilné na skúmanie správania aplikácie v čase, vrátane: + +* Nájdenie špecifických udalostí v minulosti. +* Veľkoplošné grafovanie trendov (ako napr. počet požiadaviek za minútu). +* Aktívne upozorňovanie podľa zadaných pravidiel (napríklad keď množstvo chýb za minútu presiahne určitú hranicu). diff --git a/content/sk/port-binding.md b/content/sk/port-binding.md new file mode 100644 index 000000000..ac15abd15 --- /dev/null +++ b/content/sk/port-binding.md @@ -0,0 +1,15 @@ +## VII. Port binding +### Export služieb cez port binding + +Webové aplikácie sú niekedy vykonávané vnútri webserverového kontainera. Napríklad PHP aplikácie bežia ako modul vnútri [Apache HTTPD](http://httpd.apache.org/), alebo Java aplikácie môžu bežať vnútri [Tomcat](http://tomcat.apache.org/). + +**Dvanásť faktorová aplikácia je úplne sebestačn** a nespolieha sa na vsunutie webservera v exekučnom prostredí na to, aby vytvorila webovú službu. Webová aplikácia **exportuje HTTP ako službu bindovaním na port**, a počúvaním požiadaviek prichádzajúcich na daný port. + +V lokálnom vývojárskom prostredí developer pristupuje na službu exportovanú jeho aplikáciou cez URL napríklad `http://localhost:5000/`. Pri nasadení, smerovacia vrstva presmerúva požiadavky z verejnej domény na port web procesu. + +Toto sa typicky implementuje použitím [deklarácie závislostí](./dependencies) a pridá sa tak knižnica webservera do aplikácie. Napríklad [Tornado](http://www.tornadoweb.org/) pre Python, [Thin](http://code.macournoyer.com/thin/) pre Ruby, alebo [Jetty](http://www.eclipse.org/jetty/) pre Javu a iných jazykoch bežiacich na JVM. Deje sa to úplne v *používateľskom priestore*, takže v kóde aplikácie. Dohoda s exekučným prostredím je je bindovanie na port na ktorom bude obsluhovať požiadavky. + +HTTP nie je jediná služba, ktorú je možné exportovať bindovaním na port. Skoro každý serverový softvér môže bežať na otvorenom porte a čakať na prichádzajúce požiadavky. Príklady zahŕňajú [ejabberd](http://www.ejabberd.im/) (protokol [XMPP](http://xmpp.org/)), a [Redis](http://redis.io/) (protokol [Redis](http://redis.io/topics/protocol)). + +Všimnite si, že pripojenie na port znamená, že aplikácia sa môže stať [podpornou službou](./backing-services) pre inú aplikáciu, poskytnutím URL na podpornú službu ako zdroj v [configu](./config) pre konzumujúcu aplikáciu. + diff --git a/content/sk/processes.md b/content/sk/processes.md new file mode 100644 index 000000000..071498b51 --- /dev/null +++ b/content/sk/processes.md @@ -0,0 +1,14 @@ +## VI. Procesy +### Execute the app as one or more stateless processes + +Aplikácia sa vykonáva v exekučnom prostredí ako jeden alebo viac *procesov*. + +V najjednoduchšom prípade je kód jednoduchý skript, exekučné prostredie je laptop developera s nainštalovaným kompilátorom/interpretrom jazyka, a proces sa spúšta z príkazového riadka (napríklad, `python my_script.py`). Na druhej strane spektra, produkčné nasadenie sofistikovanej aplikácie môže mať viacero [typov procesov, inštancovaných do jedného alebo viacerých procesov](./concurrency). + +**Dvanásť faktorové procesy sú bezstavové a [share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Akékoľvek dáta, ktoré treba zachovať, musia byť uložené v stavovej [podpornej službe](./backing-services), typicky databáze. + +Priestor pamäte alebo súborového systému procesu sa môže použiť ako krátka cache pre jednu transakciu. Napríklad, stiahnutie veľkého súboru, práca nad ním a uloženie výsledkov operácie do databázy. Dvanásť faktorová aplikácia nikdy neočakáva, že by bolo čokoľvek nacachované v pamäti alebo na disku pre budúce požiadavky alebo úlohy -- je vysoká šanca, že pri viacerých bežiacich procesoch bude ďalšia požiadavka vykonaná iným procesom. Aj keď beží len jeden process, reštart (spustený nasadením kódu, zmenou konfigurácie, alebo exekučným prostredím premiestni proces na iné fyzické miesto) zvyčajne vymaže všetky lokálne (napr. pamäť a súborový systém) stavy. + +Balíčkovače ako napríklad [django-assetpackager](http://code.google.com/p/django-assetpackager/) používajú súborový systém ako cache na kompilované súbory. Dvanásť faktorová aplikácia preferuje túto kompiláciu počas [fázy build](/build-release-run). Balíčkovače [Jammit](http://documentcloud.github.com/jammit/) a [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html) sa dajú nakonfigurovať, tak, že zabalia súbory počas fázy build. + +Niektoré webové systémy sa spoliehajú na ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- teda cachovanie údajov o používateľskom sedení v pamäti procesu a očakávajú, že ďalšie požiadavky od daného návštevníka budú presmerované na ten istý proces. Sticky sessions sú porušením dvanástich faktorov a nemali by sa nikdy používať ani na ne spoliehať. Stav sedenia je dobrým kandidátom pre úložisko, ktoré poskytuje vypršanie po čase, ako napr. [Memcached](http://memcached.org/) alebo [Redis](http://redis.io/). diff --git a/content/sk/toc.md b/content/sk/toc.md new file mode 100644 index 000000000..4b84ea62d --- /dev/null +++ b/content/sk/toc.md @@ -0,0 +1,38 @@ +The Twelve Factors +================== + +## [I. Zdrojový kód](./codebase) +### Jeden zdrojový kód vo verzionovacom systéme, veľa nasadení + +## [II. Závislosti](./dependencies) +### Explicitne deklarované a izolované závislosti + +## [III. Konfigurácia](./config) +### Konfigurácia uložená v prostredí + +## [IV. Podporné služby](./backing-services) +### Podporné služby sú pripojené zdroje + +## [V. Build, release, run](./build-release-run) +### Jasne oddelené fázy budovania, vydani a behu + +## [VI. Procesy](./processes) +### Aplikácia sa vykonáva ako jeden alebo viac bezstavových procesov + +## [VII. Port binding](./port-binding) +### Export služieb cez porty + +## [VIII. Concurrency](./concurrency) +### Škálovanie pomocou modelu procesov + +## [IX. Disposability](./disposability) +### Maximalizácia robustnosti rýchlym štartom a vhodným vypnutím + +## [X. Dev/prod parity](./dev-prod-parity) +### Vývojové, testovacie a produkčné prostredie sú čo najpodobnejšie ako sa dá + +## [XI. Logy](./logs) +### Logy sú prúdy udalostí + +## [XII. Admin procesy](./admin-processes) +### Spúštanie administrátorských/správcovských úloh ako jednorazových procesov diff --git a/content/sk/who.md b/content/sk/who.md new file mode 100644 index 000000000..c6b834828 --- /dev/null +++ b/content/sk/who.md @@ -0,0 +1,4 @@ +Kto by si mal prečítať tento dokument? +============================== + +Každý vývojár pracujúci na aplikácii, ktorá beží ako služba. Systémoví administrátori, ktorý také aplikácie nasadzujú. diff --git a/content/th/admin-processes.md b/content/th/admin-processes.md new file mode 100644 index 000000000..63a375d77 --- /dev/null +++ b/content/th/admin-processes.md @@ -0,0 +1,16 @@ +## XII. Admin processes +### รันงานของผู้ดูแลระบบ/การจัดการให้เป็นกระบวนการแบบครั้งเดียว + +[process formation](./concurrency) เป็นอาร์เรย์ของ process ที่ใช้ในการทำธุรกิจปรกติของ app (เช่นการจัดการ reqeust ของเว็บ) ขณะทำงาน developer มักต้องการทำการดูแลหรือบำรุงรักษาเพียงคนเดียวสำหรับ app เช่น: + +* รันการย้ายข้อมูลฐานข้อมูล (เช่น `manage.py migrate` ใน Django, `rake db:migrate` ใน Rails) +* รันคอนโซล (เป็นที่รู้จักในชื่อ [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) เพื่อรัน code แบบทันทีทันใดหรือตรวจสอบโมเดลของ app ที่ติดต่อกับฐานข้อมูลทันที ภาษาคอมพิวเตอร์ส่วนใหญ่มี REPL โดยการรัน interpreter โดยไม่ต้องมี argument ใดๆ (เช่น `python` หรือ `perl`) หรือในบางกรณีมีการแยกคำสั่ง (เช่น `irb` สำหรับ Ruby, `rails console` สำหรับ Rails) +* รันสคริปต์ครั้งเดียวที่ commit ไปที่ repo ของ app (เช่น `php scripts/fix_bad_records.php`) + +การดูแล process ครั้งเดียวควรจะทำงานในสภาพแวดล้อมที่เหมือนกับทั้วไป [long-running processes](./processes) สำหรับ app ซึ่งทำงานกับ [release](./build-release-run) ใช้ [codebase](./codebase) and [การตั้งค่า](./config) เดียวกันกับ process ใดๆที่ทำงานกับ release ผู้ดูแลระบบของ code จำเป็นต้อง ship ด้วย application code เพื่อหลีกเลี่ยงปัญหาการประสาน (synchronization) + +เทคนิค [dependency isolation](./dependencies) เดียวกันควรจะใช้กับชนิดของ process ทั้งหมด ตัวอย่างเช่น ถ้า Ruby web process ใช้คำสั่ง `bundle exec thin start` ดังนั้นการย้ายข้อมูลฐานข้อมูลควรจะใช้คำสั่ง `bundle exec rake db:migrate` ในทำนองเดียวกันกับ Python program ใช้ Virtualenv ควรจะใช้คำสั่ง `bin/python` สำหรับทำงานทั้ง Tornado webserver และการดูแลระบบ process `manage.py` ใดๆ + +Twelve-factor ชื่นชอบภาษาคอมพิวเตอร์ที่มี PERL shell out of the box เป็นอย่างมาก และซึ่งทำให้ง่ายสำหรับรันสคริปต์ครั้งเดียว ใน local deploy, developer ใช้กระบวนการดูแลระบบครั้งเดียวโดยใช้คำสั่ง shell ข้างใน app ใน production deploy, developer สามารถใช้ ssh หรือคำสั่งรีโมทอื่นที่กลไกกำทำงานโดยสภาพแวดล้อมการดำเนินงานของ deploy เพื่อรัน process + + diff --git a/content/th/background.md b/content/th/background.md new file mode 100644 index 000000000..fc4e1744c --- /dev/null +++ b/content/th/background.md @@ -0,0 +1,10 @@ +ประวัติ +========== + +ผู้มีส่วนร่วมของเอกสารนี้ได้มีส่วนเกี่ยวข้องโดยตรงกับการพัฒนาและการใช้งานแอพพลิเคชันจำนวนมาก และเกี่ยวข้องทางอ้อมสำหรับการพัฒนา การดำเนินงาน และการขยายขนาดของแอพพลิเคชันจำนวมมหาศาลผ่านงานของเราที่แพลตฟอร์ม Heroku + +เอกสารนี้สังเคราะห์จากประสบการณ์และการสังเกตทั้งหมดของพวกเราบนแอพพลิเคชัน software-as-a-service ที่หลากหลายจำนวนมาก เป็นสามเหลียมของแนวทางปฏิบัตในอุดมคติสำหรับการพัฒนาแอพพลิเคชัน ให้ความสนใจเป็นพิเศษกับพลวัตของการเจริญเติบโตของแอพพลิเคชันในช่วงเวลาหนึ่ง พลวัตของการมีส่วนร่วมระหว่างนักพัฒนาที่ทำงานกับ codebase ของแอพพลิเคชัน และหลีกเลี่ยงการใช้จ่ายของซอฟต์แวร์. + +แรงจูงใจของเราเพื่อสร้างความตระหนักของปัญหาระบบบางอย่างที่เราเห็นในการพัฒนาแอพพลิเคชันสมัยใหม่ เพื่อให้คำศัพย์ที่ใช้ร่วมกันสำหรับการพูดคุยเกี่ยวกับปัญหาเหล่านี้ และนำเสนอแนวทางแก้ไขแนวกว้างสำหรับปัญหาเหล่านี้พร้อมกับคำศัพท์ที่ใช้ประกอบกัน รูปแบบนี้ได้รับแรงบันดาลใจจากหนังสือของ Martin Fowler *Patterns of Enterprise Application Architecture* และ *Refactoring*. + + diff --git a/content/th/backing-services.md b/content/th/backing-services.md new file mode 100644 index 000000000..4e32cb5a3 --- /dev/null +++ b/content/th/backing-services.md @@ -0,0 +1,14 @@ +## IV. Backing services +### จัดการกับบริการสนับสนุน (backing service) ให้เป็นทรัพยากรที่แนบมา + +*บริการสนับสนุน (backing service)** เป็นบริการใดๆ ที่ app ใช้บริการผ่านระบบเครือข่ายซึ่งเป็นส่วนหนึ่งของการดำเนินงาน (operation) ตัวอย่างเช่น รวมที่เก็บข้อมูล (datastore) (เช่น [MySQL](http://dev.mysql.com/) หรือ [CouchDB](http://couchdb.apache.org/)), ระบบ messaging/queueing (เช่น [RabbitMQ](http://www.rabbitmq.com/) หรือ [Beanstalkd](https://beanstalkd.github.io)), บริการ SMTP สำหรับส่งอีเมล์ออก (เช่น [Postfix](http://www.postfix.org/)), และระบบ caching (เช่น [Memcached](http://memcached.org/)) + +บริการสนับสนุนอย่างเช่นฐานข้อมูลเป็นการจัดการแบบดั่งเดิมด้วยผู้จัการระบบเดียวกันกับ app ที่ทำงานหลังจาก deploy เพิ่มเติมจากบริการจัดการภายใน, app อาจจะมีบริการที่ให้บริการและจัดการโดยบริการภายนอก (third parties) ตัวอย่างเช่น รวมบริการ SMTP (เช่น [Postmark](http://postmarkapp.com/)), บริการ metrics-gathering (เช่น [New Relic](http://newrelic.com/) หรือ [Loggly](http://www.loggly.com/)), บริการ binary asset (เช่น [Amazon S3](http://aws.amazon.com/s3/)), และแม้แต่บริการ API-accessible consumer (เช่น [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), หรือ [Last.fm](http://www.last.fm/api)). + +**code สำหรับ twelve-factor app จะไม่มีความแตกต่างระหว่างบริการภายใน (local) และบริการภายนอก (third party)** ใน app ทั้งสองบริการจะเป็นทรัพยากรที่แนบอยู่ใน app และเข้าถึงได้ด้วย URL หรือที่เก็บ locator/credentials อื่นๆใน [การตั้งค่า](./config). [deploy](./codebase) ของ twelve-factor app ควรจะส่ามารถสลับสับเปลี่ยนฐานข้อมูล MySQL ใน app ด้วยบริการภายนอก (เช่น [Amazon RDS](http://aws.amazon.com/rds/)) โดยไม่ต้องเปลี่ยน code ของ app เหมือนกับ SMTP ภายใน app ควรสามารถสลับสับเปลี่ยนด้วยบริการ SMTP ภายนอกได้ (เช่น Postmark) โดยไม่ต้องเปลี่ยน code ในทั้งสองกรณีทรัพยากรจัดการด้วยการตั้งค่าที่จะต้องเปลี่ยนเท่านั้น + +สิ่งที่แตกต่างกันของบริการสนับสนุนคือ *ทรัพยากร* ตัวอย่างเช่น ฐานข้อมูล MySQL เป็นทรัพยากร; ฐานข้อมูล MySQL 2 ฐานข้อมูล (ใช้สำหรับ sharding ใน application layer) มีคุณสมบัติเป็นทรัพยากรที่แตกต่างกัน 2 แหล่ง, twelve-factor app จักการฐานข้อมูลเป็น *ทรัพยากรแนบ (attached resouces)* ซึ่งเป็นการระบุ loose coupling กับ deploy ที่ทรัพยากรเหล่านี้แนบใช้งาน + +A production deploy attached to four backing services. + +ทรัพยากรสามารถแนบและถอดออกจาก deploy ได้ ตัวอย่างเช่น ถ้าฐานข้อมูลของ app ทำงานผิดปรกติเนื่องจากปัญหาของฮาร์ดแวร์ ผู้ดูแลระบบของ app อาจจะ spin up เซิร์ฟเวอร์ฐานข้อมูลขึ้นมาใหม่จากการข้อมูลที่สำรองล่าสุด ฐานข้อมูลของ production ปัจจุบันควรจะถอดออกและแนบด้วยฐานข้อมูลใหม่ -- ทั้งหมดนี้ไม่มีการเปลี่ยนแปลง code diff --git a/content/th/build-release-run.md b/content/th/build-release-run.md new file mode 100644 index 000000000..04366e58b --- /dev/null +++ b/content/th/build-release-run.md @@ -0,0 +1,19 @@ +## V. Build, release, run +### แยกขั้นตอนของการ build และ run อย่างเคร่งครัด + +[codebase](./codebase) จะเปลี่ยนแปลงไปเป็น (non-development) deploy ด้วย 3 ขั้นตอน: + +* *ขั้นตอนการ build* เป็นการแปลงซึ่งเป็นการเปลี่ยน code repo ไปเป็นโปรแกรมที่ทำงานได้ (executable bundle) เรียกว่าการ *build* ใช้ version ของ code ที่ระบุ commit ด้วยกระบวนการ deployment ซึ่งขั้นตอนการ build นี้จะดึง[การอ้างอิง](./dependencies) และ compile เป็น binariy และ assets. +* *ขั้นตอนการ release* จะนำ build ที่ได้จากขั้นตอนการ build และรวามเข้ากับ [การตั้งค่า](./config) ของ deploy ซึ่งจะได้ *release* ที่มีทั้ง build และ การตั้งค่า ที่พร้อมจะทำงานได้ในสิ่งแวดล้อมการทำงาน +* *ขั้นตอนการ run* (หรือเรียกว่า "runtime") เป็นการทำให้ app ทำงานในสิ่งแวดล้อมการทำงาน ด้วยการเริ่มใช้งานบางเซตของ app [processes](./processes) ด้วย release ที่ถูกเลือก + +![Code becomes a build, which is combined with config to create a release.](/images/release.png) + +**Twelve-factor app ใช้การแยกขั้นตอนการ build, release และ run ออกจากกันอย่างเคร่งครัด** ตัวอย่างเช่น เป็นไปไม่ได้ที่ทำการเปลี่ยนแปลงของ code ในขณะทำงาน เนื่องจากไม่มีวิธีใดในการเผยแพร่การเปลี่ยนแปลงกลับสู่สถานะ build + +เครื่องมื่อสำหรับ deployment โดยทั่วไปจะมีเครื่องมือจัดการการ release อยู่แล้ว และส่วนใหญ่จะมีความสามารถ roll back กลับสู่ release ก่อนหน้าได้ ตัวอย่างเช่น [Capistrano](https://github.com/capistrano/capistrano/wiki) เป็นเครื่องมือ deployment ที่เก็บการ release ในไดเรกทอรีย่อยชื่อว่า `releases` ที่ซึ่ง release ปัจจุบันเชื่อมโยงเข้ากับไดเรกทอรี release ปัจจุบัน สามารถใช้คำสั่ง `rollback` เพื่อทำให้มัน roll back กลับไปเป็น release ก่อนหน้าอย่างรวดเร็ว + +ทุกๆ release ควรจะมี release ID เฉพาะเสมอ เช่น timestamp ของ release (เช่น `2011-04-06-20:32:17`) หรือจำนวนนับที่เพิ่มขึ้น (เช่น `v100`), release เป็นบัญชีแยกประเภทที่เพิ่มขึ้นได้เท่านั้นและ release ไม่สามารถแก้ไขได้เมื่อถูกสร้างขึ้นแล้ว ทุกๆ การเปลี่ยนแปลงจำเป็นต้องสร้าง release ใหม่เสมอ + +การ build เริ่มต้นโดย developer ของ app เมื่อไรก็ตามที่ code ใหม่ถูก deploy, การทำงานในขณะทำงาน ในทางตรงกันข้าม สามารถเกิดขึ้นได้โดยอัตโนมัติในกรณีที่ server reboot หรือ crashed process ถูก restart โดย process manager ดังนั้นขั้นตอนการ run ถูกทำให้มีขั้นตอนน้อยที่สุดเท่าที่จะเป็นไปได้ เพื่อป้องกันปัญหา app สามารถหยุดการทำงานได้ในเวลาตอนกลางคืนเมื่อไม่มี developer อยู่ทำงาน ขั้นตอนการ build สามารถเป็นขั้นตอนที่ซับซ้อนได้ ในเมื่อ error จะแสดงต่อ developer ผู้ซึ่งทำการ deploy มัน + diff --git a/content/th/codebase.md b/content/th/codebase.md new file mode 100644 index 000000000..6888ce90c --- /dev/null +++ b/content/th/codebase.md @@ -0,0 +1,18 @@ +## I. Codebase +### มีเพียง codebase เดียวที่ติดตามด้วย version control, มีหลาย deploy + +Twelve-factor app สามารถติดตามได้เสมอด้วย version control เช่น [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), หรือ [Subversion](http://subversion.apache.org/) สำเนาของฐานข้อมูลติดตาม version เรียกว่า *code repository* หรือเรียกสั้นๆว่า *code repo* หรือเรียกเพียงแค่ *repo* + +*codebase* เป็น repo เดียวใดๆ (ในระบบ version control ที่มีศูนย์กลางอย่างเช่น Subversion) หรือเป็นเซตของ repo ซึ่งแบ่งปัน root commit (ในระบบ version control ที่ไม่มีศูนย์กลางอย่างเช่น Git) + +![One codebase maps to many deploys](/images/codebase-deploys.png) + +มีความสัมพันธ์แบบ หนี่ง-ต่อ-หนึ่ง เสมอ ระหว่าง codebase และ app: + +* ถ้ามีหลาย codebase, จะไม่เป็น app -- จะเป็นระบบกระจาย (distributed system) แต่ละคอมโพแนนท์ในระบบกระจายเป็น app, และแต่ล่ะคอมโพแนนท์จะปฏิบัติตาม twelve-factor +* ถ้ามีหลาย app ที่ใช้งาน code เดียวกันจะเป็นการละเมิด twelve-factor วิธีแก้ปัญหาในที่นี้คือเอา code ที่ใช้ร่วมกันทำเป็น libraries ซึ่งสามารถเข้ากับ factor [dependency manager](./dependencies) + +มีเพียงหนึ่ง codebase ต่อ app แต่มีหลาย deploy หรือการนำไปใช้งานของ app, หนึ่ง *deploy* จะรัน instance ของ app นี่เป็น production site และมีหนึ่งหรือมากว่า staging site เพิ่มเติม, developer ทุกคนจะมีสำเนาเดียวของ app ที่ทำงานอยู่บนสิ่งแวดล้อมพัฒนาในเครื่องของตนเอง ซึ่งจัดได้ว่าเป็น deploy ด้วยเช่นกัน + +Codebase จะเหมือนกันตลอดทั้ง deploy ทั้งหมด แม้ว่า version จะแตกต่างกันอาจจะทำงานในแต่ล่ะ deploy ตัวอย่างเช่น developer มีบาง commit ที่ยังไม่ได้ deploy ไปยัง staging ซึ่ง staging จะมีบาง commit ที่ยังไม่ได้ deploy ไปยัง production แต่ทั้งหมดจะใช้ codebase เดียวกัน ดังนั้นจะต้องทำให้ระบุตัวตนได้ว่าเป็น deploy ที่แตกต่างกันของ app เดียวกัน + diff --git a/content/th/concurrency.md b/content/th/concurrency.md new file mode 100644 index 000000000..2d616b786 --- /dev/null +++ b/content/th/concurrency.md @@ -0,0 +1,15 @@ +## VIII. Concurrency +### ขยายออกของแอพพลิเคชันด้วยรูปแบบ process + +โปรแกรมคอมพิวเตอร์ใดๆ เมื่อทำงานแล้วจะถูกแทนที่ด้วย 1 หรือมากกว่า process เว็บแอพมีหลายรูปแบบของ process-execution ตัวอย่างเช่น PHP process ทำงานเป็น process ลูกของ Apache, เริ่มต้นตามความต้องการตามปริมาณคำขอ, Java process มีวิธีที่ตรงกันข้ามซึ่ง JVM จะใช้หนึ่ง uberprocess ขนาดใหญ่ที่สงวนบล็อกขนาดใหญ่สำหรับทรัพยากรระบบ (CPU และหน่วยความจำ) ในตอนเริ่มต้น ซึ่งจัดการ concurrency ภายในด้วย thread ทั้งสองกรณี process ที่ทำงานเป็นส่วนที่มองเห็นน้อยมากสำหรับ developer ของ app + +![Scale is expressed as running processes, workload diversity is expressed as process types.](/images/process-types.png) + +**ใน twelve-factor app, process เป็นพลเมืองชั้นหนึ่ง** Process ใน twelve-factor app จะใช้คำแนะนำจาก [the unix process model for running service daemons](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/) การใช้รูปแบบนี้ developer สามารถออกแบบ app เพื่อจัดการกับ workload ที่หลากหลายโดยการกำหนดให้ work แต่ละชนิดเป็น *process type** ตัวอย่างเช่น HTTP request อาจจะจัดการด้วย web process และ long-running background tasks จัดการด้วย worker process + +ไม่รวม process ย่อยจากการจัดการ multiplexing ภายใน ด้วย thread ข้างใน runtim VM หรือ async/evnted model ที่พบในเครื่องมือเช่น [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/) หรือ [Node.js](http://nodejs.org/) แต่ VM แต่ละตัวสามารถเติบโตได้มากเท่านั้น (การขยายแนวตั้ง) ดังนั้น application จำเป็นต้องสามารถขยายเป็นหลาย process ทำงานบนหลายเครื่องได้ + +รูปแบบ process ดีมากเมือมากับ time to scale out [share-nothing, horizontally partitionable nature of twelve-factor app processes](./processes) หมายความว่าเพิ่ม concurrency ได้ง่ายและทำงานได้น่าเชื่อถือ อาเรย์ชนิดของ process และจำนวนของ process ของแต่ละชนิด รู้จักกันใน *process formation* + +Process ของ twelve-factor app [should never daemonize](http://dustin.github.com/2010/02/28/running-processes.html) หรือเขียนไฟล์ PID แต่จะขึ้นอยู่กับตัวจัดการ process ของระบบปฏิบัติการแทน (เช่น [systemd](https://www.freedesktop.org/wiki/Software/systemd/), ตัวจัดการ process กระจายบน cloud platform หรือเครื่องมือ อย่างเช่น [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) ใน development) เพื่อจัดการ [output streams](./logs) ตอบสนองต่อ process ที่ล้มเหลว และจัดการ user-initiated restarts และ shutdowns + diff --git a/content/th/config.md b/content/th/config.md new file mode 100644 index 000000000..d094dd929 --- /dev/null +++ b/content/th/config.md @@ -0,0 +1,22 @@ +## III. Config +### จัดเก็บการตั้งค่า (config) ไว้ในสิ่งแวดล้อมของระบบ + +*การตั้งค่า (config)* ของ app เป็นสิ่งที่เปลี่ยนแปลงระหว่าง [deploys](./codebase) (staging, production, developer environments เป็นต้น) รวมทั้ง: + +* ทรัพยากรที่จัดการกับฐานข้อมูล, Memcached, และ [backing services](./backing-services) อื่นๆ +* ข้อมูลประจำตัว (credentials) สำหรับบริการภายนอก อย่างเช่น Amazon S3 หรือ Twitter +* ค่า Pre-deploy อย่างเช่น canonical hostname สำหรับ deploy + +บางครั้ง app เก็บการตั้งค่าเป็นค่าคงทีใน code เป็นการละเมิด twelve-factor ซึ่งต้องการให้ **แยกการตั้งค่าออกจาก code อย่างสมบูรณ์** การตั้งค่าสามารถเปลี่ยนแปลงได้ตาม deploy ที่ไม่อยู่ใน code + +การทดสอบ litmus เพื่อดูว่า app มีการเอาการตั้งค่าทั้งหมดออกจาก code ถูกต้องหรือไม่ ทำให้ codebase สามารถ open source ได้ตลอดเวลา โดยไม่กระทบกับ credential ใดๆ + +โปรดทราบว่าการนิยามนี้ของ "การตั้งค่า" **ไม่**รวมการตั้งค่า internal application อย่างเช่น `config/routes.rb` ใน Rails หรือ [code modules เชื่อมต่อกันอย่างไร](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) ใน [Spring](http://spring.io/) ชนิดของการตั้งค่าเหล่านี้ไม่เปลี่ยนแปลงตาม deploy และควรจะอยู่ใน code + +อีกวิธีการหนึ่งของการตั้งค่าคือการใช้ไฟล์การตั้งค่าซึ่งไม่รวมไว้ใน revision control อย่างเช่น `config/database.yml` ใน Reals ซึ่งเป็นการพัฒนาสำหรับการใช้ค่าคงที่ซึ่งถูกรวมเข้าไปใน code repo แต่ก็ยังมีจุดอ่อนคือมันจะเกิดความผิดพลาดจากการที่รวมค่าการตั้งค่านี้เข้าไปใน repo จะทำให้มีแนวโน้มที่การไฟล์การตั้งค่าจะกระจายอยู่ในที่แตกต่างกันและแตกต่างรูปแบบ ทำให้มันยากที่จะดูแลและจัดการการตั้งค่าทั้งหมดในหนึ่งที่ นอกจากนี้รูปแบบเหล่านี้ยังขึ้นอยู่กับภาษาคอมพิวเตอร์ หรือ เฉพาะ framework. + +**Twelve-factor app เก็บการตั้งค่าไว้ใน *environment variable*** (เรียกสั้นๆ ว่า *env vars* หรือ *env*) Env vars จะทำให้ง่ายที่จะเปลี่ยนแปลงระหว่าง deloy โดยปราศจากการเปลี่ยนแปลงของ code ใดๆ ไม่เหมือนกับไฟล์การตั้งค่าที่จะมีโอการผิดพลาดที่จะรวมเข้าไปใน code repo ได้ และไม่เหมือนกับไฟล์การตั้งค่าที่กำหนดเองหรือกลไกการตั้งค่าอื่นๆ อย่างเช่น Java System Properties ที่เป็ของภาษาคอมพิวเตอร์ และมาตรฐานของระบบปฏิบัติการ (OS-agnostic) + +อีกแง่มุมของการจัดการการตั้งค่าคือการจัดกลุ่ม (Grouping) บางครั้งการตั้งค่า app แบบกลุ่ม (batch) ในชื่อของกลุ่ม (เรียกว่า "environment") หลังจาก deploy เฉพาะ อย่างเช่น `development`, `test` และ `production` environment ใน Rails วิธีการนี้ทำให้การขยายไม่เรียบร้อยทำให้มี deploy ของ app ถูกสร้างมากขึ้น, จำเป็นต้องตั้งชื่อของ environment ใหม่ อย่างเช่น `staging` หรือ `qa` เป็นตั้น เมื่อ project โตขึ้น developer อาจจะเพิ่ม environments เฉพาะของตัวเองขึ้นมา เช่น `joes-staging` ผมก็คือมีการตั้งค่าจำนวนมากเกินไปซึ่งทำให้จัดการ deploy ของ app ทำได้ยากมาก + +ใน twelve-factor app, env vars เป็นรากฐานการควบควมของแต่ล่ะ evn vars อื่นๆ ไม่เคยมีการจัดกลุ่มเป็น "environments" แต่จะจัดการแบบอิสระสำหรับแต่ล่ะ deploy แทน นี่เป็นรูปแบบที่การขยายทำได้อย่างราบรื่นของ app เป็นการขยายโดยธรรมชาติของ deploy มากขึ้นตลอดอายุการทำงานของ app. diff --git a/content/th/dependencies.md b/content/th/dependencies.md new file mode 100644 index 000000000..652695987 --- /dev/null +++ b/content/th/dependencies.md @@ -0,0 +1,12 @@ +## II. Dependencies +### มีการประกาศและแยกการอ้างอิง (dependency) ทั้งหมดอย่างชัดเจน + +ภาษาโปรแกรมส่วนใหญ่จะมีระบบ packaging สำหรับรองรับ library ต่างๆ อย่างเช่น [CPAN](http://www.cpan.org/) สำหรับ Perl หรือ [Rubygems](http://rubygems.org/) สำหรับ Ruby, Library จะถูกติดตั้งผ่านทางระบบ packaging สามารถติดตั้ง system-wide (เรียกว่า "site packages") หรือกำหนดขอบเขตเป็นไดเรกทรอรีที่มี app (เรียกว่า "vendoring" หรือ "bundling") + +**twelve-factor app ไม่ขึ้นอยู่กับ implicit existence of system-wide packages.** โดยประกาศการอ้างอิงทั้งหมด อย่างครบถ้วน และอย่างแน่นอน ด้วย *dependency declaration* manifest นอกจากนี้ใช้เครื่องมือ *dependency isolation* ระหว่างทำงานเพื่อให้แน่ใจว่าไม่มีการอ้างอิงแบบปริยาย "รั่ว (leak in)" จากระบบรอบๆ, รายละเอียดการอ้างอิงที่ครบถ้วนและชัดเจนใช้รูปแบบเดียวกันทั้ง production และ development + +ตัวอย่างเช่น [Bundler](https://bundler.io/) สำหรับ Ruby มีรูปบบ `Gemfile` manifest สำหรับประการการอ้างอิง และ `bundle exec` สำหรับแยกการอ้างอิง ใน Python มีเครื่องมือ 2 ตัวสำหรับแต่ละขั้นตอน -- [Pip](http://www.pip-installer.org/en/latest/) ใช้สำหรับประกาศอ้างอิง และ [Virtualenv](http://www.virtualenv.org/en/latest/) สำหรับแยกการอ้างอิง แม้อย่าง C มี [Autoconf](http://www.gnu.org/s/autoconf/) สำหรับประการการอ้างอิง และ static linking สามารถทำแยกการอ้างอิงได้ ไม่ว่าจะใช้เครื่องมืออะไรก็ตามแต่การประการศและแยกการอ้างอิงจำเป็นเสมอที่ใช้ร่วมกัน -- ถ้ามีเพียงหนึ่งหรืออื่นๆ ไม่เพียงพอที่ตรงตาม twelve-factor + +ประโยชน์อย่างหนึ่งของการประกาศการอ้างอิงที่ชัดเจนคือลดความยุ่งยากในการติดตั้งสำหรับ developer ใหม่สำหรับ app, developer ใหม่สามารถ check out codebase ของ app มายังเครื่องที่ใช้ development ต้องการเพียงแค่ติดตั้ง language runtime และ dependency manager เป็นข้อกำหนดเบื้องต้น พวกเขาจะสามามารถติดตั้งทุกสิ่งที่ต้องการเพื่อจะรัน code ของ app ด้วย *build command* ตัวอย่างเช่น ใช้ build command สำหรับ Ruby/Bundler คือ `bundle install` ขณะที่ Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) คือ `lein deps` + +Twelve-factor app ยังคงไม่ขึ้นอยู่กับเครื่องมือที่มีอยู่แล้ว ตัวอย่างเช่นใช้ shell out ไปยัง ImageMagick หรือ `curl` ขณะที่เครื่องมือเหล่านี้อาจจะมีอยู่บนระบบส่วนใหญ่แล้ว ซึ่งจะไม่รับประกันว่าจะมีอยู่บนเครื่องทั้งหมดซึ่ง app จะทำงานในอนาคต หรือ version ที่หาเจอในเครื่องที่จะไปทำงานในอนาคตจะเข้ากันได้กับ app ถ้า app จำเป็น shell out ใช้เครื่องมือของเครื่อง ที่เครื่องมืออาจจะ vendord ให้ app diff --git a/content/th/dev-prod-parity.md b/content/th/dev-prod-parity.md new file mode 100644 index 000000000..ef98f74c8 --- /dev/null +++ b/content/th/dev-prod-parity.md @@ -0,0 +1,78 @@ +## X. Dev/prod parity +### ทำให้ development, staging และ production ให้มีความใกล้เคียงกันที่สุด + +ในอดีต มีช่องว่างที่มากมายระหว่าง development (developer แก้ไข app ในเครื่องตัวเอง [deploy](./codebase)) และ production (deploy ที่ทำงานและใช้งานโดยผู้ใช้งานที่แท้จริง) ช่องว่างที่ชัดเจนมี 3 เรื่่อง: + +* **ช่องว่างของเวลา** developer จะทำงานบน code ที่ใช้เวลาเป็นวัน, เป็นอาทิตย์ หรือเป็นเดือนที่จะเอาขึ้นสู่ production +* **ช่องว่างของบุคคล** developer เขียน code แต่วิศวกร ops ทำการ deploy code +* **ช่องว่างของเครื่องมือ** developer อาจจะใช้ stack อย่างเช่น Nginx, SQLite และ OSX ขณะที่ production deploy ใช้ Apache, MySQL และ Linux + +**Twelve-factor app ถูกออกแบบสำหรับ [การ deployment อย่างต่อเนื่อง (continuous deployment)](http://avc.com/2011/02/continuous-deployment/) ด้วยการรักษาช่องว่างระหว่าง development และ production ให้แคบที่สุด** โดยพิจารณาจากช่องว่าง 3 เรื่องด้านบน: + +* ทำให้เวลาสั้นลง: developer อาจจะเขียน code และทำการ deploy ในเวลาเพียงชั่วโมงเดียวหรือเพียงไม่กี่นาทีหลังจากเขียน code เสร็จ +* ทำให้ช่องว่างบุคคลแคบลง: developer เป็นคนเขียน code และเป็นคนที่ deploy code เองและเป็นคนที่ดูใน production เอง +* ทำให้ช่องว่างเครื่องมือแคบลง: ทำให้ใช้เครื่องมือ developement และ production เหมือนกันมากที่สุดเท่าที่จะทำได้ + +สรุปข้างบนเป็นตาราง: + + + + + + + + + + + + + + + + + + + + + + +
Traditional appTwelve-factor app
เวลาระหว่าง deploysสัปดาห์ชั่วโมง
คนเขียน code vs คน deploy code คนละคนคนเดียวกัน
สภาพแวดล้อม Dev vs productionแตกต่างกันเหมือนกันมากที่สุด
+ +[Backing services](./backing-services) อย่างเช่น ฐานข้อมูลของ app, ระบบคิว, หรือ ระบบแคช เป็นสิ่งที่ dev/prod ควรมีควมคล้ายคลึงกันมากที่สุด หลายภาษามี library ซึ่งทำให้เข้าถึง backing service ได้ง่าย รวมทั้ง *adapter* กับบริการที่แตกต่างกัน ตัวอย่างบางส่วนในตารางนี้: + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeLanguageLibraryAdapters
DatabaseRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
QueuePython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
CacheRuby/RailsActiveSupport::CacheMemory, filesystem, Memcached
+ +Developer บางครั้งหาวิธีที่ใช้ backing service ง่ายๆ ในเครื่องตัวเอง ในขณะที่ backing service ใช้งานอย่างเคร่งครัดและแข็งแกร่งใน production ตัวอย่างเช่น ใช้ SQLite ในเครื่องพัฒนา และใช้ PostgreSQL ใน production หรือใช้ local process memory สำหรับแคชใน development และ Memcached ใน production + +**Twelve-factor developer ต่อต้านกำใช้งาน backing service ที่แตกต่างกันระหว่าง development และ production** แม้ว่าเมื่อใช้ adapter ในทางทฤษฎีแล้วไม่มีความแตกต่างกันใน backing service ความแตกต่างระหว่าง backing service หมายความว่าความไม่เข้ากันเพียงเล็กน้อยที่เป็นสาเหตุให้ code ทำงานได้และผ่านการทดสอบใน development หรือ staging แต่ไปทำงานผิดพลาดใน production ความผิดหลาดเหล่านี้สร้างความไม่ลงรอยกันกับการ delopyment อย่างต่อเนื่อง และราคาของความไม่ลงรอยกันนี้และความผันผวนตามมาของการ deployment อย่างต่อเนื่องสูงมากเมื่อพิจารณาตลอดอายุการทำงานของ application + +Lightweight local service ไม่น่าสนใจมากเหมือนเมื่อก่อน ด้วย backing service สมัยใหม่อย่างเช่น Memcached, PostgreSQL และ RabbitMQ ไม่มีความแตกต่างกันในการติดตั้งและทำงาน ต้องขอบคุณระบบ packaging สมัยใหม่ อย่างเช่น [Homebrew](http://mxcl.github.com/homebrew/) และ [apt-get](https://help.ubuntu.com/community/AptGet/Howto) อีกทางเลือกหนึ่ง เครืองมือจัดเตรียมที่เปิดเผยอย่างเช่น [Chef](http://www.opscode.com/chef/) และ [Puppet](http://docs.puppetlabs.com/) รวม light-weight สิ่งแวดล้อมเสมือนอย่างเช่น [Docker](https://www.docker.com/) และ [Vagrant](http://vagrantup.com/) ทำให้ developer รัน app ในสิ่งแวดล้องของเครื่องได้ใกล้เคียงกับสิ่งแวดล้อมของ production มากที่สุด และค่าใช้จ่ายของการติดตั้งและใช้งานระบบเหล่านี้ต่ำมากถ้าเทียบกับประโยชน์ที่ได้รับสำหรับความเท่าเทียมกันของ dev/prod และการ deployment ที่ต่อเนื่อง + +Adapter ไปยัง backing service ที่แตกต่างกันยังคงมีประโยชน์อยู่ เพราะว่าจะทำให้ port ไปใช้กับ backing service ใหม่ๆ ได้อย่างง่ายดาย แต่การ deploy ทั้งหมดของ app (developer environment, staging, production) ควรจะใช้ชนิดและเวอร์ชันที่เหมือนกันของแต่ล่ะ backing service. + + diff --git a/content/th/disposability.md b/content/th/disposability.md new file mode 100644 index 000000000..13a884dc9 --- /dev/null +++ b/content/th/disposability.md @@ -0,0 +1,13 @@ +## IX. Disposability +### เพิ่มความแข็งแกร่งด้วยการเริ่มต้นระบบอย่างรวดเร็วและปิดระบบอย่างนุ่มนวล + +**Process ของ twelve-factor app จะต้อง **disposable**, หมายความว่าสามารถเริ่มต้นหรือหยุดในขณะที่แจ้งให้ทราบล่วงหน้า** นี่ส่งเสริมให้ขนายยื่ดหยุ่นอย่างรวดเร็ว, deployment ของการเปลี่ยนแปลง [code](./codebase) หรือ [การตั้งค่า](./config) อย่างรวดเร็ว และแข็งแกร่งสำหรับ production deploy + +Process ควรจะมุ่งมั่นที่จะ **ลดเวลาเริ่มต้น** จะเป็นการดีถ้า process ใช้เวลาไม่กี่วินาทีจากคำสั่งเปิดใช้งานถูกประมวลผลจนกระทั่ง process ทำงานและพร้อมสำหรับรับ request หรือ job, การใช้เวลาเริ่มต้นที่สั้นนี้จะทำให้คล่องตัวสำหรับกระบวนการ [release](./build-release-run) และขยายออก และช่วยให้แข็งแกร่งเพราะเป็นการรับประกันว่าตัวจัดการ process สามารถย้าย process ไปยังเครื่องใหม่ได้ง่าย + +Process จะต้อง **ปิดระบบอย่างนุ่มนวลเมื่อรับสัญญาณ [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** จากตัวจัดการ process สำหรับ process ของเว็บ การปิดระบบอย่างอย่างนุ่มนวลสำเร็จได้ด้วยสิ้นสุดการเฝ้าดู service port (ปฏิเสธ request ที่เข้ามาใหม่) ประมวลผล request ที่รับเข้ามาแล้วให้เสร็จ และออกจากโปรแกรม โดยนัยในรูปแบบนี้คือ HTTP request จะสั้นมาก (ไม่มากไปกว่าสองสามวินาที) หรือในกรณีของการประมวลผลที่ยาวนาน, client ควรจะพยายามต่อเนื่องที่จะติดต่ออีกครั้งเมื่อการเชื่อมต่อขาดหายไป + +สำหรับ worker process การปิดระบบอย่างนุมนวลสำเร็จได้ด้วยการคืนงานที่ทำอยู่กลับให้ work queue ตัวอย่างเช่น บน [RabbitMQ](http://www.rabbitmq.com/) worker สามารถส่ง [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack), บน [Beanstalkd](https://beanstalkd.github.io) งานจะถูกส่งกลับไปยัง queue อัตโนมัติเมือใดก็ตามที่ worker ขาดการติดต่อ ระบบ Lock-based เช่น [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) จำเป็นต้องทำให้แน่ใจว่าปล่อยงานที่ลํอกไว้ออกให้หม โดยนัยในรูปแบบนี้งานทั้งหมดเป็น [reentrant](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29) ซึ่งโดยปรกติจะสำเร็จด้วยการห่อผลลัพธ์ใน transaction หรือสร้างตัวดำเนินงาน [idempotent](http://en.wikipedia.org/wiki/Idempotence) + +Process ควรจะ **ทนทานต่อการหยุดการทำงานอย่างฉับพลัน** ในกรณีนี้ความผิดพลาดที่เกิดขึ้นในฮาร์ดแวร์ ในขณะที่กรณีนี้เกิดขึ้นน้อยมากกว่าการปิดระบบอย่างนุ่มนวลด้วย `SIGTERM` มันก็ยังมีโอกาสเกิดขึ้นได้ วิธีที่แนะนำคือใช้ robust queueing backend อย่างเช่น Beanstalkd ที่จะส่งกลับงานไปยัง queue เมื่อ client ขาดการติดต่อหรือหมดเวลา ทั้งสองวิธี twelve-factor app จะถูกออกแบบให้จัดการกับสิ่งที่คาดไม่ถึง, มีการปิดที่ผิดปรกติ [Crash-only design](http://lwn.net/Articles/191059/) ใช้แนวคิดนี้กับ [logical conclusion](http://docs.couchdb.org/en/latest/intro/overview.html) + diff --git a/content/th/intro.md b/content/th/intro.md new file mode 100644 index 000000000..56e45ded9 --- /dev/null +++ b/content/th/intro.md @@ -0,0 +1,12 @@ +บทนำ +============ + +ในยุคสมัยใหม่ ซอฟต์แวร์ถูกส่งมอบทั่วไปเป็นบริการ: เรียกว่า *web apps*, หรือ *software-as-service*. twelve-factor app เป็นหลัการสำหรับสร้างแอพพลิเคชัน software-as-a-service ที่: + +* ใช้รูปแบบ **declarative** สำหรับติดตั้งระบบอัตโนมัต เพื่อลดเวลาและค่าใช้จ่ายสำหรับนักพัฒนาใหม่ที่เข้าร่วมกับโครงการ; +* มี **clean contract** กับระบบปฏิบัติการที่แอพพลิเคชันทำงานด้วย นำเสนอ **maximun portibility** ระหว่างสิ่งแวดล้อมที่ระบบทำงาน; +* เหมาะสมสำหรับ **deployment** บน **cloud platforms** สมัยใหม่, ลดความต้องการของเซิร์ฟเวอร์และผู้ดูแลระบบ; +* **Maximized divergence** ระหว่างการพัฒนาและการใช้งานจริง ด้วยการใช้ **continuous deployment** เพื่อเพิ่มความเร็วสูงสุด; +* และสามารถ **scale up** โดยปราศจากการเปลี่ยนแปลงของ เครื่องมือ สถาปัตยกรรม หรือแนวทางปฏิบัตของการพัฒนา + +หลักการ twelve-factor สามารถประยุกต์ใช้ได้กับแอพพลิเคชันที่เขียนด้วยภาษาใดๆ และซึ่งใช้ร่วมกับบริการสนับสนุนใดๆ (ฐานข้อมูล, คิว, หน่วยความจำเคช เป็นต้น). \ No newline at end of file diff --git a/content/th/logs.md b/content/th/logs.md new file mode 100644 index 000000000..dc866e0f8 --- /dev/null +++ b/content/th/logs.md @@ -0,0 +1,17 @@ +## XI. Logs +### จัดการ logs ให้เป็นแบบ event stream + +*Logs* จะทำให้เห็นได้ว่า app ทำงานอย่างไร ในสภาพแวดล้อม server-based โดยทั่วไปจะเขียนเป็นไฟล์บนดิสก์ (ใน "logfile") แต่นี่เป็นเพียง output format เท่านั้น + +Logs เป็น [stream](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) ของการรวบรวม, time-ordered events ที่รวมรวมจาก output stream ของ process ทั้งหมดที่ทำงานอยู่และ backing service, Log ในรูปแบบเดิมโดยปรกติเป็นรูปแบบข้อความด้วยหนึ่ง event ต่อบรรทัด (แม้กระทั้ง backtrace จาก exception ที่มีหลายบรรทัด) Log ไม่มีจุดเริ่มต้นหรือสิ้นสุดที่แน่นอน แต่มีการไหลอย่างต่อเนื่องตราบใดที่ app ทำงานอยู่ + +**Twelve-factor app ไม่เคยกังวลกับการกำหนดเส้นทางหรือการจัดเก็บสตรีมข้อมูลขาออก** ไม่ควรพยายามเขียนหรือจัดการ logfile แทนที่, แต่ล่ะ process ที่ทำงานจะเขียน event stream ไม่มีการบัฟเฟอร์ ด้วย `stdout` ในระหว่าง local development, developer จะดูสตรีมนี้ในเบื้องหลังของ terminal เพื่อสังเกตุพฤติกรรมของ app + +ใน staging หรือ production deploy แต่ละสตรีมของ process จะตรวจจับโดยสภาพแวดล้อมการดำเนินงาน รวบรวมเข้าด้วยกันกับสตรีมอื่นๆ จาก app และเชื่อมเส้นทางไปที่จุดหมายปลายทางสุดท้ายที่ใช้ดูและเก็บถาวรในระยะยาว จุดหมายที่เก็บถาวรเหล่านี้ไม่สามารถมองเห็นหรือกำหนดค่าโดย app และแทนจะได้รับการจัดการอย่างสมบูรณ์โดยสภาพแวดล้อมการดำเนินงาน, Open-source log routers (เช่น [Logplex](https://github.com/heroku/logplex) และ [Fluentd](https://github.com/fluent/fluentd)) มีไว้เพื่อการนี้ + +สตรีมเหตุการณ์สำหรับ app สามารถกำหนดเส้นทางไปที่ไฟล์ หรือดูได้ผ่านเรียลไทม์ใน terminal สตรีมสามารถส่งไป log indexing และระบบวิเคราะห์ เช่น [Splunk](http://www.splunk.com/) หรือ ระบบคลังข้อมูลทั่วไป เช่น [Hadoop/Hive](http://hive.apache.org/) ระบบเหล่านี้มีพลังมากและยืดหยุ่นในการตรวจสอบพฤติกรรมของ app ในช่วงเวลาหนึ่ง, รวมทั้ง: + +* ค้นหาเหตุการณ์เฉพาะที่ผ่านมา +* กราฟขนาดใหญ่สำหรับแสดงแนวโน้ม (เช่น จำนวน request ต่อนาที) +* การแจ้งเตือนแบบแอคทีฟตามการวิเคราะห์พฤติกรรมที่ผู้ใช้ระบุ (เช่น การแจ้งเตือนเมื่อจำนวน error ต่อนาทีเกินเกณฑ์ที่กำหนด) + diff --git a/content/th/port-binding.md b/content/th/port-binding.md new file mode 100644 index 000000000..967e82063 --- /dev/null +++ b/content/th/port-binding.md @@ -0,0 +1,12 @@ +## VII. Port binding +### นำออกบริการด้วยการเชื่อมโยง port + +เว็บแอพ (Web App) บางครั้งทำงานข้างใน webserver container. ตัวอย่างเช่น PHP app จะทำงานเป็นโมดูลข้างใน [Apache HTTPD](http://httpd.apache.org/) หรือ Java app จะทำงานข้างใน [Tomcat](http://tomcat.apache.org/) เป็นต้น + +**Twelve-factor app เป็น self-contained โดยสมบูรณ์** และไม่ขึ้นอยู่กับ runtime injection ของ webserver เข้ามายังสภาพแวดล้อมการดำเนินงานเพิ่อสร้าง web-facing service. เว็บแอพ **นำออก HTTP เป็นบริการโดยเชื่อมโยงกับ port** และคอยตรวจสอบ request ที่เข้ามาจาก port นั้น + +นี้เป็นการทำงานปรกติโดยใช้ [ประกาศการอ้างอิง](./dependencies) เพื่อเพิ่ม webserver library ของ app, เช่น [Tornado](http://www.tornadoweb.org/) สำหรับ Python, [Thin](http://code.macournoyer.com/thin/) สำหรับ Ruby หรือ [Jetty](http://www.eclipse.org/jetty/) สำหรับ Java และภาษา JVM-based อื่นๆ เกิดขึ้นใน *user space* นั้นคือภายใน code ของ app ซึ่งสัญญากับสภาพแวดล้อมการดำเนินงานที่เชื่อมโยงกับ port เพื่อบริการ request ที่เข้ามา + +HTTP ไม่เป็นเพียง service ที่สามารถนำออกโดยการเชื่อมโยง port, server software เกือบทุกชนิดสามารถทำงานผ่านการเชื่อมโยง process ไปยัง port และรอ request ที่เข้ามา, ตัวอย่างรวมทั้ง ejabberd](http://www.ejabberd.im/) (speaking [XMPP](http://xmpp.org/)), และ [Redis](http://redis.io/) (speaking the [Redis protocol](http://redis.io/topics/protocol)) + +หมายเหตุ, วิธีการเชื่อมโยง port หมายความว่า app จะกลายเป็น [backing service](./backing-services) สำหรับ app อื่นๆ โดยการให้ URL กับ backing app เป็นตัวจัดการทรัพยากรใน [การตั้งค่า](./config) สำหรับใช้งาน app diff --git a/content/th/processes.md b/content/th/processes.md new file mode 100644 index 000000000..85bee3cea --- /dev/null +++ b/content/th/processes.md @@ -0,0 +1,14 @@ +## VI. Processes +### รันแอพพลิเคชันเป็นหนึ่งหรือมากกว่าให้เป็น stateless processes + +App ทำงานในสภาพแวดล้อมการดำเนินงานด้วยหนึ่งหรือมากกว่า *processes* + +ในกรณีที่ง่ายที่สุดคือ code คือ stand-alone script, สภาพแวดล้อมการดำเนินงานคือเครื่องคอมพิวเตอร์อง developer ที่ติดตั้ง language runtime และวิธีการคือเปิด app ด้วยคำสั่ง (ตัวอย่างเช่น `python my_script.py`) ในอีกด้านหนึ่ง app ที่ซับซ้อนที่ deploy บน production ใช้หลาย [process types, instantiated into zero or more running processes](./concurrency) + +**Twelve-factor processes เป็น stateless และ [share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** ข้อมูลใดๆที่จำเป็นต้องเก็บแบบถาวรจำเป็นต้องเก็บไว้ใน stateful [backing service](./backing-services) โดยปรกติจะเป็นฐานข้อมูล + +พื้นที่หน่วยความจำหรือระบบไฟล์ของ process สามารถใช้เป็นช่วงสั้นๆ ได้, single-transaction cache. ตัวอย่างเช่น, การดาวน์โหลดไฟล์ขนาดใหญ่, ดำเนินงานกับไฟล์นั้น และเก็บผลลัพธ์ของการดำเนินงานไว้ในฐานข้อมูล twelve-factor app ไม่เคยสมมติว่ามีอะไรแคชในหน่วยความจำหรือบน disk จะพร้อมใช้งานใน request หรือ job ในอนาคต -- มีหลาย process ทำงานมีโอกาสสูงมากที่ในอนาคต request จะทำงานบน process ที่แตกต่างกัน แม้ว่าทำงาน process เดียว เมื่อมีการ restart (trigger โดย code deploy, config change หรือเปลี่ยนสภาพแวดล้อมการทำงาน) จะลบสภานะของ app ทั้งหมดอย่างสมบูรณ์ (เช่น หน่วยความจำ และระบบไฟล์) + +Asset packagers อย่างเช่น [django-assetpackager](http://code.google.com/p/django-assetpackager/) ใช้ระบบไฟล์เป็นแคชของการ compiled asset. Twelve-factor app ชอบที่จะทำ compiling เช่นนี้ในระหว่าง [ขั้นตอนการ build](/build-release-run) Asset packagers อย่างเช่น [Jammit](http://documentcloud.github.com/jammit/) และ [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html) สามารถตั้งค่าให้ pacakge asset ระหว่างขั้นตอนการ build ได้ + +บางระบบเว็บขึ้นอยู่กับ ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- นั้นคือ, ทำการแคชขอมูล user session ในหน่วยความจำของ app สำหรับดำเนินการในอนาคตจากผู้เยี่ยมชมเดียวกันที่เชื่อมโยงกับ process เดียวกัน, Sticky session เป็นการละเมิด twelve-factor และไม่ควรใช้หรือพึ่งพา, ข้อมูลสถานะ Session เป็นสิ่งที่เหมาะสมอย่างมากสำหรับที่เก็บข้อมูลที่มีการหมดเวลา (time-expireation) อย่างเช่น [Memcached](http://memcached.org/) หรือ [Redis](http://redis.io/) diff --git a/content/th/toc.md b/content/th/toc.md new file mode 100644 index 000000000..2e0fb2380 --- /dev/null +++ b/content/th/toc.md @@ -0,0 +1,38 @@ +The Twelve Factors +================== + +## [I. Codebase](./codebase) +### มีเพียง codebase เดียวที่ติดตามด้วย version control, มีหลาย deploy + +## [II. Dependencies](./dependencies) +### มีการประกาศและแยกการอ้างอิง (dependency) ทั้งหมดอย่างชัดเจน + +## [III. Config](./config) +### จัดเก็บการตั้งค่า (config) ไว้ในสิ่งแวดล้อมของระบบ + +## [IV. Backing services](./backing-services) +### จัดการกับบริการสนับสนุน (backing service) ให้เป็นทรัพยากรที่แนบมา + +## [V. Build, release, run](./build-release-run) +### แยกขั้นตอนของการ build และ run อย่างเคร่งครัด + +## [VI. Processes](./processes) +### รันแอพพลิเคชันเป็นหนึ่งหรือมากกว่าให้เป็น stateless processes + +## [VII. Port binding](./port-binding) +### นำออกบริการด้วยการเชื่อมโยง port + +## [VIII. Concurrency](./concurrency) +### ขยายออกของแอพพลิเคชันด้วยรูปแบบ process + +## [IX. Disposability](./disposability) +### เพิ่มความแข็งแกร่งด้วยการเริ่มต้นระบบอย่างรวดเร็วและปิดระบบอย่างนุ่มนวล + +## [X. Dev/prod parity](./dev-prod-parity) +### รักษา development, staging และ production ให้มีความใกล้เคียงกันที่สุด + +## [XI. Logs](./logs) +### จัดการ logs ให้เป็นแบบ event stream + +## [XII. Admin processes](./admin-processes) +### รันงานของผู้ดูแลระบบ/การจัดการให้เป็นกระบวนการแบบครั้งเดียว diff --git a/content/th/who.md b/content/th/who.md new file mode 100644 index 000000000..2f7d1fd66 --- /dev/null +++ b/content/th/who.md @@ -0,0 +1,4 @@ +ใครควรจะอ่านเอกสารนี้? +============================== + +นักพัฒนาที่สร้างแอพพลิเคชันซึ่งทำงานเป็นเซอร์วิซ (service) วิศวกรดำเนินงานผู้ซึ่งปรับใช้ (deploy) หรือจัดการแอพพลิเคชันดังกล่าว diff --git a/content/tr/admin-processes.md b/content/tr/admin-processes.md new file mode 100644 index 000000000..73f35724b --- /dev/null +++ b/content/tr/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Yönetim Süreçleri +### Yönetim görevlerini tek seferlik süreçler olarak çalıştırma + +[Süreç formasyonu](./concurrency) uygulama çalışırken uygulamanın sıradan işlerini (web isteklerini idare etmek gibi) yapmakta kullanılan süreçlerin bir dizisidir. Ayrı olarak, geliştiriciler çoğunlukla uygulamanın bir kereye mahsus yönetimsel veya bakım görevlerini yapmayı dileyecekler. Örneğin: + +* Veri modelindeki (İng. migrations) değişiklikleri veritabanına yansıtmak (Django'da `manage.py migrate`, Rails'de `rake db:migrate`). +* Herhangi bir kodu çalıştırmak veya canlı yayın veritabanındaki verileri denetlemek için konsolu ([REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) kabuğu olarak da bilinir) çalıştırmak. Çoğu dil hiçbir argüman olmadan (`python` veya `perl`), veya bazı durumlarda ayrı komutlarla (Ruby için `irb`, Rails için `rails console`) bir REPL sağlar. +* Uygulamanın kod deposundaki betikleri çalıştırmak (`php scripts/fix_bad_records.php`). + +Tek sefer çalıştırılması gereken yönetsel işlere ait süreçler de, uygulamanın uzun süre çalışan sıradan [süreçleri](./processes) ile birebir aynı ortamda, aynı [sürümdeki](./build-release-run) [kod tabanı](./codebase) ve [yapılandırmayı](./config) kullanarak çalışmalıdır. Uyum sorunu yaşamamak için, uygulamanın yönetimini sağlayan kod da uygulama ile birlikte geliştirilmeli ve yayınlanmalıdır. + +Aynı [bağımlılık yalıtımı](./dependencies) teknikleri bütün süreç tiplerinde kullanılmalıdır. Örneğin, eğer Ruby web süreçleri `bundle exec thin start` komutunu kullanıyorsa, veritabanı göçü de `bundle exec rake db:migrate` komutu kullanmalıdır. Aynı durumda, Virtualenv kullanan bir Python programı, Tornado web sunucusu ve herhangi bir `manage.py` yönetici süreçlerinin ikisini de çalıştırabilmek için `bin/python` kullanmalıdır. + +On iki faktör, REPL kabuğunu kendisi sağlayan ve tek seferlik betikleri çalıştırmayı kolaylaştıran dilleri fazlasıyla destekler. Yerel dağıtımda, geliştiriciler uygulamanın dizininde doğrudan komut satırında tek seferlik yönetici süreçlerini çalıştırır. Canlı yayın dağıtımında ise, geliştiriciler bu gibi bir süreci çalıştırmak için ssh veya dağıtımın çalışma ortamı tarafından sağlanan diğer uzak komut çalıştırma mekanizmasını kullanabilir. diff --git a/content/tr/background.md b/content/tr/background.md new file mode 100644 index 000000000..dd37f9f62 --- /dev/null +++ b/content/tr/background.md @@ -0,0 +1,8 @@ +Arkaplan +========== + +Bu belgeye katkıda bulunan kişiler, yüzlerce uygulamanın geliştirilmesi ve yayınlanmasında doğrudan yer almış, ve dolaylı olarak Heroku platformundaki üzerinde çalıştığımız yüz binlerce uygulamanın geliştirilmesi, çalıştırılması ve ölçeklendirilmesine tanık olmuştur. + +Bu belge birçok yazılım servisinde edindiğimiz deneyim ve gözlemlerimizin bir sentezidir. Uygulama geliştirme aşamasındaki ideal pratiklerin, uygulamaların zaman içindeki organik büyüyüşlerine gösterilen özel ilginin, bir uygulamanın kodları üzerinde çalışan geliştiriciler arasındaki işbirliği dinamiklerinin, ve yazılım erozyonunun getirdiği masraftan kaçınmanın toplamı niteliğindedir. + +Motivasyonumuz modern uygulama geliştirmelerinde gördüğümüz bazı sistemik problemlere olan farkındalığı arttırmak, bahsi geçen problemler için ortak bir terminoloji belirlemek, ve bu problemlere karşı bir dizi çözüm konsepti sunmaktır. Bu konsept oluşturulurken, Martin Fowler'ın kitapları olan *Patterns of Enterprise Application Architecture* ve *Refactoring*'den ilham alınmıştır. diff --git a/content/tr/backing-services.md b/content/tr/backing-services.md new file mode 100644 index 000000000..52b55c678 --- /dev/null +++ b/content/tr/backing-services.md @@ -0,0 +1,14 @@ +## IV. Yardımcı servisler +### Yardımcı servisleri iliştirilmiş kaynaklar olarak ele almak + +Bir *yardımcı servis* uygulamanın kendi işlevselliğinin bir parçası olarak ağ üzerinden tükettiği herhangi bir servistir. Yardımcı servislere örnek olarak; veritabanları ([MySQL](http://dev.mysql.com/) veya [CouchDB](http://couchdb.apache.org/) gibi), mesajlaşma/kuyruk sistemleri ([RabbitMQ](http://www.rabbitmq.com/) veya [Beanstalkd](https://beanstalkd.github.io)), e-posta göndermek için SMTP servisleri ([Postfix](http://www.postfix.org/) gibi) ve önbellekleme sistemleri ([Memcached](http://memcached.org/) gibi) gösterilebilir. + +Veritabanları gibi yardımcı servisler, geleneksel olarak uygulamayı da yöneten sistem yöneticileri tarafından yönetilirler. Ancak bu yerel servislere ilave olarak, uygulama üçüncü parti uygulamalar tarafından sağlanan ve yönetilen servislere de sahip olabilirler. Bunlardan bazıları; SMTP servisleri ([Postmark](http://postmarkapp.com/) gibi), metrik toplama servisleri ([New Relic](http://newrelic.com/) veya [Loggly](http://www.loggly.com/) gibi), statik içerik barındırma servisleri ([Amazon S3](http://aws.amazon.com/s3/) gibi) ve hatta API-erişilebilir tüketici servisleridir ([Twitter](http://dev.twitter.com/), [Google Maps](http://code.google.com/apis/maps/index.html), ve [Last.fm](http://www.last.fm/api) gibi). + +**On iki faktör uygulamaları için bir servisin yerel veya üçüncü parti olmasının farkı yoktur.** Uygulama için, her ikisi de ek kaynaktır ve [yapılandırmada](./config) saklanmış URL'ler veya yer belirleyici ve kimlik bilgileri ikilisi aracılığıyla erişilir. On iki faktör uygulamasının bir dağıtımı, uygulama kodunda hiçbir değişiklik yapmak zorunda kalmadan yerel bir MySQL veritabanı kullanmaktan üçüncü parti bir veritabanı ([Amazon RDS](http://aws.amazon.com/rds/) gibi) kullanmaya geçebilmelidir. Aynı şekilde yerel bir SMTP servisinden (Postmark gibi), kod değişikliği olmaksızın bir üçüncü parti SMTP servisine geçiş yapılabilir. Her iki durumda da, değişmesi gereken şey sadece yapılandırma ayarlarındaki bağlantı bilgileridir. + +Her bir destek servisi bir *kaynaktır*. Örneğin, bir MySQL veritabanı bir kaynaktır; iki MySQL veritabanı (uygulama katmanında parçalanma [İng. sharding] için kullanılan) iki farklı kaynak olarak nitelendirilir. On iki faktör uygulaması bu veritabanlarına, bağlı oldukları dağıtımlara gevşek bağlaşımlarını belirten *ek kaynak* olarak davranır. + +Canlı yayın dağıtımı dört destek servisine bağlanmış. + +Kaynaklar dağıtımlara istenilen zamanda eklenilip çıkartılabilir. Örneğin, eğer uygulamanın veritabanı donanımsal sorunlar yaşıyorsa, uygulamanın yöneticisi son yedeklemeden geri yüklenmiş yeni bir veritabanı sunucusu oluşturabilir. Problemli veritabanının uygulamadan bağlantısı kesilip, yeni veritabanı bağlanabilir, hem de hiçbir kod değişikliği olmadan. diff --git a/content/tr/build-release-run.md b/content/tr/build-release-run.md new file mode 100644 index 000000000..fa0c99184 --- /dev/null +++ b/content/tr/build-release-run.md @@ -0,0 +1,18 @@ +## V. Derleme, yayınlama, çalıştırma +### Derleme ve çalıştırma aşamalarını tam olarak ayırma + +Bir [kod tabanı](./codebase) üç aşamada (geliştirme dağıtımı olmayan) dağıtıma dönüşür: + +* *Derleme aşaması* kod deposunun *derleme* olarak bilinen çalıştırılabilir bir pakete çevrilmesidir. Dağıtım evresi tarafından seçilen commit'teki kod kullanılır. Sistem, üçüncü parti [bağımlılıkları](./dependencies) toparlar ve çalıştırılabilirleri ve statik dosyaları derler. +* *Yayınlama aşaması*, derleme aşaması tarafından üretilmiş derlemeyi alır ve dağıtımı güncel [yapılandırmasıyla](./config) birleştirir. Son durumda oluşan *yayın* derleme ve yapılandırmanın ikisini de içerir ve çalışma ortamında çalıştırmak için hazırdır. +* *Çalıştırma evresi* (aynı zamanda "runtime" olarak bilinir) seçili yayının karşılığındaki [süreçleri](./processes) başlatarak, çalıştırma ortamındaki uygulamayı çalıştırır. + +![Kod, sürüm oluşturmak için yapılandırmayla birleşmiş derlemeye dönüşür.](/images/release.png) + +**On iki faktör uygulamalarının derleme, yayınlama ve çalıştırma aşamaları tamamen birbirinden bağımsızdır.** Örneğin, koddaki değişiklikleri derleme aşamasına geri döndürmenin bir yolu olmadığı için çalışma zamanında kodda değişiklik yapmak imkansızdır. + +Dağıtım araçları genelde yayın yönetim araçları da sunar. En dikkat çeken yetenekleri ise bir önceki yayına geri dönebilmeleridir. Örneğin, [Capistrano](https://github.com/capistrano/capistrano/wiki) farklı yayınları `releases` adındaki bir alt dizinde depolar. Çalışıyor olan yayın ise bu alt dizinlerden birine oluşturulmuş bir kısayol dosyasıdır. Capistrano'nun `rollback` komutu, kısayol dosyasının işaret ettiği dizini değiştirerek önceki bir yayına dönüş yapmayı kolaylaştırır. + +Her yayın zaman damgası gibi (`2011-04-06-20:32:17` gibi) özel bir ID'ye veya her yeni yayında artan bir numaraya (`v100` gibi) sahip olmalıdır. Yayınlar yalnızca eklemeli bir defterdir ve bir kere oluşturulduğu zaman değiştirilemez. Herhangi bir değişiklik yeni bir yayın oluşturmalıdır. + +Derlemeler, geliştiricilerin kod değişikliklerini kod depolarına yüklemesiyle başlatılır. Çalıştırma evresi ise, sunucuların yeniden başlatılması veya çökmüş süreçlerin tekrar ayağa kaldırılması gibi durumlarda otomatik olarak gerçekleştirilir. Bu yüzden çalıştırma evresi olabildiği kadar az sayıda hareketli parçaya sahip olmalıdır ki, gecenin bir yarısında, işinin başında olan hiçbir geliştirici yokken bozulmasın. Derleme evresi ise daha karmaşık olabilir, çünkü hatalar dağıtımı çalıştıran geliştiricilerin her zaman önündedir. diff --git a/content/tr/codebase.md b/content/tr/codebase.md new file mode 100644 index 000000000..06187f0e2 --- /dev/null +++ b/content/tr/codebase.md @@ -0,0 +1,17 @@ +## I. Kod Tabanı +### Sürüm kontrol sistemi üzerinde tek bir kod tabanı, birden fazla dağıtım + +On iki faktör bir uygulama her zaman [Git](http://git-scm.com/), [Mercurial](http://mercurial.selenic.com/) veya [Subversion](http://subversion.apache.org/) gibi bir sürüm kontrol sistemiyle izlenir. Bu sürüm kontrol sistemindeki dosya veritabanına kod deposu (İng. code repository) veya kısaca depo (İng. repo) denir. + +Bir *kod tabanı*, tek bir depo (Subversion gibi merkezi sürüm kontrol sistemi) ya da kök *commit* paylaşan birden fazla depodan (Git gibi merkezi olmayan sürüm kontrol sistemi) oluşur. + +![Bir kod tabanı bir çok dağıtımla eşlenir](/images/codebase-deploys.png) + +Kod tabanı ve uygulama arasında her zaman birebir ilişki vardır: + +* Eğer birden fazla kod tabanı varsa bu bir uygulama değil, dağıtık sistemdir. Dağıtık sistemdeki her bileşen bir uygulamadır ve her biri on iki faktörle bireysel olarak uyumlu olmalıdır. +* Aynı kodu paylaşan birden fazla uygulama, on iki faktörü ihlal eder. Burada çözüm, paylaşılan kodun [bağımlılık yöneticisi](./dependencies) aracılığıyla dahil edilebilecek kütüphanelere dönüştürülmesidir. + +Uygulamanın sadece bir kod tabanı vardır fakat birden fazla dağıtımı olacaktır. Bir *dağıtım*, uygulamanın çalışan bir örneğidir. Bu dağıtımlar genelde bir canlı yayın (İng. production) ve bir veya birkaç test ortamıdır. Ayrıca her geliştiricinin kendi yerel geliştirme ortamında çalışan bir kopyası vardır ve bunların her biri aynı zamanda dağıtım olarak nitelendirilirler. + +Dağıtımlarda anlık olarak farklı sürümler etkin olabilir fakat kod tabanı tüm dağıtımlarda aynıdır. Örneğin, bir geliştirici henüz commit'lemediği değişiklikleri çalıştırıyor olabilir, veya test ortamında henüz canlı yayına dağıtılmamış bir sürüm çalışıyor olabilir. Bu nedenle hepsi ayrı dağıtım olarak tanımlanır ama kod tabanı aynıdır. diff --git a/content/tr/concurrency.md b/content/tr/concurrency.md new file mode 100644 index 000000000..9ef8f593f --- /dev/null +++ b/content/tr/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Eş Zamanlılık +### Süreç modeli yardımıyla dağıtıklaştırma + +Herhangi bir bilgisayar programı bir kere çalıştığı zaman bir veya daha fazla süreç tarafından temsil edilir. Web uygulamaları çeşitli süreç çalıştırma formlarına sahiptir. Örneğin, PHP süreçleri Apache'nin alt süreci olarak çalışır, ve istek hacmine göre ihtiyaç duyuldukça başlatılır. Java süreçleri karşıt yaklaşımı benimser; JVM, başlangıçta büyük miktarda sistem kaynağı (CPU ve bellek) ayıran büyük bir süreci başlatır, ve eşzamanlı iş parçacıkları (İng. threads) aracılığıyla JVM içerisinde dahili olarak yönetilir. Her iki durumda, çalışan süreçler, uygulamanın geliştiricilerine minimum düzeyde görünürdür. + +![Ölçek, çalışan süreçler olarak ifade edilir, iş yükü çeşitliliği ise süreç tipi olarak tanımlanır.](/images/process-types.png) + +**On iki faktör uygulamasında, süreçler birinci sınıf üyelerdir.** On iki faktör uygulamasındaki süreçler arkaplan servis programları çalıştırmak için olan [Unix süreç modeli](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/)nden güçlü ipuçları alır. Bu modeli kullanarak geliştirici, uygulamasının her iş tipini bir *süreç tipine* atayarak, farklı iş yüklerini kontrol etmek için uygulamasını planlayabilir. Örneğin, HTTP istekleri web süreçleri tarafından işlenir ve uzun çalışan arkaplan görevleri, işçi süreçler tarafından işlenir. + +Bu, çalışma zamanı (İng. runtime) içindeki iş parçacıkları veya [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/) ve [Node.js](http://nodejs.org/) gibi araçlarda bulunan asenkron/olay-bazlı model gibi, süreçlerin kendi çok-kanallılığını hariç tutmaz. Fakat bir sanal makinanın dikey ölçekte büyümesinin bir sınırı vardır. Bu yüzden uygulama aynı zamanda birden fazla fiziksel makinede çalışan çoklu süreçleri içerebilmelidir. + +Bu süreç modeli, konu ölçeklendirmeye geldiğinde gerçekten farkını ortaya koyar. Paylaşımsız, yatay olarak bölümlenebilir bir doğası olan on iki faktör uygulama süreçleri, daha fazla eş zamanlılık eklemenin kolay ve güvenilir bir iş olduğu anlamına gelir. Süreç tipleri dizisi ve her bir tipin süreç sayısı *süreç formasyonu* olarak bilinir. + +On iki faktör uygulama süreçleri [asla arkaplan süreçleri başlatmamalı](http://dustin.github.com/2010/02/28/running-processes.html) ya da PID dosyaları yazmamalıdır. Bunun yerine, [çıktı akışlarını](./logs) kontrol etmek, çökmüş süreçlere cevap vermek, kullanıcı sebepli tekrar başlatma ve kapatmaları süreçek için işletim sistemlerinin süreç yöneticisine ([systemd](https://www.freedesktop.org/wiki/Software/systemd/) gibi bulut platformunda yayınlanmış süreç yöneticisi veya geliştirme sırasında [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html)'e benzer araçlar) dayanır. diff --git a/content/tr/config.md b/content/tr/config.md new file mode 100644 index 000000000..4fa9b30d3 --- /dev/null +++ b/content/tr/config.md @@ -0,0 +1,22 @@ +## III. Yapılandırma +### Yapılandırma ayarlarını ortam değişkeni saklama + +Bir uygulamanın *yapılandırma ayarları* [dağıtımlar](./codebase) arasında farklı olma ihtimali olan her şeydir. Örneğin: + +* Veritabanlarının, önbellekleme servislerinin ve diğer [yardımcı servislerin](./backing-services) erişim bilgileri +* Amazon S3 ve Twitter gibi dış servisler için kimlik bilgileri +* Dağıtımlar için standart sunucu ismi gibi dağıtım-öncesi değerler + +Uygulamalar bazen yapılandırma ayarlarını kod içerisinde saklar. Bu on iki faktörün, **yapılandırmayı koddan mutlak ayrımını** gerektiren kuralın ihlalidir. Yapılandırma ayarları dağıtımlar arasında değişir, ama kod değişmez. + +Bir uygulamanın herhangi bir kimlik bilgisinin gizliliğini ihlal etmeden açık kaynak yapılabilip yapılamayacak olması, tüm yapılandırmaları koddan doğru bir biçimde çıkarılıp çıkarılmadığını belirleyebilecek bir litmus testidir. + +Bu *yapılandırma ayarı* tanımının, [Spring](http://spring.io/)'de [kod modüllerinin bağlantısında](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) olduğu gibi ve Rails'deki `config/routes.rb` gibi dahili uygulama yapılandırmasını **içermediğini** unutmayın. Bu tip yapılandırmalar, dağıtımlar arasında değişiklik göstermeyeceği için, kod içinde gerçekleştirilmeleri mantıklıdır. + +Yapılandırmaya diğer bir yaklaşım da Rails'deki `config/database.yml` gibi dosyaların versiyon kontrol sistemine dahil edilmeden kullanımıdır. Bu, kod deposuna dahil edilmiş sabitler kullanmaya göre büyük bir gelişimdir, fakat hala zayıflıkları vardır: Bu dosyaların yanlışlıkla versiyon kontrol sistemine dahil edilme olasılığı oldukça yüksektir. Yapılandırma dosyalarının farklı yerlerde ve farklı formatlarda dağılmış olması eğilimi mevcuttur, ve bu durum bütün yapılandırmayı bir yerde görmeyi ve yönetmeyi zorlaştırır. Dahası, bu formatlar genelde dil veya çatı için özelleşmiştir. + +**On iki faktör uygulamalarında yapılandırma *ortam değişkenlerinde* kaydedilir** (sıklıkla *env vars* veya *env* olarak kısaltılır). Ortam değişkenleri herhangi bir kod değişikliği olmadan, dağıtımlar arasında kolay değişebilir; Yapılandırma dosyalarının aksine, kod deposuna yanlışlıkla dahil edilme ihtimali düşüktür; ve özel yapılandırma dosyalarının veya Java sistem özellikleri gibi yapılandırma mekanizmalarının aksine, onlar dil ve işletim sisteminden etkilenmez. + +Yapılandırma yönetiminin diğer bir açısı da gruplandırmadır. Bazen uygulamalar, Rails'deki `geliştirme`, `test` ve `canlı` ortamları gibi belirli dağıtımlardan sonra adlandırılmış gruplar içinde yapılandırılır. Bu yöntem temiz bir şekilde ölçeklenemez. Çünkü uygulamanın daha fazla dağıtımı oluştukça, yeni ortam isimleri gerekli olur, `staging` veya `qa` gibi. Projeler ilerde geliştikçe, geliştiriciler `joes-staging` kendi özel ortam değişkenlerini ekleyebilir. Bu da yapılandırma dosyalarının hızla artmasıyla sonuçlanarak dağıtım yönetimini oldukça kırılganlaştırır. + +On iki faktör uygulamasında ortam değişkenleri parçacıklı kontrol edilirler, birbirlerinden bağımsızlardır. Asla gruplandırılmazlar, onun yerine her bir dağıtım için bağımsız olarak yönetilirler. Bu, uygulamayı yaşam süresi boyunca daha fazla dağıtıma genişletmeyi sorunsuzca ölçeklendiren bir modeldir. diff --git a/content/tr/dependencies.md b/content/tr/dependencies.md new file mode 100644 index 000000000..017302353 --- /dev/null +++ b/content/tr/dependencies.md @@ -0,0 +1,12 @@ +## II. Bağımlıklar +### Bağımlılıkların açıkça tanımlanması ve izole edilmesi + +Çoğu programlama dili destek kütüphanelerini dağıtmak için bir paketleme sistemi sunar. Mesela Perl için [CPAN](http://www.cpan.org/), Ruby için [Rubygems](http://rubygems.org/). Bir paketleme sistemi aracılığıyla yüklenen kütüphaneler, sistem genelinde ("site paketleri" olarak bilinir) yüklenebilir veya uygulamanın bulunduğu dizine ("sağlayıcı" veya "paketleme" olarak bilinir) dahil edilebilir. + +**On iki faktör bir uygulama asla bir sistem geneli paketin yüklü olduğunu varsaymaz.** Bir *bağımlılık bildirimi* manifestosu ile tüm bağımlılıkları tam ve eksiksiz olarak bildirir. Üstelik bağımlılıkların çevredeki sistemden sızmamasını sağlamak için çalıştırma sırasında bir *bağımlılık yalıtım* aracı kullanılır. Tam ve açık bağımlılık belirtimi hem canlı yayın hem de geliştirme için eşit olarak uygulanmaktadır. + +Örneğin, Ruby'nin [Bundler](https://bundler.io/)'ı, bağımlılık bildirimi için `Gemfile` manifesto formatını ve bağımlılık yalıtımı için `bundle exec`'i sunar. Python'da bu adımlar için iki ayrı araç bulunur: [Pip](http://www.pip-installer.org/en/latest/) bildirimde, [Virtualenv](http://www.virtualenv.org/en/latest/) de yalıtımda kullanılır. C bile bağımlılık bildirimi için [Autoconf](http://www.gnu.org/s/autoconf/)'a sahiptir ve bağımlılık yalıtımı statik link ile sağlanır. Ne olursa olsun birbiriyle uyumlu çalışan yazılım uygulaması, bağımlılık bildirimi ve bağımlılık yalıtımı birlikte kullanılmalıdır, sadece birinin olması on iki faktör için yeterli değildir. + +Açık bağımlılık bildiriminin bir faydası da uygulamaya yeni katılan geliştiriciler için kurulumu kolaylaştırmasıdır. Yeni geliştirici bilgisayarında yalnızca programlama dilini ve bağımlılık yöneticisine sahip olarak uygulamanın kod tabanını indirebilir. Uygulamanın içindeki önceden belirlenmiş bir *derleme komutu* uygulama kodunun çalışması için ihtiyaç duyulan her şeyi yükleyebilecektir. Örneğin bu komut Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) için `lein deps` iken, Ruby/Bundler için `bundle install`'dur. + +On iki faktör uygulamaları herhangi bir sistem aracının yüklü olduğunu varsaymaz. Örnekler `ImageMagick` yada `curl` kullanımını içerir. Bu araçlar çoğu sistemde var olabilse de, uygulamanın gelecekte çalışabileceği sistemlerde bu araçların var olup olmayacağının veya bu araçların sürümlerinin uygulamayla uyumlu olup olmayacağının garantisi yoktur. Uygulamanın bir sistem aracına ihtiyacı oluşuyorsa, o aracın uygulamanın içine dahil edilmesi gerekir. diff --git a/content/tr/dev-prod-parity.md b/content/tr/dev-prod-parity.md new file mode 100644 index 000000000..38678a3d6 --- /dev/null +++ b/content/tr/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X.Geliştirme/Üretim Eşitliği +### Geliştirme, test etme ve canlı yayın ortamının birbirine olabildiğince benzer olması + +Tarihsel olarak, geliştirme ortamı (geliştiricinin uygulamanın yerel [dağıtımına](./codebase) anlık düzenlemeler yaptığı) ve canlı yayın (uygulamanın son kullanıcılar tarafından erişilen çalışan dağıtımı) arasında önemli aralıklar olurdu. Bu aralıklar üç alanda belirtilir: + +* **Zaman aralığı:** bir geliştirici kod üzerinde günler, haftalar hatta aylar boyunca bile çalışabilir. +* **Çalışan aralığı:** Geliştiriciler kod yazar, operasyon mühendisleri dağıtımını sağlar. +* **Araçların aralığı:** Geliştiriciler Apache, MySQL ve Linux kullanırken; canlı yayında Nginx, SQLite, ve OS X gibi teknolojiler kullanıyor olabilir. + +**On iki faktör uygulaması, geliştirme ve canlı yayın aralığını küçük tutarak, [sürekli dağıtım](http://avc.com/2011/02/continuous-deployment/) için tasarlanmıştır.** Yukarda tanımlanan üç aralığa bakarsak: + +* Zaman aralığını küçültme: bir geliştirici kod yazabilir ve bu kodu saatler veya hatta dakikalar sonra dağıtmış olabilir. +* Eleman aralığını küçültme: kodu yazan geliştiriciler, kodu dağıtmakla ve canlı yayındaki davranışını izlemekle yakından ilişkilidir. +* Araçların aralığını küçültme: geliştirmeyi ve canlı yayını olabildiği kadar benzer tut. + +Üstekileri bir tablo olarak özetlersek: + + + + + + + + + + + + + + + + + + + + + + +
Geleneksel uygulamaOn iki faktör uygulaması
Dağıtımlar arasındaki zamanHaftalarSaatler
Kod yazarları ve kod dağıtımcılarıFarklı insanlarAynı insanlar
Geliştirme ve canlı yayın ortamıFarklıOlabildiğince benzer
+ +Uygulamanın veritabanı, kuyruk sistemi veya önbellek gibi [yardımcı servisleri](./backing-services), geliştirme/canlı yayın eşitliğinin önemli olduğu bir alandır. Birçok dil, farklı tipteki servislerin *uyarlayıcılarını* (adaptörlerini) içeren, yardımcı servislere ulaşımı kolaylaştıran kütüphaneler önerir. Bazı örnekler aşağıdaki tabloda vardır. + + + + + + + + + + + + + + + + + + + + + + + + + + +
TipDilKütüphaneUyarlayıcı
VeritabanıRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
KuyrukPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
ÖnbellekRuby/RailsActiveSupport::CacheBellek, dosya sistemi, Memcached
+ +Geliştiriciler, canlı yayında daha ciddi ve sağlam yardımcı servisleri kullanırken, bazen kendi yerel ortamlarında hafif yardımcı servisleri kullanmak isterler. Örneğin, yerelde SQLite, canlı yayında ise PostgreSQL kullanılır, veya yerelde geçici depolama (İng. cache) için süreç belleği, canlı yayında ise Memcached kullanılır. + +**On iki faktör geliştiricisi**, uyarlayıcılar teorik olarak yardımcı servislerdeki herhangi bir farklılığı soyutluyor olsa bile, **geliştirme ve canlı yayın arasında faklı yardımcı servisi kullanma isteğine karşı direnir.** Yardımcı servisler arasındaki farklılıklar, küçük uyumsuzlukların ortaya çıkmasına, yerelde çalışan ve testleri geçen kodun, canlı yayında başarısız olmaya neden olmasına sebep olabilir. Bu tür hatalar, sürekli dağıtıma köstek olan bir sürtünme yaratır. Bu sürtünme maliyeti ve sonraki devamlı dağıtımın azaltılması, bir uygulamanın ömrünün toplamı düşünüldüğünde oldukça yüksektir. + +Hafif yerel servisler eskiye göre daha az çekicidir. Memcached, PostgreSQL ve RabbitMQ gibi modern yardımcı servisleri, [Homebrew](http://mxcl.github.com/homebrew/) ve [apt-get](https://help.ubuntu.com/community/AptGet/Howto) gibi modern paket sistemleri sayesinde kolayca yüklenebilir ve çalıştırılabilir. Alternatif olarak, [Chef](http://www.opscode.com/chef/) ve [Puppet](http://docs.puppetlabs.com/) gibi ortam hazırlayıcı araçlar, ve [Vagrant](http://vagrantup.com/) ve [Docker](https://www.docker.com/) gibi hafif sanal ortam sağlayıcıları, geliştiricilerin canlı yayın ortamına çok benzeyen yerel ortamda çalışabilmelerini sağlar. Bu sistemlerin yüklenmesi ve kullanımının maliyeti, geliştirme ve canlı yayın eşitliği ve sürekli dağıtımın faydasıyla karşılaştırıldığında oldukça düşüktür. + +Farklı yardımcı servislerin uyarlayıcıları hala kullanışlıdır, çünkü yeni yardımcı servislere bağlanmayı nispeten zahmetsiz yapar. Ama uygulamanın bütün dağıtımları (geliştirme, test, canlı yayın ortamları) her bir yardımcı servisinin aynı tip ve versiyonunu kullanmalıdır. diff --git a/content/tr/disposability.md b/content/tr/disposability.md new file mode 100644 index 000000000..3c29257eb --- /dev/null +++ b/content/tr/disposability.md @@ -0,0 +1,12 @@ +## IX. İmha edilebilirlik +### Hızlı başlangıç ve zararsız sonlanma ile maksimum servis sağlığı + +**On iki faktör uygulamalarının [süreçleri](./processes) *tek kullanımlıktır*, yani anlık olarak başlatılabilir ve durdurulabilirler.** Bu hızlı esnek ölçeklemeyi, [kod](./codebase) ve [yapılandırma](./config) değişikliklerinin hızlı dağıtımı ve canlı yayın dağıtımlarının sağlamlığını arttırır. + +Süreçler **başlangıç zamanını küçültmeye** çabalamalıdır. İdeal olarak, bir sürecin başlatma komutunun çalıştırılmasından, sürecin ayağa kalkmış ve istek/işleri karşılamaya hazır hale gelmesine kadar olan süre birkaç saniyedir. Kısa başlama zamanı [yayınlama](./build-release-run) süreci ve ölçeklenme için daha fazla çeviklik sağlar; ve sağlamlığına yardımcı olur, çünkü süreç yöneticisi süreçleri yeni fiziksel makinelere daha kolay taşıyabilir. + +Süreçler, süreç yöneticisinden **[SIGTERM](http://en.wikipedia.org/wiki/SIGTERM) sinyalini aldıkları zaman, kontrollü şekilde kapanırlar.** Bir web süreci için kontrollü kapama, servis portunun dinlenmesinin kesilmesi (dolayısıyla herhangi bir yeni istek reddedilir), eğer varsa o an işleniyor olan isteğin tamamlanmasına izin verilmesi ve daha sonra sürecin sonlandırılması şeklinde gerçekleşir. Bu modelin içeriğinde HTTP istekleri kısadır (birkaç saniyeden fazla değildir) veya uzun sorgulama durumlarında, istemci bağlantıyı kaybettiği zaman sorunsuzca tekrar bağlanmayı denemelidir. + +Bir işçi süreç için kontrollü kapama, güncel işin iş kuyruğuna döndürülmesiyle sonuçlanır. Örneğin [RabbitMQ](http://www.rabbitmq.com/)'da işçi [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack) sinyali gönderebilir; [Beanstalkd](https://beanstalkd.github.io)'da herhangi bir zamanda işçi süreç bağlantıyı kopardığında iş kuyruğa otomatik olarak döndürülür. Kilit tabanlı sistemler, [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) gibi, üzerinde çalışıyor oldukları işin kilitlerini kaldırdıklarından emin olmalıdır. Bu modelin içeriğinde bütün işler [tekrar girişli](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29)dir, genellikle sonuçların bir transaksiyonda (İng. transaction) saklanması veya süreci [eşgüçlü](http://en.wikipedia.org/wiki/Idempotence) yapmasıyla gerçekleşir. + +Süreçler, donanımsal sorun oluşması gibi durumlarda oluşacak **ani sonlanmalara karşı dayanıklı olmalıdır.** Bu `SIGTERM` ile kontrollü kapamadan daha az yaygın bir olaydır, ancak yine de gerçekleşebilir. Önerilen yaklaşım, Beanstalkd gibi sağlam arkaplan kuyruklama sistemlerinin kullanımıdır. Bu sistemler, istemciler oturumu kapattığı zaman veya süre aşımı durumlarında işi kuyruğa döndürür. Her iki durumda, on iki faktör uygulaması kontrollü olmayan sonlandırmaları idare edebilmek için tasarlanmıştır. [Crash-only tasarım](http://lwn.net/Articles/191059/) bu konsepti [mantıksal sonucu](http://docs.couchdb.org/en/latest/intro/overview.html)na ulaştırır. diff --git a/content/tr/intro.md b/content/tr/intro.md new file mode 100644 index 000000000..879ff1105 --- /dev/null +++ b/content/tr/intro.md @@ -0,0 +1,12 @@ +Giriş +========== + +Modern çağda yazılımlar çoğunlukla "web uygulaması" ya da "yazılım hizmeti" olarak isimlendirilen servisler olarak sunulurlar. *On iki faktörlü uygulama*, servis olarak çalışan yazılımlar (İng. *software as a service* veya *SaaS*) geliştirmek için bir yöntembilimdir. Bu yöntembilimin kuralları ve faydaları şunlardır: + +* Projenin kurulum otomasyonu için **açıklayıcı** (İng. declarative) biçimler kullanır. Bu şekilde, projeye yeni katılan geliştiricilerin geliştirmeye başlama zamanını ve maliyetinı en aza indirir; +* Üzerinde çalıştığı işletim sistemi ile arasında **basit bir bağlılık** vardır. Bu, tüm çalıştırma ortamlarına (Docker gibi *container* sistemleri ve sıradan işletim sistemlerine) **maksimum uyumluluk** sağlar; +* Sunucu ve sistem yönetimine olan ihtiyacı ortadan kaldıran modern **bulut platformlarına kurulum** için uygundur; +* Geliştirme ve canlı yayın ortamları arasında **farklılıklaşmayı minimize ederek**, maksimum çeviklik ile **sürekli dağıtımı**n önünü açar; +* Kullanılan araçlarda, mimaride veya geliştirme pratiklerinde önemli değişikliklere gerek duymadan **ölçeklenebilir**. + +On iki faktör uygulaması herhangi bir programlama dili ile yazılmış ve yardımcı (veritabanları, kuyruk işleyiciler, önbellek, vb. gibi) servislerin herhangi bir kombinasyonuna sahip tüm uygulamalara uygulanabilir. diff --git a/content/tr/logs.md b/content/tr/logs.md new file mode 100644 index 000000000..4c9dfe306 --- /dev/null +++ b/content/tr/logs.md @@ -0,0 +1,16 @@ +## XI. Günlükler +### Günlüklere olay akışı gibi davranma + +*Günlükler* çalışan bir uygulamanın davranışlarını izleyebilme imkanı sağlar. Sunucu tabanlı ortamlarda genellikle diskteki bir dosyaya yazılırlar (ve bunlara log dosyası denir); ama bu sadece bir çıktı formatıdır. + +Günlükler, bütün çalışan süreçler ve destek servislerinin çıktı akışlarından kümelenmiş, zaman sıralı olayların [akışıdır](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/). Günlükler en ham haliyle her bir satırda bir olay içeren yazı formatındadır (ancak hata kayıtlarındaki detaylar birden fazla satıra yayılabilir). Günlüklerin belirlenmiş bir başlangıcı ve sonu yoktur, uygulama işlediği sürece akış devam eder. + +**On iki faktör uygulaması çıkış akışlarının depolaması veya yönlendirilmesiyle ilgilenmez.** Log dosyalarına yazmayı, ya da log dosyalarını yönetmeyi denememelidir. Bunun yerine, her çalışan süreç kendi olay akışını tamponlamadan (İng. buffer) `stdout`'a yazar. Yerel geliştirme süresince, geliştirici uygulamanın davranışını gözlemlemek için terminallerinde bu akışı inceleyebilirler. + +Test ve canlı yayın dağıtımlarında her bir sürecin akışı çalışma ortamı tarafından yakalanır, diğer bütün akışlarla birleştirilir, ve görüntüleme ve uzun dönem arşivleme için bir veya daha fazla son hedeflerine yönlendirilirler. Bu arşivsel hedefler uygulama tarafından görülebilir veya yapılandırılabilir değildir, tamamen çalışma ortamı tarafından yönetilirler. Açık kaynak log yönlendiricileri ([Logplex](https://github.com/heroku/logplex) ve [Fluentd](https://github.com/fluent/fluentd) gibi) bu amaç için kullanılabilir. + +Bir uygulamanın olay akışı dosyaya yönlendirilebilir veya terminalden gerçek zamanlı olarak izlenebilir. En önemlisi, akış [Splunk](http://www.splunk.com/) gibi log saklama ve analiz sistemine veya [Hadoop/Hive](http://hive.apache.org/) gibi genel amaçlı bir veri depolama sistemine gönderilebilir. Bu sistemler uygulamanın zaman içindeki davranışlarında gözlem yapmak için büyük güç ve esneklik sağlar. Örneğin: + +* Geçmişteki spesifik olayları bulmak. +* Eğilimlerin geniş aralıklı grafikleri (her bir dakika için olan istekler gibi). +* Kullanıcı tanımlı davranışları algılayıp aktif uyarı sağlama (Bir dakikadaki hataların miktarı belirli bir alt sınırı geçtiği zaman olan uyarı gibi). diff --git a/content/tr/port-binding.md b/content/tr/port-binding.md new file mode 100644 index 000000000..f7c6871d2 --- /dev/null +++ b/content/tr/port-binding.md @@ -0,0 +1,14 @@ +## VII. Port Bağlama +### Port bağlama yolu üzerinden dışarı aktarma + +Web uygulamaları bazen web sunucu taşıyıcıları içinde çalıştırılırlar. Örneğin, PHP uygulamaları modül olarak [Apache HTTPD](http://httpd.apache.org/) içinde veya Java uygulamaları [Tomcat](http://tomcat.apache.org/) içinde çalıştırılabilirler. + +**On iki faktör uygulama tamamen kendi kendine yeterlidir** ve web'e açılan bir servis sunmak için çalıştırma ortamına başka bir web sunucusu enjekte edilmesini beklemez. Bu web uygulaması servisini HTTP üzerinden bir porta bağlanarak sunar ve o porta gelen istekleri dinler. + +Yerel geliştirme ortamında, geliştiriciler uygulamanın servislerine ulaşmak için `http://localhost:5000/` gibi bir URL'yi ziyaret eder. Dağıtımda, bir yönlendirme katmanı halka açık bir adrese gelen istekleri karşılayıp porta bağlanmış web süreçlerine aktarırlar. + +Uygulamalar web sunucusu özelliği edinmek için genellikle [bağımlılık tanımlaması](./dependencies) kullanarak Python için [Tornado](http://www.tornadoweb.org/), Ruby için [Thin](http://code.macournoyer.com/thin/) veya Java ve diğer JVM-tabanlı diller için [Jetty](http://jetty.codehaus.org/jetty/) gibi kütüphaneler kullanırlar. Bu, *kullanıcı alanında* yani uygulamanın kodu içinde gerçekleşir. Çalışma ortamıyla olan anlaşma isteklere hizmet veren bir porta bağlanmaktır. + +HTTP, port bağlama ile dışarı aktarılabilen tek protokol değildir. Nerdeyse her sunucu yazılım tipi bir porta bağlanarak ve gelen istekleri dinleyerek çalışabilir. Örnekler [ejabberd](http://www.ejabberd.im/) ([XMPP](http://xmpp.org/) ile haberleşir) ve [Redis](http://redis.io/)'i ([Redis protocol](http://redis.io/topics/protocol) ile haberleşir) içerir. + +Ayrıca not edilmelidir ki, porta bağlanma yaklaşımı, bir uygulamanın başka bir uygulamaya [yardımcı servis](./backing-services) olmasını sağlayabilir. Bunu, uygulamanın servise bağlanabileceği bir URL sağlayarak yapar. diff --git a/content/tr/processes.md b/content/tr/processes.md new file mode 100644 index 000000000..645d68317 --- /dev/null +++ b/content/tr/processes.md @@ -0,0 +1,14 @@ +## VI. Süreçler +### Uygulamayı bir veya daha fazla bağımsız süreç olarak çalıştırma + +Uygulama bir veya birden fazla *süreç* olarak çalıştırma ortamında çalıştırılır. + +En basit senaryoda, kod bağımsız çalışan bir betiktir, çalışma ortamı ise geliştiricinin dil çalışma zamanı yüklenmiş bilgisayarıdır ve süreç komut satırı aracılığıyla başlatılır (Örneğin, `python my_script.py`). Spekturumun diğer ucunda, gelişmiş bir uygulamanın canlı yayın dağıtımı birden fazla [sıfır veya daha fazla aktif süreci bulunan bir süreç tipi](./concurrency)ne sahip olabilir. + +**On iki faktör süreçleri durumsuz ve [paylaşımsızdır](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Saklanmasına ihtiyaç duyulan herhangi bir veri, durum-sahibi bir [yardımcı serviste](./backing-services) saklanmalıdır. Bu servis genelde bir veritabanı olur. + +Süreçler, bellekleri ve dosya sistemini, kısa süreli tek süreçli önbellekler olarak kullanabilirler. Örneğin, büyük bir dosya indiririp, üzerinde bir operasyon uygulayıp, operasyonun sonuçlarını veri tabanında saklayabilir. On iki faktör uygulaması, bellek veya diskte depolanmış hiçbir şeyin gelecekteki istek veya işlerde erişilebilir olacağını varsaymaz. Birden çok süreç çalıştıran sistemlerde, gelecekteki bir isteğin farklı bir süreç tarafından sunulma şansı yüksektir. Sadece bir süreç çalıştırıldığında bile, tekrar başlatma (kod dağıtımı, yapılandırma değişikliği veya çalışma ortamı sürecin farklı fiziksel adrese tekrar yerleştirimi tarafından tetiklenebilir) genellikle bütün yerel (bellek ve dosya sistemi v.b gibi) durumları temizler. + +[django-assetpackager](http://code.google.com/p/django-assetpackager/) gibi statik içerik paketleyicileri dosya sistemini derlenmiş statikleri önbelleklemek için kullanır. On iki faktör uygulaması, bu derlemeyi uygulamanın derlenmesi aşamasında yapmayı tercih eder. [Jammit](http://documentcloud.github.com/jammit/) ve [Rails asset pipeline](http://ryanbigg.com/guides/asset_pipeline.html) gibi paketleyiciler derleme aşamasında çalışmak için yapılandırılabilir. + +Bazı web sistemleri [yapışkan oturum (İng. sticky sessions)](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) denilen giriş yapmış kullanıcı bilgisini uygulamanın belleğinde tutan yöntemi kullanır. "Sticky sessions" on iki faktör kurallarını ihlal eden bir yöntemdir ve asla kullanılmamalıdır. Oturum verisi [Memcached](http://memcached.org/) ve [Redis](http://redis.io/)gibi zaman aşımı özelliği sunan veritabanları için iyi bir veri adayıdır. diff --git a/content/tr/toc.md b/content/tr/toc.md new file mode 100644 index 000000000..4f664e29d --- /dev/null +++ b/content/tr/toc.md @@ -0,0 +1,38 @@ +On İki Faktör +============= + +## [I. Kod tabanı](./codebase) +### Sürüm kontrol sistemi üzerinde tek bir kod tabanı, birden fazla dağıtım + +## [II. Bağımlılıklar](./dependencies) +### Bağımlılıkların açıkça tanımlanması ve izole edilmesi + +## [III. Yapılandırma](./config) +### Yapılandırma ayarlarını ortam değişkeni olarak saklama + +## [IV. Yardımcı servisler](./backing-services) +### Yardımcı servisleri iliştirilmiş kaynaklar olarak ele almak + +## [V. Derleme, yayınlama, çalıştırma](./build-release-run) +### Derleme ve çalıştırma aşamalarını tam olarak ayırma + +## [VI. Süreçler](./processes) +### Uygulamayı bir veya daha fazla bağımsız süreç olarak çalıştırma + +## [VII. Port bağlama](./port-binding) +### Servisin portlar üzerinden sunulması + +## [VIII. Eş zamanlılık](./concurrency) +### Süreç modeli ile ölçeklendirme + +## [IX. İmha edilebilirlik](./disposability) +### Hızlı başlangıç ve zararsız sonlanma ile maksimum servis sağlığı + +## [X.Geliştirme/Üretim Eşitliği](./dev-prod-parity) +### Geliştirme, test etme ve canlı yayın ortamının birbirine olabildiğince benzer olması + +## [XI. Günlükler](./logs) +### Günlükleri olay akışı olarak ele almak + +## [XII. Yönetici Süreci](./admin-processes) +### Yönetici/yönetim görevlerini tek seferlik süreçler olarak çalıştırma diff --git a/content/tr/who.md b/content/tr/who.md new file mode 100644 index 000000000..2a539286f --- /dev/null +++ b/content/tr/who.md @@ -0,0 +1,4 @@ +Bu belgeyi kim okumalı? +======================= + +Servis yazılımı geliştiren tüm geliştiriciler. Bu tür uygulamaları yayınlayan ve yöneten operasyon mühendisleri. diff --git a/content/uk/admin-processes.md b/content/uk/admin-processes.md new file mode 100644 index 000000000..19b876297 --- /dev/null +++ b/content/uk/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Задачі адміністрування +### Виконуйте задачі адміністрування/керування за допомогою разових процесів + +[Формація процесів](./concurrency) є певним набором процесів, які необхідні для виконання регулярних задач застосунку (наприклад, обробка веб-запитів). Разом з тим, розробникам часто необхідно виконувати разові адміністративні задачі для обслуговування застосунку, такі як: + +* Запуск міграції бази даних (наприклад, `manage.py migrate` в Django, `rake db:migrate` в Rails). +* Запуск консолі ([REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop)) для виконання довільного коду або перевірки моделі застосунку на діючій базі даних. Більшість мов надають REPL шляхом запуску інтерпретатора без будь-яких аргументів (наприклад, `python` або `perl`) або в деяких випадках мають окрему команду (наприклад, `irb` для Ruby, `rails console` для Rails). +* Запуск разових скриптів, збережених в репозиторії застосунку (наприклад, `php scripts/fix_bad_records.php`). + +Разові процеси адміністрування слід запускати в такому ж середовищі, в якому запущені регулярні [тривалі процеси](./processes) застосунку. Вони запускаються на базі [релізу](./build-release-run), використовуючи ту ж [кодову базу](./codebase) і [конфігурацію](./config), як і будь-який інший процес на базі цього релізу. Для уникнення проблем з синхронізацією код адміністрування має поставлятися з кодом застосунку. + +Для всіх типів процесів мають використовуватися однакові методи [ізоляції залежностей](./dependencies). Наприклад, якщо веб-процес Ruby використовує команду `bundle exec thin start`, то для міграції бази даних слід використовувати `bundle exec rake db:migrate`. Аналогічно, для програми на Python з Virtualenv слід використовувати `bin/python` як для запуску веб-сервера Tornado, так і для запуску будь-яких `manage.py` процесів адміністрування. + +Методологія дванадцяти факторів надає перевагу мовам, які мають REPL "з коробки", і які дозволяють легко запускати разові скрипти. У локальному development середовищі розробник може запустити процес адміністрування за допомогою консольної команди всередині директорії застосунку. У production середовищі для запуску такого процесу розробники можуть використовувати ssh або інший механізм віддаленого виконання команд, що надається середовищем виконання. \ No newline at end of file diff --git a/content/uk/background.md b/content/uk/background.md new file mode 100644 index 000000000..fb1c16ccf --- /dev/null +++ b/content/uk/background.md @@ -0,0 +1,8 @@ +Передумови +========== + +Люди, що працювали над цим документом, брали безпосередню участь в розробці і розгортанні сотень застосунків, і мимоволі стали свідками розвитку, експлуатації та масштабування сотень тисяч застосунків під час нашої роботи над платформою [Heroku](http://www.heroku.com/). + +В цьому документі узагальнюється весь наш досвід використання і спостереження за найрізноманітнішими SaaS-застосунками "в дикій природі". Документ об'єднує ідеальні практики розробки застосунків, особлива увага приділяється динаміці органічного росту застосунку з плином часу, взаємодії між розробниками, які працюють над кодом застосунку, та [уникненню витрат при ерозії програмного забезпечення](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Наша мета полягає в тому, щоб підвищити обізнаність про деякі системні проблеми, які ми бачили в практиці розробки сучасних застосунків, а також в тому, щоб сформулювати спільні загальні поняття для обговорення цих проблем, і запропонувати набір загальних концептуальних рішень цих проблем з супутньою термінологією. Формат навіяний книгами Мартіна Фаулера (Martin Fowler) *[Patterns of Enterprise Application Architecture](https://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* та *[Refactoring](https://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)*. \ No newline at end of file diff --git a/content/uk/backing-services.md b/content/uk/backing-services.md new file mode 100644 index 000000000..ee2457558 --- /dev/null +++ b/content/uk/backing-services.md @@ -0,0 +1,14 @@ +## IV. Сторонні служби +### Вважайте сторонні служби (backing services) підключеними ресурсами + +*Стороння служба* — це будь-яка служба, яка доступна застосунку по мережі і необхідна для його нормальної роботи: бази даних (наприклад, [MySQL](http://dev.mysql.com/) або [CouchDB](http://couchdb.apache.org/)), системи черг повідомлень (наприклад, [RabbitMQ](http://www.rabbitmq.com/) або [Beanstalkd](https://beanstalkd.github.io)), служби SMTP для вихідної пошти (наприклад, [Postfix](http://www.postfix.org/)), системи кешування (наприклад, [Memcached](http://memcached.org/)) тощо. + +Допоміжні служби, такі як бази даних, традиційно управляються тими ж системними адміністраторами, які розгортають застосунок. Окрім локальних служб, застосунок може також використовувати служби, що надаються і керуються третіми сторонами: SMTP-сервіси (наприклад, [Postmark](http://postmarkapp.com/)), сервіси збору метрик (наприклад, [New Relic](http://newrelic.com/) або [Loggly](http://www.loggly.com/)), сховища бінарних даних (наприклад, [Amazon S3](http://aws.amazon.com/s3/)), а також різні сервіси, що надають доступ через API (наприклад, [Twitter](http://dev.twitter.com/), [Google Maps](https://developers.google.com/maps/), або [Last.fm](http://www.last.fm/api)). + +**Код застосунку дванадцяти факторів не бачить жодних відмінностей між локальними і сторонніми сервісами.** Для застосунку кожен з них є підключеним ресурсом, доступним за URL-адресою або іншими даними, що зберігаються в [конфігурації](./config). [Розгортання](./codebase) застосунку дванадцяти факторів повинно мати можливість, наприклад, замінити локальну базу даних MySQL на будь-яку керовану третьою стороною (наприклад, [Amazon RDS](http://aws.amazon.com/rds/)) без жодних змін в коді застосунку. Крім того, локальний сервер SMTP може бути замінений на сторонній SMTP-сервіс (наприклад, Postmark) без зміни коду. В обох випадках необхідно змінити лише налаштування відповідного ресурсу в конфігурації застосунку. + +Кожна окрема стороння служба є *ресурсом*. Наприклад, база даних MySQL є ресурсом; дві бази даних MySQL (що використовуються для шардінгу на рівні застосунку) кваліфікуються як два різних ресурси. Застосунок дванадцяти факторів сприймає ці бази даних як *підключені ресурси*, що вказує на їхній слабкий зв'язок з розгортанням, в якому вони підключені. + +production-розгортання, в якому підключені чотири сторонні служби + +Ресурси за необхідності можуть бути підключені та відключені до розгортання застосунку. Наприклад, якщо база даних застосунку функціонує некорекно у зв'язку з апаратними проблемами, адміністратор може запустити новий сервер бази даних, відновленої з останньої резервної копії. Поточна база даних може бути відключена, а нова база даних підключена — все це без будь-яких змін коду. diff --git a/content/uk/build-release-run.md b/content/uk/build-release-run.md new file mode 100644 index 000000000..eaaed6b44 --- /dev/null +++ b/content/uk/build-release-run.md @@ -0,0 +1,18 @@ +## V. Збірка, реліз, виконання +### Суворо відокремлюйте етапи збірки та виконання + +[Кодова база](./codebase) перетворюється в розгортання (крім розгортання для розробки) у три етапи: + +* *Етап збірки* — це трансформація, яка перетворює код в репозиторії у пакунок, що може бути запущений, і який називається *збірка*. Використовуючи версію коду за вказаним у процесі розгортання коммітом, етап збірки завантажує [залежності](./dependencies) та компілює бінарні файли і ресурси (assets). +* *Етап релізу* приймає збірку, отриману на етапі збірки, і об'єднує її з поточною [конфігурацією](./config) розгортання. Отриманий *реліз* містить збірку і конфігурацію і готовий до негайного запуску в середовищі виконання. +* *Етап виконання* (також відомий як "runtime") запускає застосунок у середовищі виконання, увімкнувши деякий набір [процесів](./processes) застосунку з певного релізу. + +![Код стає збіркою, яка поєднується з конфігурацією для створення релізу.](/images/release.png) + +**Застосунок дванадцяти факторів дотримується суворого відокремлення етапів збірки, релізу і виконання.** Наприклад, не можна вносити зміни в код під час етапу виконання, оскільки немає способу поширити ці зміни назад на етап збірки. + +Інструменти розгортання, як правило, надають засоби керування релізами, які дають можливість відкату до попередньої версії. Наприклад, інструмент розгортання [Capistrano](https://github.com/capistrano/capistrano/wiki) зберігає релізи в підкаталог з назвою `releases`, де поточний реліз є символічним посиланням на каталог поточного релізу. Команда Capistrano `rollback` дає можливість швидко виконати відкат до попередньої версії. + +Кожен реліз повинен завжди мати унікальний ідентифікатор, наприклад, мітку часу релізу (наприклад, `2011-04-06-20:32:17`) або номер, що зростає (наприклад, `v100`). Релізи можуть тільки додаватися, неможливо змінити реліз після його створення. Будь-які зміни мають створювати новий реліз. + +Збірка ініцюється розробником застосунку щоразу при розгортанні нового коду. Запуск етапу виконання, навпаки, може відбуватися автоматично в таких випадках, як перезавантаження сервера або перезапуск процесу, шо впав, менеджером процесів. Таким чином, етап виконання має бути максимально технічно простим, бо проблеми, які заважають застосунку запуститися, можуть призвести до його зупинки посеред ночі, коли розробників немає на місці. Етап збірки може бути більш складним, бо можливі помилки завжди видимі розробнику, який запустив процес розгортання. \ No newline at end of file diff --git a/content/uk/codebase.md b/content/uk/codebase.md new file mode 100644 index 000000000..75e86bf68 --- /dev/null +++ b/content/uk/codebase.md @@ -0,0 +1,17 @@ +## I. Кодова база +### Одна кодова база, що відслідковується в системі контролю версій та має багато розгортань + +Застосунок дванадцяти факторів завжди відслідковуються в системі контролю версій, такій як [Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/) або [Subversion](http://subversion.apache.org/). Копія бази даних відстеження ревізій називається *репозиторій коду (code repository)*, що часто скорочується до *code repo* або просто *repo*. + +*Кодова база* — це один репозиторій (в централізованих системах контролю версій, як Subversion), або декілька репозиторіїв, які мають спільний початковий комміт (в децентралізованих системах контролю версій, як Git). + +![Одна кодова база — багатьо розгортань](/images/codebase-deploys.png) + +Завжди існує однозначна відповідність між кодовою базою і застосунком: + +* За наявності кількох баз коду, це не застосунок, це — розподілена система. Кожен компонент в розподіленій системі є застосунком, і кожен з них може окремо дотримуватися дванадцяти факторів. +* Кілька різних застосунків, що спільно використовують загальну базу коду, є порушенням дванадцяти факторів. Рішенням в даній ситуації є виділення загального коду в бібліотеки, які можуть бути підключені через [менеджер залежностей](./dependencies). + +Існує тільки одна кодова база для кожного застосунку, але може бути багато розгортань одного і того самого застосунку. *Розгортанням (deploy)* є запущений екземпляр застосунку. Це, як правило, production-сайт і один або більше staging-сайтів (проміжних розгортань). Крім того, розробник має копію застосунку, запущеного в його локальному середовищі розробки. Кожну з таких копій також можна кваліфікувати як розгортання (deploy). + +Кодова база має бути єдина для всіх розгортань, хоча в кожному розгортанні можуть бути активні різні її версії. Наприклад, розробник може мати деякі зміни у коді, які ще не додані в staging-розгортання; staging-розгортання може мати деякі зміни, які ще не додані в production-розгортання. Але всі вони використовують одну і ту саму кодову базу, таким чином можна їх ідентифікувати як різні розгортання одного і того ж застосунку. \ No newline at end of file diff --git a/content/uk/concurrency.md b/content/uk/concurrency.md new file mode 100644 index 000000000..de609a2c8 --- /dev/null +++ b/content/uk/concurrency.md @@ -0,0 +1,14 @@ +## VIII. Конкурентність +### Масштабуйте застосунок за допомогою процесів + +Будь-яка комп'ютерна програма після запуску представлена одним або декількома процесами. Веб-додатки мають різні форми виконання процесів. Наприклад, PHP-процеси виконуються як дочірні процеси Apache, які запускаються в разі потреби в залежності від навантаження. Java-процеси використовують протилежний підхід: JVM забезпечує один масивний мета-процес, який резервує велику кількість системних ресурсів (процесора і пам'яті) під час його запуску, і керує конкурентністю всередині себе за допомогою потоків виконання (threads). В обох випадках запущені процеси видимі для розробників застосунку мінімально. + +![Масштабування виражається у вигляді запущених процесів, різноманітність навантаження виражається в типах процесів.](/images/process-types.png) + +**В застосунку дванадцяти факторів, процеси є сутностями першого класу.** Процеси в застосунку дванадцяти факторів взяли сильні сторони від [моделі процесів UNIX для запуску сервісів](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Використовуючи цю модель, розробник може спроектувати свій застосунок таким чином, що для обробки різних робочих навантажень необхідно призначити кожному виду робіт свій *тип процесу*. Наприклад, HTTP-запити можуть бути оброблені за допомогою веб-процесу (web process), а тривалі фонові завдання оброблені робочим процесом (worker process). + +Це не виключає можливості використання індивідуального мультиплексування для окремих процесів через потоки виконання віртуальної машини або асинхронні/подієві моделі в таких інструментах, як [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/) або [Node.js](http://nodejs.org/). Але індивідуальна віртуальна машина може масшабуватися тільки обмежено (вертикальне масшабування), тому застосунок також повинен мати можливість бути запущеним як декілька процесів на декількох фізичних машинах. + +Модель, побудована на процесах, дійсно показує себе з найкращого боку, коли постає необхідність масштабування. [Відсутність розділених даних і горизонтальне розділення процесів застосунку дванадцяти факторів](./processes) означає, що додавання більшої конкурентності є простою і надійною операцією. Масив типів процесів і кількість процесів кожного типу називається *формацією процесів*. + +Процеси застосунку дванадцяти факторів [ніколи не мають демонізуватися](http://dustin.github.com/2010/02/28/running-processes.html) та записувати PID-файли. Замість цього вони мають покладатися на менеджер процесів операційної системи (наприклад, [systemd](https://www.freedesktop.org/wiki/Software/systemd/), розподілений менеджер процесів на хмарній платформі, або в процесі розробки на такий інструмент, як [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html)) для керування [потоком виведення](./logs), реагування на падіння процесів і обробку ініційованих користувачем перезавантаження чи завершення роботи. diff --git a/content/uk/config.md b/content/uk/config.md new file mode 100644 index 000000000..8205ba784 --- /dev/null +++ b/content/uk/config.md @@ -0,0 +1,22 @@ +## III. Конфігурація +### Зберігайте конфігурацію в середовищі виконання + +*Конфігурація* застосунку — це все, що може змінюватися між [розгортаннями](./codebase) (staging-розгортання, production-розгортання, локальне середовище розробника тощо). Це включає: + +* Параметри підключення до бази даних, Memcached і інших [сторонніх сервісів](./backing-services); +* Реєстраційні дані для підключення до зовнішніх сервісів, таких як Amazon S3 або Twitter; +* Значення, що залежать від середовища розгортання, такі як канонічне ім'я хосту. + +Застосунки іноді зберігають конфігурації як константи в коді. Це є порушенням методології дванадцяти факторів, яка вимагає **обов'язкового відокремлення конфігурації від коду**. Конфігурації застосунку в розгортаннях суттєво відрізняються, код — однаковий. + +Лакмусовим папірцем того, чи правильно розділені конфігурація і код, є можливість в будь-який момент відкрити вихідний код застосунку у вільний доступ, при цьому не оприлюднюючи будь-яких приватних даних. + +Зверніть увагу, що визначення "конфігурації" **не включає** в себе внутрішні налаштування застосунку, такі як `сonfig/routes.rb` в Rails, або [як пов'язані основні модулі](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) в [Spring](http://spring.io/). Ці налаштування не змінюються між розгортаннями, і тому краще місце для них — саме в коді. + +Іншим підходом до конфігурації є використання конфігураційних файлів, що не зберігаються в систему контролю версій, таких як `сonfig/database.yml` в Rails. Це перевага у порівнянні з використанням констант в коді, але все ж таки має суттєві недоліки: є ймовірність помилково зберегти файл конфігурації в репозиторій; існує тенденція коли конфігураційні файли розкидані в різних місцях і в різних форматах, і стає важко передивлятися всі налаштування і керувати ними в одному місці. Крім того, формати цих файлів, як правило, специфічні для конкретної мови програмування чи фреймворку. + +**Застосунок дванадцати факторів зберігає конфігурацію в *змінних оточення*** (часто скорочується до *env vars* або *env*). Значення змінних оточення легко змінити між розгортаннями без зміни коду; на відміну від конфігураційних файлів, менш ймовірно випадково зберегти їх в репозиторій коду; і на відміну від конфігураційних файлів або інших механізмів конфігурації, таких як Java System Properties, вони є стандартом, незалежним від мови програмування чи фреймворку. + +Іншим аспектом керування конфігурацією є групування. Іноді застосунки об'єднують конфігурації в іменовані групи (які часто називаються "оточеннями"), які називаються в залежності від конкретного розгортання, наприклад, `development`, `test` і `production` оточення в Rails. Цей метод погано масштабується: чим більше створюється різних розгортань застосунку, тим більше необхідно нових імен оточень, наприклад, `staging` або `qa`. При подальшому рості проекту розробники можуть додавати свої власні спеціальні оточення, наприклад, `joes-staging`, що призводить до комбінаторного вибуху конфігурації, який робить керування розгортанням застосунку нестабільним. + +У застосунку дванадцяти факторів змінні оточення є незв'язаними між собою засобами керування. Кожна змінна повністю незалежна від інших. Вони ніколи не групуються разом в "оточення", керування ними здійснюється незалежно для кожного розгортання. Ця модель добре масштабується разом з появою більшої кількості розгортань застосунку протягом його експлуатації. \ No newline at end of file diff --git a/content/uk/dependencies.md b/content/uk/dependencies.md new file mode 100644 index 000000000..64dde9f30 --- /dev/null +++ b/content/uk/dependencies.md @@ -0,0 +1,12 @@ +## II. Залежності +### Явно оголошуйте та ізолюйте залежності + +Більшість мов програмування мають системи пакунків для розповсюдження бібліотек, такі як [CPAN](http://www.cpan.org/) для Perl або [Rubygems](http://rubygems.org/) для Ruby. Бібліотеки, встановлені через систему пакунків, можуть бути доступними для всієї системи (так звані "site-packages") або встановлені в каталог застосунку (так звані "vendoring" або "bundling"). + +**Застосунок дванадцяти факторів ніколи не залежить від неявно існуючих, досупних всій системі пакунків.** Застосунок повно і точно вказує всі свої залежності за допомогою маніфесту *оголошення залежностей*. Крім того, він використовує інструмент *ізоляції залежністей* під час виконання, щоб гарантувати, що ніякі неявні залежності не "просочилися" з зовнішньої системи. Повна і явна специфікація залежностей використовується однаково як при розробці, так і в production. + +Наприклад, [Bundler](https://bundler.io/) в Ruby використовує `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/) для оголошення залежностей, а статичне зв'язування може забезпечити ізоляцію залежностей. Який би не використовувався набір інструментів, оголошення і ізоляція залежностей завжди мають використовуватися разом — тільки одне або інше не є достатньою умовою для задоволення дванадцяти факторів. + +Однією з переваг явного оголошення залежностей є те, що це спрощує налаштування застосунку для нових розробників. Новий розробник може скопіювати кодову базу застосунку на свою машину, необхідними вимогами для якої є тільки наявність середовища виконання мови програмування та наявність менеджера залежностей. Все необхідне для запуску коду застосунку може бути налаштоване за допомогою визначеної *команди збірки*. Наприклад, команда збірки для Ruby/Bundler є `bundle install`, а для Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) це `lein deps`. + +Застосунок дванадцяти факторів також ніколи не залежить від неявно існуючих будь-яких системних інструментів. Прикладом може бути запуск застосунком таких системних інструментів, як ImageMagick або `curl`. У той час, як ці інструменти можуть бути встановлені на багатьох або навіть більшості систем, немає жодної гарантії, що вони будуть встановлені на всіх системах, де застосунок може запускатися в майбутньому, або версія інструменту, встановлена в системі, буде сумісна з застосунком. Якщо застосунку потрібно запускати певні системні інструменти, то такі інструменти мають бути включені в сам застосунок. \ No newline at end of file diff --git a/content/uk/dev-prod-parity.md b/content/uk/dev-prod-parity.md new file mode 100644 index 000000000..d31c57991 --- /dev/null +++ b/content/uk/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. Dev/prod паритет +### Прагніть максимальної ідентичності development, staging та production середовищ + +Історично склалося, що є суттєві відмінності між development середовищем (розробник вносить живі зміни в [локально розгорнутий](./codebase) застосунок) і production середовищем (до якого мають доступ кінцеві користувачі). Ці відмінності проявляються в трьох областях: + +* **Різниця в часі**: Розробник може працювати над кодом, який потрапить у production через дні, тижні або навіть місяці; +* **Різниця в персоналі**: Розробники пишуть код, Ops-інженери розгортають його; +* **Різниця в інструментах**: Розробники можуть використовувати стек технологій такий, як Nginx, SQLite та OS X, в той час як на production використовується Apache, MySQL та Linux. + +**Застосунок дванадцяти факторів проектується для [безперервного розгортання](http://avc.com/2011/02/continuous-deployment/), завдяки мінімізації різниці між production і development середовищами.** Розглянемо три відмінності, описані вище: + +* Зменшити різницю в часі: розробник може написати код і він буде розгорнутий через декілька годин або навіть хвилин; +* Зменшити різницю в персоналі: розробники, які писали код, беруть активну участь в його розгортанні і спостерігають за його поведінкою на production; +* Зменшити різницю в інструментах: тримати development та production середовища максимально ідентичними. + +Резюмуючи сказане вище в таблицю: + + + + + + + + + + + + + + + + + + + + + + +
Традиційний застосунокЗастосунок дванадцати факторів
Час між розгортаннямиТижніГодини
Автор коду/той хто розгортаєРізні людиТі ж люди
Dev/Prod розгортанняРізніМаксимально ідентичні
+ +[Сторонні служби](./backing-services), такі як бази даних, системи черг повідомлень або кеш, є однією з областей, де dev/prod паритет має важливе значення. Багато мов програмування мають бібліотеки, які спрощують доступ до сторонніх служб, в тому числі, *адаптери* для різних видів сервісів. Деякі приклади наведені в таблиці нижче. + + + + + + + + + + + + + + + + + + + + + + + + + + +
ТипМоваБібліотекаАдаптери
База данихRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
Черга повідомленьPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
КешRuby/RailsActiveSupport::CacheПам'ять, файлова система, Memcached
+ +Іноді розробники бачать переваги у використанні "легких" сторонніх служб в їхньому локальному середовищі, в той час як більш серйозні і надійні сторонні служби будуть використовуватися у production. Наприклад, локально використовують SQLite, а на production PostgreSQL; або локально пам'ять процесу для кешування, а на production Memcached. + +**Розробник застосунку дванадцяти факторів уникає використання різних сторонніх служб в development і production середовищах**, навіть якщо адаптери теоретично абстраговані від будь-яких відмінностей у сторонніх службах. Відмінності між сторонніми службами означають, що може виникнути крихітна несумісність, в результаті чого код, який працював і пройшов тестування в development та staging середовищах, після розгортання не працює в production середовищі. Такий тип помилок створює перешкоди, які нівелюють переваги безперервного розгортання. Ціна цих перешкод і подальшого відновлення безперервного розгортання надзвичайно висока, якщо розглядати в сукупності за весь час експлуатації застосунку. + +Встановлення локально "легких" сторонніх сервісів вже не є таким привабливим, як було раніше. Сучасні надійні сторонні сервіси, такі як Memcached, PostgreSQL і RabbitMQ, досить легко встановити і запустити завдяки сучасним менеджерам пакунків, таким як [Homebrew](http://mxcl.github.com/homebrew/) і [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Крім того, декларативні інструменти підготовки середовища, такі як [Chef](http://www.opscode.com/chef/) і [Puppet](http://docs.puppetlabs.com/), у поєднанні з "легким" віртуальним середовищем, таким як [Vagrant](http://vagrantup.com/), дозволяють розробникам запускати локальні середовища, які наближені до production. Ціна встановлення і використання цих систем є низькою у порівнянні з користю dev/prod паритету і безперервного розгортання. + +Адаптери для різних сторонніх сервісів все ж корисні, тому що вони роблять перенесення застосунку для використання з іншими сторонніми сервісами відносно безболісним. Але всі розгортання застосунку (development, staging та production середовища) мають використовувати один і той самий тип і версію кожного зі сторонніх сервісів. \ No newline at end of file diff --git a/content/uk/disposability.md b/content/uk/disposability.md new file mode 100644 index 000000000..1aa86f6dd --- /dev/null +++ b/content/uk/disposability.md @@ -0,0 +1,12 @@ +## IX. Утилізовуваність +### Підвищуйте надійність за допомогою швидкого запуску і коректного вимкнення + +**[Процеси](./processes) застосунку дванадцати факторів є *утилізовуваними*, тобто вони можуть бути запущені або зупинені в будь-який момент.** Це сприяє гнучкому масштабуванню, швидкому розгортанню [коду](./codebase) або змінам [конфігурації](./config) і надійності production-розгортання. + +Слід намагатися **мінімізувати час запуску процесів**. В ідеалі час між моментом виконання команди запуску процесу і моментом, коли процес готовий приймати запити чи задачі, має тривати лише пару секунд. Короткий час запуску забезпечує більшу гнучкість для [релізу](./build-release-run) і масштабування. Крім того, це підвищує стійкість, оскільки менеджер процесів може легко переміщувати процеси на нові фізичні машини у разі необхідності. + +Процеси мають **коректно завершувати свою роботу, коли вони отримують [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** сигнал від диспетчеру процесів. Для веб-процесу коректне завершення роботи досягається завдяки припиненню прослуховування порту, до якого він прив'язаний (що означає відмову від отримання будь-яких нових запитів), завершенню обробки будь-яких поточних запитів та зупинці самого процесу. В цій моделі передбачається, що HTTP-запити короткі (не більше ніж кілька секунд), а у разі довгих запитів (long polling) клієнт має намагатися відновити з'єднання у разі його втрати. + +Для процесу, що виконує фонові задачі (worker), коректне завершення роботи досягається за рахунок повернення поточного завдання назад у чергу задач. Наприклад, в [RabbitMQ](http://www.rabbitmq.com/) робочий процес може надіслати команду [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); в [Beanstalkd](https://beanstalkd.github.io) завдання повертається в чергу автоматично щоразу, коли процес втрачає з'єднання. Системи, що використовують блокування, такі як [Delayed Job](https://github.com/collectiveidea/delayed_job#readme), мають бути повідомлені, щоб звільнити блокування задачі. В цій моделі передбачається, що всі задачі є [повторно вхідними](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), що зазвичай досягається шляхом обертання результатів їхньої роботи в транзакції або шляхом використання [ідемпотентних](http://en.wikipedia.org/wiki/Idempotence) операцій. + +Процеси також мають бути **стійкі до раптової зупинки** в разі відмови апаратних засобів, на яких вони запущені. Хоча це менш ймовірна подія, ніж коректне завершення роботи за допомогою сигналу `SIGTERM`, вона все ж таки може статися. Рекомендованим підходом є використання надійних черг завдань, таких як Beanstalkd, які повертають завдання в чергу задач, коли клієнти втрачають з'єднання або від'єднуються по тайм-ауту. У будь-якому випадку, застосунок дванадцяти факторів має проектуватися таким чином, щоб обробляти несподівані та некоректні вимкнення. Прикладом вдалої реалізації [архітектури "тільки аварійного вимкнення" (Crash-only design)](http://lwn.net/Articles/191059/) є [СouchDB](http://docs.couchdb.org/en/latest/intro/overview.html). diff --git a/content/uk/intro.md b/content/uk/intro.md new file mode 100644 index 000000000..736e89c77 --- /dev/null +++ b/content/uk/intro.md @@ -0,0 +1,12 @@ +Вступ +===== + +У наш час програмне забезпечення зазвичай поставляється у вигляді сервісів, що називаються *веб-застосунки* (web-apps) або *software-as-a-service* (SaaS). Застосунок дванадцяти факторів — це методологія для створення SaaS-застосунків, які: + +* Використовують **декларативний** формат для автоматизації встановлення та налаштування, що зводить до мінімуму витрати часу і коштів для нових розробників, що приєднуються до проекту; +* Мають **угоду** з операційною системою, пропонуючи **максимальну переносимість** між середовищами виконання; +* Придатні для **розгортання** на сучасних **хмарних платформах**, що усуває необхідність у серверах та їх системному адмініструванні; +* **Мінімізують різницю** між середовищем розробки і production середовищем, що дозволяє **безперервне розгортання** (continuous deployment) для забезпечення максимальної спритності розробки (agility); +* Можуть **масштабуватися** без значних змін в інструментах, архітектурі і практиці розробки. + +Методологію дванадцяти факторів можна використати для застосунків, що написані будь-якою мовою програмування та використовують будь-яку комбінацію із сторонніх служб (бази даних, черги, кеш-пам'ять тощо). \ No newline at end of file diff --git a/content/uk/logs.md b/content/uk/logs.md new file mode 100644 index 000000000..324dc0b39 --- /dev/null +++ b/content/uk/logs.md @@ -0,0 +1,16 @@ +## XI. Журналювання +### Сприймайте журналювання (logs) як потоки подій + +*Журналювання* забезпечує наочне уявлення про поведінку запущеного застосунку. Зазвичай у серверних середовищах журнали записуються у файл на диску ("logfile"), але це лише один з форматів виведення. + +Журнал — це [потік](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) агрегованих, впорядкованих за часом подій, зібраних з потоків виведення всіх запущених процесів і сторонніх сервісів. Журнал в сирому вигляді, як правило, має текстовий формат з однією подією на кожен рядок (хоча трасування винятків можуть займати кілька рядків). Журнали не мають фіксованого початку і кінця, потік безперервний поки працює застосунок. + +**Застосунок дванадцяти факторів ніколи не займається маршрутизацію і зберіганням свого потоку виведення.** Застосунок не повинен записувати журнал у файл або керувати файлами журналів. Замість цього кожен запущений процес записує свій потік подій без буферизації в стандартне виведення `stdout`. В development середовищі розробник має можливість переглядати цей потік в терміналі, щоб спостерігати за поведінкою застосунку. + +В staging та production розгортаннях потік виведення кожного процесу перехоплюється середовищем виконання, збирається разом з усіма іншими потоками виведення застосунку і спрямовується до одного або кількох кінцевих пунктів призначення для перегляду і довгострокового архівування. Ці кінцеві пункти призначення не видимі для застосунку і не налаштовуються ним, вони керуються середовищем виконання. Для цього можуть бути використані маршрутизатори журналів з відкритим вихідним кодом (наприклад, [Logplex](https://github.com/heroku/logplex) та [Fluentd](https://github.com/fluent/fluentd)). + +Потік подій застосунку може бути направлений у файл або переглянутий у терміналі в режимі реального часу. Найважливішим є те, що потік може бути направлений у систему індексування і аналізу журналів, таку як [Splunk](http://www.splunk.com/), або систему зберігання даних загального призначення, таку як [Hadoop/Hive](http://hive.apache.org/). Ці системи мають широкі можливості і гнучкість для детального аналізу поведінки застосунку протягом тривалого часу, в тому числі: + +* Виявлення конкретних подій у минулому; +* Побудова графіків трендів (наприклад, кількість запитів за хвилину); +* Активне оповіщення відповідно до визначених користувачем евристичних правил (наприклад, попередження, коли кількість помилок за хвилину перевищує певний поріг). diff --git a/content/uk/port-binding.md b/content/uk/port-binding.md new file mode 100644 index 000000000..99ae00cb7 --- /dev/null +++ b/content/uk/port-binding.md @@ -0,0 +1,14 @@ +## VII. Прив'язка портів +### Експортуйте сервіси за допомогою прив'язки портів (port binding) + +Веб-застосунки іноді запускаються всередині контейнера веб-сервера. Наприклад, PHP-застосунок може бути запущений як модуль всередині [Apache HTTPD](http://httpd.apache.org/) або Java-застосунок може бути запущений всередині [Tomcat](http://tomcat.apache.org/). + +**Застосунок дванадцяти факторів є повністю автономним** і в процесі виконання, щоб створити веб-сервіс, доступний через web, не покладається на ін'єкцію веб-сервера в середовище виконання. Веб-застосунок **експортує HTTP-сервіс шляхом прив'язки до порту** і прослуховує запити, що надходять на цей порт. + +У локальному development середовищі розробник відвідує URL-адресу вигляду `http://localhost:5000/` для доступу до сервісу, що експортується застосунком. При розгортанні рівень маршрутизації обробляє запити до загальнодоступного хосту і перенаправляє їх до порту, до якого прив'язано веб-процес. + +Як правило, це реалізується за допомогою [оголошення залежностей] (./dependencies) шляхом додавання бібліотеки веб-сервера до застосунку, наприклад, [Tornado](http://www.tornadoweb.org/) для Python, [Thin](http://code.macournoyer.com/thin/) для Ruby або [Jetty](http://www.eclipse.org/jetty/) для Java та інших мов на основі JVM. Це відбувається повністю в *просторі користувача*, тобто в коді застосунку. Прив'язка до порту для обробки запитів є "угодою" із середовищем виконання. + +HTTP — не єдиний сервіс, який може бути експортований шляхом прив'язки до порту. Майже будь-який вид серверного програмного забезпечення може бути запущений, прив'язаний до порту і може очікувати вхідні запити. Прикладами є [ejabberd](http://www.ejabberd.im/) (використовує [XMPP](http://xmpp.org/)) і [Redis](http://redis.io/) (використовує [протокол Redis](http://redis.io/topics/protocol)). + +Також зверніть увагу, що підхід прив'язки до портів означає, що застосунок може виступати як [стороння служба](./backing-services) для іншого застосунку, надаючи свою URL-адресу як ресурс в [конфігурації](./config) застосунку-споживача. \ No newline at end of file diff --git a/content/uk/processes.md b/content/uk/processes.md new file mode 100644 index 000000000..be4a0b338 --- /dev/null +++ b/content/uk/processes.md @@ -0,0 +1,14 @@ +## VI. Процеси +### Запускайте застосунок як один або декілька процесів без збереження внутрішньго стану (stateless) + +Застосунок запускається в середовищі виконання у вигляді одного або декількох *процесів*. + +У найпростішому випадку код є окремим скриптом, середовище виконання — ноутбук розробника зі встановленим середовищем виконання мови програмування, а процес запускається за допомогою командного рядка (наприклад, `python my_script.py`). В іншому випадку, це може бути production-розгортання складного застосунку, яке може використовувати багато [типів процесів, кожен з яких запущений у необхідній кількості екземплярів](./concurrency). + +**Процеси застосунку дванадцяти факторів не зберігають внутрішній стан (stateless) і [не розділяють ресурси](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Будь-які дані, що підлягають збереженню, мають зберігатися в [сторонній службі](./backing-services) зі збереженням внутрішнього стану (stateful) (як правило, в базі даних). + +Пам'ять та файлова система процесу можуть бути використані як короткостроковий кеш. Наприклад, завантаження, обробка і збереження великого файлу в базі даних. Застосунок дванадцяти факторів ніколи не припускає, що щось, закешоване в пам'яті або на диску, буде доступне при наступному запиті — за наявності багатьох запущених процесів різних типів є велика ймовірність, що наступний запит буде оброблений іншим процесом. Навіть при роботі тільки одного процесу перезапуск (викликаний розгортанням, змінами конфігурації або переміщенням процесу в інше фізичне місце розташування середовищем виконання), як правило, призведе до знищення всіх локальних (у пам'яті і файловій системі) станів. + +Пакувальники ресурсів (наприклад, [Jammit](http://documentcloud.github.com/jammit/) або [django-compressor](http://django-compressor.readthedocs.org/)) використовують файлову систему як кеш для скомпільованих ресурсів. Застосунок дванадцяти факторів надає перевагу здійсненню такої компіляції під час [етапу збірки](./build-release-run), наприклад, як в [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html), а не під час виконання. + +Деякі веб-системи покладаються на ["липкі сесії"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) — тобто кешують дані сесії користувача в пам'яті процесу застосунку і очікують, що наступні запити від того ж самого користувача будуть спрямовані до того ж самого процесу. Липкі сесії є порушенням дванадцяти факторів і їх ніколи не слід використовувати та покладатися на них. Дані сесії користувача є хорошим кандидатом для сховища даних, яке надає функцію обмеження терміну зберігання, наприклад, [Memcached](http://memcached.org/) або [Redis](http://redis.io/). \ No newline at end of file diff --git a/content/uk/toc.md b/content/uk/toc.md new file mode 100644 index 000000000..b9f5cb23e --- /dev/null +++ b/content/uk/toc.md @@ -0,0 +1,38 @@ +Дванадцять факторів +=================== + +## [I. Кодова база](./codebase) +### Одна кодова база, що відслідковується в системі контролю версій та має багато розгортань + +## [II. Залежності](./dependencies) +### Явно оголошуйте та ізолюйте залежності + +## [III. Конфігурація](./config) +### Зберігайте конфігурацію в середовищі виконання + +## [IV. Сторонні служби](./backing-services) +### Вважайте сторонні служби (backing services) підключеними ресурсами + +## [V. Збірка, реліз, виконання](./build-release-run) +### Суворо відокремлюйте етапи збірки та виконання + +## [VI. Процеси](./processes) +### Запускайте застосунок як один або декілька процесів без збереження внутрішньго стану (stateless) + +## [VII. Прив'язка портів](./port-binding) +### Експортуйте сервіси за допомогою прив'язки портів (port binding) + +## [VIII. Конкурентність](./concurrency) +### Масштабуйте застосунок за допомогою процесів + +## [IX. Утилізовуваність](./disposability) +### Підвищуйте надійність за допомогою швидкого запуску і коректного вимкнення + +## [X. Dev/prod паритет](./dev-prod-parity) +### Прагніть максимальної ідентичності development, staging та production середовищ + +## [XI. Журналювання](./logs) +### Сприймайте журналювання (logs) як потоки подій + +## [XII. Задачі адміністрування](./admin-processes) +### Виконуйте задачі адміністрування/керування за допомогою разових процесів \ No newline at end of file diff --git a/content/uk/who.md b/content/uk/who.md new file mode 100644 index 000000000..2041a0c75 --- /dev/null +++ b/content/uk/who.md @@ -0,0 +1,4 @@ +Кому слід читати цей документ? +============================== + +Розробникам, які створюють SaaS-застосунки. Ops-інженерам, які виконують розгортання і керування такими застосунками. \ No newline at end of file diff --git a/content/vi/admin-processes.md b/content/vi/admin-processes.md new file mode 100644 index 000000000..60bf77426 --- /dev/null +++ b/content/vi/admin-processes.md @@ -0,0 +1,14 @@ +## XII. Tiến trình quản trị +### Thực thi nhiệm vụ quản trị như là một tiến trình + +[Công thức cho các tiến trình](./concurrency) là danh sách các tiến trình được sử dụng để thực thi các nghiệp vụ của ứng dụng (như là điều khiển web) khi chúng vận hành. Ngoài ra, lập trình viên thường mong muốn thực hiện các nhiệm vụ quản trị ứng dụng như là: + +* Áp dụng các thay đổi cho cơ sở dữ liệu (như là `manage.py migrate` với Django, `rake db:migrate` với Rails). +* Giao diện điều khiển trực tiếp ứng dụng (được biết đến như là vỏ [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop)) để vận hành các đoạn mã nguồn tuỳ ý hoặc kiểm tra các mô hình của ứng dụng đối với cơ sở dữ liệu hiện tại. Hầu hết các ngôn ngữ cung cấp REPL bằng cách thực thi một bộ biên dịch không có tham số như là (e.g. `python` or `perl`) hoặc trong vài trường hợp có các câu lệnh đặc biệt (như là `irb` với Ruby, `rails console` với Rails). +* Thực thi một lần đoạn kịch bản được quản lý trên kho mã nguồn của ứng dụng (như là `php scripts/fix_bad_records.php`). + +Tiến trình quản trị thực thi một lần nên đươcj vận hành trong một môi trường giống như [tiến trình vận hành lâu dài](./processes) của ứng dụng. Với một bản [phát hành](./build-release-run), các tiến trình quản trị sử dụng cùng [mã gốc](./codebase) và [cấu hình](./config) như bất kỳ các tiến trình vận hành trong bản phát hành đó. Đoạn mã quản trị cần được triển khai cùng với mã của ứng dụng để đảm bảo không có các vấn đề về mặt động bộ hoá. + +Kỹ thuật [cô lập phụ thuộc](./dependencies) tương tự được sử dụng cho cùng một kiểu tiến trình. Ví dụ tiến trình web sử dụng Ruby sử dụng câu lệnh `bundle exec thin start`, sau đó việc đồng bộ hoá cơ sở dữ liệu sử dụng câu lệnh `bundle exec rake db:migrate`. Tương tự, một chương trình Python sử dụng môi trường ảo cung cấp câu lệnh `bin/python` cho việc vận hành máy chủ web Tornado và bất cứ tiến trình quản trị thông qua `manage.py`. + +Mười hai hệ số ưu tiên sử dụng các ngôn ngữ cung cấp vỏ REPL linh hoạt, và làm nó trở nên dễ dàng cho việc thực thi một lần các kịch bản. Trong môi trường triển khai cục bộ, lập trình viên thực thi các tiến trình quản trị bằng cách thực thi trực tiếp các câu lệnh trong thư mục lưu trữ mã nguồn của ứng dụng. Trong môi trường vận hành thực tế, lập trình viên có thể sử dụng ssh hoặc các câu lệnh điều khiển thực thi cơ chế được cung cấp bởi môi trường vận hành của quá trình triển khai để thực thi các tiến trình. diff --git a/content/vi/background.md b/content/vi/background.md new file mode 100644 index 000000000..927c3e61e --- /dev/null +++ b/content/vi/background.md @@ -0,0 +1,17 @@ +Gốc gác +======= + +Tất cả tác giả của tài liệu này đã trực tiếp tham gia vào quá trình phát triển và triển +khai của hàng trăm ứng dụng, và gián tiếp theo dõi các quá trình phát triển, vận hành, +và mở rộng của hàng nghìn ứng dụng thông qua công việc của chúng tôi trên hệ thống [Heroku](http://www.heroku.com/). + +Tài liệu này là cô đọng của tất cả kinh nghiệm và quan sát của chúng tôi trên một số lượng +lớn các ứng dụng-như-một-dịch vụ ở ngoài. Đây là kết hợp của kiến thức thực hành chuẩn mực +trong việc phát triển ứng dụng, với trọng tâm vào cơ cấu phát triển cơ bản của ứng dụng trong +một khoảng thời gian, cơ cấu động của sự hợp tác giữa các lập trình viên đang làm việc trên +cùng một mã gốc, và [tránh rò rỉ chi phí phát triển phần mềm](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/). + +Động lực của chúng tôi là tăng cường nhận thức về các vấn đề hệ thống mà chúng tôi biết +với các qui trình phát triển ứng dụng hiện tại, để chia sẻ một kho kiến thức thảo luận +về các vấn đề này, và để cung cấp một chuỗi các giải pháp mở chác vấn đề trên và cũng đi kèm +với các thuật ngữ chuyên môn. Định dạng này lấy ý tưởng từ cuốn sách *[Patterns of Enterprise Application Architecture](http://books.google.com/books/about/Patterns_of_enterprise_application_archi.html?id=FyWZt5DdvFkC)* và *[Refactoring](http://books.google.com/books/about/Refactoring.html?id=1MsETFPD3I0C)* của ông Martin Fowler. diff --git a/content/vi/backing-services.md b/content/vi/backing-services.md new file mode 100644 index 000000000..19b2301e9 --- /dev/null +++ b/content/vi/backing-services.md @@ -0,0 +1,14 @@ +## IV. Dịch vụ hỗ trợ +### Dịch vụ hỗ trợ như là tài nguyên bổ xung + +*Dịch vụ hỗ trợ* là các dịch vụ mà ứng dụng sử dụng thông qua mạng như là một thành phần trong vận hành. Ví dụ bao gồm nơi lưu trữ dữ liệu (như là [MySQL](http://dev.mysql.com/) hoặc [CouchDB](http://couchdb.apache.org/)), hệ thống tin nhắn/hàng đợi (như là [RabbitMQ](http://www.rabbitmq.com/) hoặc [Beanstalkd](http://kr.github.com/beanstalkd/)), dịch vụ SMTP để gửi thư điện tử ra ngoài (như là [Postfix](http://www.postfix.org/)), và hệ thống đệm (như là [Memcached](http://memcached.org/)). + +Dịch vụ hỗ trợ như cơ sở dữ liệu thường được quản lý bởi chính hệ thống quản trị của dịch vụ đó trong quá trình triển khai ứng dụng. Thêm vào đó, việc quản trị dịch vụ cục bộ, các ứng dụng có thể sử dụng các dịch vụ được cung cấp và quản lý bởi bên thứ ba. Ví dụ như các dịch vụ SMTP (như [Postmark](http://postmarkapp.com/)), các dịch vụ thu thập thông tin đo lường (metrics-gathering services) (như [New Relic](http://newrelic.com/) hay [Loggly](http://www.loggly.com/)), dịch vụ tài sản nhị phân (binary assets services) (như [Amazon S3](http://aws.amazon.com/s3/)), và các dịch vụ sử dụng API (như [Twitter](http://dev.twitter.com/), [Google Maps](http://code.google.com/apis/maps/index.html), hoặc [Last.fm](http://www.last.fm/api)). + +**Mã nguồn của ứng dụng áp dụng mười hai-hệ số cho phép không có sự khác biệt giữa dịch vụ cục bộ và bên thứ ba.** Đối với ứng dụng, cả tài nguyên bổ xung và có thể truy cập thông qua URL hoặc thông tin tài khoản được lưu trữ trong [cấu hình](./config). Một [triển khai](./codebase) của ứng dụng áp dụng mười hai-hệ số có thể chuyển đổi giữa cơ sở dữ liệu MySQL cục bộ với một cơ sở dữ liệu được quản lý bởi bên thứ ba (như [Amazon RDS](http://aws.amazon.com/rds/)) mà không phải thay đổi bất kỳ một đoạn mã nguồn nào của ứng dụng. Giống như, máy chủ SMTP cục bộ có thể được thay thế bởi dịch SMTP của bên thứ ba (như Postmark) mà không thay đổi mã nguồn. Trong cả hai trường hợp, chúng ta chỉ cần thay đổi các tài nguyên được quản lý trong cấu hình. + +Mỗi dịch vụ hỗ trợ riêng biệt là một *tài nguyên*. Ví dụ, cơ sở dữ liệu MySQL là một tài nguyên, hai cơ sở dữ liệu MySQL (sử dụng cho việc phân tách ở tầng ứng dụng) được xác định là hai tài nguyên riêng biệt. Ứng dụng áp dụng mười hai-hệ số đối xử các cơ sở dữ liệu như là *tài nguyên bổ sung*, nhằm đảm bảo kết nối lỏng lẻo với triên khai mà chúng được bổ xung. + +A production deploy attached to four backing services. + +Tài nguyển có thể được thêm vào triển khai khi cần thiết. Ví dụ, nếu cơ sở dữ liệu của ứng dụng bị mất do lỗi phần cứng, quản trị viên của ứng dụng có thể thêm vào một máy chủ cơ sở dữ liệu được khôi phục từ các sao lưu trước đó. Các thay đổi bao gồm cơ sở dữ liệu chính đang sử dụng có thể được loại bỏ, và bổ xung cơ sở dữ liệu mới có thể xảy ra mà không cần thay đổi bất kỳ một đoạn mã nguồn nào. diff --git a/content/vi/build-release-run.md b/content/vi/build-release-run.md new file mode 100644 index 000000000..d3ccc9cf5 --- /dev/null +++ b/content/vi/build-release-run.md @@ -0,0 +1,18 @@ +## V. Xây dựng, phát hành, vận hành +### Tách biệt hoàn toàn giữa bước xây dựng và vận hành + +[Mã gốc](./codebase) được chuyển sang (tạm dừng phát triển) triển khai thông qua ba bước: + +* Bước xây dựng* là bước chuyển các đoạn mã thành các gói có khả năng thực thi được gọi là một *bản xảy dựng*. Sử dụng phiên bản của mã nguồn ở một bản cam kết (commit) quy định bở quy trình triển khai, bước xây dựng lấy về và cung cấp các [phụ thuộc](./dependencies) và biên dịch các thành phần và tài nguyên. +* Bước phát hành* sử dụng các kết quả của bước xây dựng và kết hợp với các [cấu hình](./config) triển khai hiện tại. Kết quả của *phát hành* bao gồm cả bản xây dựng và các câu hình cho phép ứng dụng có thể được vận hành trong môi trường vận hành. +* Bước vận hành* (được biết như là "thời gian vận hành" (runtime)) vận hành ứng dụng trong môi trường thực thi, bằng việc thực thi một tập các [tiến trình](./process) của của ứng dụng với một phiên bản phát hành cụ thể. + +![Mã nguồn được xây dựng, kết hợp với các cấu hình để cung cập một phát hành.](/images/release.png) + +**Ứng dụng sử dụng mười hai-hệ số tách biệt hoàn toàn giữa các bước xây dựng, phát hành và vận hành.** Ví dụ, chúng ta không thể tạo ra các thay đổi của mã nguồn khi đang vận hành, do đó không có khả năng quay ngược lại bước xây dựng. + +Công cụ triển khai thường cung cấp công cụ quản lý phát hành, cùng với các ký pháp cho phép quay ngược lại bản phat hành trước đó. Ví dụ, công cụ triển khai [Capistrano](https://github.com/capistrano/capistrano/wiki) lưu trữ các phát hành trong thư mục con tên là `releases`, nơi mà phiên bản hiện tại được liên kết giả đến thư mục phát hành hiện tại. Lệnh `rollback` làm cho việc quay trở lại phiên bản trước trở nên dễ dàng. + +Mỗi phát hành đều có một định danh duy nhất ID, như là dựa vào thời gian phát hành (như `2011-04-06-20:32:17`) hoặc một số tự tăng (như `v100`). Các phiên bản được tạo ra thành một chuỗi liên tục và một phiên bản không thể thay đổi sau khi nó được tạo ra. Bất cứ thay đổi nào đểu tạo ra một bản phát hành mới. + +Các bước xây dựng được khởi tạo với nhà phát triển ứng dụng khi mà mã nguồn được triển khai. Thời gian thực thi, ngược lại, có thể tự động xảy ra trong trường hợp các máy chủ được khởi động lại, hoặc tiến trình tạm dừng được khởi động lại bởi bộ quản lý các tiến trình. Do đó, bước vận hành nên được giữ các thành phần thay đổi càng ít càng tốt, vì các sự cố xảy ra làm ứng dụng không vận hành được có thể gây ra các thiệt hại lúc nửa đêm khi mà không có bất kỳ lập trình viên nào có thể khắc phục sự cố. Bước xây dựng có thể phức tạp hơn, vì các lỗi có thể xuất hiện trước mắt cho lập trình viên, người đang thực hiện triển khai biết được. diff --git a/content/vi/codebase.md b/content/vi/codebase.md new file mode 100644 index 000000000..9be6bc17d --- /dev/null +++ b/content/vi/codebase.md @@ -0,0 +1,24 @@ +## I. Mã gốc (codebase) +### Một mã gốc (codebase) được theo dõi với hệ thống quản lý phiên bản, và nhiều lần triển khai (deploy) + +Một ứng dụng 12-hệ số luôn luôn được theo dõi bới hê thống quản lý phiên bản, như là [Git](http://git-scm.com/), [Mercurial](http://mercurial.selenic.com/), hay [Subversion](http://subversion.apache.org/). Một bản lưu của cơ sở dữ liệu các phiên bản được gọi là **kho mã (code repository)**, và hay được viết vắn tắt thành *code repo* hay *repo*. + +Một *mã gốc* là bất kì một repo riêng lẻ (trong một hệ thống quản lý phiên bản thống nhất như Subversion), hoặc bất kì một nhóm các repo chia sẻ cùng một commit nguồn (root commit) (trong một hệ thống quản lý phiên bản kiểu phân quyển như Git). + +![Một mã gốc được gắn với nhiều triển khai](/images/codebase-deploys.png) + +Sẽ luôn luôn là sự tương quan một-với-một giữa mã gốc và ứng dụng: + +* Nếu có nhiều mã gốc, đấy không phải là một ứng dụng -- mà là một hệ thống phân tán. Với các +phần tử trong một hệ thống phân tán là một ứng dụng, với mỗi cá thể tuân theo luật 12-hệ số. +* Nhiều ứng dụng chia sẻ cùng một mã là vi phạm luật của 12-hệ số. Giải pháp ở đây là xem xét +để nhóm các mã chia sẻ thành các thư viện mà có thể được nhúng vào thông qua [trình quản lý các gói phụ thuộc (dependency manager)](./dependencies). + +Chỉ có một mã gốc từng ứng dụng, nhưng sẽ có nhiều triển khai của một ứng dụng. Một *triển khai* là một đối tượng thực thi của ứng dụng đó. Đây là trường hợp rất phổ biến của các trang +đã đi vào hoạt động, và của một vài trang thử nghiệm. Thêm vào đó mỗi lập trình viên sẽ có một +bản lưu của ứng dụng đang chạy trên môi trường phát triển cá nhân, mỗi bản đều được coi như là +một triển khai. + +Mã gốc sẽ giống nhau trên các triển khai, tuy là phiên bản khác nhau có thể hoạt dộng trong mỗi triển khai. Lấy một ví dụ, một lập trình viên có nhiều commit nhưng chưa triển khai vào +hệ thống thử (staging); hệ thống thử có nhiều commit mà chưa được triển khai trên hệ thống sản xuất (production). Nhưng cả hai đều chia sẻ cùng một mã gốc; thế nên phải định dạng chúng +như những cá thể triển khai của cùng một ứng dụng. diff --git a/content/vi/concurrency.md b/content/vi/concurrency.md new file mode 100644 index 000000000..8b3518328 --- /dev/null +++ b/content/vi/concurrency.md @@ -0,0 +1,15 @@ +## VIII. Đồng bộ hoá +### Mở rộng theo chiều ngang thông qua mô hình tiến trình + +Bất kỳ chương trình máy tính nào, khi vận hành, đều được đại diện bởi một hoặc nhiều tiến trình. Ứng dụng web có thể sử dụng bất kỳ dạng nào của tiến trình vận hành. Ví dụ, tiến trình PHP vận hành như là tiến trình con của Apache, chạy như một tiến trình nền dựa vào số lượng yêu cầu được gửi đến. Ứng dụng Java, tiếp cận theo cách ngược lại, với JVM cung cấp một tiến trình nền tảng lớn (a massive uberprocess) với lượng lớn các tài nguyên (CPU và bộ nhớ) được cấp phát ngay từ đầu, việc đồng bộ hoá được quản lý bên trong thông qua các luồng. Trong cả hai trường hợp, các tiến trình vận hành chỉ hiện hữu rất ít đối với các nhà phát triển của ứng dụng. +developers of the app. + +![Mở rộng được biểu diễn thông qua các tiến trình vận hành, Scale is expressed as running processes, hình thái của tải được biểu diễn như là kiểu tiến trình.](/images/process-types.png) + +**Trong ứng dụng áp dụng mười hai hệ số, các tiến trình là thành phần nền tảng đầu tiên.** Các tiến trình trong ứng dụng áp dụng mười hai hệ số sử dụng các tín hiệu rõ rệt từ [các mô hình tiến trình của unix cho các dịch vụ chạy nền](http://adam.heroku.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/). Sử dụng mô hinh này, các lập trình viên có thể thiết kế ứng dụng của họ để điều khiển các công việc khác nhau bằng cách gán mỗi loại tương ứng với một *kiểu tiến trình*. Ví dụ, yêu cầu HTTP có thể điều khiển bởi tiến trình web, và các ứng dụng chạy gầm tốn nhiều thời gian có thể được quản lý bởi các tiến trình làm việc. + +Điều này không loại bỏ các tiến trình các nhân khỏi việc quản lý chính các kênh nội bộ của tiến trình đó, thông qua các luồng bên trong máy áo đang thực thi, hoặc mô hình bất đồng bộ/xự kiện trong các công cụ như là [EventMachine](http://rubyeventmachine.com/), [Twisted](http://twistedmatrix.com/trac/), hoặc [Node.js](http://nodejs.org/). Nhưng một máy ảo (VM) riêng biệt chỉ có thể mở rộng (mở rộng theo chiều dọc), do đó ứng dụng cần có thể mở rộng thành các tiến trình chạy trên nhiều máy chủ vật lý. + +Mô hình tiến trình thực sự nổi trội khi mà việc mở rộng tài nguyên trở nên phổ biển. [Việc không chia sẻ, phân hoạch tự nhiên của các tiến trình của ứng dụng áp dụng mười hai hệ số](./processes) có nghĩa việc thêm các tiến trình đồng bộ hơn là đơn giản và tin cậy. Danh sách các kiểu tiến tình và số lượng tiến trình mỗi loại được biết đến như là *công thức tiến trình*. + +Tiến trình của ứng dụng mười hai hệ số [không bao giờ chạy như là dịch vụ nền](http://dustin.github.com/2010/02/28/running-processes.html) hoặc ghi ra tệp tin PID. Thay vào đó, tin tưởng vào hệ thống quản lý tiến trình của hệ điều hành (như là [Upstart](http://upstart.ubuntu.com/), hoặc hệ thống quản lý tiến trình phân tán trên nền tảng đám mấy, hoặc công cụ như là [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) trong quá trình phát triển) để quản lý [luồng xuất ra](./logs), phản hồi các tiến trình bị lỗi, và quản lý yêu cầu khởi động lại hoặc ngưng hoạt động của người dùng. diff --git a/content/vi/config.md b/content/vi/config.md new file mode 100644 index 000000000..f4273dc08 --- /dev/null +++ b/content/vi/config.md @@ -0,0 +1,27 @@ +## III. Cấu hình +### Lưu trữ cấu hình trong môi trường + +Cấu hình của ứng dụng là những thứ có thể thay đổi qua các [triển khai](./codebase) (hệ thống thử, hệ thống sản xuất, môi trường phát triển, etc). Nó bao gồm: +* Tài nguyên xử lý cơ sở dữ liệu, Memcached, và [dịch vụ lớp dưới](./backing-services) khác +* Thông tin đăng nhập đến các dịch vụ như là Amazon S3 hay Twitter +* Các giá trị ứng với từng triển khai như như là tên của máy chủ để triển khai + +Các ứng dụng thường lưu trữ các cấu hình như là hằng số trong mã nguồn. Điều này không phù hợp với nguyên tắc của 12-thừa số, yêu cầu **giới hạn tách biệt các cấu hình khỏi mã nguồn**. Các cấu hình thay đổi qua các triển khai, mã nguồn thì không. + +Một litmus test cho ứng dụng có các cấu hình được thừa số hoá chính xác là mã gốc có khả năng nguồn mở hoá bất kỳ lúc nào mà không lo sợ bị mất các thông tin đăng nhập. + +Chú ý rằng, định nghĩa của "cấu hình" không bao gồm các cấu hình nội tại của ứng dụng, như là `config/routes.rb` trong Rails, hoặc [các thành phần được kết nối](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) trong [Spring](http://spring.io/). Những cấu hình kiểu này thường không thay đổi giữa các triển khai, và do đó đã thực hiện tốt trong mã nguồn. + +Một cách tiếp cận khác với các cấu hình là việc sử dụng tệp tin cấu hình mà tệp tin đó không được quản lý phiên bản, như là `config/database.yml` trong Rails. Đây là một cải tiến lớn so với việc +sử dụng hằng số trong mã nguồn đã được quản lý phiên bản, nhưng vẫn có điểm yếu: dễ bị thêm nhầm vào quản lý phiên bản, các tệp tin cấu hình dễ bị phân tán ở những nơi khác nhau và các định dạng khác +nhau, làm cho nó trở nên khó đọc và quản lý tất các cấu hỉnh một cách tập trung. Ngoài ra, định dạng của các tệp tin chứa cấu hình thường do đặc tả của ngôn ngữ- hoặc framework-. + +**Ứng dụng áp dụng mười hai thừa số chứa các cấu hình trong *environment variables (biến môi trường)*** (thường viết tắt là *env vars* hoặc *env*). Các biến môi trường rất dễ để thay đổi giữa các triển khai +mà không phải thay đổi mã nguồn; không giống như tệp tin cấu hình, vẫn có khả năng để bị thêm vào kho mã (code repository); và không giống như các tệp tin cấu hình tuỳ chỉnh, hoặc cơ chế quảnl lý cấu +hình như là *Java System Properties*, các biến môi trường là *agnostic standard* theo ngôn ngữ và hệ điều hành. + +Một khía cạnh khác của quản lý cấu hình là nhóm các cấu hình. Đôi khi, các ứng dụng tổ chức các cấu hình theo nhóm (thường được gọi là "các môi trường") được đặt tên theo các triển khai, như là các môi trường`development`, `test`, and `production` trong Rails. Phương pháp này không mở rộng rõ ràng: nếu như có nhiều triển khải của ứng dụng được tạo ra, tên của các môi trường rất quan trọng, như là `staging` hoặc `qa`. Nếu một dự án phát triển sau này, lập trình viên có thể thêm các môi trường của riêng họ như là `joes-staging`, kết quả là một sự bùng nổ về các cấu hình, làm cho việc quản lý +các triển khai trở nên không ổn định. + +Trong một ứng dụng áp dụng mười hai thừa số, các biến môi trường được quản lý chi tiết, hoàn toàn độc lập với các biến môi trường khác. Chúng không được nhóm với nhau như là các "môi trường", nhưng +thay vào đó được quản lý độc lập theo các triển khai. Mô hình này giúp cho việc mở rộng trở nên trơn tru như là việc thêm vào các triển khai theo vòng đời của phần mềm được mở rộng một cách tự nhiên. diff --git a/content/vi/dependencies.md b/content/vi/dependencies.md new file mode 100644 index 000000000..0c73a06f2 --- /dev/null +++ b/content/vi/dependencies.md @@ -0,0 +1,23 @@ +## II. Các phụ thuộc +### Khai báo rõ ràng và phân tách các phụ thuộc + +Hầu hết các ngôn ngữ lập trình đều cung cấp hệ thống gói để phân phối các gói thư viện hỗ trợ, ví dụ như [CPAN](http://www.cpan.org/) cho Perl hay [Rubygems](http://rubygems.org/) cho Ruby. Các thư viện cài đặt thông qua một hệ thống gói có thể được cài đặt ở mức phủ hệ thống (được biết đến với thuật ngữ "site packages") hay được nhóm và trong một thư mục có kèm ứng +dụng (được biết đến với thuật ngữ "vendoring" hay "bundling"). + +**Một ứng dụng 12-hệ số không bao giờ phụ thuộc vào sự hiện diện tuyệt đối của các gói hệ +thống.** Nó khai báo toàn bộ các phụ thuộc hoàn toàn thông qua bản kê khai *khai báo phụ thuộc*. Hơn thế nữa nó còn sử dụng công cụ *phân cách phụ thuộc* trong quá trình thực thi để +đảm bảo rằng không có các phụ thuộc tuyệt đối nào bị "lọt" vào trong các hệ thống xung quanh. +Khai báo đầy đủ và rõ ràng các phụ thuộc được áp dụng đồng đều cho cả hệ thống sản xuất và +phát triển. + +Lấy ví dụ [Gem Bundler](http://gembundler.com/) của Ruby cung cấp định dạng kê khai `Gemfile` để khai báo phụ thuộc và `bundle exec` để phân cách phụ thuộc. Với Python thì có công cụ riêng biệt cho các bước trên -- [Pip](http://www.pip-installer.org/en/latest/) được dùng để khai báo [Virtualenv](http://www.virtualenv.org/en/latest/) để phân cách. Ngay cả C có [Autoconf](http://www.gnu.org/s/autoconf/) để khai báo phụ thuộc, và liên kết tĩnh (static linking) có thể cung cấp phân cách phụ thuộc. Bất kể công cụ gì, kê khai phụ thuộc và phân cách luôn phải đi đôi với nhau -- chỉ cần thiếu một trong hai là không đạt yêu câu của của 12-hệ số. + +Một ích lợi khác của khai báo phụ thuộc rõ ràng là nó đơn giản hoá quá trình cài đặt cho +lập trình viên mới tiếp nhận dự án. Các lập trình viên mới có thể lấy về mã trên hệ thống +phát triển của họ, chỉ với một yêu cầu là cài đặt trước ngôn ngữ lập trình và trình quản lý +phụ thuộc. Chúng có thể được dùng để thiết lập mọi thứ cần để vận hành một ứng dụng với một +*lệnh biên dịch/xây dựng* định sẵn. Lấy một ví dụ cụ thể là lệnh thiết lập cho Ruby/Bundler là `bundle install`, còn với Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) là `lein deps`. + +Các ứng dụng 12-hệ số đông thời có thể không phụ thuộc vào bất cứ sự hiện diện của các công cụ hệ thống tuyệt đối nào. Các ví dụ bao gồm các công cụ cài đặt sẵn như ImageMagick hay `curl`. Trong khi các công cụ trên có thể hiện diện trên đa số các hệ thống, nhưng không có gì bảo +đảm là chúng sẽ hiện diện trên toàn bộ các hệ thống mà ứng dụng có thể chạy trong tương la, hoặc có chăng phiên bản tìm thấy trên các hệ thống tương lai sẽ tương thích với ứng dụng. Nếu ứng dụng cần được cài sẵn như một công cụ hệ thống, các công cụ đó nên được đi kèm cùng +với ứng dụng. diff --git a/content/vi/dev-prod-parity.md b/content/vi/dev-prod-parity.md new file mode 100644 index 000000000..bf83fb9c9 --- /dev/null +++ b/content/vi/dev-prod-parity.md @@ -0,0 +1,75 @@ +## X. Sự tương đồng giữa quá trình phát triển và vận hành thực tế +### Đảm bảo sự tương đồng giữa môi trường phát triển, kiểm thử và thực tế + +Trước đây, có sự khác biệt nhất định giữa quá trình phát triển (lập trình viên có thể tạo ra các bản chỉnh sửa [triển khai](./codebase) cục bộ của ứng dụng) và vận hành thực tế (phiên bản được triển khai thực tế và truy cập bởi khách hàng). Khác biệt này được thể hiện ở ba lĩnh vực: + +* **Về thời gian**: Lập trình viên có thể làm việc với mã nguồn hàng ngày, tuận, thậm chỉ là hàng tháng để có một phiên bản vận hành thực tế. +* **Về tính cá nhân**: Lập trình viên viết mã nguồn, người vận hành triển khai mã nguồn đó. +* **Về công cụ**: Lập trình viên có thể sử dụng tập các công cụ như là Nginx, SQLite, và OS X, trong khi triển khai thực tế sử dụng Apache, MySQL, và Linux. + +**Ứng dụng áp dụng mười hai hệ số được thiết kế để [triển khai liên tục](http://www.avc.com/a_vc/2011/02/continuous-deployment.html) bằng việc giảm thiểu khác biệt giữa quá trình triển khai và vận hành thực tế.** Chúng ta cùng xem lại các sự khác biệt ở trên: + +* Giảm thiểu thời gian: lập trình viên có thể viết mã nguồn và nó được triển khai vài giờ, thậm chí vài phút sau đó. +* Giảm thiểu tính cá nhân: lập trình viên người viết ra các dòng lệnh, có thể tham gia trực tiếp vào quá trình triển khai và quan sát các hình vi của ứng dụng trong môi trường vận hành thực tế. +* Giảm thiểu các công cụ: đảm bảo sự tương đồng giữa môi trường phát triển và vận hành. + +Tổng kết vấn đề trên thông qua bảng sau: + + + + + + + + + + + + + + + + + + + + + +
Ứng dụng truyền thốngỨng dụng sử dụng mười hai hệ số
Thời gian giữa các lần triển khaiHàng tuầnHàng giờ
Tác giả và người triển khai mã nguồnKhác nhauCùng một người
Môi trường phát triển và thực tếKhông đồng nhấtTương đồng
+ +[Dịch vụ hỗ trợ](./backing-services), như là cơ sở dữ liệu của ứng dụng, hệ thống hàng đợi hoặc bộ đệm, là nơi mà thường có sự khác biệt giữa môi trường phát triển và vận hành. Rất nhiều ngôn ngữ cung cấp các thư viện, bao gồm nhiều *mô phỏng* của các loại dịch vụ khác nhau được cung cấp để làm đơn giản hoá việc truy cập các dịch vụ hỗ trợ. Một vài ví dụ ở bảng sau: + + + + + + + + + + + + + + + + + + + + + + + + + + +
LoạiNgôn ngữThư việnMô phỏng
Cơ sở dữ liệuRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
Hàng đợiPython/DjangoCeleryRabbitMQ, Beanstalkd, Redis
Bộ đệmRuby/RailsActiveSupport::CacheMemory, filesystem, Memcached
+ +Lập trình viên thường thích sử dụng các dịch vụ hỗ trợ đơn giản trên môi trường cục bộ của họ, trong khi nhiều dịch vụ hỗ trợ mạnh mẽ và an toàn hơn được sử dụng trong môi trường vận hành thực tế. Ví dụ, sử dụng SQLite ở cục bộ và Postgresql trong vận hành, hoặc sử dụng trực tiếp bộ nhớ cho bộ đệm trong phát triển và Memcached trong vận hành. + +**Ứng dụng sử dụng mười hai hệ số không cho phép sử dụng dịch vụ hỗ trợ khác nhau giữa môi trường phát triển và vận hành**, mặc dù các bộ mô phỏng có thể trừu tượng hoá bất kỳ sự khác biệt của dịch vụ hỗ trợ. Sự khác biệt giữa dịch vụ hỗ trợ có nghĩa là dù bất kỳ sự không đồng bộ nhỏ nào cũng có thể mở rộng, là nguyên nhân cho việc mã nguồn có thể hoạt động tốt ở môi trường phát triển hoặc kiểm thử nhưng không hoạt động trong môi trường thực tế. Các kiểu lỗi này làm cản trở quá trình triển khai liên tục. Chi phí cho các cản trở và làm giảm ảnh hưởng cho chúng thường rất tốn kém trong suốt quá trình phát triển của một ứng dụng. + +Các dịch vụ đơn giản ở cục bộ không được ưu tiên như các dịch vụ tương tự. Các dịch vụ hỗ trợ hiện đại như Memcached, PostgreSQL, và RabbitMQ không quá khó để cài đặt thông qua các dịch vụ đóng gói như là [Homebrew](http://mxcl.github.com/homebrew/) và [apt-get](https://help.ubuntu.com/community/AptGet/Howto). Ngoài ra, các công cụ cung cấp khai báo [Chef](http://www.opscode.com/chef/) và [Puppet](http://docs.puppetlabs.com/) kết hợp với các môi trường ảo hoá đơn giản [Vagrant](http://vagrantup.com/) cho phép lập trình viên có thể vận hành ở cục bộ một môi trường khá giống với môi trường vận hành thực tế. Chi phí cho việc cài đặt và sử dụng nhỏ hơn rất nhiều so với chi phí của triển khai liên tục và sự khác biệt giữa môi trường phát triển và vận hành. + +Bộ mô phỏng đối với các dịch vụ hỗ trợ vẫn có ích, vì chúng làm giảm ảnh hưởng của việc chuyển đổi sang dịch vụ hỗ trợ mới. Nhưng tất cả các bước triển khai của ứng dụng (môi trường của lập trình viên, kiểm thử, vân hành thực tế) nên sử dụng cùng một loại và phiên bản của các kiểu dịch vụ hỗ trợ. diff --git a/content/vi/disposability.md b/content/vi/disposability.md new file mode 100644 index 000000000..698c1902d --- /dev/null +++ b/content/vi/disposability.md @@ -0,0 +1,12 @@ +## IX. Tính khả dụng +### Tối ưu hoá với khởi động nhanh và dừng phần mềm ổn định + +**[Tiến trình](./processes) của ứng dụng áp dụng mười hai thừa số luôn *sẵn sàng* (disposable), có nghĩa là bạn có thể chạy hoặc dừng phần mềm tại một thời điểm báo trước.** Điều này tạo điều kiện cho việc mở rộng trở nên dễ dàng hơn, việc triển khai nhanh các thay đổi của [mã nguồn](./codebase) hoặc [cấu hình](./config), và sự linh hoạt quá trình triển khai sản phẩm. + +Các tiến trình nên cố gắng **giảm thiểu thời gian khởi động**. Lý tưởng nhất, một tiến trình chỉ cần một vài giây kể từ khi có lệnh khởi động cho đến khi tiến trình bắt đầu và sẵn sàng để nhận yêu cầu hay bắt đầu công việc. Thời gian khởi động ngắn cho phép quá trình triển khai và mở rộng nhanh hơn; và hỗ trợ mạnh mẽ hơn, vì hệ thống quản lý các tiến trình có thể dễ dàng mang các tiến trình tới các máy chủ vật lý khi có các cảnh báo. + +Tiến trình **ngưng hoạt động linh hoạt khi chúng nhận được một tín hiệu [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)** từ hệ thống quản lý các tiến trình. Đối với ứng dụng web, việc ngưng hoạt động linh hoạt rất dễ thực hiện bằng cách ngừng lắng nghe trên công dịch vụ (do đó từ chối bất kỳ một yêu cầu mới nào), cho phép các yêu cầu hiện tại được kết thúc, và thoát ra. Ý tưởng của mô hình này là các yêu cầu HTTP cần thực hiện trong thời gian ngắn (thông thường không quá một vài giây), hoặc trong trường hợp kết nối lâu hơn, ứng dụng cần thực hiện kết nối lại khi các kết nối đã bị mất. + +Đối với các tiến trình thực thi, việc ngưng hoạt động linh hoạt có thể đạt được bằng cách trả các công việc trở lại hàng đợi. Ví dụ, trên [RabbitMQ](http://www.rabbitmq.com/) các tiến trình thực thi chỉ cần gửi lại một [`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack); trên [Beanstalkd](http://kr.github.com/beanstalkd/), các công việc được trả lại hàng đợi tự động khi mà các tiến trình thực thi bị mất kết nối. Hệ thống sử dụng khoá như là [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) cần đảm bảo sẽ giải phóng các bản ghi công việc. Ý tưởng của mô hình này là tất các các công việc cần [có khả năng quay lại][reentrant](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29), thường đạt đường bằng cách đóng gói các kết quả thành các giao dịch, hoặc tạo ra các toán tử [không thay đổi kết quả nếu đầu vào không thay đổi dù gọi một hay nhiều lần (idempotent)](http://en.wikipedia.org/wiki/Idempotence). + +Các tiến trình cũng **có khả năng chống lại các lỗi bất thường**, như các thiết bị phần cứng đột nhiên ngừng hoạt động. Điều này thường ít khi xảy ra hơn là việc ngừng hoạt động linh hoạt với tín hiệu `SIGTERM`, nhưng vẫn có khả năng xảy ra. Cách tiếp cận thường được khuyến nghị là sử dụng cơ chế hàng đợi đằng sau, như là Beanstalkd, các công việc quay trở lại hàng đợi khi mà các kết nối bị ngừng hoặc quá hạn thời gian. Ngoài ra, ứng dụng sử dụng mười hai hệ số được thiết kế để có thể điều khiển các trường hợp ngừng hoạt động đột ngột, ép buộc. [Thiết kế chỉ có đổ vỡ] đem khái niệm này vào [các kết luận logic]](http://docs.couchdb.org/en/latest/intro/overview.html) của nó. diff --git a/content/vi/intro.md b/content/vi/intro.md new file mode 100644 index 000000000..4e4eaa8dc --- /dev/null +++ b/content/vi/intro.md @@ -0,0 +1,20 @@ +Giới thiệu +========== + +Ngày nay, phần mềm thường được chuyển giao như là một dịch vụ: còn được +gọi là *các ứng dụng web*, hay *phần mềm-như-một-dịch vụ (software-as-a-service)*. +Ứng dụng 12-hệ số là một phương pháp để xây dựng các ứng dụng phần mềm-như-một-dịch vụ với +các tiêu chí sau: + +* Sử dụng các định dạng theo kiểu **tường thuật** cho việc thiết lập tự động hoá, để +cắt giảm chi phí và thời gian cho lập trình viên mới tham gia dự án; +* Có một **hợp đồng sạch** với hệ điều hành bên dưới, cung cấp **tối đa khả năng dịch chuyển** giữa các môi trường thực thi; +* Phù hợp để **triển khai** trên các **nền tảng đám mây** mới, cắt giảm yêu cầu quản trị +cho server và hệ thống; +* **Giảm thiểu sự khác nhau** giữa môi trường phát triển và môi trường sản xuất, cho phép đạt được sự linh hoạt tối đa +trong **triển khai liên tục**; +* Và có thể **mở rộng** mà không cần thay đổi lớn cho các công cụ, kiến trúc, hoặc cách thức +phát triển. + +Phương pháp 12-hệ số có thể được áp dụng cho các ứng dụng viết bằng bất kì ngôn ngữ lập +trình nào, và sử dụng bất kì kết hợp giữa các dịch vụ backend (cơ sở dữ liệu, queue, memory cache, vv.). diff --git a/content/vi/logs.md b/content/vi/logs.md new file mode 100644 index 000000000..cd82d4a4a --- /dev/null +++ b/content/vi/logs.md @@ -0,0 +1,16 @@ +## [XI. Nhật ký](./logs) +### Nhật ký là các luồng sự kiện + +*Nhật ký* cung cấp khả năng thể hiện các hình vi của ứng dụng đang vận hành, trong môi trường máy chủ chúng thường được ghi lại thành các tệp tin trên ổ đĩa cứng (a "logfile"); nhưng chỉ có một định dạng biểu diễn duy nhất. + +Nhật ký như là [luồng](http://adam.heroku.com/past/2011/4/1/logs_are_streams_not_files/) của sự kết hợp, theo trình tự thời gian của các sự kiện, được thu thập từ các luồng ra của các tiến trình đang vận hành và dịch vụ hỗ trợ của ứng dụng. Nhật ký ở dạng nguyên gốc thường là các chuỗi ký tự được định dạng với mỗi sự kiện trên một dòng (mặc dù các truy vết của ngoại lệ thường chia thành nhiều dòng). Nhật ký không có định điểm bắt đầu hay kết thúc, nhưng là luồng liên tục miễn là ứng dụng vẫn đang vận hành. + +**Ứng dụng sử dụng mười hai hệ số không bao giờ quan tâm đến việc điều hướng hay lưu trữ luồng đầu ra.** Ứng dụng không nên ghi hoặc quản lý các logfiles. Thay vào đó, mỗi tiến trình đang vận hành ghi các luồng sự kiện, không có bộ đệm, ra `stdout`. Trong môi trường phát triển cục bộ, lập trình viên sẽ xem các luồng này ở trên thiết bị đầu cuối để nắm bắt được hành vi của ứng dụng. + +Trong quá trình triển khai kiểm thử hoặc kiểm thử, mỗi luồng của tiến trình sẽ được lưu trữ bởi môi trường thực thi, thu tập cùng với tất các các luồng của ứng dụng, và định hướng đến một hoặc nhiều điểm đến cuối cùng để đọc và lưu trữ lâu dài. Các bộ định hướng nhật ký nguồn mở (như là [Logplex](https://github.com/heroku/logplex) và [Fluent](https://github.com/fluent/fluentd)) luôn sẵn sàng cho mục đích này. + +Luồng sự kiện của ứng dụng có thể định hướng ra các tệp tin, hoặc xem xét thời gian thực ở thiết bị đầu cuối. Hơn nữa, luồng còn có thể được đánh chỉ mục và phân tích bởi hệ thống như là [Splunk](http://www.splunk.com/), hoặc hệ thống phân tích dữ liệu tổng quát như là [Hadoop/Hive](http://hive.apache.org/). Các hệ thống này cung cấp các công cụ mạnh mẽ và linh hoạt cho việc phân tích hành vi của ứng dụng theo thời gian như là: + +* Tìm kiếm các sự kiện đặc biệt trong quá khứ +* Đồ thị hoá xu hướng tổng quát (đồ thị số lượng yêu cầu theo phút) +* Kích hoạt các cảnh báo theo kinh nghiệm của người dùng (như là cảnh báo khi số lượng lỗi theo phút vượt quá ngưỡng nào đó). diff --git a/content/vi/port-binding.md b/content/vi/port-binding.md new file mode 100644 index 000000000..ed02cbd9b --- /dev/null +++ b/content/vi/port-binding.md @@ -0,0 +1,14 @@ +## VII. Mở cổng mạng +### Cung cấp các dịch vụ thông qua mở cổng mạng + +Các ứng dụng web thường được thực thi bên trong một máy chủ web. Ví dụ, ứng dụng PHP có thể thực thi như là một thành phần của [Apache HTTPD](http://httpd.apache.org/), hoặc ứng dụng Java có thể thực thi thông qua [Tomcat](http://tomcat.apache.org/). + +**Ứng dụng áp dụng mười hai-hệ số có khả năng tự đóng gói hoàn toàn chính nó** và không phụ thuộc vào việc tích hợp thêm máy chủ web trong thời gian thực thi vào môi trường thực thi để tạo ra dịch vụ web. Ứng dụng web **cung cấp cơ chế HTTP như là dịch vụ bởi việc mở một cổng nhất định**, và lắng nghe các yêu cầu được gửi tới cổng này. + +Trong môi trường phát triển cục bộ, lập trình viên có thể truy cập dịch vụ thông qua URL như là `http://localhost:5000/` để truy cập đến các dịch vụ được cung cấp bởi ứng dụng của họ. Trong triển khai, lớp điều khiển luồng sẽ điều khiểu các yêu cầu từ đường dẫn công khai thông qua tên máy chủ đến tiến trình cung cấp cổng của ứng dụng. + +Việc này thường được triển khai bằng [các định nghĩa ràng buộc](./dependencies) để thêm các thư viện máy chủ cho ứng dụng như là [Tornado](http://www.tornadoweb.org/) cho Python, [Thin](http://code.macournoyer.com/thin/) cho Ruby, hoặc [Jetty](http://jetty.codehaus.org/jetty/) cho Java và các ngôn ngữ dựa trên máy ảo JVM. Điều này được xử lý ở *không gian của người dùng*, hay bên trong mã nguồn của ứng dụng. Ràng buộc đối với môi trường thực thi là việc mở cổng dịch vụ để lắng nghe các yêu cầu. + +HTTP không phải là dịch vụ duy nhất mà có thể cung cấp bởi việc mở cộng mạng. Gần như bất kỳ máy chủ phần mềm nào cũng có thể vận hành như là tiến trình được mở cổng mạng và chờ đợi các yêu cầu được gửi tới. Ví dụ bao gôm [ejabberd](http://www.ejabberd.im/) (sử dụng [XMPP](http://xmpp.org/)), và [Redis](http://redis.io/) (sử dụng [giao thức Redis](http://redis.io/topics/protocol)). + +Chú ý là cách tiếp cận bằng mở cổng mạng có nghĩa là ứng dụng có thể trở thành [dịch vụ hỗ trợ(./backing-services) cho bất kỳ ứng dụng nào khác, bằng việc cung cấp URL đến dịch vụ hỡ trợ như là tài nguyên được điều khiển tronng [cấu hình](./config) cho ứng dụng cần sử dụng dịch vụ. diff --git a/content/vi/processes.md b/content/vi/processes.md new file mode 100644 index 000000000..b020e5740 --- /dev/null +++ b/content/vi/processes.md @@ -0,0 +1,14 @@ +## VI. Tiến trình +### Vận hành ứng dụng như là một hoặc nhiều tiến trình phi trạng thái + +Ứng dụng được vận hành trong môi trường vận hành như là một hoặc nhiều *tiến trình*. + +Trong trường hợp đơn giản, mã nguồn là các kịch bản độc lập, môi trường vận hành chính là máy tính của nhà phát triển với ngôn ngữ thực thi được cài đặt, và tiến trình được khởi chạy thông qua dòng lệnh (ví dụ, `python my_script.py`). Ở một khía cạnh khác, triển khai thực tế của ứng dụng phức tạp có thể sử dụng nhiều [xử lý từ không đến nhiều kiểu tiến trình ngay lập tức](./concurrency). + +**Tiến trình áp dụng mười hai hệ số là phi trạng thái và không chia sẻ bất cứ tài nguyên nào](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** Bất kỳ dữ liệu nào cần lưu trữ lâu dài cần được lưu trữ trong [dịch vụ hỗ trợ](./backing-services) đầy đủ trạng thái, thông thường là cơ sở dữ liệu. + +Không gian bộ nhớ hoặc hệ thống tệp tin của tiến trình có thể được sử dụng như là bộ đệm tạm thời, thông qua luồng xử lý duy nhất. Ví dụ, việc tải một tệp tin lớn, tiến trình tải xuống và lưu trữ kết quả của tiến trình được lưu trữ trong cơ sở dữ liệu. Ứng dụng theo mười hai hệ số không bao giờ giả sử rằng có bất cứ cơ chế đệm nào của bộ nhớ hay ổ đĩa cứng sẵn sàng cho các yêu cầu hoặc công việc trong tương lai -- với nhiều tiến trình mà mỗi kiểu vận hành, mà tỷ cao các yêu cầu trong tương lai được xử lý bởi tiến trình khác. Mặc dù chỉ chạy một tiến trình, việc khởi động lại (được kích hoạt bởi mã nguồn triển khai, thay đổi cấu hình hoặc môi trường thực thi được thay đổi lại đến một tài nguyên vật lý khác), thường sẽ loại bỏ toàn bộ trạng thái cục bộ (như là bộ nhớ và hệ thống tệp tin). + +Bộ đóng gói tài nguyên (như [Jammit](http://documentcloud.github.com/jammit/) hoặc [django-compressor](http://django-compressor.readthedocs.org/)) sử dụng hệ thống tệp tin như là bộ đệm cho việc biên dịch các tài nguyên. Ứng dụng sử dụng mười hai hệ số thường thực thi việc biên dịch này trong [bước xây dựng](./build-release-run), như [Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html), hơn là ở bước vận hành. + +Một vài hệ thống web dựa vào ["sticky sessions"](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) -- đó là cơ chế lưu trữ tạm thời các dữ liệu của người dùng theo phiên làm việc trong bộ nhớ của các tiến trình vận hành ứng dụng và trông đợi các yêu cầu từ cùng một người dùng được định hướng tới cùng tiến trình. *Sticky sessions* đã vi phạm nguyên tắc của mười hai hệ số và không nên được sử dụng hoặc áp dụng theo. Dữ liệu trạng thái của các phiên làm việc là nên được lưu trữ trong các nơi lưu trữ cung cấp khả năng hết hạn theo thời gian như là [Memcached](http://memcached.org/) hoặc [Redis](http://redis.io/). diff --git a/content/vi/toc.md b/content/vi/toc.md new file mode 100644 index 000000000..9cdaf0ac7 --- /dev/null +++ b/content/vi/toc.md @@ -0,0 +1,38 @@ +12 hệ số +======== + +## [I. Mã gốc](./codebase) +### Một mã gốc được theo dõi với hệ thống quản lý phiên bản, và nhiều lần triển khai + +## [II. Các phụ thuộc](./dependencies) +### Khai báo rõ ràng và phân tách các phụ thuộc + +## [III. Cấu hình](./config) +### Lưu trữ cấu hình trong môi trường + +## [IV. Dịch vụ hỗ trợ](./backing-services) +### Dịch vụ hỗ trợ như là tài nguyên bổ xung + +## [V. Xây dựng, phát hành, vận hành](./build-release-run) +### Tách biệt hoàn toàn giữa bước xây dựng và vận hành + +## [VI. Tiến trình](./processes) +### Vận hành ứng dụng như là một hoặc nhiều tiến trình phi trạng thái + +## [VII. Mở cổng mạng](./port-binding) +### Cung cấp các dịch vụ thông qua công mạng + +## [VIII. Đồng bộ](./concurrency) +### Mở rộng theo chiều ngang thông qua mô hình tiến trình + +## [IX. Tính khả dụng](./disposability) +### Tối ưu hoá với khởi động nhanh và dừng phần mềm ổn định + +## [X. Sự tương đồng giữa quá trình phát triển và vận hành thực tế](./dev-prod-parity) +### Đảm bảo sự tương đồng giữa môi trường phát triển, kiểm thử và thực tế + +## [XI. Nhật ký](./logs) +### Nhật ký là các luồng sự kiện + +## [XII. Tiến trình quản trị](./admin-processes) +### Thực thi nhiệm vụ quản trị như là một tiến trình diff --git a/content/vi/who.md b/content/vi/who.md new file mode 100644 index 000000000..8e2dc2753 --- /dev/null +++ b/content/vi/who.md @@ -0,0 +1,5 @@ +Ai nên đọc tài liệu này? +======================== + +Bất kì lập trình viên đang xây dựng các ứng dụng-như-một-dịch vụ. Các kỹ sư hệ +thống đảm nhiệm triển khai hoặc quản lý các ứng dụng. diff --git a/content/zh_cn/admin-processes.md b/content/zh_cn/admin-processes.md new file mode 100644 index 000000000..715266ee3 --- /dev/null +++ b/content/zh_cn/admin-processes.md @@ -0,0 +1,14 @@ +## XII. 管理进程 +### 后台管理任务当作一次性进程运行 + +[进程构成](./concurrency)(process formation)是指用来处理应用的常规业务(比如处理 web 请求)的一组进程。与此不同,开发人员经常希望执行一些管理或维护应用的一次性任务,例如: + +* 运行数据移植(Django 中的 `manage.py migrate`, Rails 中的 `rake db:migrate`)。 +* 运行一个控制台(也被称为 [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell),来执行一些代码或是针对线上数据库做一些检查。大多数语言都通过解释器提供了一个 REPL 工具(`python` 或 `perl`) ,或是其他命令(Ruby 使用 `irb`, Rails 使用 `rails console`)。 +* 运行一些提交到代码仓库的一次性脚本。 + +一次性管理进程应该和正常的 [常驻进程](./processes) 使用同样的环境。这些管理进程和任何其他的进程一样使用相同的 [代码](./codebase) 和 [配置](./config) ,基于某个 [发布版本](./build-release-run) 运行。后台管理代码应该随其他应用程序代码一起发布,从而避免同步问题。 + +所有进程类型应该使用同样的 [依赖隔离](./dependencies) 技术。例如,如果Ruby的web进程使用了命令 `bundle exec thin start` ,那么数据库移植应使用 `bundle exec rake db:migrate` 。同样的,如果一个 Python 程序使用了 Virtualenv,则需要在运行 Tornado Web 服务器和任何 `manage.py` 管理进程时引入 `bin/python` 。 + +12-factor 尤其青睐那些提供了 REPL shell 的语言,因为那会让运行一次性脚本变得简单。在本地部署中,开发人员直接在命令行使用 shell 命令调用一次性管理进程。在线上部署中,开发人员依旧可以使用ssh或是运行环境提供的其他机制来运行这样的进程。 diff --git a/content/zh_cn/background.md b/content/zh_cn/background.md new file mode 100644 index 000000000..32d89ff1c --- /dev/null +++ b/content/zh_cn/background.md @@ -0,0 +1,9 @@ +背景 +========== + +本文的贡献者参与过数以百计的应用程序的开发和部署,并通过 [Heroku](http://www.heroku.com/) 平台间接见证了数十万应用程序的开发,运作以及扩展的过程。 + +本文综合了我们关于 SaaS 应用几乎所有的经验和智慧,是开发此类应用的理想实践标准,并特别关注于应用程序如何保持良性成长,开发者之间如何进行有效的代码协作,以及如何 [避免软件污染](http://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts/) 。 + +我们的初衷是分享在现代软件开发过程中发现的一些系统性问题,并加深对这些问题的认识。我们提供了讨论这些问题时所需的共享词汇,同时使用相关术语给出一套针对这些问题的广义解决方案。本文格式的灵感来自于 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)* 。 + diff --git a/content/zh_cn/backing-services.md b/content/zh_cn/backing-services.md new file mode 100644 index 000000000..6843f8945 --- /dev/null +++ b/content/zh_cn/backing-services.md @@ -0,0 +1,14 @@ +## IV. 后端服务 +### 把后端服务(*backing services*)当作附加资源 + +*后端服务*是指程序运行所需要的通过网络调用的各种服务,如数据库([MySQL](http://dev.mysql.com/),[CouchDB](http://couchdb.apache.org/)),消息/队列系统([RabbitMQ](http://www.rabbitmq.com/),[Beanstalkd](https://beanstalkd.github.io)),SMTP 邮件发送服务([ Postfix](http://www.postfix.org/)),以及缓存系统([Memcached](http://memcached.org/))。 + +类似数据库的后端服务,通常由部署应用程序的系统管理员一起管理。除了本地服务之外,应用程序有可能使用了第三方发布和管理的服务。示例包括 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](https://developers.google.com/maps/), [Last.fm](http://www.last.fm/api))。 + +**12-Factor 应用不会区别对待本地或第三方服务。** 对应用程序而言,两种都是附加资源,通过一个 url 或是其他存储在 [配置](./config) 中的服务定位/服务证书来获取数据。12-Factor 应用的任意 [部署](./codebase) ,都应该可以在不进行任何代码改动的情况下,将本地 MySQL 数据库换成第三方服务(例如 [Amazon RDS](http://aws.amazon.com/rds/))。类似的,本地 SMTP 服务应该也可以和第三方 SMTP 服务(例如 Postmark )互换。上述 2 个例子中,仅需修改配置中的资源地址。 + +每个不同的后端服务是一份 *资源* 。例如,一个 MySQL 数据库是一个资源,两个 MySQL 数据库(用来数据分区)就被当作是 2 个不同的资源。12-Factor 应用将这些数据库都视作 *附加资源* ,这些资源和它们附属的部署保持松耦合。 + +一种部署附加4个后端服务 + +部署可以按需加载或卸载资源。例如,如果应用的数据库服务由于硬件问题出现异常,管理员可以从最近的备份中恢复一个数据库,卸载当前的数据库,然后加载新的数据库 -- 整个过程都不需要修改代码。 diff --git a/content/zh_cn/build-release-run.md b/content/zh_cn/build-release-run.md new file mode 100644 index 000000000..09e0f443b --- /dev/null +++ b/content/zh_cn/build-release-run.md @@ -0,0 +1,18 @@ +## V. 构建,发布,运行 +### 严格分离构建和运行 + +[基准代码](./codebase) 转化为一份部署(非开发环境)需要以下三个阶段: + +* *构建阶段* 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包 [依赖项](./dependencies),编译成二进制文件和资源文件。 +* *发布阶段* 会将构建的结果和当前部署所需 [配置](./config) 相结合,并能够立刻在运行环境中投入使用。 +* *运行阶段* (或者说“运行时”)是指针对选定的发布版本,在执行环境中启动一系列应用程序 [进程](./processes)。 + +![代码被构建,然后和配置结合成为发布版本](/images/release.png) + +**12-factor 应用严格区分构建,发布,运行这三个步骤。** 举例来说,直接修改处于运行状态的代码是非常不可取的做法,因为这些修改很难再同步回构建步骤。 + +部署工具通常都提供了发布管理工具,最引人注目的功能是退回至较旧的发布版本。比如, [Capistrano](https://github.com/capistrano/capistrano/wiki) 将所有发布版本都存储在一个叫 `releases` 的子目录中,当前的在线版本只需映射至对应的目录即可。该工具的 `rollback` 命令可以很容易地实现回退版本的功能。 + +每一个发布版本必须对应一个唯一的发布 ID,例如可以使用发布时的时间戳(`2011-04-06-20:32:17`),亦或是一个增长的数字(`v100`)。发布的版本就像一本只能追加的账本,一旦发布就不可修改,任何的变动都应该产生一个新的发布版本。 + +新的代码在部署之前,需要开发人员触发构建操作。但是,运行阶段不一定需要人为触发,而是可以自动进行。如服务器重启,或是进程管理器重启了一个崩溃的进程。因此,运行阶段应该保持尽可能少的模块,这样假设半夜发生系统故障而开发人员又捉襟见肘也不会引起太大问题。构建阶段是可以相对复杂一些的,因为错误信息能够立刻展示在开发人员面前,从而得到妥善处理。 diff --git a/content/zh_cn/codebase.md b/content/zh_cn/codebase.md new file mode 100644 index 000000000..5cc3b90eb --- /dev/null +++ b/content/zh_cn/codebase.md @@ -0,0 +1,17 @@ +## I. 基准代码 +### 一份基准代码(*Codebase*),多份部署(*deploy*) + +12-Factor应用(译者注:应该是说一个使用本文概念来设计的应用,下同)通常会使用版本控制系统加以管理,如[Git](http://git-scm.com/), [Mercurial](https://www.mercurial-scm.org/), [Subversion](http://subversion.apache.org/)。一份用来跟踪代码所有修订版本的数据库被称作 *代码库*(code repository, code repo, repo)。 + +在类似 SVN 这样的集中式版本控制系统中,*基准代码* 就是指控制系统中的这一份代码库;而在 Git 那样的分布式版本控制系统中,*基准代码* 则是指最上游的那份代码库。 + +![一份代码库对应多份部署](/images/codebase-deploys.png) + +基准代码和应用之间总是保持一一对应的关系: + +* 一旦有多个基准代码,就不能称为一个应用,而是一个分布式系统。分布式系统中的每一个组件都是一个应用,每一个应用可以分别使用 12-Factor 进行开发。 +* 多个应用共享一份基准代码是有悖于 12-Factor 原则的。解决方案是将共享的代码拆分为独立的类库,然后使用 [依赖管理](./dependencies) 策略去加载它们。 + +尽管每个应用只对应一份基准代码,但可以同时存在多份部署。每份 *部署* 相当于运行了一个应用的实例。通常会有一个生产环境,一个或多个预发布环境。此外,每个开发人员都会在自己本地环境运行一个应用实例,这些都相当于一份部署。 + +所有部署的基准代码相同,但每份部署可以使用其不同的版本。比如,开发人员可能有一些提交还没有同步至预发布环境;预发布环境也有一些提交没有同步至生产环境。但它们都共享一份基准代码,我们就认为它们只是相同应用的不同部署而已。 diff --git a/content/zh_cn/concurrency.md b/content/zh_cn/concurrency.md new file mode 100644 index 000000000..212debfb2 --- /dev/null +++ b/content/zh_cn/concurrency.md @@ -0,0 +1,14 @@ +## VIII. 并发 +### 通过进程模型进行扩展 + +任何计算机程序,一旦启动,就会生成一个或多个进程。互联网应用采用多种进程运行方式。例如,PHP 进程作为 Apache 的子进程存在,随请求按需启动。Java 进程则采取了相反的方式,在程序启动之初 JVM 就提供了一个超级进程储备了大量的系统资源(CPU 和内存),并通过多线程实现内部的并发管理。上述 2 个例子中,进程是开发人员可以操作的最小单位。 + +![扩展表现为运行中的进程,工作多样性表现为进程类型。](/images/process-types.png) + +**在 12-factor 应用中,进程是一等公民。**12-Factor 应用的进程主要借鉴于 [unix 守护进程模型](https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/) 。开发人员可以运用这个模型去设计应用架构,将不同的工作分配给不同的 *进程类型* 。例如,HTTP 请求可以交给 web 进程来处理,而常驻的后台工作则交由 worker 进程负责。 + +这并不包括个别较为特殊的进程,例如通过虚拟机的线程处理并发的内部运算,或是使用诸如 [EventMachine](https://github.com/eventmachine/eventmachine), [Twisted](http://twistedmatrix.com/trac/), [Node.js](http://nodejs.org/) 的异步/事件触发模型。但一台独立的虚拟机的扩展有瓶颈(垂直扩展),所以应用程序必须可以在多台物理机器间跨进程工作。 + +上述进程模型会在系统急需扩展时大放异彩。 [12-Factor 应用的进程所具备的无共享,水平分区的特性](./processes) 意味着添加并发会变得简单而稳妥。这些进程的类型以及每个类型中进程的数量就被称作 *进程构成* 。 + +12-Factor 应用的进程 [不需要守护进程](http://dustin.github.com/2010/02/28/running-processes.html) 或是写入 PID 文件。相反的,应该借助操作系统的进程管理器(例如 [systemd](https://www.freedesktop.org/wiki/Software/systemd/) ,分布式的进程管理云平台,或是类似 [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) 的工具),来管理 [输出流](./logs) ,响应崩溃的进程,以及处理用户触发的重启和关闭超级进程的请求。 diff --git a/content/zh_cn/config.md b/content/zh_cn/config.md new file mode 100644 index 000000000..bcc671be5 --- /dev/null +++ b/content/zh_cn/config.md @@ -0,0 +1,22 @@ +## III. 配置 +### 在环境中存储配置 + +通常,应用的 *配置* 在不同 [部署](./codebase) (预发布、生产环境、开发环境等等)间会有很大差异。这其中包括: + +* 数据库,Memcached,以及其他 [后端服务](./backing-services) 的配置 +* 第三方服务的证书,如 Amazon S3、Twitter 等 +* 每份部署特有的配置,如域名等 + +有些应用在代码中使用常量保存配置,这与 12-Factor 所要求的**代码和配置严格分离**显然大相径庭。配置文件在各部署间存在大幅差异,代码却完全一致。 + +判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息。 + +需要指出的是,这里定义的"配置"并**不**包括应用的内部配置,比如 Rails 的 `config/routes.rb`,或是使用 [Spring](http://spring.io/) 时 [代码模块间的依赖注入关系](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html) 。这类配置在不同部署间不存在差异,所以应该写入代码。 + +另外一个解决方法是使用配置文件,但不把它们纳入版本控制系统,就像 Rails 的 `config/database.yml` 。这相对于在代码中使用常量已经是长足进步,但仍然有缺点:总是会不小心将配置文件签入了代码库;配置文件的可能会分散在不同的目录,并有着不同的格式,这让找出一个地方来统一管理所有配置变的不太现实。更糟的是,这些格式通常是语言或框架特定的。 + +**12-Factor推荐将应用的配置存储于 *环境变量* 中**( *env vars*, *env* )。环境变量可以非常方便地在不同的部署间做修改,却不动一行代码;与配置文件不同,不小心把它们签入代码库的概率微乎其微;与一些传统的解决配置问题的机制(比如 Java 的属性配置文件)相比,环境变量与语言和系统无关。 + +配置管理的另一个方面是分组。有时应用会将配置按照特定部署进行分组(或叫做“环境”),例如Rails中的 `development`,`test`, 和 `production` 环境。这种方法无法轻易扩展:更多部署意味着更多新的环境,例如 `staging` 或 `qa` 。 随着项目的不断深入,开发人员可能还会添加他们自己的环境,比如 `joes-staging` ,这将导致各种配置组合的激增,从而给管理部署增加了很多不确定因素。 + +12-Factor 应用中,环境变量的粒度要足够小,且相对独立。它们永远也不会组合成一个所谓的“环境”,而是独立存在于每个部署之中。当应用程序不断扩展,需要更多种类的部署时,这种配置管理方式能够做到平滑过渡。 diff --git a/content/zh_cn/dependencies.md b/content/zh_cn/dependencies.md new file mode 100644 index 000000000..ce9a3eb4b --- /dev/null +++ b/content/zh_cn/dependencies.md @@ -0,0 +1,12 @@ +## II. 依赖 +### 显式声明依赖关系( *dependency* ) + +大多数编程语言都会提供一个打包系统,用来为各个类库提供打包服务,就像 Perl 的 [CPAN](http://www.cpan.org/) 或是 Ruby 的 [Rubygems](http://rubygems.org/) 。通过打包系统安装的类库可以是系统级的(称之为 "site packages"),或仅供某个应用程序使用,部署在相应的目录中(称之为 "vendoring" 或 "bunding")。 + +**12-Factor规则下的应用程序不会隐式依赖系统级的类库。** 它一定通过 *依赖清单* ,确切地声明所有依赖项。此外,在运行过程中通过 *依赖隔离* 工具来确保程序不会调用系统中存在但清单中未声明的依赖项。这一做法会统一应用到生产和开发环境。 + +例如, 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 规范。 + +显式声明依赖的优点之一是为新进开发者简化了环境配置流程。新进开发者可以检出应用程序的基准代码,安装编程语言环境和它对应的依赖管理工具,只需通过一个 *构建命令* 来安装所有的依赖项,即可开始工作。例如,Ruby/Bundler 下使用 `bundle install`,而 Clojure/[Leiningen](https://github.com/technomancy/leiningen#readme) 则是 `lein deps`。 + +12-Factor 应用同样不会隐式依赖某些系统工具,如 ImageMagick 或是`curl`。即使这些工具存在于几乎所有系统,但终究无法保证所有未来的系统都能支持应用顺利运行,或是能够和应用兼容。如果应用必须使用到某些系统工具,那么这些工具应该被包含在应用之中。 diff --git a/content/zh_cn/dev-prod-parity.md b/content/zh_cn/dev-prod-parity.md new file mode 100644 index 000000000..70f668c7f --- /dev/null +++ b/content/zh_cn/dev-prod-parity.md @@ -0,0 +1,76 @@ +## X. 开发环境与线上环境等价 +### 尽可能的保持开发,预发布,线上环境相同 + +从以往经验来看,开发环境(即开发人员的本地 [部署](./codebase))和线上环境(外部用户访问的真实部署)之间存在着很多差异。这些差异表现在以下三个方面: + +* **时间差异:** 开发人员正在编写的代码可能需要几天,几周,甚至几个月才会上线。 +* **人员差异:** 开发人员编写代码,运维人员部署代码。 +* **工具差异:** 开发人员或许使用 Nginx,SQLite,OS X,而线上环境使用 Apache,MySQL 以及 Linux。 + +**12-Factor 应用想要做到 [持续部署](http://avc.com/2011/02/continuous-deployment/) 就必须缩小本地与线上差异。** 再回头看上面所描述的三个差异: + +* 缩小时间差异:开发人员可以几小时,甚至几分钟就部署代码。 +* 缩小人员差异:开发人员不只要编写代码,更应该密切参与部署过程以及代码在线上的表现。 +* 缩小工具差异:尽量保证开发环境以及线上环境的一致性。 + +将上述总结变为一个表格如下: + + + + + + + + + + + + + + + + + + + + + + +
传统应用12-Factor 应用
每次部署间隔数周几小时
开发人员 vs 运维人员不同的人相同的人
开发环境 vs 线上环境不同尽量接近
+ +[后端服务](./backing-services) 是保持开发与线上等价的重要部分,例如数据库,队列系统,以及缓存。许多语言都提供了简化获取后端服务的类库,例如不同类型服务的 *适配器* 。下列表格提供了一些例子。 + + + + + + + + + + + + + + + + + + + + + + + + + + +
类型语言类库适配器
数据库Ruby/RailsActiveRecordMySQL, PostgreSQL, SQLite
队列Python/DjangoCeleryRabbitMQ, Beanstalkd, Redis
缓存Ruby/RailsActiveSupport::CacheMemory, filesystem, Memcached
+ +开发人员有时会觉得在本地环境中使用轻量的后端服务具有很强的吸引力,而那些更重量级的健壮的后端服务应该使用在生产环境。例如,本地使用 SQLite 线上使用 PostgreSQL;又如本地缓存在进程内存中而线上存入 Memcached。 + +**12-Factor 应用的开发人员应该反对在不同环境间使用不同的后端服务** ,即使适配器已经可以几乎消除使用上的差异。这是因为,不同的后端服务意味着会突然出现的不兼容,从而导致测试、预发布都正常的代码在线上出现问题。这些错误会给持续部署带来阻力。从应用程序的生命周期来看,消除这种阻力需要花费很大的代价。 + +与此同时,轻量的本地服务也不像以前那样引人注目。借助于[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/) 这样轻量的虚拟环境就可以使得开发人员的本地环境与线上环境无限接近。与同步环境和持续部署所带来的益处相比,安装这些系统显然是值得的。 + +不同后端服务的适配器仍然是有用的,因为它们可以使移植后端服务变得简单。但应用的所有部署,这其中包括开发、预发布以及线上环境,都应该使用同一个后端服务的相同版本。 diff --git a/content/zh_cn/disposability.md b/content/zh_cn/disposability.md new file mode 100644 index 000000000..121699b65 --- /dev/null +++ b/content/zh_cn/disposability.md @@ -0,0 +1,13 @@ +## IX. 易处理 +### 快速启动和优雅终止可最大化健壮性 + +**12-Factor 应用的 [进程](./processes) 是 *易处理(disposable)*的,意思是说它们可以瞬间开启或停止。** 这有利于快速、弹性的伸缩应用,迅速部署变化的 [代码](./codebase) 或 [配置](./config) ,稳健的部署应用。 + +进程应当追求 **最小启动时间** 。 理想状态下,进程从敲下命令到真正启动并等待请求的时间应该只需很短的时间。更少的启动时间提供了更敏捷的 [发布](./build-release-run) 以及扩展过程,此外还增加了健壮性,因为进程管理器可以在授权情形下容易的将进程搬到新的物理机器上。 + +进程 **一旦接收 [终止信号(`SIGTERM`)](http://en.wikipedia.org/wiki/SIGTERM) 就会优雅的终止** 。就网络进程而言,优雅终止是指停止监听服务的端口,即拒绝所有新的请求,并继续执行当前已接收的请求,然后退出。此类型的进程所隐含的要求是HTTP请求大多都很短(不会超过几秒钟),而在长时间轮询中,客户端在丢失连接后应该马上尝试重连。 + +对于 worker 进程来说,优雅终止是指将当前任务退回队列。例如,[RabbitMQ](http://www.rabbitmq.com/) 中,worker 可以发送一个[`NACK`](http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack)信号。 [Beanstalkd](https://beanstalkd.github.io) 中,任务终止并退回队列会在worker断开时自动触发。有锁机制的系统诸如 [Delayed Job](https://github.com/collectiveidea/delayed_job#readme) 则需要确定释放了系统资源。此类型的进程所隐含的要求是,任务都应该 [可重复执行](http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29) , 这主要由将结果包装进事务或是使重复操作 [幂等](http://en.wikipedia.org/wiki/Idempotence) 来实现。 + +进程还应当**在面对突然死亡时保持健壮**,例如底层硬件故障。虽然这种情况比起优雅终止来说少之又少,但终究有可能发生。一种推荐的方式是使用一个健壮的后端队列,例如 [Beanstalkd](https://beanstalkd.github.io) ,它可以在客户端断开或超时后自动退回任务。无论如何,12-Factor 应用都应该可以设计能够应对意外的、不优雅的终结。[Crash-only design](http://lwn.net/Articles/191059/) 将这种概念转化为 [合乎逻辑的理论](http://couchdb.apache.org/docs/overview.html)。 + diff --git a/content/zh_cn/intro.md b/content/zh_cn/intro.md new file mode 100644 index 000000000..a6fc37eef --- /dev/null +++ b/content/zh_cn/intro.md @@ -0,0 +1,11 @@ +简介 +============ +如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论: + +* 使用**标准化**流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。 +* 和操作系统之间尽可能的**划清界限**,在各个系统中提供**最大的可移植性**。 +* 适合**部署**在现代的**云计算平台**,从而在服务器和系统管理方面节省资源。 +* 将开发环境和生产环境的**差异降至最低**,并使用**持续交付**实施敏捷开发。 +* 可以在工具、架构和开发流程不发生明显变化的前提下实现**扩展**。 + +这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。 diff --git a/content/zh_cn/logs.md b/content/zh_cn/logs.md new file mode 100644 index 000000000..4204a7794 --- /dev/null +++ b/content/zh_cn/logs.md @@ -0,0 +1,16 @@ +## XI. 日志 +### 把日志当作事件流 + +*日志* 使得应用程序运行的动作变得透明。在基于服务器的环境中,日志通常被写在硬盘的一个文件里,但这只是一种输出格式。 + +日志应该是 [事件流](https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/) 的汇总,将所有运行中进程和后端服务的输出流按照时间顺序收集起来。尽管在回溯问题时可能需要看很多行,日志最原始的格式确实是一个事件一行。日志没有确定开始和结束,但随着应用在运行会持续的增加。 + +**12-factor应用本身从不考虑存储自己的输出流。** 不应该试图去写或者管理日志文件。相反,每一个运行的进程都会直接的标准输出(`stdout`)事件流。开发环境中,开发人员可以通过这些数据流,实时在终端看到应用的活动。 + +在预发布或线上部署中,每个进程的输出流由运行环境截获,并将其他输出流整理在一起,然后一并发送给一个或多个最终的处理程序,用于查看或是长期存档。这些存档路径对于应用来说不可见也不可配置,而是完全交给程序的运行环境管理。类似 [Logplex](https://github.com/heroku/logplex) 和 [Fluentd](https://github.com/fluent/fluentd) 的开源工具可以达到这个目的。 + +这些事件流可以输出至文件,或者在终端实时观察。最重要的,输出流可以发送到 [Splunk](http://www.splunk.com/) 这样的日志索引及分析系统,或 [Hadoop/Hive](http://hive.apache.org/) 这样的通用数据存储系统。这些系统为查看应用的历史活动提供了强大而灵活的功能,包括: + +* 找出过去一段时间特殊的事件。 +* 图形化一个大规模的趋势,比如每分钟的请求量。 +* 根据用户定义的条件实时触发警报,比如每分钟的报错超过某个警戒线。 diff --git a/content/zh_cn/port-binding.md b/content/zh_cn/port-binding.md new file mode 100644 index 000000000..2c217f7c4 --- /dev/null +++ b/content/zh_cn/port-binding.md @@ -0,0 +1,14 @@ +## VII. 端口绑定 +### 通过端口绑定(*Port binding*)来提供服务 + +互联网应用有时会运行于服务器的容器之中。例如 PHP 经常作为 [Apache HTTPD](http://httpd.apache.org/) 的一个模块来运行,正如 Java 运行于 [Tomcat](http://tomcat.apache.org/) 。 + +**12-Factor 应用完全自我加载** 而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用 **通过端口绑定来提供服务** ,并监听发送至该端口的请求。 + +本地环境中,开发人员通过类似`http://localhost:5000/`的地址来访问服务。在线上环境中,请求统一发送至公共域名而后路由至绑定了端口的网络进程。 + +通常的实现思路是,将网络服务器类库通过 [依赖声明](./dependencies) 载入应用。例如,Python 的 [Tornado](http://www.tornadoweb.org/), Ruby 的[Thin](http://code.macournoyer.com/thin/) , Java 以及其他基于 JVM 语言的 [Jetty](http://www.eclipse.org/jetty/)。完全由 *用户端* ,确切的说应该是应用的代码,发起请求。和运行环境约定好绑定的端口即可处理这些请求。 + +HTTP 并不是唯一一个可以由端口绑定提供的服务。其实几乎所有服务器软件都可以通过进程绑定端口来等待请求。例如,使用 [XMPP](http://xmpp.org/) 的 [ejabberd](http://www.ejabberd.im/) , 以及使用 [Redis 协议](http://redis.io/topics/protocol) 的 [Redis](http://redis.io/) 。 + +还要指出的是,端口绑定这种方式也意味着一个应用可以成为另外一个应用的 [后端服务](./backing-services) ,调用方将服务方提供的相应 URL 当作资源存入 [配置](./config) 以备将来调用。 diff --git a/content/zh_cn/processes.md b/content/zh_cn/processes.md new file mode 100644 index 000000000..4491514a4 --- /dev/null +++ b/content/zh_cn/processes.md @@ -0,0 +1,14 @@ +## VI. 进程 +### 以一个或多个无状态进程运行应用 + +运行环境中,应用程序通常是以一个和多个 *进程* 运行的。 + +最简单的场景中,代码是一个独立的脚本,运行环境是开发人员自己的笔记本电脑,进程由一条命令行(例如`python my_script.py`)。另外一个极端情况是,复杂的应用可能会使用很多 [进程类型](./concurrency) ,也就是零个或多个进程实例。 + +**12-Factor 应用的进程必须无状态且 [无共享](http://en.wikipedia.org/wiki/Shared_nothing_architecture) 。** 任何需要持久化的数据都要存储在 [后端服务](./backing-services) 内,比如数据库。 + +内存区域或磁盘空间可以作为进程在做某种事务型操作时的缓存,例如下载一个很大的文件,对其操作并将结果写入数据库的过程。12-Factor应用根本不用考虑这些缓存的内容是不是可以保留给之后的请求来使用,这是因为应用启动了多种类型的进程,将来的请求多半会由其他进程来服务。即使在只有一个进程的情形下,先前保存的数据(内存或文件系统中)也会因为重启(如代码部署、配置更改、或运行环境将进程调度至另一个物理区域执行)而丢失。 + +源文件打包工具([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) ,而不是在运行阶段。 + +一些互联网系统依赖于 “[粘性 session ](http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence)”, 这是指将用户 session 中的数据缓存至某进程的内存中,并将同一用户的后续请求路由到同一个进程。粘性 session 是 12-Factor 极力反对的。Session 中的数据应该保存在诸如 [Memcached](http://memcached.org/) 或 [Redis](http://redis.io/) 这样的带有过期时间的缓存中。 diff --git a/content/zh_cn/toc.md b/content/zh_cn/toc.md new file mode 100644 index 000000000..277ef7006 --- /dev/null +++ b/content/zh_cn/toc.md @@ -0,0 +1,38 @@ +12-factors +================== + +## [I. 基准代码](./codebase) +### 一份基准代码,多份部署 + +## [II. 依赖](./dependencies) +### 显式声明依赖关系 + +## [III. 配置](./config) +### 在环境中存储配置 + +## [IV. 后端服务](./backing-services) +### 把后端服务当作附加资源 + +## [V. 构建,发布,运行](./build-release-run) +### 严格分离构建和运行 + +## [VI. 进程](./processes) +### 以一个或多个无状态进程运行应用 + +## [VII. 端口绑定](./port-binding) +### 通过端口绑定提供服务 + +## [VIII. 并发](./concurrency) +### 通过进程模型进行扩展 + +## [IX. 易处理](./disposability) +### 快速启动和优雅终止可最大化健壮性 + +## [X. 开发环境与线上环境等价](./dev-prod-parity) +### 尽可能的保持开发,预发布,线上环境相同 + +## [XI. 日志](./logs) +### 把日志当作事件流 + +## [XII. 管理进程](./admin-processes) +### 后台管理任务当作一次性进程运行 diff --git a/content/zh_cn/who.md b/content/zh_cn/who.md new file mode 100644 index 000000000..c54277fae --- /dev/null +++ b/content/zh_cn/who.md @@ -0,0 +1,4 @@ +读者应该是哪些人? +============================== + +任何 SaaS 应用的开发人员。部署和管理此类应用的运维工程师。 diff --git a/locales/cs.yml b/locales/cs.yml new file mode 100644 index 000000000..1879c4baa --- /dev/null +++ b/locales/cs.yml @@ -0,0 +1,7 @@ +cs: + # Name of language listed in locales menu + language: Česky (cs) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: " - česká verze" diff --git a/locales/de.yml b/locales/de.yml new file mode 100644 index 000000000..18557d8b9 --- /dev/null +++ b/locales/de.yml @@ -0,0 +1,7 @@ +de: + # Name of language listed in locales menu + language: "Deutsch (de)" + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "Dies ist eine Übersetzung." diff --git a/locales/el.yml b/locales/el.yml new file mode 100644 index 000000000..7a292ab43 --- /dev/null +++ b/locales/el.yml @@ -0,0 +1,7 @@ +el: + # Name of language listed in locales menu + language: "Ελληνικά (el)" + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "Μετάφραση από το πρωτότυπο" diff --git a/locales/en.yml b/locales/en.yml new file mode 100644 index 000000000..7188c643a --- /dev/null +++ b/locales/en.yml @@ -0,0 +1,7 @@ +en: + # Name of language listed in locales menu + language: English (en) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "" diff --git a/locales/es.yml b/locales/es.yml new file mode 100644 index 000000000..cfb55fb96 --- /dev/null +++ b/locales/es.yml @@ -0,0 +1,7 @@ +es: + # Name of language listed in locales menu + language: Español (es) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: (Traducción de la versión original en Inglés) diff --git a/locales/fr.yml b/locales/fr.yml new file mode 100644 index 000000000..03ec78988 --- /dev/null +++ b/locales/fr.yml @@ -0,0 +1,7 @@ +fr: + # Name of language listed in locales menu + language: "Français (fr)" + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "Ce texte est une traduction" diff --git a/locales/it.yml b/locales/it.yml new file mode 100644 index 000000000..98c4ada16 --- /dev/null +++ b/locales/it.yml @@ -0,0 +1,7 @@ +it: + # Name of language listed in locales menu + language: Italiano (it) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: (Questo testo è una traduzione della versione originale in inglese.) diff --git a/locales/ja.yml b/locales/ja.yml new file mode 100644 index 000000000..bd5305ca0 --- /dev/null +++ b/locales/ja.yml @@ -0,0 +1,7 @@ +ja: + # Name of language listed in locales menu + language: 日本語 (ja) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: (日本語訳) diff --git a/locales/ko.yml b/locales/ko.yml new file mode 100644 index 000000000..a48103a42 --- /dev/null +++ b/locales/ko.yml @@ -0,0 +1,7 @@ +ko: + # Name of language listed in locales menu + language: 한국어 (ko) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: (한국어) diff --git a/locales/pl.yml b/locales/pl.yml new file mode 100644 index 000000000..2364030c8 --- /dev/null +++ b/locales/pl.yml @@ -0,0 +1,7 @@ +pl: + # Name of language listed in locales menu + language: "Polski (pl)" + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "- edycja polska" diff --git a/locales/pt_br.yml b/locales/pt_br.yml new file mode 100644 index 000000000..1a4eafbf6 --- /dev/null +++ b/locales/pt_br.yml @@ -0,0 +1,7 @@ +pt_br: + # Name of language listed in locales menu + language: Brazilian Portuguese (pt_br) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "(traduzido)" diff --git a/locales/ru.yml b/locales/ru.yml new file mode 100644 index 000000000..e85f7348f --- /dev/null +++ b/locales/ru.yml @@ -0,0 +1,7 @@ +ru: + # Name of language listed in locales menu + language: Русский (ru) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: (Русский перевод) \ No newline at end of file diff --git a/locales/sk.yml b/locales/sk.yml new file mode 100644 index 000000000..795b517f8 --- /dev/null +++ b/locales/sk.yml @@ -0,0 +1,7 @@ +sk: + # Name of language listed in locales menu + language: Slovensky (sk) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: " - slovenská verzia" diff --git a/locales/th.yml b/locales/th.yml new file mode 100644 index 000000000..ec1ba28de --- /dev/null +++ b/locales/th.yml @@ -0,0 +1,7 @@ +th: + # Name of language listed in locales menu + language: ภาษาไทย (th) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "แปลภาษาไทย" diff --git a/locales/tr.yml b/locales/tr.yml new file mode 100644 index 000000000..ee1dbcd3e --- /dev/null +++ b/locales/tr.yml @@ -0,0 +1,7 @@ +tr: + # Name of language listed in locales menu + language: Turkish (tr) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "Türkçe çeviri" diff --git a/locales/uk.yml b/locales/uk.yml new file mode 100644 index 000000000..77a1b9c6b --- /dev/null +++ b/locales/uk.yml @@ -0,0 +1,7 @@ +uk: + # Name of language listed in locales menu + language: "Українська (uk)" + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "(Переклад українською)" diff --git a/locales/vi.yml b/locales/vi.yml new file mode 100644 index 000000000..d07b54091 --- /dev/null +++ b/locales/vi.yml @@ -0,0 +1,7 @@ +vi: + # Name of language listed in locales menu + language: Tiếng Việt (vi) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: "Đây là bản dịch." diff --git a/locales/zh_cn.yml b/locales/zh_cn.yml new file mode 100644 index 000000000..7010edd45 --- /dev/null +++ b/locales/zh_cn.yml @@ -0,0 +1,7 @@ +zh_cn: + # Name of language listed in locales menu + language: 简体中文 (zh_cn) + + # A text to make known that the article is a translation not an original. + # Empty for English, original. + translation: (简体中文) diff --git a/public/12factor.mobi b/public/12factor.mobi new file mode 100644 index 000000000..23a194238 Binary files /dev/null and b/public/12factor.mobi differ diff --git a/public/css/mobile.css b/public/css/mobile.css index 81b5c89ec..72ad90ace 100644 --- a/public/css/mobile.css +++ b/public/css/mobile.css @@ -1,3 +1,79 @@ +@media screen and (min-width: 1041px) { + + section { + min-width: 65em; + } + + article, nav { + max-width: 55em; + } +} + +@media screen and (min-width: 481px) and (max-width: 800px) { + article img { + float: none; + display: block; + margin: 0 auto; + } +} + +@media screen and (min-width: 481px) and (max-width: 1040px) { + + header { + font-size: 1em; + } + + article, nav { + width:85%; + min-width: none; + max-width: none; + } + + section, footer { + width:100%; + min-width: none; + max-width: none; + } + + article h1, article h2, article h3, article p, article table { + padding-left: 15px; + padding-right: 15px; + } + + article ul, article ol { + padding-left: 35px; + padding-right: 10px; + text-align: left; + } + + article table { + font-size: 0.8em; + } + + article table td { + padding-left: 0.25em; + padding-right: 0.25em; + } + + article img { + max-width: 100%; + margin-bottom: 1em; + } + + nav a { + padding:1em; + } + + nav a { + padding:1em; + } + + footer { + padding-left: 0; + padding-right: 0; + } +} + @media screen and (max-width: 480px) { header { font-size: 0.75em; @@ -34,12 +110,8 @@ margin-bottom: 1em; } - #prev { - margin-left: 1em; - } - - #next { - margin-right: 1em; + nav a { + padding: 1em; } footer { diff --git a/public/css/screen.css b/public/css/screen.css index 74d6eb81b..489301b59 100644 --- a/public/css/screen.css +++ b/public/css/screen.css @@ -9,7 +9,7 @@ body { h1, h2, h3 { padding: 0; margin: 0; -} +} h1, h2 { line-height: 1.25em; @@ -40,8 +40,8 @@ header h1 a { section { padding-top: 16pt; text-align: center; - min-width: 65em; } + section h1 { font-size: 19pt; } @@ -49,16 +49,18 @@ section h1 { article { padding-top: 8pt; } + article, nav { margin: 0 auto; text-align: justify; - max-width: 55em; } + article p a, article li a { text-decoration: none; border-bottom: 1px dashed #444; color: #000; } + article p a:hover, article li a:hover { color: #337; } @@ -87,7 +89,7 @@ section.concrete h2 a:hover { color: #337; } section.concrete h3 { - color: #555; + color: #333; font-weight: normal; } @@ -98,7 +100,7 @@ section#factor h2 { section#factor h3 { font-size: 17pt; font-weight: normal; - color: #999; + color: #555; margin-bottom: 16pt; } @@ -106,6 +108,15 @@ nav { margin-top: 16pt; margin-bottom: 48pt; } +nav #locales { + text-align: center; +} +nav #locales a { + color: #000; +} +nav #locales span { + font-weight: bold; +} nav #next { float: right; } @@ -113,6 +124,7 @@ nav #prev { float: left; } nav #next a, nav #prev a { + display: block; font-size: 19pt; text-decoration: none; color: #000; @@ -133,7 +145,7 @@ td, th { } footer { - color: #444; + color: #999; font-size: 10pt; background: #000; padding-top: 24pt; @@ -143,12 +155,8 @@ footer { min-height: 56pt; } -footer span { - display: block; -} - footer a { - color: #444; + color: #999; } article img { @@ -160,3 +168,9 @@ article img.full { float: none; margin-left: 0; } + +.cpra a img { + height: 17px; + margin-bottom: -2px !important; + margin-right: 5px; +} \ No newline at end of file diff --git a/public/images/favicon.ico b/public/images/favicon.ico new file mode 100644 index 000000000..4d4245a9c Binary files /dev/null and b/public/images/favicon.ico differ diff --git a/public/images/privacy.png b/public/images/privacy.png new file mode 100644 index 000000000..565afc979 Binary files /dev/null and b/public/images/privacy.png differ diff --git a/views/factor.erb b/views/factor.erb index 40eee4d0e..404a0bd01 100644 --- a/views/factor.erb +++ b/views/factor.erb @@ -6,6 +6,7 @@
diff --git a/views/home.erb b/views/home.erb index 6a81c3d47..14c1d5f5f 100644 --- a/views/home.erb +++ b/views/home.erb @@ -5,12 +5,5 @@
-
<%= render_markdown('toc') %>
+
<%= render_markdown('toc') %>
- - diff --git a/views/layout.erb b/views/layout.erb index 387b138b0..e7a2cbb41 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -3,38 +3,46 @@ - The Twelve-Factor App + The Twelve-Factor App <%= I18n.t(:translation) %> - + - - - - - <% if ENV['GOOGLE_ANALYTICS_KEY'] %> - - <% end %> + + + <% if ENV['GOOGLE_TAG_MANAGER_ACCOUNT'] %> + + + + + <% end %> +
-

The Twelve-Factor App

+

The Twelve-Factor App

<%= yield %> + + diff --git a/web.rb b/web.rb index a53c0cc35..6f2f81b66 100644 --- a/web.rb +++ b/web.rb @@ -1,5 +1,27 @@ require 'sinatra' require 'maruku' +require 'i18n' +require 'rack/ssl-enforcer' + +configure do + use Rack::SslEnforcer if ENV['FORCE_SSL'] + I18n.enforce_available_locales = true + I18n.load_path = Dir[File.join(settings.root, 'locales', '*.yml')] + I18n.backend.load_translations + I18n.default_locale = :en +end + +before do + I18n.locale = I18n.default_locale +end + +before '/:locale/*' do + locale = params[:locale].to_sym + if locale != I18n.default_locale && I18n.available_locales.include?(locale) + I18n.locale = locale + request.path_info = '/' + params[:splat][0] + end +end get '/' do erb :home @@ -15,22 +37,33 @@ helpers do def render_markdown(file) - markdown = File.read("content/#{file}.md") + markdown = File.read("content/#{I18n.locale}/#{file}.md", :encoding => 'utf-8') Maruku.new(markdown).to_html rescue Errno::ENOENT - puts "No content for #{file}, skipping" + puts "No content for #{I18n.locale}/#{file}, skipping" end def render_prev(factor) idx = TOC.index(factor) return if idx == 0 - "« Previous" + "« Previous" end def render_next(factor) idx = TOC.index(factor) return if idx == TOC.size-1 - "Next »" + "Next »" + end + + def render_locales(factor) + I18n.available_locales.map {|locale| + if locale == I18n.locale + "#{I18n.t(:language)}" + else + path_prefix = locale == I18n.default_locale ? "" : "/#{locale}" + "#{I18n.t(:language, :locale => locale)}" + end + }.join(" | ") end end