Docker + LAMP + AWS Beanstalk

Rodrigo Klosowski
Jul 20, 2017 · 11 min read

Apesar de haver alguns tutoriais demonstrando a utilização do Apache e PHP em containers docker, poucos funcionam "out of the box", além de apresentarem pouca flexibilidade em relação as dependências exigidas pela sua aplicação.

Outra configuração muito mal entendida consiste na integração do ambiente de desenvolvimento PHP com banco de dados MySQL, utilizando RDS em um ambiente de produção AWS (Amazon Web Services), mais especificamente o Elastic Beanstalk.

Neste artigo será descrita a implementação de um servidor Apache+PHP containerizado, permitindo maior flexibilidade em suas aplicações e em seguida esse container será implementado em produção utilizando o Elastic Beanstalk.


Servidor Apache+PHP em Docker

Segundo a AWS, um docker consiste uma plataforma de software que permite a criação, o teste e a implantação de aplicações rapidamente. O docker cria pacotes de software em unidades padronizadas chamadas de contêineres que têm tudo o que o software precisa para ser executado, inclusive bibliotecas, ferramentas de sistema, código e runtime. Ao usar o docker, é possível implantar e escalar rapidamente aplicações em qualquer ambiente e ter a certeza de que o seu código será executado.

Assim, assumindo que você ao menos se familiarizou com os conceitos básicos e as vantagens da utilização de um container docker podemos iniciar a criação de nosso container Apache+PHP.

  1. Instalar o Docker

As etapas posteriores necessitam que o docker esteja instalado e configurado em sua máquina. As instruções e o instalador encontram-se no site do docker.

Crie também uma conta no Docker Hub, para poder salvar suas imagens no repositório Docker.

2. Dockerfile

O arquivo Dockerfile é responsável pela descrição da imagem do nosso container, para mais informações consulte a documentação do docker.

Neste exemplo será instalado a versão 5.6 do PHP, caso deseje-se uma versão mais recente como a 7.0 ou 7.1, basta substituir a versão do php.

Para iniciar crie o arquivo Dockerfile na pasta desejada com o seguinte conteúdo.

# ./DockerfileFROM php:5.6-apache
MAINTAINER Rodrigo Klosowski
# Habilito por padrão algumas extensões úteis para o php como o gd.RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng12-dev \
&& docker-php-ext-install -j$(nproc) iconv mcrypt \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd
COPY app/ /var/www/html/EXPOSE 80

Os arquivos presentes em ./app serão utilizados pela maquina do docker na pasta raiz do server, ou seja é nesta pasta que sua aplicação ou site php deve ser inserido.

Para poder testar o funcionamento do seu servidor Apache, insira o arquivo index.php na pasta app, com o seguinte conteúdo.

<? //index.php ?>
<? echo "<h1>Meu Site utilizando Docker + PHP</h1>"; ?>

Insira também um arquivo info.php, onde podemos verificar as configurações e extensões habilitadas pelo php.

<? //info.php ?>
<? phpinfo(); ?>

Seu projeto inicial deve conter a seguinte estrutura:

Estrutura do diretório inicial para o projeto.

3. "Buildar" o container

Assim que finalizar a edição dos arquivos acima, podemos construir a imagem do nosso container para testa-lo.

Execute o comando a baixo na pasta em que encontra-se o Dockerfile. Substituindo 'mysite' pelo nome de sua aplicação ou pelo nome que deseja que a sua imagem seja criada. Não esqueça do ponto no final do comando, indicando o diretório atual.

docker build -t user/mysite .

Com o comando abaixo inicie a imagem que acabamos de criar.

docker run -p 8080:80 -d -v /Users/rodrigo/Documents/Docker/mysite/app:/var/www/html user/mysite

Onde:

  • -p: Indica as portas utilizadas pelo container, na qual a porta 80 do container será publicada na porta 8080 do Host;
  • -d: Faz com que o processo rode como um daemon;
  • -v: Permite que as alterações feitas no código sejam refletidas para o container, sem a necessidade de construi-lo novamente. Substitua os endereços absolutos pelos endereços da sua aplicação;

