Sejam bem vindos ao oitavo post do blog.
Iremos configurar e executar uma aplicação Laravel (PHP)
Repositório:
https://github.com/brunocaramelo/docker-compose-php-application-example
Dependência | Descrição | Versão |
---|---|---|
PHP | Usado para Backend | 7.4.11 |
Nginx | Usado como Web server | 1.19.3 |
Mariadb | Usado como Banco de dados SQL | 10.5.6-MariaDB |
Redis | Usado com Cache Storage | 6.0.8 |
RabbitMq | Usado para mensageria | 3.8.9 |
Premissas
Ter as seguintes dependências previamente instaladas e configuradas:
- Docker
- Docker Compose
Composição de Serviços
Especificações de serviços da aplicação.
Serviço | Descrição | Dependências de serviços |
---|---|---|
php | Domínio da aplicação backend da API exposta com o PHP FPM. | mysql, redis, rabbitmq |
worker-php | Domínio da aplicação para execução de rotinas. | mysql |
worker-queue | Domínio da aplicação para consumo da mensageria. | mysql, rabbitmq |
web | Recurso responsável pelo Web server da aplicação com montagem para configuração. | php |
rabbitmq | Recurso responsável pela Mensageria e prover a interface gráfica. | |
mysql | Recurso responsável pela base de dados SQL persistida em disco local. |

Entendo a configuração do serviço: php
php: # Nome do serviço build: # Inicio da sessão build context: . # Nivel onde o build deve ser executado dockerfile: ./docker/php7-fpm/Dockerfile # Dockerfile escolhido (padrão arquivo com nome Dockerfile, no mesmo nivel do arquivo docker-compose) image: repo-registry-local/libraryapitest-app-example:v4.0 # imagem que sera usada como base do build. pode ser usado tambem para que seja enviado ao registry, como este exemplo container_name: php-library-example # nome do container ao subir o serviço depends_on: # depencia de outros serviços, ira iniciar apenas quando a lista abaixo estiver de pé - redis - mysql - rabbitmq command: bash -c "php artisan migrate && php-fpm" # sobreposicao do atributo CMD do Dockerfile env_file: # vairaveis de ambiente vindas de um arquivo - docker/docker-compose-env/application.env environment: # variaveis de ambiente explicitas, tambem pode ser usado para sobreescrever variaveis APP_NAME: 'Sobrepondo - Library API' links: # Quando listado, o container passa e ver os serviços abaixo - mysql - redis - rabbitmq volumes: # Area destinada a montagem externa - ./application/:/app:rw - /app/vendor
Topologia da aplicação

Iniciando a aplicação
agora que temos um entendimento básico sobre os recursos da aplicação, iremos iniciá-la.
docker-compose up -d
O comando acima executa faz com que todos os serviços contido em nosso docker-compose sejam iniciados, tendo o seguinte resultado.
Starting redis-library ... done Starting mysql-library ... done Starting rabbitmq ... done Starting php-library-example-worker ... done Starting php-library-example ... done Starting php-library-worker-queue-example ... done Starting nginx-library ... done
Também é possível discriminar os serviços que queremos iniciar como o comando abaixo.
docker-compose up rabbitmq mysql -d
Ou executar o build de todos os serviços ou de um determinado servico conforme podemos ver abaixo.
docker-compose build docker-compose build php
Verificando Serviços
Podemos verificar se os serviços iniciaram corretamente com o seguinte comando :
docker ps
Com o seguinte resultado:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2f0d029513c3 nginx:1.19-alpine "/docker-entrypoint.…" 3 days ago Up 18 minutes 0.0.0.0:80->80/tcp nginx-library 90a5a7a0d335 repo-registry-local/libraryapitest-app-example:v4.0 "docker-php-entrypoi…" 3 days ago Up 18 minutes 9000/tcp php-library-example 9630371843b4 libraryapiotra:php-worker-example "docker-php-entrypoi…" 3 days ago Up 18 minutes 9000/tcp php-library-example-worker 71861ab99b26 libraryapiotra:php-worker-queue "docker-php-entrypoi…" 3 days ago Up 18 minutes 9000/tcp php-library-worker-queue-example 9fcb27caaceb mariadb:latest "docker-entrypoint.s…" 13 days ago Up 19 minutes 0.0.0.0:3306->3306/tcp mysql-library 40f05238ace7 rabbitmq:3-management-alpine "docker-entrypoint.s…" 13 days ago Up 18 minutes 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 15691-15692/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp rabbitmq e85dbe64c2e6 redis:alpine "docker-entrypoint.s…" 13 days ago Up 18 minutes 6379/tcp redis-library
Visualizando documentação da API (Swagger)
Ao inciar nossa aplicação, podemos ver a documentação da API. a partir do seguinte endereço:
http://localhost/api/documentation

Entendendo as interdependências
Iremos utilizar algumas rotas para entender melhor a participação de diferentes serviços entre si, para isso iremos ver 3 casos de uso:
– VER DETALHE DE LIVRO
– ENVIAR MENSAGEM AO MESSAGE BROKER
– PROCESSAR MENSAGEM DO MESSAGE BROKER
DETALHAMENTO DOS CASOS DE USO
1 – VER DETALHE DE LIVRO
Este recurso tem como finalidade apresentar o detalhamento de um livro, utilizando o recurso de Cache para evitarmos o uso de uma base de dados SQL por exemplo, durante o tempo em que o Cache existir, ou que se tenha uma alteração no dado, momentos em que o índice é invalidado.
Representação UML da rota: GET book/{bookId}

