Instalando um Framework em um container Docker, exemplo com laravel
Instalando um Framework em um container Docker
Objetivo
Este artigo tem por objetivo demonstrar como realizar a instalação de um framework em um container e gerar uma imagem personalizada do zero.
Para este exemplo vamos utilizar o laravel, porém o demonstrado aqui pode ser aplicada a quaisquer outros cenários semelhantes.
Planejamento
Para iniciar os nossos trabalhos vamos executar um container PHP, da seguinte forma:
docker run -it --name php php:7.4-cli bash
root@5eccc7905844:/#
Uma vez executado o container a primeira coisa que vamos fazer é atualizar o sources de pacotes dando um apt-get update
root@5eccc7905844:/# apt-get update
Get:1 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:2 http://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [44.1 kB]
Get:4 http://deb.debian.org/debian bullseye/main amd64 Packages [8183 kB]
Get:5 http://deb.debian.org/debian-security bullseye-security/main amd64 Packages [246 kB]
Get:6 http://deb.debian.org/debian bullseye-updates/main amd64 Packages [14.8 kB]
Fetched 8652 kB in 1s (7523 kB/s)
Reading package lists... Done
O próximo passo vai ser definir em qual diretório vamos instalar o laravel, no nosso exemplo vamos instalar em /var/www
root@ea8bb49926c4:/# cd /var/www/
Agora vamos partir para a instalação do laravel, baseado nessa documentação, para facilitar o desenvolvimento, vamos utilizar o compose que é um tipo de gerenciador de pacotes. Para fazer a instalação do compose vamos utilizar essa documentação.
Sendo assim vamos executar os comandos necessários no nosso container:
root@ea8bb49926c4:/var/www# php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
root@ea8bb49926c4:/var/www# php -r "if (hash_file('sha384', 'composer-setup.php') ===
'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
Installer verified
root@ea8bb49926c4:/var/www# php composer-setup.php
All settings correct for using Composer
Downloading...
Composer (version 2.5.8) successfully installed to: /var/www/composer.phar
Use it: php composer.phar
root@ea8bb49926c4:/var/www# php -r "unlink('composer-setup.php');"
Podemos notar que após a instalação temos um arquivo chamado composer.phar
root@ea8bb49926c4:/var/www# ls
composer.phar html
Podemos então executar o composer da seguinte forma:
root@ea8bb49926c4:/var/www# php composer.phar
______
/ ____/___ ____ ___ ____ ____ ________ _____
/ / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
/_/
Composer version 2.5.8 2023-06-09 17:13:21
Usage:
command [options] [arguments]
....
É sabido que o composer para funcionar bem, necessita de uma lib chamada libzip, sendo assim vamos fazer a instalação dessa dependência:
root@ea8bb49926c4:/var/www# apt-get install libzip-dev -y
Também será necessário instalar a extensão zip do php
root@ea8bb49926c4:/var/www# docker-php-ext-install zip
Agora que temos o composer podemos utilizar ele para criar um projeto utilizando o laravel como framework, conforme essa documentação. Sendo assim vamos executar:
root@ea8bb49926c4:/var/www# php composer.phar create-project --prefer-dist laravel/laravel laravel
Ao final da instalação podemos verificar que o laravel está instalado:
...
> @php artisan key:generate --ansi
Application key set successfully.
root@ea8bb49926c4:/var/www# ls
composer.phar html laravel
root@ea8bb49926c4:/var/www# ls laravel/
README.md artisan composer.json config package.json public routes storage vendor
app bootstrap composer.lock database phpunit.xml resources server.php tests webpack.mix.js
Dockerfile
Note que tudo que executamos até o momento são ações que podemos traduzir para um Dockerfile
, sendo assim, como nosso objetivo é criar uma imagem do zero, vamos criar um Dockerfile e começar a edita-lo:
FROM php:7.4-cli
WORKDIR /var/wwww
RUN apt-get update && \
apt-get install libzip-dev -y && \
docker-php-ext-install zip
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
php composer-setup.php && \
php -r "unlink('composer-setup.php');"
RUN php composer.phar create-project --prefer-dist laravel/laravel laravel
Note que cada comando que executamos anteriormente foi traduzido para uma layer da nossa imagem no Dockerfile.
O próximo passo será executar o laravel, mas antes vamos tentar buildar a nossa imagem, para isso abra um novo terminal e entre no diretório onde está o Dockerfile que criamos acima.
Agora execute o docker build e veja se não ocorrem erros:
docker build -t jorgerabello/custom-laravel:latest .
Ao final do processo você deve ter uma imagem gerada, mais ou menos assim:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jorgerabello/custom-laravel latest 37ef640b9ad0 4 seconds ago 554MB
Voltando ao nosso container de base, o laravel tem um programa chamado artisan, esse artisan nos ajuda a criar componentes de aplicação, no caso vamos utilizar o artisan para subir a nossa aplicação, sendo assim:
Entre no diretório do laravel:
root@ea8bb49926c4:/var/www# cd laravel/
Veja que temos o artisan nesse diretório
root@ea8bb49926c4:/var/www/laravel# ls
README.md artisan composer.json config package.json public routes storage vendor
app bootstrap composer.lock database phpunit.xml resources server.php tests webpack.mix.js
Vamos exeutar o artisan
root@ea8bb49926c4:/var/www/laravel# php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
[Thu Jun 29 03:53:19 2023] PHP 7.4.33 Development Server (http://127.0.0.1:8000) started
Note que subimos um servidor na porta 8000.
Sabendo disso, queremos que ao executar um container com a nossa imagem, queremos que isso seja executado, além disso queremos que o acesso a porta 8000 seja liberado então vamos editar novamente nosso Dockerfile:
FROM php:7.4-cli
WORKDIR /var/wwww
RUN apt-get update && \
apt-get install libzip-dev -y && \
docker-php-ext-install zip
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
php composer-setup.php && \
php -r "unlink('composer-setup.php');"
RUN php composer.phar create-project --prefer-dist laravel/laravel laravel
ENTRYPOINT [ "php", "laravel/artisan", "serve" ]
ENTRYPOINT vs CMD
Porém se fizermos dessa forma não vamos conseguir acessar o laravel, isso por que se você prestou atenção ao executar o laravel, ele fica liberado para acesso apenas dentro do container, veja só:
root@ea8bb49926c4:/var/www/laravel# php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
[Thu Jun 29 03:53:19 2023] PHP 7.4.33 Development Server (http://127.0.0.1:8000) started
Ou seja se eu for na minha máquina e tentar acessar não será possível.
Olhando o help da artisan, podemos notar que é possível passar um host e uma porta como parâmetros.
root@ea8bb49926c4:/var/www/laravel# php artisan serve --help
Description:
Serve the application on the PHP development server
Usage:
serve [options]
Options:
--host[=HOST] The host address to serve the application on [default: "127.0.0.1"]
--port[=PORT] The port to serve the application on
--tries[=TRIES] The max number of ports to attempt to serve from [default: 10]
--no-reload Do not reload the development server on .env file changes
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
--env[=ENV] The environment the command should run under
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Porém queremos que o host e a porta possam ser modificados quando alguém executar um container com a nossa imagem, então além do ENTRYPOINT vamos utilizar o CMD, então nosso Dockerfile vai ficar assim
FROM php:7.4-cli
WORKDIR /var/wwww
RUN apt-get update && \
apt-get install libzip-dev -y && \
docker-php-ext-install zip
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
php composer-setup.php && \
php -r "unlink('composer-setup.php');"
RUN php composer.phar create-project --prefer-dist laravel/laravel laravel
ENTRYPOINT [ "php", "laravel/artisan", "serve" ]
CMD [ "--host=0.0.0.0" ]
Por padrão será passado --host=0.0.0.0
mas isso poderá ser alterado via parâmetro, na prática quando a nossa imagem for executada em um container, teremos um comando mais ou menos assim: php laravel/artisan serve --host=0.0.0.0
.
Vamos fazer novamente o build da nossa imagem e tentar subir um container com ela:
docker build -t jorgerabello/custom-laravel:latest .
docker run --rm --name custom-laravel -p 8000:8000 jorgerabello/custom-laravel
Starting Laravel development server: http://0.0.0.0:8000
[Thu Jun 29 04:10:42 2023] PHP 7.4.33 Development Server (http://0.0.0.0:8000) started
Se você tentar acessar no seu navegador http://localhost:8000/ verá que agora o acesso ao laravel vai ser realizado com sucesso.
Agora como utilizar CMD podemos por exemplo querer ao invés de utilizar a porta 8000 querer utilizar a porta 8001, sendo assim poderíamos executar
docker run --rm --name custom-laravel-2 -p 8001:8001 jorgerabello/custom-laravel --host=0.0.0.0 --port=8001
Note que você agora tem 2 containers sendo executados
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3158a14d1f1e jorgerabello/custom-laravel "php laravel/artisan…" 29 seconds ago Up 29 seconds 0.0.0.0:8001->8001/tcp, :::8001->8001/tcp custom-laravel-2
70e92d27ac9a jorgerabello/custom-laravel "php laravel/artisan…" 6 minutes ago Up 6 minutes 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp custom-laravel
E que você pode acessar o laravel tanto no container que está executando na porta 8000 http://localhost:8000/ como na 8801 http://localhost:8001.
Publicando a imagem
Agora que sabemos que nossa imagem está estável, vamos subir ela no dockerhub
docker push jorgerabello/custom-laravel:latest