4. (Opcional) Atualizar o php.ini

Caso em sua aplicação seja necessário configurar diversas instâncias do arquivo php.ini, modifique seu Dockerfile conforme o código abaixo:

FROM php:5.6-apache
MAINTAINER Rodrigo Klosowski
# Habilito por padrão algumas extensões úteis para o php como o gd.RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng12-dev \
&& docker-php-ext-install -j$(nproc) iconv mcrypt \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd
# Redefine o arquivo php.ini
COPY config/php.ini /usr/local/etc/php/
# Os arquivos presentes em app serão construidos no server do container
COPY app/ /var/www/html/
EXPOSE 80

Não esqueça de adicionar seu novo php.ini na pasta config criada dentro do nosso diretório de trabalho.

Nova estrutura, caso deseje modificar o php.ini do seu servidor. (opcional)

Assim, todas as alterações realizadas sobre as configurações do php serão refletidas sobre seu container.

5. Fazer push da sua imagem

Para checar se tudo ocorreu corretamente até esta etapa, você deve ser capaz de visualizar a seguinte página após executar a imagem criada com o comando abaixo, substituindo o nome da sua imagem e o caminho dos seus arquivos:

docker run -p 8080:80 -d -v /Users/rodrigo/Documents/Docker/mysite/app:/var/www/html user/mysite

Caso você tenha chegado até aqui, faça o push da sua imagem para o Docker Hub, este passo é fundamental, pois facilitará a integração da nossa imagem com os serviços da Amazon. Para este exemplo estaremos criando um repositório público.

Faça o push de sua imagem utilizando os seguintes comandos.

docker login
docker push user/mysite

6. (opcional) Criando um Docker Compose

O Docker Compose, originalmente chamado de fig, foi criado com o propósito de orquestrar a criação e administração de um conjunto de containers a partir do uso de um simples arquivo de configuração em formato YAML. Esse simples arquivo basicamente define todos os containers que serão usados por um projeto, suas conexões entre si, volumes usados (para poder armazenar dados de forma persistente), e demais configurações que você pode passar para o Docker

Logo, para facilitar a utilização em desenvolvimento e tornar nosso container mais escalável iremos criar um arqui Docker Compose com algumas configurações iniciais.

version: '3'
services:
web:
image: user/mysite
#build: .
#Definicao das variáveis de ambiente, úteis reutilizar o código em desenvolvimento local e em produção.

environment:
- RDS_HOSTNAME=myhostname
- RDS_PORT=myport
- RDS_DB_NAME=mydbname
- RDS_USERNAME=myusername
- RDS_PASSWORD=mypassword
#Usar a porta 8080 no servidor local
ports:
- "8080:80"
volumes:
- ./app:/var/www/html

Salve o arquivo na raiz do diretório que estávamos trabalhando como "docker-compose.yml".

Agora sempre que formos utilizar essa imagem, basta executar o comando.

docker-compose up -d

Mais simples não?


Criando sua aplicação no Elastic Beanstalk

Para criarmos o primeiro deploy de nossa aplicação você deve ter uma conta no AWS, a qual pode ser criada gratuitamente.

Em seus serviços AWS vá atéa dashboard do Elastic Beansalk e inicie a criação de uma nova aplicação.

Inicie nomeando e descrevendo sua aplicação.

Importante: Durante a criação do environment da sua aplicação selecione a plataforma docker, fica pra outra hora criarmos uma plataforma multi-container.

Após selecionar a plataforma como docker, você deverá selecionar a opção upload your code na sessão Application code.

Calma! vou explicar o que você utilizará como código. Esta etapa é importantíssima.

