Ambiente LAMP e Redis com Docker e Docker Compose

| Por Mauro J. Miranda

O Docker é uma plataforma de código aberto que permite automatizar o processo de criação, implantação e execução de aplicativos dentro de contêineres. Docker Compose é uma ferramenta que simplifica o processo de definição e execução de aplicativos multi-contêiner com Docker.

Neste artigo, vamos aprender como criar um ambiente de desenvolvimento PHP com MySQL e Redis usando Docker e Docker Compose.

Pré-requisitos

Antes de começarmos, quero frisar que vamos criar tudo no sistema operacional Linux. Certifique-se de ter o Docker e o Docker Compose instalados em uma maquina. Você pode encontrar instruções de instalação em Docker Documentation e Docker Compose Documentation.

Estrutura do Projeto

Vamos criar um diretório para nosso projeto e dentro dele teremos a seguinte estrutura:

- meu-projeto/
  - bin/
  	- 000-default.conf
  	- Dockerfile
  	- php.ini
  - logs/
  	- apache/
  	- xdebug/
  - www/
  - .env
  - docker-compose.yml
  - Makefile

No arquivo 000-default.conf vamos colocar as configurações do hosts do apache:

<VirtualHost *:80>
	ServerAdmin webmaster@localhost
	DocumentRoot ${APACHE_DOCUMENT_ROOT}
	ServerName localhost
	<Directory ${APACHE_DOCUMENT_ROOT}>
		AllowOverride all
	</Directory>
</VirtualHost>

Como este é um modelo ambiente que pode ser usado para aplicações wordpress, ou outros frameworks, onde seus arquivos index podem variar de localização, adiacionamos a variavel APACHE_DOCUMENT_ROOT que serve para informar ao apache onde está localizado o nosso arquivo index.php, como mostraremos mais adiante.

No arquivo php.ini colocaremos as configurações básicas para o PHP:

memory_limit = 256M
post_max_size = 100M
upload_max_filesize = 100M

# Xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.idekey=VSCODE

No Dockerfile vamos então colocar todas as configurações de imagem, importar virtual host e importar o php.ini:

FROM php:8.3-apache

# Surprime reclamações do debconf de tentar instalar pacotes apt interativamente
# https://github.com/moby/moby/issues/4032#issuecomment-192327844

ARG DEBIAN_FRONTEND=noninteractive

