A seguir, um passo a passo de como configurar e implantar um aplicativo Django no Amazon Web Services (AWS) enquanto permanece são.
Ferramentas/tecnologias utilizadas:
- Python v2.7.8
- Django v1.7
- Amazon Elastic Beanstalk, EC2, S3 e RDS
- EB CLI 3.x
- PostgreSQL
Agora com Python 3! Confira a versão atualizada deste artigo aqui.
Este artigo foi atualizado para cobrir a implantação com o Python 3 porque a AWS agora adora muito o Python 3.
Elastic Beanstalk vs EC2
O Elastic Beanstalk é uma plataforma como serviço (PaaS) que simplifica a configuração, implantação e manutenção de seu aplicativo na Amazon AWS. É um serviço gerenciado, acoplando o servidor (EC2), banco de dados (RDS) e seus arquivos estáticos (S3). Você pode implantar e gerenciar rapidamente seu aplicativo, que é dimensionado automaticamente à medida que seu site cresce. Confira a documentação oficial para mais informações.
Primeiros passos
Usaremos um aplicativo simples de “Imagem do Dia”, que você pode pegar neste repositório:
$ git clone https://github.com/realpython/image-of-the-day.git
$ cd image-of-the-day/
$ git checkout tags/start_here
Após baixar o código, crie um virtualenv e instale os requisitos via pip:
$ pip install -r requirements.txt
Em seguida, com o PostgreSQL rodando localmente, configure um novo banco de dados chamado
iotd
. Além disso, dependendo de sua configuração local do Postgres, pode ser necessário atualizar os DATABASES
configuração em settings.py . Por exemplo, atualizei a configuração para:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'iotd',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}
}
Agora você pode configurar o esquema do banco de dados, criar um superusuário e executar o aplicativo:
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
Navegue até a página de administração em seu navegador em http://localhost:8000/admin e adicione uma nova imagem, que será exibida na página principal.
O aplicativo não deve ser muito empolgante; estamos apenas usando-o para fins de demonstração. Tudo o que faz é permitir que você carregue uma imagem através da interface de administração e exiba essa imagem em tela cheia na página principal. Dito isto, embora este seja um aplicativo relativamente básico, ele ainda nos permitirá explorar uma série de “pegadinhas” que existem ao implantar no Amazon Beanstalk e no RDS.
Agora que temos o site funcionando em nossa máquina local, vamos iniciar o processo de implantação da Amazon.
CLI para AWS Elastic Beanstalk
Para trabalhar com um Amazon Elastic Beanstalk, podemos usar um pacote chamado awsebcli. No momento da redação deste artigo, a versão mais recente do é 3.0.10 e a maneira recomendada de instalá-lo é com pip:
$ pip install awsebcli
Não use brew para instalar este pacote. No momento da redação deste artigo, ele instala a v2.6.3, que está quebrada de maneiras sutis que levarão a uma séria frustração.
Agora teste a instalação para ter certeza de que está funcionando:
$ eb --version
Isso deve fornecer um bom número de versão 3.x:
EB CLI 3.0.10 (Python 2.7.8)
Para realmente começar a usar o Elastic Beanstalk, você precisará de uma conta na AWS (surpresa!). Cadastre-se ou faça o login).
Configurar EB – Inicializar seu aplicativo
Com a CLI do AWS Elastic Beanstalk funcionando, a primeira coisa que queremos fazer é criar um ambiente Beanstalk para hospedar o aplicativo. Execute isso no diretório do projeto (“image-of-the-day”):
$ eb init
Isso fará com que você faça várias perguntas para ajudá-lo a configurar seu ambiente.
Região padrão
Escolher a região mais próxima de seus usuários finais geralmente fornecerá o melhor desempenho. Confira este mapa se não tiver certeza de qual escolher.
Credenciais
Em seguida, ele solicitará suas credenciais da AWS.
Aqui, você provavelmente desejará configurar um usuário do IAM. Consulte este guia para saber como configurar um. Se você configurar um novo usuário, precisará garantir que o usuário tenha as permissões apropriadas. A maneira mais simples de fazer isso é apenas adicionar “Acesso de administrador” ao usuário. (No entanto, essa provavelmente não é uma ótima opção por motivos de segurança.) Para as políticas/funções específicas que um usuário precisa para criar/gerenciar um aplicativo Elastic Beanstalk, consulte o link aqui.
Nome do aplicativo
Isso será o padrão para o nome do diretório. Apenas vá com isso.
Versão do Python
Em seguida, a CLI deve detectar automaticamente que você está usando o Python e apenas solicitar a confirmação. Diga sim. Então você precisa selecionar uma versão da plataforma. Selecione
Python 2.7
. SSH
Diga sim para configurar o SSH para suas instâncias.
Par de chaves RSA
Em seguida, você precisa gerar um par de chaves RSA, que será adicionado ao seu ~/.ssh pasta. Esse par de chaves também será carregado para a chave pública do EC2 para a região especificada na etapa um. Isso permitirá que você faça SSH em sua instância do EC2 posteriormente neste tutorial.
O que realizamos?
Uma vez
eb init
for concluído, você verá uma nova pasta oculta chamada .elasticbeanstalk no diretório do seu projeto:├── .elasticbeanstalk
│ └── config.yml
├── .gitignore
├── README.md
├── iotd
│ ├── images
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── iotd
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── manage.py
│ ├── static
│ │ ├── css
│ │ │ └── bootstrap.min.css
│ │ └── js
│ │ ├── bootstrap.min.js
│ │ └── jquery-1.11.0.min.js
│ └── templates
│ ├── base.html
│ └── images
│ └── home.html
├── requirements.txt
└── www
└── media
└── sitelogo.png
Dentro desse diretório está um
config.yml
file, que é um arquivo de configuração que é usado para definir certos parâmetros para seu aplicativo Beanstalk recém-criado. Neste ponto, se você digitar
eb console
ele abrirá seu navegador padrão e navegará até o console do Elastic Beanstalk. Na página, você deve ver um aplicativo (chamado image-of-the-day
se você estiver seguindo exatamente), mas sem ambientes. Um aplicativo representa seu aplicativo de código e é o que
eb init
criado para nós. Com o Elastic Beanstalk, um aplicativo pode ter vários ambientes (ou seja, desenvolvimento, teste, preparação, produção). Depende completamente de você como você deseja configurar/gerenciar esses ambientes. Para aplicativos simples do Django, gosto de ter o ambiente de desenvolvimento no meu laptop e, em seguida, criar um ambiente de teste e de produção no Beanstalk. Vamos configurar um ambiente de teste…
Configurar EB – Criar um ambiente
Voltando ao terminal, no diretório do seu projeto digite:
$ eb create
Assim como
eb init
, este comando fará uma série de perguntas. Nome do ambiente
Você deve usar uma convenção de nomenclatura semelhante à que a Amazon sugere - por exemplo, application_name-env_name - especialmente quando/se você começar a hospedar vários aplicativos com a AWS. Eu usei -
iod-test
. Prefixo DNS CNAME
Ao implantar um aplicativo no Elastic Beanstalk, você obtém automaticamente um nome de domínio como xxx.elasticbeanstalk.com.
DNS CNAME prefix
é o que você quer que seja usado no lugar de xxx
. Basta ir com o padrão. O que acontece agora?
Neste ponto
eb
irá realmente criar seu ambiente para você. Seja paciente, pois isso pode levar algum tempo.
Se você receber um erro ao criar o ambiente, como -aws.auth.client.error.ARCInstanceIdentityProfileNotFoundException
- verifique se as credenciais que você está usando possuem permissões apropriadas para criar o ambiente Beanstalk, conforme discutido anteriormente neste post.
Imediatamente após a criação do ambiente,
eb
tentará implantar seu aplicativo, copiando todo o código em seu diretório de projeto para a nova instância do EC2, executando pip install -r requirements.txt
no processo. Você deve ver várias informações sobre o ambiente que está sendo configurado exibidas na tela, bem como informações sobre
eb
tentando implantar. Você também verá alguns erros. Em particular, você deve ver essas linhas enterradas em algum lugar na saída:ERROR: Your requirements.txt is invalid. Snapshot your logs for details.
Não se preocupe - não é realmente inválido. Verifique os logs para obter detalhes:
$ eb logs
Isso pegará todos os arquivos de log recentes da instância do EC2 e os enviará para o seu terminal. É muita informação, então você pode querer redirecionar a saída para um arquivo (
eb logs -z
). Examinando os registros, você verá um arquivo de registro chamado eb-activity.log :Error: pg_config executable not found.
O problema é que tentamos instalar o
psycopy2
(as ligações do Postgres Python), mas também precisamos que os drivers do cliente Postgres sejam instalados. Como eles não são instalados por padrão, precisamos instalá-los primeiro. Vamos corrigir isso… Personalizando o processo de implantação
eb
irá ler o .config
personalizado arquivos de uma pasta chamada “.ebextensions” no nível raiz do seu projeto (diretório “imagem do dia”). Estes .config
arquivos permitem que você instale pacotes, execute comandos arbitrários e/ou defina variáveis de ambiente. Os arquivos no diretório “.ebextensions” devem estar em conformidade com JSON
ou YAML
sintaxe e são executados em ordem alfabética. Instalando pacotes
A primeira coisa que precisamos fazer é instalar alguns pacotes para que nosso
pip install
comando será concluído com sucesso. Para fazer isso, vamos primeiro criar um arquivo chamado .ebextensions/01_packages.config :packages:
yum:
git: []
postgresql93-devel: []
As instâncias do EC2 executam o Amazon Linux, que é um tipo de Redhat, para que possamos usar o yum para instalar os pacotes de que precisamos. Por enquanto, vamos instalar apenas dois pacotes - git e o cliente Postgres.
Depois de criar esse arquivo para reimplantar o aplicativo, precisamos fazer o seguinte:
$ git add .ebextensions/
$ git commit -m "added eb package configuration"
Temos que confirmar as alterações porque o comando de implantação
eb deploy
funciona com o último commit e, portanto, só estará ciente das alterações do nosso arquivo depois de enviá-las para o git. (Observe que não temos que empurrar; estamos trabalhando em nossa cópia local…) Como você provavelmente adivinhou, o próximo comando é:
$ eb deploy
Agora você deve ver apenas um erro:
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
ERROR: Your WSGIPath refers to a file that does not exist.
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.
Vamos descobrir o que está acontecendo…
Configurando nosso ambiente Python
As instâncias do EC2 no Beanstalk executam o Apache, e o Apache encontrará nosso aplicativo Python de acordo com o WSGIPATH que definimos. Por padrão
eb
assume que nosso arquivo wsgi é chamado application.py . Existem duas maneiras de corrigir isso - Opção 1:usar definições de configuração específicas do ambiente
$ eb config
Este comando abrirá seu editor padrão, editando um arquivo de configuração chamado .elasticbeanstalk/iod-test.env.yml . Este arquivo não existe localmente;
eb
retirou-o dos servidores da AWS e o apresentou a você para que você possa alterar as configurações nele. Se você fizer alguma alteração neste pseudo-arquivo e depois salvar e sair, eb
atualizará as configurações correspondentes em seu ambiente Beanstalk. Se você pesquisar os termos 'WSGI' no arquivo, deverá encontrar uma seção de configuração semelhante a esta:
aws:elasticbeanstalk:container:python:
NumProcesses: '1'
NumThreads: '15'
StaticFiles: /static/=static/
WSGIPath: application.py
Atualize o WSGIPath:
aws:elasticbeanstalk:container:python:
NumProcesses: '1'
NumThreads: '15'
StaticFiles: /static/=static/
WSGIPath: iotd/iotd/wsgi.py
E então você terá o WSGIPath configurado corretamente. Se você salvar o arquivo e sair,
eb
atualizará a configuração do ambiente automaticamente:Printing Status:
INFO: Environment update is starting.
INFO: Updating environment iod-test's configuration settings.
INFO: Successfully deployed new configuration to environment.
INFO: Environment update completed successfully.
A vantagem de usar o
eb config
método para alterar as configurações é que você pode especificar configurações diferentes por ambiente. Mas você também pode atualizar as configurações usando o mesmo .config
arquivos que estávamos usando antes. Isso usará as mesmas configurações para cada ambiente, como o .config
os arquivos serão aplicados na implantação (após as configurações de eb config
Foram aplicados). Opção 2:como usar as configurações globais
Para usar o
.config
opção de arquivo, vamos criar um novo arquivo chamado /.ebextensions/02_python.config :option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "iotd.settings"
"PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
"aws:elasticbeanstalk:container:python":
WSGIPath: iotd/iotd/wsgi.py
NumProcesses: 3
NumThreads: 20
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "www/static/"
O que está acontecendo?
DJANGO_SETTINGS_MODULE: "iotd.settings"
- adiciona o caminho para o módulo de configurações."PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
- atualiza nossoPYTHONPATH
para que o Python possa encontrar os módulos em nosso aplicativo. (Observe que o uso do caminho completo é necessário.)WSGIPath: iotd/iotd/wsgi.py
define nosso caminho WSGI.NumProcesses: 3
eNumThreads: 20
- atualiza o número de processos e threads usados para executar nosso aplicativo WSGI."/static/": "www/static/"
define nosso caminho de arquivos estáticos.
Novamente, podemos fazer um
git commit
em seguida, um eb deploy
para atualizar essas configurações. Em seguida, vamos adicionar um banco de dados.
Configurando um banco de dados
Tente visualizar o site implantado:
$ eb open
Este comando mostrará o aplicativo implantado em seu navegador padrão. Você deve ver um erro de conexão recusada:
OperationalError at /
could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5432?
Isso ocorre porque ainda não configuramos um banco de dados. Neste ponto
eb
configurará seu ambiente Beanstalk, mas não configurará o RDS (a camada do banco de dados). Temos que configurar isso manualmente. Configuração do banco de dados
Novamente, use
eb console
para abrir a página de configuração do Beanstalk. A partir daí, faça o seguinte:
- Clique no link "Configuração".
- Role até o final da página e, na seção "Tier de dados", clique no link "criar um novo banco de dados RDS".
- Na página de configuração do RDS, altere o "DB Engine" para "postgres".
- Adicione um "Nome de usuário mestre" e uma "Senha mestre".
- Salve as alterações.
O Beanstalk criará o RDS para você. Agora precisamos fazer com que nosso aplicativo Django se conecte ao RDS. O Beanstalk nos ajudará aqui, expondo várias variáveis de ambiente nas instâncias do EC2 para nós que detalham como se conectar ao servidor Postgres. Então, tudo o que precisamos fazer é atualizar nosso settings.py para tirar vantagem dessas variáveis de ambiente. Confirme se os
DATABASES
parâmetro de configuração reflete o seguinte em settings.py :if 'RDS_DB_NAME' in os.environ:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ['RDS_DB_NAME'],
'USER': os.environ['RDS_USERNAME'],
'PASSWORD': os.environ['RDS_PASSWORD'],
'HOST': os.environ['RDS_HOSTNAME'],
'PORT': os.environ['RDS_PORT'],
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'iotd',
'USER': 'iotd',
'PASSWORD': 'iotd',
'HOST': 'localhost',
'PORT': '5432',
}
}
Isso simplesmente diz:“Use as configurações da variável de ambiente, se houver, caso contrário, use nossas configurações de desenvolvimento padrão”. Simples.
Gerenciando migrações de banco de dados
Com nossa configuração de banco de dados, ainda precisamos garantir que as migrações sejam executadas para que a estrutura da tabela de banco de dados esteja correta. Podemos fazer isso modificando .ebextensions/02_python.config e adicionando as seguintes linhas na parte superior do arquivo:
container_commands:
01_migrate:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py migrate --noinput"
leader_only: true
container_commands
permitem que você execute comandos arbitrários depois que o aplicativo for implantado na instância do EC2. Como a instância do EC2 é configurada usando um ambiente virtual, devemos primeiro ativar esse ambiente virtual antes de executar nosso comando migrate. Também o leader_only: true
A configuração significa "Executar este comando apenas na primeira instância ao implantar em várias instâncias". Não esqueça que nossa aplicação usa o admin do Django, então vamos precisar de um superusuário…
Criar o usuário administrador
Infelizmente
createsuperuser
não permite que você especifique uma senha ao usar o --noinput
opção, então teremos que escrever nosso próprio comando. Felizmente, o Django facilita muito a criação de comandos personalizados. Crie o arquivo iotd/images/management/commands/createsu.py :
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
class Command(BaseCommand):
def handle(self, *args, **options):
if not User.objects.filter(username="admin").exists():
User.objects.create_superuser("admin", "[email protected]", "admin")
Certifique-se de adicionar o
__init__.py
apropriado arquivos também:└─ management
├── __init__.py
└── commands
├── __init__.py
└── createsu.py
Este arquivo permitirá que você execute
python manage.py createsu
, e ele criará um superusuário sem solicitar uma senha. Sinta-se à vontade para expandir o comando para usar variáveis de ambiente ou outro meio para permitir que você altere a senha. Depois de criar o comando, podemos adicionar outro comando ao nosso
container_commands
seção em .ebextensions/02_python.config :02_createsu:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py createsu"
leader_only: true
Antes de testar isso, vamos garantir que nossos arquivos estáticos estejam todos no lugar correto…
Arquivos estáticos
Adicione mais um comando em
container_commands
:03_collectstatic:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py collectstatic --noinput"
Então o arquivo inteiro fica assim:
container_commands:
01_migrate:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py migrate --noinput"
leader_only: true
02_createsu:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py createsu"
leader_only: true
03_collectstatic:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py collectstatic --noinput"
option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "iotd.settings"
"PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
"ALLOWED_HOSTS": ".elasticbeanstalk.com"
"aws:elasticbeanstalk:container:python":
WSGIPath: iotd/iotd/wsgi.py
NumProcesses: 3
NumThreads: 20
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "www/static/"
Agora precisamos garantir que o
STATIC_ROOT
está definido corretamente no settings.py Arquivo:STATIC_ROOT = os.path.join(BASE_DIR, "..", "www", "static")
STATIC_URL = '/static/'
Certifique-se de confirmar o
www
diretório para git para que o diretório estático possa ser criado. Em seguida, execute eb deploy
novamente, e agora você deve estar no negócio:INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.
Neste ponto, você deve poder acessar http://your_app_url/admin, fazer login, adicionar uma imagem e ver essa imagem exibida na página principal do seu aplicativo.
Sucesso!
Usando S3 para armazenamento de mídia
Com essa configuração, cada vez que implantarmos novamente, perderemos todas as nossas imagens enviadas. Por quê? Bem, quando você executa
eb deploy
, uma nova instância é gerada para você. Não é isso que queremos, pois teremos entradas no banco de dados para as imagens, mas sem imagens associadas. A solução é armazenar os arquivos de mídia no Amazon Simple Storage Service (Amazon S3) em vez de na própria instância do EC2. Você vai precisar:
- Criar um bucket
- Pegue o ARN do seu usuário (Amazon Resource Name)
- Adicionar permissões de bucket
- Configure seu aplicativo Django para usar o S3 para servir seus arquivos estáticos
Como já existem boas anotações sobre isso, vou apenas apontar para o meu favorito:Usando o Amazon S3 para armazenar seus arquivos estáticos e de mídia do Django
Configuração do Apache
Como estamos usando o Apache com o Beanstalk, provavelmente queremos configurar o Apache para (entre outras coisas) habilitar a compactação gzip para que os arquivos sejam baixados mais rapidamente pelos clientes. Isso pode ser feito com
container_commands
. Crie um novo arquivo .ebextensions/03_apache.config e adicione o seguinte:container_commands:
01_setup_apache:
command: "cp .ebextensions/enable_mod_deflate.conf /etc/httpd/conf.d/enable_mod_deflate.conf"
Então você precisa criar o arquivo
.ebextensions/enable_mod_deflate.conf
:# mod_deflate configuration
<IfModule mod_deflate.c>
# Restrict compression to these MIME types
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xml+rss
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/css
# Level of compression (Highest 9 - Lowest 1)
DeflateCompressionLevel 9
# Netscape 4.x has some problems.
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
<IfModule mod_headers.c>
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</IfModule>
</IfModule>
Fazer isso ativará a compactação gzip, o que deve ajudar no tamanho dos arquivos que você está baixando. Você também pode usar a mesma estratégia para reduzir e combinar automaticamente seu CSS/JS e fazer qualquer outro pré-processamento necessário.
Solução de problemas
Não se esqueça do muito útil
eb ssh
comando, que o levará à instância do EC2 para que você possa bisbilhotar e ver o que está acontecendo. Ao solucionar problemas, existem alguns diretórios que você deve conhecer:/opt/python
- Raiz de onde seu aplicativo terminará./opt/python/current/app
- O aplicativo atual que está hospedado no ambiente./opt/python/on-deck/app
- O aplicativo é inicialmente colocado no convés e, após a conclusão de toda a implantação, ele será movido paracurrent
. Se você estiver recebendo falhas em seuscontainer_commands
, confira oon-deck
pasta e não a pastacurrent
pasta./opt/python/current/env
- Todas as variáveis de ambiente queeb
configurará para você. Se você estiver tentando reproduzir um erro, talvez seja necessário primeirosource /opt/python/current/env
para configurar as coisas como seriam quando eb deploy estiver em execução.opt/python/run/venv
- O env virtual usado pelo seu aplicativo; você também precisará executarsource /opt/python/run/venv/bin/activate
se você estiver tentando reproduzir um erro
Conclusão
A implantação no Elastic Beanstalk pode ser um pouco assustadora no começo, mas depois que você entende onde estão todas as partes e como as coisas funcionam, é realmente muito fácil e extremamente flexível. Ele também oferece um ambiente que será dimensionado automaticamente à medida que seu uso aumentar. Espero que agora você tenha o suficiente para ser perigoso! Boa sorte em sua próxima implantação do Beanstalk.
Perdemos alguma coisa? Tem alguma outra dica ou truque? Por favor, comente abaixo.