A Amazon nos fornece algumas escolhas nessa etapa, pois podemos enviar um zip contendo o nosso código fonte e alguns arquivos de configuração. Porém lembra que nós já fizemos o push da nossa imagem do container para o Docker Hub? Então, caso sua imagem já esteja hospedada em um repositório, esta etapa será muito mais fácil de ser configurada e a manutenção de sua aplicação também será simplificada.

Caso tenhamos este repositório criado no Docker Hub iremos criar apenas um arquivo de configuração chamado de "Dockerrun.aws.json" e nele diremos como o EB deve ser configurado e onde deverá procurar as imagens necessárias para montar nossa aplicação. Para ver mais detalhes sobre esse arquivo e adicionar configurações extras confira este link.

Por simplicidade criamos o arquivo abaixo de maneira simplista. O arquivo foi salvo como "Dockerrun.aws.json".

{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "user/mysite",
"Update": "true"
},
"Ports": [
{
"ContainerPort": "80"
}
]
}

O nome da imagem corresponde com o nome do seu repositório no DockerHub. Faça o upload desse arquivo durante a criação da sua aplicação, na sessão Application code.

Aguarde por alguns instantes até que todas as configurações sejam realizadas e você estará pronto para prosseguir.

Apesar de ainda não termos sido criado nosso banco de dados, podemos verificar se o container que criamos funcionou.

Caso seja possível visualizar a tela do dashboard de sua aplicação como a imagem abaixo, provavelmente a aplicação de teste que criamos já está rodando no domínio configurado para sua aplicação. Verifique!

Percorremos um longo caminho até aqui, agora iremos iniciar a criação do nosso banco de dados MySql utilizando o RDS.

Configurar o banco RDS

Você pode usar uma instância DB do Amazon Relational Database Service (Amazon RDS) para armazenar dados coletados e modificados pelo seu aplicativo. O banco de dados pode ser anexado ao seu ambiente e gerenciado pelo Elastic Beanstalk, ou criado e gerenciado externamente, sendo o último indicado para ambientes em produção, sendo necessário realizar a configuração de um grupo de segurança independente.

Neste exemplo será criado um banco diretamente pelo RDS e não pelo Elastic Beanstalk, tornando nosso banco mais independente de nossa aplicação, eles serão vinculados posteriormente utilizando grupos de segurança e VPS.

  1. Criando sua instância RDS

Vá até o dashboard do RDS e inicie a criação da sua instância e inicie escolhendo a engine do db que deseja utilizar, no nosso caso utilizaremos o mysql.

Informe o usuário e senha para administrar seu banco e aplique as alterações. Utilize o VPC default e deixe que o RDS crie um novo grupo de segurança para essa aplicação na aba avançada. Caso ainda apresente dúvidas consulte a documentação.

Aguarde a atualização que pode durar até 10 minutos.

2. Grupos de Segurança

Esta etapa é extremamente importante, pois ela possibilitará que seu banco seja acessado por algum cliente sql, como por exemplo o MySQLWorkbench, e verificar o funcionamento do banco.

Primeiramente vá até a instância do seu banco de dados, clique com o botão direito para ver os detalhes dessa instância. Em seguida procure pela opção Security Groups e clique no link ao lado.

Agora, na aba detalhada dos grupos de segurança da sua instância, busque pelo menu inbound. Neste local devem ser configurados todos os grupos ou endereços que devem ter acesso ao seu banco de dados.

Adicione novas regras. Recomendo habilitar o seu IP local, para poder acessar utilizando um cliente SQL em seu host. Habilitar o acesso do grupo que contém sua aplicação Elastic Beanstalk, a qual deve ser uma das opções disponíveis da seleção. Adicione mais regras que você julgar necessário em sua aplicação.

3. Vincular o RDS ao Elastic Beanstalk

Agora iremos vincular nossa aplicação Elastic Beanstalk ao banco que criamos.

Primeiramente vá até o dashboard da aplicação que criamos no beanstalk e clique em configurações no menu da esquerda. Agora clique no menu Instances e na opção EC2 security groups adicione separado por vírgula o nome do grupo de segurança da sua instância RDS. Por padrão deve ser algo como 'rds-launch-wizard'.