Representação da aplicação para a rota: GET book/{bookId}

Ao clicar em Try it out >> preencher o campo Id do Livro >> clicar em Execute.

Nesta rota utilizamos um Cache para consulta executada ,utilizando o Driver que envia para o Redis, conforme podemos ver abaixo, foram visualizados três livros: livro 13, 15 e 16, e temos o valor do índice gerado em nossa instancia Redis.

2 – ENVIAR MENSAGEM AO MESSAGE BROKER
Este recurso tem como finalidade enviar uma mensagem a nosso Message Broker, para que seja processado em outro momento de forma assíncrona.
Representação UML da rota: POST /author/process/message

Representação da aplicação para a rota: POST /author/process/message
Após clicar em Try it out >> preencher o campo de mensagem >> clicar em Execute.

Receberemos uma mensagem que nossa messagem sera processada. esta mensagem apenas e gerada, caso nosso Message Broker recebeu e aceitou nossa mensagem.
Acessando O Message Broker:
http://localhost:15672

Login: admin
Password: admin
Verificando Mensagens recebidas em:
http://localhost:15672/#/queues

Podemos notar que temos 4 mensagens aguardando processamento. na fila chamada test, que foi configurada em nossa aplicação Laravel.
Ao Clicar no Menu Messages:

{"displayName":"App\\Jobs\\ProcessExperimentalJob","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"timeout":null,"timeoutAt":null,"data":{"commandName":"App\\Jobs\\ProcessExperimentalJob","command":"O:31:\"App\\Jobs\\ProcessExperimentalJob\":8:{s:40:\"\u0000App\\Jobs\\ProcessExperimentalJob\u0000message\";s:87:\"Place the message here for the processing queue received at: 2021-01-30 22:51:54:507117\";s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:15:\"chainConnection\";N;s:10:\"chainQueue\";N;s:5:\"delay\";N;s:7:\"chained\";a:0:{}}"},"id":"bLVXYvR1U9wzTXtGJNQEiLl2wkx8Zqtl"}
Exemplo de payload de uma mensagem enviada pela nossa aplicação.
3 – PROCESSAR MENSAGEM DO MESSAGE BROKER
Este recurso tem como finalidade processar uma mensagem vinda do nosso Message Broker, poderemos ver seu processamento, assim como sua conclusão em nossa fila.
Representação UML do processamento de filas

Representação da aplicação sobre processamento de filas

Execução do serviço:

php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30a841676.51726260] Processing: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | {"message":"Place the message here for the processing queue received at: 2021-01-30 22:51:54:507117 Processed on: 2021-01-31 00:47:38:247462","context":[],"level":200,"level_name":"INFO","channel":"local","datetime":{"date":"2021-01-31 00:47:38.249261","timezone_type":3,"timezone":"UTC"},"extra":[]} php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30a841676.51726260] Processed: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30a913a25.80490108] Processing: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | {"message":"Place the message here for the processing queue received at: 2021-01-30 22:51:54:579488 Processed at: 2021-01-31 00:47:38:251189","context":[],"level":200,"level_name":"INFO","channel":"local","datetime":{"date":"2021-01-31 00:47:38.251229","timezone_type":3,"timezone":"UTC"},"extra":[]} php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30a913a25.80490108] Processed: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30abadad8.37346333] Processing: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | {"message":"Place the message here for the processing queue received at: 2021-01-30 22:51:54:753117 Processed at: 2021-01-31 00:47:38:253215","context":[],"level":200,"level_name":"INFO","channel":"local","datetime":{"date":"2021-01-31 00:47:38.253247","timezone_type":3,"timezone":"UTC"},"extra":[]} php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30abadad8.37346333] Processed: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30b0eb9b5.50128892] Processing: App\Jobs\ProcessExperimentalJob php-library-worker-queue-example | {"message":"Place the message here for the processing queue received at: 2021-01-30 22:51:55:052662 Processed at: 2021-01-31 00:47:38:254837","context":[],"level":200,"level_name":"INFO","channel":"local","datetime":{"date":"2021-01-31 00:47:38.254869","timezone_type":3,"timezone":"UTC"},"extra":[]} php-library-worker-queue-example | [2021-01-31 00:47:38][6015e30b0eb9b5.50128892] Processed: App\Jobs\ProcessExperimentalJob
Conforme podemos ver acima. Vimos que quando o nosso serviço worker-queue verificou que existiam mensagens para processar ele as executou,
vimos sua saída, pois ele esta usando o /dev/stderr para escrever logs:
Podemos ver com o seguinte comando:
docker-compose logs worker-queue
Verificando mensagens após o processamento na aplicação

Vimos o funcionamento de uma mini aplicação e a comunicação entre seus componentes.
Encerramos por aqui.
Espero ter sido claro na explicação.
Obrigado pela atenção, até a próxima!