- semelhante à maioria dos PaaS como Heroku, o AppFog também utiliza Amazon AWS EC2 por baixo. Mas diferente do Heroku ela permite escolher algumas das zonas geográficas e também outros IaaS como HP OpenStack e Microsoft Azure. Pra maioria das pessoas usar a zona US-EAST-1 que é a padrão é o suficiente.
- semelhante ao Heroku, você pode controlar tudo por linha de comando, basta instalar com
gem install af
e ler esta documentação. semelhante ao Heroku, ele também tem add-ons mas numa quantidade ainda muito inferior. Alguns dos principais estão lá como LogEntries, Blitz, Memcachier, Mailgun e outros.
diferente do Heroku, ela vem pré-configurada com um número maior de perfis de aplicação, Java Grails, Java Spring, Node Express, PHP Wordpress, Python Django, Ruby on Rails e muito mais.
- diferente do Heroku, a precificação não é por número de instâncias. Em vez disso ele funciona num modelo "pré-pago" (mais sobre isso abaixo)
- diferente do Heroku, ela tem mais serviços próprios como MySQL, PostgreSQL, MongoDB, Redis, RabbitMQ
Precificação
A parte da precificação é onde a AppFog mais se diferencia dos demais, ao mesmo tempo oferecendo vantagem e desvantagem.
O que eles fazem é oferecer pacotes pré-pagos que inclui:
- limite de quantidade de RAM compartilhada
- limite de quantidade de instâncias
- limite de tamanho dos bancos de dados
- limite de endpoints SSL
- limite de RAM compartilhada entre os bancos de dados
- limite de transferência de gigabits na rede
- limite na quantidade de requisições por segundo
Por exemplo, tem 3 camadas no limite de 2GB: o free (que só permite domínio *.af.cm), o que não tem suporte a SSL e o que tem suporte a 1 endpoint SSL. Respectivamente o preço varia de USD 0, depois USD 20 e USD 50.
Esses 2 GB podem ser distribuídos entre servidores web, e até 8 instâncias de serviços (bancos de dados). O que dá pra fazer com isso? Em uma conta de USD 20 eu coloquei 7 sites pequenos, respectivamente com:
- 2 instâncias de 320Mb cada
- 1 instância de 160Mb
- 1 instância de 128Mb
- 1 instância de 256Mb
- 1 instância de 128Mb
- 1 instância de 192Mb
- 1 instância de 128Mb
Lembram que um dyno no Heroku é de 512Mb? O problema de um dyno fixo é que sites pequenos desperdiçam espaço e sites grandes não cabem. No caso do AppFog ele me deixa decidir quanto quero alocar para cada site até o mínimo de 128Mb. Então, em 2Gb ou eu faço 16 sites de 128Mb cada, como posso fazer uma única instância de 2GB de uma vez só.
Agora vem o problema: se eu quiser usar mais de 2GB (no momento, nessa conta que estou testando já usei 1.66GB e 7 dos 8 serviços) o próximo plano é de 4GB com 16 serviços por USD 100. Acima dele é de 16GB com 64 serviços a USD 380, e o maior é de 32GB com 128 serviços a USD 720.
Eu não diria que é caro, mas o preço salta em pulos muito grandes de um para o outro. No Heroku, acima de USD 36 por uma dyno, posso ir escalando em pulos menores de menos de USD 36. O modelo de negócios do Heroku é "on-demand" o do AppFog é "pré-pago". O pré-pago tem preço de entrada menor mas pode ficar caro mais rápido do que o Heroku dependendo do tipo de aplicação.
Na teoria os preços do Appfog são bem mais em conta que o Heroku. No caso anterior, estou gastando 10 instâncias de Heroku a aproximadamente USD 323, mais USD 400 de banco de dados. No AppFog eu teria que escolher provavelmente o plano de 16GB, que custa USD 380. No Heroku, o próximo salto com mais uma dyno iria de USD 323 para USD 431. No AppFog eu precisaria pular pro plano de USD 720.
A grande maioria dos sites não vai planos muito maiores que o de 4GB, que custa USD 100, o equivalente a 2 dynos no Heroku, sem contar banco de dados. Nesse caso o AppFog pode ficar no mínimo 2 vezes mais barato. Quando chegar no plano dos USD 380 ou USD 720 é que pode fazer um pouco mais de diferença, mas mesmo assim o AppFog ainda parece continuar mais barato.
Porém onde o Appfog sai mais barato, também não tem algumas funcionalidades cruciais.
Maior Problema
O maior problema do AppFog são os serviços de bancos de dados. Primeiro de tudo: ele não oferece serviços de backup e restore. Ele espera que você faça seu próprio backup, o que é um absurdo. Ou seja, se você tem dados de missão crítica, não use o AppFog até ele ter no mínimo backup e SLA para tempo de resposta em emergência.
Tem muita pouca informação sobre o tuning dos bancos de dados. Eu espero que não seja a configuração padrão que vem na instalação, que são sempre muito ruins para produção. O Heroku Postgres configura as instâncias com ignorantes GIGABYTES de cache.
Não dá pra escalar os bancos horizontalmente, fazendo master-slave. No Heroku Postgres existe a opção de Follows.
Como disse no artigo anterior, a funcionalidade matadora do Heroku é definitivamente o Heroku Postgresql. Eu não recomendaria o AppFog para clientes por causa dessa enorme deficiência no suporte a banco de dados. Não adianta nada conseguir escalar instâncias web se o próximo gargalo vai ser o banco de dados. É o dilema mais antigo da literatura web e o que a maioria dos PaaS ainda não resolveu decentemente.
Setup e Deployments
Depois de instalar a gem o processo é bem simples:
1 2 3 |
# só a primeira vez $ gem install af $ af login |
Para criar a aplicação, a partir do diretório o código do seu projeto, faça:
1 |
af push sua_aplicacao --runtime ruby193 |
Ele vai fazer várias perguntas que devem ser simples de se responder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Would you like to deploy from the current directory? [Yn]: y Detected a Rails Application, is this correct? [Yn]: y 1: AWS US East - Virginia 2: AWS EU West - Ireland 3: AWS Asia SE - Singapore 4: Rackspace AZ 1 - Dallas 5: HP AZ 2 - Las Vegas Select Infrastructure: 1 Application Deployed URL [teste.aws.af.cm]: Memory reservation (128M, 256M, 512M, 1G, 2G) [256M]: 128M How many instances? [1]: Bind existing services to 'teste'? [yN]: n Create services to bind to 'teste'? [yN]: y 1: mongodb 2: mysql 3: postgresql 4: rabbitmq 5: redis What kind of service?: 2 Specify the name of the service [mysql-e4aa3]: teste-db Create another? [yN]: n Would you like to save this configuration? [yN]: n |
Agora, toda vez que atualizar o código, para fazer um novo deployment faça:
1 |
af update sua_aplicacao |
Existe um problema que o Appfog diz que sabe que existe mas continua me irritando profundamente. Depois de tentar rodar a aplicação ele precisa fazer o processo de rodar migrations, executar asset precompiling, e isso pode demorar. Parece que o comando fica preso e dá timeout, e com isso o aplicativo fica num estado não finalizado. Você precisa ficar tentando rodar o update repetidas vezes até finalmente ele conseguir subir.
Um dos problemas pode ser que sua instância esteja muito pequena em tamanho de memória e a tarefa de asset precompiling pode consumir muita RAM no processo e dar crash por falta de memória. Se a aplicação for muito grande em assets uma coisa que pode ser feita é gerar o precompiling localmente antes do update. "Parece" (não confirmei) que ele sobe os assets no update e aí o precompiling (aliado ao turbo-sprockets) não precisa repetir o processo no deploy.
Novamente, como no Heroku, ele não tem opção de zero downtime, para não tirar a aplicação do ar durante um deployment, então use um horário de pouco movimento para essas atualizações, especialmente por causa de problema atual de timeout de conexão.
A diferença do plano grátis para o plano inicial de USD 20 é que só no plano pago você pode apontar seu domínio. Para mapear a aplicação faça:
1 |
af map sua_aplicacao www.sua_aplicacao.com.br |
E no seu serviço de DNS aponte o naked domain (sem subdomínio) como um redirect para o www e faça o www ser do tipo CNAME apontando para cname01.aws.af.cm
. Esta documentação explica em mais detalhes.
Tunnel
Uma opção que inicialmente é interessante mas depois é bem chata é em como se conectar diretamente no banco de dados ou como rodar tarefas rake por exemplo. No Heroku é muito simples como expliquei no artigo anterior, no AppFog é um pouco burocrático.
Pra começar, uma coisa que não mencionei é o AppFog é construído sobre o CloudFoundry.org, o PaaS da VMWare que tem partes open source. Na Rubyconf Brasil 2012 o Martin Englund apresentou essa plataforma, assista à gravação da palestra.
Voltando ao assunto, a forma para acessar seus serviços é usar uma funcionalidade chamada caldecott. Em essência você pode criar um servidor que vai servir de túnel entre você e seu serviço, mapeando uma porta local. No caso ela usa a porta 10000 do seu localhost.
Para abrir um túnel é simples, apenas execute:
1 |
af tunnel |
A partir daí basta escolher qual serviço você quer se conectar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
1: foo1-db 2: foo2-db ... 7: foo7-db Which service to tunnel to?: 7 Getting tunnel connection info: OK Service connection info: username : usM...XDS password : pCS...sN1 name : d92...05e infra : aws Starting tunnel to tinyclone-db on port 10000. 1: none 2: mysql 3: mysqldump Which client would you like to start?: 1 Open another shell to run command-line clients or use a UI tool to connect using the displayed information. Press Ctrl-C to exit... |
Se for um mysql você pode conectar assim:
1 |
mysql -u usM...XDS -ppCS...sN1 -h localhost -P 10000 d92...05e |
Obviamente, vai aparecer um usuário, senha e nome do banco diferentes. Anote o seu e faça a conexão.
Agora, digamos que você queira executar alguma tarefa rake, ou mesmo abrir o console do rails. Para isso você vai precisar ter mais trabalho. Edite o arquivo config/database.yml local do seu projeto e adicione a seguinte configuração no final:
1 2 3 4 5 6 7 8 |
appfog: adapter: postgres encoding: UTF8 pool: 5 database: d92...05e username: usM...XDS password: pCS...sN1 port: 10000 |
Agora você pode executar comandos assim:
1 |
RAILS_ENV=appfog rails console |
Cuidado, se precisar de configurações de ambiente, copie o config/environments/production.rb para config/environments/appfog.rb
Não é confortável como um heroku run rails console
mas funciona.
Paliativo para o Backup
Não ter um backup me deixa nervoso. Como paliativo (e um paliativo bem ruim, deixemos claro) fiz o seguinte script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/env ruby # add to your crontab: # * 5,13,22 * * * backup_appfog.rb APPFOG_BIN = "#{ENV['HOME']}/.rvm/gems/ruby-1.9.3-p392/bin/af" BACKUP_DIR = "#{ENV['HOME']}/Documents/Appfog-Backup/" dbs = %w(foo1 foo2 foo3) dbs.each do |db| puts "backup: #{db}" `#{APPFOG_BIN} export-service #{db} > #{BACKUP_DIR}#{db}.log` end dbs.each do |db| log = File.read("#{BACKUP_DIR}#{db}.log").split("\n") url = log.select { |line| line =~ /^http/ }.first puts "download: #{url}" `curl -o #{BACKUP_DIR}#{db}.dump #{url}` end |
Customize para seu gosto (mudando nomes de diretórios e bancos de dados, claro) e adicione no crontab mais ou menos assim:
1 |
* 5,13,22 * * * /seu_diretorio_home_/.rvm/rubies/ruby-1.9.3-p392/bin/ruby /seu_diretorio_home_/backup_appfog.rb |
Novamente, mude a frequência (no exemplo, ele só vai executar às 5h, 13h e 22h), local do executável do Ruby (dependendo se está instalado nativo, com RVM ou RBENV) e nome do script.
O dump que ele baixa é um arquivo em formato gz (tipo Zip). Use a ferramenta do mysql ou pg_restore ou outro dependendo do banco para restaurar local, por exemplo.
Outra forma (que não dá pra colocar no cron e rodar automaticamente) é abrir um túnel como expliquei acima e usar diretamente o mysqldump e pg_dump a partir dos dados de conexão que ele fornece.
Conclusão
Como disse antes, estou rodando já 7 sites na conta de USD 20 da Appfog. Como podem imaginar não são sites pesados e respondem rápido ao tráfego.
Me incomoda muito as atuais deficiências do banco de dados. Não ter backup é o pior deles, seguido por não conseguir facilmente escalar horizontalmente criando slaves read-only.
A ferramenta de linha de comando tem dezenas de opções, muitas até que o Heroku não tem, mas ela tem esse bug horrível de dar timeout e deixar o servidor em estado instável o que prejudica o downtime em todo deployment. Eles precisam consertar isso logo.
O estilo de "pré-pago" não funciona pra todo mundo. No meu caso, como não pretendo ir muito acima dos USD 50 com isso, é o suficiente. Pra muitos sites pequenos, o próprio plano de USD 20 vai ser mais do que suficiente e nesse sentido ele tem um custo muito mais barato do que o Heroku.
Escalar os servidores web horizontalmente é simples, mas novamente vai estar limitado a quanto o banco aguenta, e nesse momento não sei dizer porque ele não documenta isso (pelo menos eu não achei). Também gosto do fato de estar tudo implementado numa plataforma robusta como o CloudFoundry, que só tem a evoluir principalmente depois que a aquisição da Pivotal Labs pela EMC gerou o Pivotal One.
No geral é uma boa solução, especialmente se você quiser misturar num mesmo ambiente coisas como PHP (que o Heroku não suporta), com banco de dados MySQL (novamente, que o Heroku não suporta).