Neste post vamos aprender a criar um ambiente de desenvolvimento PHP no docker, utilizando o Nginx como webserver, MySql como nosso banco de dados e para teste um projeto Laravel. Utilizaremos o docker-compose e um Dockerfile para isso.
Com o docker-compose estou rodando três containers cada um com: PHP (junto ao composer, xdebug e configurações), Nginx e o MySql.
O proposito deste guia é apenas te dar alguma referencia e ajuda, não se sinta preso(a) nas mesmas configurações.
Índice
- Repositório GITHUB
O ambiente já pronto no meu repositório do GITHUB. - Pré-requisitos
Antes de fazer qualquer coisa vamos instalar todos os pré-requisitos. - Arvore de diretórios
Onde seus projetos, backup e configurações vão estar. - Makefile [opcional]
Automatizando seu ambiente com um makefile. - Configurando o php.dockerfile
Instalando xdebug, composer, bibliotecas e setando configurações. - Configurando o Nginx com certificado SSL.
Configurando PHP-FPM para o Nginx, gerando um certificado SSL e o configurando no nosso servidor. - docker-compose.yml
Construindo nossas imagens nos containers. - Rodando e testando nosso projeto
Repositório no GITHUB
Um método pratico e rápido para conseguir esse ambiente é clonando meu repositório no GITHUB, para isso você pode fazer o download em zip de todo o projeto, ou utilizar o GIT para fazer o clone dele.
Para realizar o clone do repositório utilizando o GIT, basta abrir seu terminal, navegar até o local onde deseja em que seu ambiente esteja e utilize o comando abaixo:
git clone https://github.com/julianoaj/docker-php-laravel-nginx-mysql
Pronto! Feito isso basta abrir seu navegador e entrar no seu localhost.
Instalando os pré-requisitos
Esse ambiente foi feito no windows, mas o docker funcionará em qualquer sistema operacional, basta seguir as orientações de instalação na documentação oficial:
Para checar se tudo foi instalado com sucesso basta entrar com os seguintes comandos no seu terminal:
docker-compose docker -v
[docker-compose
] vai printar todos os comandos do docker-compose, [docker -v
] vai printar a versão do docker.
Ferramentas opcionais:
Arvore de diretórios
Antes de começarmos configurar nosso ambiente precisamos de uma arvore de diretórios. Aqui você escolherá onde seus projetos, backups e configurações vão estar.
Minha arvore de diretórios:
\---environmentProject | docker-compose.yml | Makefile | nginx.dockerfile | php.dockerfile | README.md | +---confs | +---Mysql_db | | backup.ibd | | | +---servers | | server.conf | | | \---ssl | localhost.crt | localhost.key | \---projects \---www index.php
Makefile
Em vez de digitar comandos complexos no seu terminal você pode usar um Makefile para tornar isso mais fácil.
O pré-requisito para usar um Makefile é instalar o comando make
que funciona em qualquer sistema operacional, basta seguir o manual de instalação na sessão de pré-requisitos.
Com o comando make instalado, eu não recomendo, mas você pode clonar meu repositório do github e usar meu Makefile com alguns comandos de atalhos já definidos.
Para checar meu Makefile e a tabela de comandos que eu fiz é só dar uma passada no meu repositório do github.
Configurando o php.dockerfile
Está na hora de construirmos nosso container PHP com o xdebug, composer e configurações dentro de um Dockerfile, para isso precisamos criar o arquivo no nosso diretório raiz /environmentProject/php.dockerfile
.
Dentro do arquivo vamos setar nossa versão do PHP. A versão que iremos usar aqui será a do PHP 7.4 FPM, para conseguirmos usar essa versão dentro do nosso Dockerfile precisamos verificar a tag dela no dockerhub. Com a tag em mãos a primeira linha do nosso Dockerfile deverá ficar assim:
FROM php:7.4-fpm
Lista de tags você pode verificar aqui!
Core Extensions:
Seguindo a versão vamos instalar as core extensions, ou seja, extensões necessárias para nosso ambiente:
RUN apt-get update && apt-get install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ && docker-php-ext-install mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
Dependendo da versão do PHP que você vai usar algumas extensões já vem instaladas. Para verificar a lista de todas as extensões já instaladas na versão do PHP que você usou, no seu terminar use o comando docker run –rm php:7.4-fpm php -m
PECL extensions:
Está na vez de algumas extensões para performance e utilidade, porem não necessárias, para isso utilizaremos o PECL, um repositório de extensões do PHP.
Aqui instalaremos o xdebug, libmencached e o zlib1g. Com isso adicionaremos mais algumas linhas no nosso dockerfile:
RUN pecl install xdebug-3.0.4 \ && docker-php-ext-enable xdebug RUN apt-get install -y libmemcached-dev zlib1g-dev \ && pecl install memcached-3.1.5 \ && docker-php-ext-enable memcached
Packages:
Para instalação de pacotes utilizaremos o composer, junto ao zip e unzip:
RUN apt-get install zip unzip \ && curl -sS https://getcomposer.org/installer -o composer-setup.php \ && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ && unlink composer-setup.php
Configurações:
Aqui vamos setar nosso timezone e ativaremos o opcache para performance do PHP:
RUN echo 'date.timezone="America/Sao_Paulo"' >> /usr/local/etc/php/conf.d/date.ini \ && echo 'opcache.enable=1' >> /usr/local/etc/php/conf.d/opcache.conf \ && echo 'opcache.validate_timestamps=1' >> /usr/local/etc/php/conf.d/opcache.conf \ && echo 'opcache.fast_shutdown=1' >> /usr/local/etc/php/conf.d/opcache
Você pode verificar a lista de tags para timezone aqui.
Configurando o Nginx FastCGI com certificado SSL para o PHP e o Laravel
Para conseguirmos utilizar o PHP e o Laravel com Nginx precisamos configurar o FastCGI e algumas outras coisas. Vamos quebrar isso em dois passos:
- Gerar o certificado SSL [opcional]
Você pode usar meu Makefile para gerar um certificado SSL usando apenas o comandomake gen-ssl
no seu terminal (caso você seja um usuário de windows) ou siga os passos deste GUIA. - Server
server.conf
Para gerenciarmos nosso servidor do Nginx precisamos criar um arquivo do tipo.conf
e vamos cria-lo em:/environmentProject /confs /servers /server.conf
Edite o server.conf
e configure o seu servidor para que ouça a porta 80
e a 443
(porta ssl) do container, coloque o caminho de localização do seu certificado SSL na frente de ssl_certificate
e ssl_certificate_key
e por ultimo passe todas as configurações necessárias para a utilização do Nginx FastCGI do PHP-FPM. Exemplo:
server { ############# Ports ################# listen 80; listen 443 ssl; ##################################### root /var/www/projects/; ########## SSL CERTIFICATE ########## ssl_certificate /var/www/ssl/localhost.crt; ssl_certificate_key /var/www/ssl/localhost.key; ##################################### autoindex on; ########## FAST CGI CONFIG ########## location ~ \.php$ { fastcgi_index index.php; fastcgi_pass php:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
Isso deverá ser o suficiente para rodar sua aplicação PHP nativa. Com o Laravel seu server.conf deverá ficar como:
server { listen 80; listen 443 ssl; server_name example.com; root /var/www/projects/example-app/public; ssl_certificate /var/www/ssl/localhost.crt; ssl_certificate_key /var/www/ssl/localhost.key; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; index index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_index index.php; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } }
Essa configuração foi tirada diretamente da documentação do Laravel.
docker-compose.yml
Chegou a hora de juntarmos tudo usando o docker-compose.
Eu não vou entrar em detalhes neste guia sobre versões, serviços, volumes, etc… caso fique com duvidas sobre alguma coisa de uma olhada na documentação.
Crie o arquivo do tipo .yml
na seguinte localização: /environmentProject/docker-compose.yml
.
Edite ele e vamos começar:
Versão:
A primeira linha do nosso docker-compose.yml deverá ser a versão do docker-compose que usaremos, no nosso caso iremos utilizar a ultima já lançada:
version: "3.9"
Serviços
Seguindo a linha de versionamento vamos aos serviços. Os services nada mais são do que containers, no nosso caso levantaremos 3 containers: Nginx, PHP e o MySql. Vamos quebrar tudo em etapas:
Um arquivo docker-compose.yml deve seguir todas as normas de indentação, caso contrario obteremos erros. De uma checada na documentação caso fique com duvidas.
-
Nginx
Aqui estamos construindo nosso container do Nginx. Apenas preste atenção nas configurações de volumes e portas, que serão onde você deverá colocar a localização da sua pasta de projetos, certificados e servidores. Esses caminhos serão compartilhados diretamente com o container. Sua configuração deverá se parecer com isso:
services: web-server: image: nginx:1.21.1 container_name: webdev-nginx ports: - "80:80" - "443:443" networks: - web-dev volumes: - ./confs/servers/:/etc/nginx/conf.d/ - ./projects:/var/www/projects - ./confs/ssl/:/var/www/ssl
Com essa configuração de volumes você poderá configurar qualquer coisa sem a necessidade de ficar entrando no seu container.
-
PHP
volumes
desse container deve ser o mesmo que o projects do Nginx.php: build: dockerfile: ./php.dockerfile context: . image: php7.4-fpm container_name: webdev-php volumes: - "./projects:/var/www/projects" ports: - "9000:9000" networks: - web-dev
-
MySql
Aqui vamos setar nossas configurações de banco de dados. Em MYSQL_PASSWORD é onde você deverá colocar a sua senha, MYSQL_DATABASE o nome banco de dados criado na inicialização, MYSQL_USER nome de usuário. Caso queira mudar as portas fique a vontade também.
db: image: mysql:8.0.26 container_name: webdev-mysql volumes: - ./confs/mysql_db:/var/lib/mysql command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: test_db MYSQL_USER: devuser MYSQL_PASSWORD: devpass ports: - "3306:3306" networks: - web-dev
- Network
Nossa network vai trazer todos containers juntos em uma mesma rede e a configuração para isso é simples.networks: web-dev: driver: bridge
Rodando e testando nossa aplicação
Com tudo já configurado chegou a hora de darmos vida ao nosso ambiente.
No seu terminal navegue até o diretório /environmentProject/
e passe o comando para o docker-compose começar a construir os containers:
docker-compose build
Assim que a execução do comando for finalizada entre com o comando para começar a rodar os containers:
docker-composer up -d
Feito isso basta entrar no seu localhost e pronto!
Com tudo ja rodando, chegou a hora de testarmos nossa conexão com o banco de dados, para isso crie um arquivo dentro da pasta projects
chamado de index.php
(/environmentProject /projects /index.php
). Dentro do arquivo cole o código a baixo:
<?php $host = 'db'; $user = 'devuser'; $password = 'devpass'; $db = 'test_db'; $conn = new mysqli($host, $user, $password, $db); if ($conn->connect_error){ echo 'connection failed' . $conn->connect_error; } else { echo 'Successfully connected to MySql'; } ?>
acesse http://localhost/index.php caso receba a mensagem de Successfully connected to MySql sua conexão está ok.
Caso queira testar sua conexão via Laravel você vai precisar editar o arquivo /example-app/.env e setar as seguintes configurações:
DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=test_db DB_USERNAME=devuser DB_PASSWORD=devpass
Feito isso, salve e execute os seguintes comandos no seu terminal:
docker exec (container_id) composer dump-autoload docker exec (container_id) php artisan migrate
Caso não receba nenhuma mensagem de erro sua conexão com o banco de dados está ok e você está pronto para começar a codar!
Agradeço sua paciência e espero que tenha conseguido criar seu ambiente de desenvolvimento. Caso ainda reste alguma duvida eu ficaria contente em te responder, basta entrar em contato. Muito obrigado e até a próxima!