# Update
RUN apt -y update --fix-missing && \
	apt upgrade -y && \
	apt --no-install-recommends install -y apt-utils && \
	rm -rf /var/lib/apt/lists/*
	
# Instala ferramentas e bibliotecas importantes
RUN apt -y update && \
	apt -y --no-install-recommends install nano wget \
	ssh \
	rsync \
dialog \
libsqlite3-dev \
libsqlite3-0 && \
	apt -y --no-install-recommends install default-mysql-client \
zlib1g-dev \
libzip-dev \
libicu-dev && \
	apt -y --no-install-recommends install --fix-missing apt-utils \
build-essential \
git \
curl \
libonig-dev && \
	apt install -y iputils-ping && \
	apt -y --no-install-recommends install--fix-missing libcurl4 \
	libssl-dev \
	libargon2-dev \
libcurl4-openssl-dev \
libpq-dev \
libpspell-dev \
libsnmp-dev \
zip \
openssl && \
	rm -rf /var/lib/apt/lists/* && \
	curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
	
# Install xdebug
RUN pecl install redis-3.3.1 && \
	docker-php-ext-enable xdebug && \
	mkdir /var/log/xdebug
	
# Install redis
RUN pecl install redis-5.3.3 && \
	docker-php-ext-enable redis
	
# Install imagick
RUN apt update && \
	apt -y --no-install-recommends install --fix--missing libmagickwand-dev && \
	rm -rf /var/lib/apt/lists/*
	
# Workarround until imagick is available in pecl with php8 support
# Imagick Commit to install
# https://github.com/Imagick/imagick
ARG IMAGICK_COMMIT="661405abe21d12003207bc8eb0963fafc2c02ee4"

RUN cd /usr/local/src && \
	git clone https://github.com/Imagick/imagick && \
	cd imagick && \
	git checkout ${IMAGICK_COMMIT} && \
	phpize && \
	./configure && \
	make && \
	make install && \
	cd .. && \
	rm -rf imagick && \
	docker-php-ext-enable imagick
	
# Other PHP8 Extensions
RUN docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
	&& docker-php-ext-install pdo pdo_pgsql pgsql
	
# install PHP LDAP support
RUN \
	apt-get update && \
	apt-get install libldap2-dev -y && \
	rm -rf /var/lib/apt/lists/* && \
	docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && \
	docker-php-ext-install ldap
	
RUN docker-php-ext-install pdo_mysql && \
	docker-php-ext-install pdo_sqlite && \
	docker-php-ext-install bcmath && \
	docker-php-ext-install mysqli && \
	docker-php-ext-install curl && \
	docker-php-ext-install zip && \
	docker-php-ext-install -j$(nproc) intl && \
	docker-php-ext-install mbstring && \
	docker-php-ext-install gettext && \
	docker-php-ext-install calendar && \
	docker-php-ext-install exif
	
# Install Freetype
RUN apt-get -y update && \
	apt-get --no-install-recommends install -y libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev && \
	rm -rf /var/lib/apt/lists/* && \
	docker-php-ext-configure gd --enable-gd --with-freetype --with-jpeg && \
	docker-php-ext-install gd
	
COPY php.ini /usr/local/etc/php/php.ini
COPY 000-default.conf /etc/apache2/sites-enabled/000-default.conf

# Enable SSL support
RUN a2enmod ssl && a2enmod rewrite && a2enmod expires

# Enable apache modules
RUN a2enmod rewrite headers

# Cleanup
RUN rm -rf /usr/src/*

Proximo passo precisamos colocar as informações no arquivo docker-compose.yml, vamos informar quais são os servidores que queremos rodar:

 # docker-compose.yml
version: "3"

services:
  phpserver:
    build:
      context: ./bin
    container_name: "${PROJECT_NAME}-phpserver-8.3"
    restart: "always"
    ports:
      - "${HOST_MACHINE_UNSECURE_HOST_PORT}:80"
      - "${HOST_MACHINE_SECURE_HOST_PORT}:443"
    links:
      - dbserver
    volumes:
      - ${DOCUMENT_ROOT}:/var/www/html
      - ${LOG_DIR}:/var/log/apache2
      - ${XDEBUG_LOG_DIR}:/var/log/xdebug
    environment:
      APACHE_DOCUMENT: ${APACHE_DOCUMENT_ROOT}
      XDEBUG_CONFIG: "client_host=host.docker.internal remote_port=${XDEBUG_PORT}"
  
  gulpserver:
    image: quissama/gulp:0.1.0
    container_name: ${PROJECT_NAME}-gulp
    depends_on:
      - phpserver
    volumes:
      - "${DOCUMENT_ROOT}:/opt"
    command: sh -c "npm install && gulp watch"

  dbserver:
    image: mariadb:10.6
    container_name: "${PROJECT_NAME}-mariadb-server-10.6"
    restart: "always"
    ports:
      - "${HOST_MACHINE}:3306"
    volumes:
      - ${MYSQL_INITDB_DIR}:/docker-entrypoint-initdb.d
      - ${MYSQL_DATA_DIR}:/var/lib/mysql
      - ${MYSQL_LOG_DIR}:/var/log/mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

  phpmyadmin:
    image: phpmyadmin
    container_name: ${PROJECT_NAME}-phpmyadmin
    links:
      - dbserver
    environment:
      PMA_HOST: dbserver
      PMA_PORT: 3306
      PMA_USER: root
      PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      UPLOAD_LIMIT: ${UPLOAD_LIMIT}
      MEMORY_LIMIT: ${MEMORY_LIMIT}
    ports:
      - "${HOST_MACHINE_PMA_PORT}:80"
      - "${HOST_MACHINE_PMA_SECURE_PORT}:443"
    volumes:
      - /sessions
      - ${PHP_INI}:/usr/local/etc/php/conf.d/php-phpmyadmin.ini

  redis:
    image: redis:latest
    container_name: "${PROJECT_NAME}-redis"
    ports:
      - "${HOST_MACHINE_REDIS_PORT}:6379" 

O arquivo .env

 PROJECT_NAME=lampr

# PHP
APACHE_DOCUMENT_ROOT=/var/www/html
HOST_MACHINE_UNSECURE_HOST_PORT=80
HOST_MACHINE_SECURE_HOST_PORT=443
DOCUMENT_ROOT=./www
APACHE_LOG_DIR=./logs/apache2
XDEBUG_LOG_DIR=./logs/xdebug

# DB
HOST_MACHINE_MYSQL_PORT=3306
MYSQL_INITDB_DIR=./config/initdb
MYSQL_DATA_DIR=./data/mysql
MYSQL_LOG_DIR=./logs/mysql
MYSQL_ROOT_PASSWORD=panther
MYSQL_DATABASE=docker
MYSQL_USER=docker
MYSQL_PASSWORD=docker

# PHP MY ADMIN
UPLOAD_LIMIT=512M
MEMORY_LIMIT=512M
HOST_MACHINE_PMA_PORT=8080
HOST_MACHINE_PMA_SECURE_PORT=8443
PHP_INI=./config/php/php.ini

# REDIS
HOST_MACHINE_REDIS_PORT=./config/php/php.ini

O arquivo Makefile

 # Makefile for Docker Compose

# Define the default target
.DEFAULT_GOAL := help

# Display the message
help:
	@echo "Usage:"
	@echo "	make up		- Start Docker Compose"
	@echo "	make down	- Stop Docker Compose"
	@echo "	make help	- Display this help message"

# Start Docker Compose
up:
	docker compose up --build -d

down-all:
	docker compose down

# Clean up resources
clean: down

# Ensure the the necessary dependencies are installed
deps:
	@command -v docker compose > /dev/null 2>&1 || { echo >&2 "Docker Compose is required but not installed. Aborting.";  exit 1;}

.PHONY: help up clean deps

Para para rodar a aplicação vamos executar o comando:

$ make up

Podemos ver o resultado logo abaixo:

Para parar o ambiente, vamos executar o comando:

$ make down

É isso. até aqui mostrei como criar um ambiente de desenvolvimento LAMP usando o Docker, Lembrando que foi criando em cima do Linux. No proximo arquivo vou mostrar como criar uma imagem PHP com o Docker.