DevSecOpsARTIGO

Docker de aplicação web em Python

Neste artigo, vamos descrever como fazer o dock de um aplicativo simples de formulário web, originalmente escrito para o ambiente Elastic Beanstalk Python.

Há algumas semanas a Elastic Beanstalk anunciou o suporte para a implementação e gerenciamento de containers Docker na nuvem AWS. Neste artigo, vamos descrever como fazer o dock de um aplicativo simples de formulário web, originalmente escrito para o ambiente Elastic Beanstalk Python.

Sobre o aplicativo

Desenvolvemos e divulgamos o aplicativo há alguns meses. Há uma série de vídeos em quatro partes e um post que detalha o uso do DynamoDB e do SNS com o app. Neste artigo, faremos uma análise em 4 fases sobre como o aplicativo roda com o Docker e o Elastic Beanstalk.

Código fonte para referência

O código fonte para a aplicação Python original (ou seja, sem o dock) está disponível no GitHub (no ramo principal). A versão “Dockerized” está no ramo docker.

E se você preferir o código e comparativos para blogar a respeito, confira a visualização disponível no GitHub para comparar as diferenças entre esses dois ramos. Verifique os arquivos adicionados e cada linha alterada em Dockerize neste exemplo.

Fase 1: Adição de um Dockerfile

Vamos começar analisando o código fonte do GitHub:

$> git clone git@github.com:awslabs/eb-py-flask-signup.git
$> cd eb-py-flask-signup
$> git checkout master

Analisando os conteúdos do diretório, vemos que este é um aplicativo web simples escrito em Python, que usa o framework Flask, o Boto para interagir com o DynamoDB e o SNS, e algumas outras dependências declaradas no arquivo requirements.txt.

Em seguida, criamos um Dockerfile que irá construir uma imagem adequada para executar esta aplicação. O Dockerfile fica no diretório com o restante da fonte do aplicativo (ou seja, ao lado de requirements.txt, application.py etc):

FROM ubuntu:12.10
 
# Install Python Setuptools
RUN apt-get install -y python-setuptools
 
# Install pip
RUN easy_install pip
 
# Add and install Python modules
ADD requirements.txt /src/requirements.txt
RUN cd /src; pip install -r requirements.txt
 
# Bundle app source
ADD . /src
 
# Expose
EXPOSE 5000
 
# Run
CMD ["python", "/src/application.py"]

Fase 2: Testes locais

Embora este aplicativo exija uma tabela DynamoDB e o tópico SNS para ser totalmente funcional, podemos testá-lo sem eles:

Em primeiro lugar, construa a imagem Docker:

$> docker build -t eb-py-sample .

Por último, execute um container a partir da imagem (mapeando a porta 5000 do container para a porta de host 8080, e defina algumas env vars discutidas abaixo):

$> docker run -d \
-e APP_CONFIG=application.config.example \
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-p 8080:5000 \
eb-py-sample

No OS X podemos abrir http://localhost:8080 e lá está o app!

local_app

Sidebar: Usamos as opções – e para passar adiante algumas variáveis de ambiente:

  1. APP_CONFIG: O aplicativo requer esta variável de ambiente para apontar para o arquivo de configuração. Apontamos para o arquivo de configuração padrão que vem com o aplicativo. Você poderia criar uma tabela DynamoDB e um tópico SNS e adicioná-los a este arquivo conf para fazer o app funcionar perfeitamente em um env dev local.
  2. AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY: O aplicativo usa o Boto para se conectar ao DynamoDB e ao SNS, e o Boto usa essas variáveis de ambiente para assinar as requisições para esses serviços. Isso vale apenas para o dev local. Quando implementarmos a Elastic Beanstalk usaremos o IAM Roles.

Fase 3: Modificar .ebextensions

Nosso aplicativo possui um diretório “especial.ebextensions” com um arquivo setup.config. Usamos o arquivo para informar ao Elastic Beanstalk que este deve criar a tabela DynamoDB e ao tópico SNS nossas necessidades de aplicativo, e também para criar um arquivo de configuração do app – /var/app/app.config – que inclui os nomes da tabela DynamoDB e o tópico SNS que acabou de ser criado.

O arquivo também detalha algumas coisas específicas ao tipo de ambiente Python (ao contrário do Docker) no Elastic Beanstalk. Precisamos remover os bits agora:

Modifique o membro files para remover as chaves owner e group para que se pareçam com:

files:
"/var/app/app.config":
mode: "000444"
content: |
AWS_REGION = '`{ "Ref" : "AWS::Region"}`'
STARTUP_SIGNUP_TABLE = '`{ "Ref" : "StartupSignupsTable"}`'
NEW_SIGNUP_TOPIC = '`{ "Ref" : "NewSignupTopic"}`'

Modifique option_settings para remover mapeamento estático de arquivos para que se pareça com:

option_settings:
"aws:elasticbeanstalk:customoption":
"AlarmEmail" : "nobody@amazon.com"
"aws:elasticbeanstalk:application:environment":
"APP_CONFIG": "/var/app/app.config"
"FLASK_DEBUG": "false"
"THEME": "flatly"

Confira o artigo anterior para mais informações sobre setup.config, ou consulte setup.config do Dockerized no GitHub

Fase 4: Implementação do Elastic Beanstalk

Já construímos e testamos o container localmente, removemos algumas .ebextensions que eram específicas do ambiente Elastic Beanstalk Python, e agora estamos prontos para implementá-lo com confiança!

Criamos um arquivo chamado Dockerrun.aws.json no mesmo lugar em que criamos o Dockerfile. Este arquivo informará ao Elastic Beanstalk como deve executar o container Docker e se parece com isso (veja o quadro abaixo para mais detalhes sobre este arquivo):

"AWSEBDockerrunVersion": "1",
"Volumes": [
{
"ContainerDirectory": "/var/app",
"HostDirectory": "/var/app"
}
],
"Logging": "/var/eb_log"
}

Sidebar sobre o Dockerrun.aws.json:

O membro Volumes irá mapear /var/app na instância EC2 de /var/app no container. Isso permite que o aplicativo em execução no container do Docker acesse o arquivo app.config criado por .ebextensions/setup.config. O membro Logging indica ao Elastic Beanstalk que nosso aplicativo Dockerized irá gravar logs em /var/eb_log no container. Beanstalk puxará automaticamente os logs a partir deste diretório sempre que o usuário clicar em Snapshot Logs no console, ou se ativar a rotação automática de log.

Vamos comitar as alterações e usar o git archive para fazer um zip para implementar a Elastic Beanstalk (você pode usar a ferramenta zip ou Finder ou ainda Windows Explorer para obter o mesmo):

$> git add Docker* && git commit -am "Dockerized"
$> git archive --format=zip HEAD > eb-py-flask-signup.zip

E então implementamos o zip via Elastic Beanstalk Management Console.

app_deploying

Quando nosso ambiente estiver verde, poderemos, é claro, acessá-lo e verificar se funciona:

deployed_app
Também faremos um snapshot dos logs do ambiente:

logs-1024x640

Referências

***

Artigo escrito por Jonathan Fritz, Senior Product Manager da Amazon EMR.

Este artigo faz parte do AWSHUB, rede de profissionais AWS gerenciado pelo iMasters.

Chef Evangelist na Amazon Web Services.

Ver perfil