4. Variáveis de Ambiente

Em seguida, passe as informações de conexão ao seu ambiente, usando as propriedades do ambiente.

Você pode usar as mesmas propriedades, o que permitirá que você use o mesmo código de aplicativo com instâncias de banco de dados integradas e instâncias externas de banco de dados, ou escolha seus próprios nomes de propriedade.

Para isso, ainda nas configurações da aplicação do Elastic Beanstalk, vá até o menu de configurações e em seguida clique em Software Configuration. Crie as principais variáveis úteis para receber as configurações sobre o seu banco de dados no seu container e tornar igual seu driver de conexão com o banco de dados em php no estágio de desenvolvimento e produção. Recomendo utilizar os padrões já definidos pela AWS.

RDS_HOSTNAME - O nome do host da instância DB.
Etiqueta do console Amazon RDS - Endpoint é o nome do host.
RDS_PORT - A porta na qual a instância DB aceita conexões. O valor padrão varia entre os motores DB.
Etiqueta do console Amazon RDS - Port
RDS_DB_NAME - O nome do banco de dados, ebdb.
Etiqueta da console Amazon RDS - DB Name
RDS_USERNAME - O nome de usuário que você configurou para o seu banco de dados.
Etiqueta do console Amazon RDS - Username
RDS_PASSWORD - A senha que você configurou para seu banco de dados.

Ufa!

Agora vamos testar se conseguimos importar as variáveis de ambiente com as informações para realizarmos as conexões com o banco de dados na nossa aplicação PHP.

Lembra daquele arquivo index.php que criamos no início desse projeto? Vamos atualizar ele, agora utilizaremos ele para ver se conseguimos importar corretamente as variáveis no nosso container.

<? //index.php ?><? echo "<h1>Meu Site utilizando Docker + PHP + MySql</h1>";$dbhost = getenv('RDS_HOSTNAME');
$dbport = getenv('RDS_PORT');
$dbname = getenv('RDS_DB_NAME');
$username = getenv('RDS_USERNAME');
$password = getenv('RDS_PASSWORD');
echo ('<p>$dbhost = '.$dbhost.'</p>');
echo ('<p>$dbport = '.$dbport.'</p>');
echo ('<p>$dbname = '.$dbname.'</p>');
echo ('<p>$username = '.$username.'</p>');
echo ('<p>$password = '.$password.'</p>');
?>

Agora não esqueça de construir novamente a sua imagem com o novo código fonte e realizar o push da sua imagem para o DockerHub.

docker build -t user/mysite .
docker push user/mysite

No menu da sua aplicação no Elastic Beanstalk realize um novo deploy, utilizando o mesmo arquivo de configuração "Dockerrun.aws.json".

BOOOOA! Se tudo ocorreu corretamente você deve ser capaz de visualizar na URL da sua aplicação as informações necessárias para realizar a conexão com o seu banco de dados a partir do seu container PHP+Apache.

Agora basta continuar o desenvolvimento ou realizar o deploy de sua aplicação e conectar com o banco de dados utilizando PDO, MySQLi ou sua ferramenta favorita.


Dica: Após se habituar com alguns conceitos básicos da utilização e implementação de seus ambientes Docker em AWS, experimente utilizar as ferramentas EB CLI para gerenciar a manutenção e deploy de sua aplicação por linhas de comando. Por exemplo para verificar se as variáveis de ambiente foram criadas, basta utilizar o comando abaixo.

eb printenv

Mais informações para instalar e utilizar podem ser encontradas na documentação da AWS.


Conclusão

Uma vez que sua aplicação seja transformada em uma imagem Docker, ela pode ser instanciada como container em qualquer ambiente que desejar, ou seja, isso significa que você poderá utilizar a sua aplicação no notebook do desenvolvedor da mesma forma que ela seria executada no servidor de produção.

Garanto que seus ciclos de desenvolvimento e produção serão muito mais ágeis e simples.

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade