<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog do Fernando Jorge Mota</title>
	<atom:link href="https://fjorgemota.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://fjorgemota.com/</link>
	<description>Dicas e ferramentas para facilitar o seu dia-a-dia como desenvolvedor</description>
	<lastBuildDate>Sun, 07 Jul 2024 23:23:24 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
<site xmlns="com-wordpress:feed-additions:1">71563333</site>	<item>
		<title>Docker Networks - Ou como configurar PHP-FPM+MySQL no Docker com o Nginx externo</title>
		<link>https://fjorgemota.com/2024/07/07/docker-networks-ou-como-configurar-php-fpmmysql-no-docker-com-o-nginx-externo/</link>
					<comments>https://fjorgemota.com/2024/07/07/docker-networks-ou-como-configurar-php-fpmmysql-no-docker-com-o-nginx-externo/#comments</comments>
		
		<dc:creator><![CDATA[Fernando]]></dc:creator>
		<pubDate>Sun, 07 Jul 2024 23:03:27 +0000</pubDate>
				<category><![CDATA[Dicas]]></category>
		<category><![CDATA[caddy]]></category>
		<category><![CDATA[containers]]></category>
		<category><![CDATA[desenvolvimento]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[ferramentas]]></category>
		<guid isPermaLink="false">https://fjorgemota.com/?p=5436</guid>

					<description><![CDATA[<!-- wp:paragraph -->
<p>Quando eu postei o <a href="https://fjorgemota.com/2016/01/14/docker-containers-para-a-vida-ou-nao/">tutorial completo sobre Docker</a>, muitos anos atrás, algumas pessoas comentaram pedindo mais detalhes a respeito desse trecho aqui que comentei no post:</p>
<!-- /wp:paragraph -->

<!-- wp:pullquote -->
<figure class="wp-block-pullquote"><blockquote><p>Esse blog que vos fala, por exemplo, está rodando sob dois containers do Docker, um para o php-fpm, outro para o MySQL. Onde está o Nginx? Está fora, instalado na máquina principal, e aí o Nginx se conecta com o php-fpm para poder renderizar essa página da forma que você vê.</p></blockquote></figure>
<!-- /wp:pullquote -->

<!-- wp:paragraph -->
<p>Bom, depois de.. <em>*check notes*</em>, mais de OITO anos, chegou a hora de eu detalhar como funciona isso, afinal, antes tarde do que mais tarde, certo? Então vamos lá.</p>
<!-- /wp:paragraph -->


<span id="more-5436"></span>


<!-- wp:paragraph -->
<p>O Docker, como vocês bem sabem se vocês leram o post referido acima, consegue isolar os processos em containers que compartilham o mesmo kernel, mas cada processo deve ser um container próprio, isolado. Apesar disso, é possível estabelecer um <em>setup</em> onde os containers comunicam entre si, e também com o mundo exterior. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>No caso desse blog que vos fala, conforme referido no trecho citado acima, temos três peças (2 rodando em containers) se comunicando entre si:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><!-- wp:list-item -->
<li><strong>Nginx</strong> - Que é instalado na máquina principal, e fica escutando na porta 80 e 443, e por onde a maior parte dos usuários se conecta</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>MySQL</strong> - Que escuta na clássica porta 3306, mas que NÃO é exposta para fora de container algum, em nenhuma porta. Ficando mais "isolado", por assim dizer.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>PHP-FPM</strong> - Que escuta na porta 9000 dentro do container, mas é exposta apenas localmente (e isso é importante!) dentro da máquina como porta 2004. A ideia é que o Nginx consiga usar a porta 2004 rodando no host 127.0.0.1 (ou seja, o melhor host, o <em>localhost</em>!) para se comunicar com o PHP-FPM.</li>
<!-- /wp:list-item --></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Note que em nenhum momento eu mencionei que há um link (que usando o <em><a href="https://docs.docker.com/network/links/">legacy linking system</a></em> seria algo tipo <code>-l mysql:mysql</code>) entre o PHP-FPM e o MySQL. Mas, como você pode imaginar, por causa do <a href="https://br.wordpress.org/">WordPress</a> tal conexão se faz necessária, caso contrário esse blog não funcionaria pois o PHP nunca conseguiria se comunicar com o MySQL (afinal, os containers são isolados, certo?). </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Para fazer isso, usamos o que o Docker chama de "<a href="https://docs.docker.com/network/#user-defined-networks">Docker User-Defined Network</a>", ou Rede Docker definida pelo usuário, em tradução livre. O que é isso? Imagine que cada container Docker - apesar de rodar um único processo cada - é como se fosse uma rede de computadores. Com base no que sabemos até então, temos a seguinte situação:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8759,"width":"839px","height":"auto","sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image size-full is-resized"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png" alt="Diagrama mostrando você se conectando ao Nginx, que por sua vez se comunica com o PHP-FPM, mas sem se comunicar com o MySQL" class="wp-image-8759" style="width:839px;height:auto"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Um rede definida pelo usuário, no Docker, nada mais é do que uma rede DENTRO do próprio Docker. No caso desse blog, temos uma rede no Docker chamada <code>fjorgemota-com</code>, e a estrutura fica mais ou menos assim:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8760,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image size-full"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png" alt="Diagrama mostrando você se conectando ao Nginx, que por sua vez se comunica com o PHP-FPM e este se comunica com o MySQL" class="wp-image-8760"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>O que que isso implica, necessariamente? Implica que, assim como no caso da rede LOCAL na sua casa, onde seu celular consegue se comunicar com seu computador e vice-versa, cada container DENTRO da rede <code>fjorgemota-com</code> também consegue se comunicar um com o outro. Porém, da mesma forma que alguém externo à rede local da sua casa NÃO consegue se conectar diretamente ao seu computador ou ao seu celular, um <em>container </em>que esteja FORA da rede <code>fjorgemota-com</code> também não consegue se comunicar nem com o MySQL, e nem com o PHP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Entretanto, assim como você PODE expor o seu computador conectado na rede interna da sua casa para o mundo exterior, o fato de um container estar dentro de uma rede definida por usuário também não o impossibilita de expor portas da mesma forma, como no caso do container do PHP-FPM cuja porta 9000 é exposta como 2004 dentro do servidor.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Tutorial</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Como a configuração do Nginx pode variar DEMAIS de máquina para máquina, vamos fazer uma configuração mais simples aqui, <a href="https://caddyserver.com">usando o Caddy</a>, que é bem mais simples de configurar (bastando um simples arquivo de configuração!). <strong>Vamos ao tutorial</strong>:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>1) <a href="https://docs.docker.com/engine/installation/">Baixe e instale o Docker</a> (importante ter uma máquina de 64 bits, pois é o único ambiente no qual o Docker efetivamente roda..)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>2) <a href="https://caddyserver.com/download">Baixe e instale o Caddy</a> para sua máquina (basta clicar no botão de Download na página, você não precisa de nenhum plugin extra)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>3) Crie uma rede definida por usuário, usando <code>docker network create tutorial-fjorgemota-com</code>. A saída desse comando deve ser um simples <em>hash</em>, conforme mostrado abaixo:</p>
<!-- /wp:paragraph -->

<!-- wp:embed {"url":"https://asciinema.org/a/yOfuP5h3XHzoRq6matGusmWqA","type":"rich","providerNameSlug":"asciinema"} -->
<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
https://asciinema.org/a/yOfuP5h3XHzoRq6matGusmWqA
</div></figure>
<!-- /wp:embed -->

<!-- wp:paragraph -->
<p>4) Agora, vamos criar os containers! Primeiro, inicialize o MySQL usando <code>docker run --name bd-tutorial-fjorgemota-com --network tutorial-fjorgemota-com --network-alias mysql -e </code><code>MYSQL_DATABASE</code>=tutorial_blog<code> -e MYSQL_ROOT_PASSWORD=12345678 -d mysql</code>. A saida do Docker deve ser algo assim:</p>
<!-- /wp:paragraph -->

<!-- wp:embed {"url":"https://asciinema.org/a/yQcI4KaMU00CMl4lLFqQQ0btk","type":"rich","providerNameSlug":"asciinema"} -->
<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
https://asciinema.org/a/yQcI4KaMU00CMl4lLFqQQ0btk
</div></figure>
<!-- /wp:embed -->

<!-- wp:paragraph -->
<p>5) <a href="https://br.wordpress.org/latest-pt_BR.zip">Baixe o WordPress</a> e descompacte-o para uma pasta chamada <code>wordpress</code>. No Linux, você pode usar <code>wget -O wordpress.zip https://br.wordpress.org/latest-pt_BR.zip &#38;&#38; unzip wordpress.zip</code>, conforme mostra a saída abaixo:</p>
<!-- /wp:paragraph -->

<!-- wp:embed {"url":"https://asciinema.org/a/t8wxbPWqCqHxM8pw9KZesSncC","type":"rich","providerNameSlug":"asciinema"} -->
<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
https://asciinema.org/a/t8wxbPWqCqHxM8pw9KZesSncC
</div></figure>
<!-- /wp:embed -->

<!-- wp:paragraph -->
<p>7) Crie um arquivo chamado <code>Dockerfile</code> para preparar a imagem do PHP-FPM para ter as extensões necessárias para rodar o WordPress. O arquivo deve ter o seguinte conteúdo:</p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":true} -->
<pre class="wp-block-code"><code lang="docker" class="language-docker line-numbers">FROM php:8.3-fpm 
RUN apt-get update &#38;&#38; apt-get install -y \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libxpm-dev \
    libwebp-dev \
    libxslt1-dev \
    libzip-dev \
    libonig-dev \
    libtidy-dev \
    libicu-dev \
    imagemagick \
    libmagickwand-dev \
    less \
    &#38;&#38; pecl install imagick \
    &#38;&#38; pecl install apcu \
    &#38;&#38; docker-php-ext-configure gd --with-freetype --with-jpeg --with-xpm --with-webp \
    &#38;&#38; docker-php-ext-install mbstring mysqli zip bcmath exif xsl intl pdo_mysql gd tidy \
    &#38;&#38; docker-php-ext-enable imagick apcu \
    &#38;&#38; apt-get clean &#38;&#38; rm -rf /var/lib/apt/lists/*
</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Para contextualização, aqui estamos apenas algumas dependêcnias necessárias para a execução do WordPress, uma vez que a imagem <code>php:8.3-fpm</code> vem sem as extensões necessárias instaladas/ativadas.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>8) Construa a imagem acima usando <code>docker build -t tutorial-php-fjorgemota-com .</code> </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>O comando deve mostrar algo assim:</p>
<!-- /wp:paragraph -->

<!-- wp:embed {"url":"https://asciinema.org/a/hBFE89RMUvwbOcEGicBKUKMI6","type":"rich","providerNameSlug":"asciinema"} -->
<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
https://asciinema.org/a/hBFE89RMUvwbOcEGicBKUKMI6
</div></figure>
<!-- /wp:embed -->

<!-- wp:paragraph -->
<p>9) Rode o <em>container</em> do PHP-FPM usando essa pasta do wordpress como volume, e mapeando para <code>/wordpress</code>. Sem entrar na pasta <code>wordpress</code>, criada acima, o comando fica assim <code>docker run -v $(pwd)/wordpress:$(pwd)/wordpress --network tutorial-fjorgemota-com  -p 127.0.0.1:2004:9000 -d tutorial-php-fjorgemota-com</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Esse comando deve ter um simples <em>hash</em> como saída, conforme mostrado abaixo:</p>
<!-- /wp:paragraph -->

<!-- wp:embed {"url":"https://asciinema.org/a/LqEjOkCw191JSKqctixl4Kbpj","type":"rich","providerNameSlug":"asciinema"} -->
<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
https://asciinema.org/a/LqEjOkCw191JSKqctixl4Kbpj
</div></figure>
<!-- /wp:embed -->

<!-- wp:paragraph -->
<p>Com isso, você deve ter o container rodando PHP-FPM rodando na mesma rede do container do MySQL. E o PHP-FPM deve estar exposto na porta 2004 no seu computador.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>7) Agora, vamos configurar o Caddy para se conectar no PHP-FPM na sua máquina. Na mesma pasta onde está a pasta <code>wordpress</code>, crie um arquivo chamado <code>Caddyfile</code> com o seguinte conteúdo:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code class="">:8080 {
    root * wordpress
    encode gzip
    php_fastcgi 127.0.0.1:2004
    file_server
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>8) Então, execute <code>caddy run Caddyfile</code> </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Se tudo deu certo, você deve ver algo assim:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">[fernando@fernando-ryzen ~]$ caddy run
2024/07/07 22:39:08.186	INFO	using adjacent Caddyfile
2024/07/07 22:39:08.187	WARN	Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies	{"adapter": "caddyfile", "file": "Caddyfile", "line": 2}
2024/07/07 22:39:08.188	INFO	admin	admin endpoint started	{"address": "localhost:2019", "enforce_origin": false, "origins": ["//127.0.0.1:2019", "//localhost:2019", "//[::1]:2019"]}
2024/07/07 22:39:08.188	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc000429880"}
2024/07/07 22:39:08.188	INFO	http.log	server running	{"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2024/07/07 22:39:08.188	INFO	autosaved config (load with --resume flag)	{"file": "/home/fernando/.local/share/caddy/autosave.json"}
2024/07/07 22:39:08.188	INFO	serving initial configuration
2024/07/07 22:39:08.189	WARN	tls	storage cleaning happened too recently; skipping for now	{"storage": "FileStorage:/home/fernando/.local/share/caddy", "instance": "cf543b53-950d-435f-8cfc-59ea67aff4c5", "try_again": "2024/07/08 22:39:08.189", "try_again_in": 86399.99999981}
2024/07/07 22:39:08.189	INFO	tls	finished cleaning storage units</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>9) Acesse <a href="http://127.0.0.1:8080">http://127.0.0.1:8080</a> no seu navegador. Você verá a tela de instalação do WordPress:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8746,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/image.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/image-1024x515.png" alt="" class="wp-image-8746"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Clique em "Vamos lá!"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>10) Nessa tela de configuração do banco de dados:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8749,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/image-1.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/image-1-1024x517.png" alt="" class="wp-image-8749"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Informe os seguintes dados:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><strong>Nome do banco de dados:</strong> tutorial_blog</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Nome de usuário:</strong> root</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Senha:</strong> 12345678</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Servidor do banco de dados:</strong> mysql</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Prefixo da tabela:</strong> wp_</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Clique em "Enviar"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>11) O WordPress te pedirá para criar um arquivo <code>wp-config.php</code> com o código que ele passar: </p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8750,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/image-2.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/image-2-1024x518.png" alt="" class="wp-image-8750"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Entre na pasta <code>wordpress</code> e crie o arquivo <code>wp-config.php</code> com aquele conteúdo informado.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Clique em "Instalar"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>12) O WordPress te pedirá mais algumas informações,  agora a respeito do site. Preencha com os  dados que bem entender:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8751,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/image-3.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/image-3-1024x513.png" alt="" class="wp-image-8751"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Clique em "Instalar WordPress"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>13) O WordPress estará instalado:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8752,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://fjorgemota.com/wp-content/uploads/2024/07/image-4.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/07/image-4-1024x513.png" alt="" class="wp-image-8752"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Agora você tem o Caddy conectando ao PHP-FPM rodando dentro de um container Docker, e se comunicando com o MySQL em outro container Docker dentro da mesma rede.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Conclusão</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Como dá pra ver, mesmo com o uso de <em>containers</em>, não há a necessidade de se preocupar em colocar TUDO dentro do Docker. É possível ter uma certa flexibilidade, ainda mais em termos de serviços de rede (como o MySQL ou o PHP-FPM). </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Naturalmente, entretanto, ter mais containers rodando no Docker tende a facilitar mais a vida em alguns cenários. Em ambientes de desenvolvimento, por exemplo, quando você usa algo como o <a href="https://fjorgemota.com/2016/01/27/docker-compose-ou-como-organizar-containers-docker-de-maneira-facil/">Docker Compose</a>, <strong>todo</strong> o processo de instalação e configuração de um projeto se resume a alguns poucos comandos. Não há a necessidade de, por exemplo, pedir pela instalação de softwares adicionais (como o Caddy, no caso desse post), nem de configurações extras. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Portanto, como tudo na vida, decidir como estruturar sua aplicação é uma questão de custo benefício. No meu caso, o blog roda dessa forma (só que usando Nginx em vez do Caddy) pois isso me facilita a instalação e configuração de outros projetos, além do blog. Por exemplo, posso usar o Gitea (que é uma alternativa mais moderna ao <a href="https://fjorgemota.com/2016/01/25/gogs-um-sistema-versatil-para-hospedagem-de-repositorios-git/">Gogs, sobre o qual já falei aqui no blog</a>), <a href="https://fjorgemota.com/2023/03/30/dokku-deploy-simplificado-para-os-seus-projetos/">o Dokku</a> e outros serviços tendo apenas um servidor web como "porta principal" do servidor. Logo, acaba valendo mais a pena ter tudo centralizado em uma única configuração do <em>Nginx</em>. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>E você? Como gosta de estruturar os seus projetos? Compartilhe nos comentários!</p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[
<p>Quando eu postei o <a href="https://fjorgemota.com/2016/01/14/docker-containers-para-a-vida-ou-nao/">tutorial completo sobre Docker</a>, muitos anos atrás, algumas pessoas comentaram pedindo mais detalhes a respeito desse trecho aqui que comentei no post:</p>



<figure class="wp-block-pullquote"><blockquote><p>Esse blog que vos fala, por exemplo, está rodando sob dois containers do Docker, um para o php-fpm, outro para o MySQL. Onde está o Nginx? Está fora, instalado na máquina principal, e aí o Nginx se conecta com o php-fpm para poder renderizar essa página da forma que você vê.</p></blockquote></figure>



<p>Bom, depois de.. <em>*check notes*</em>, mais de OITO anos, chegou a hora de eu detalhar como funciona isso, afinal, antes tarde do que mais tarde, certo? Então vamos lá.</p>



<span id="more-5436"></span>



<p>O Docker, como vocês bem sabem se vocês leram o post referido acima, consegue isolar os processos em containers que compartilham o mesmo kernel, mas cada processo deve ser um container próprio, isolado. Apesar disso, é possível estabelecer um <em>setup</em> onde os containers comunicam entre si, e também com o mundo exterior. </p>



<p>No caso desse blog que vos fala, conforme referido no trecho citado acima, temos três peças (2 rodando em containers) se comunicando entre si:</p>



<ol class="wp-block-list">
<li><strong>Nginx</strong> - Que é instalado na máquina principal, e fica escutando na porta 80 e 443, e por onde a maior parte dos usuários se conecta</li>



<li><strong>MySQL</strong> - Que escuta na clássica porta 3306, mas que NÃO é exposta para fora de container algum, em nenhuma porta. Ficando mais "isolado", por assim dizer.</li>



<li><strong>PHP-FPM</strong> - Que escuta na porta 9000 dentro do container, mas é exposta apenas localmente (e isso é importante!) dentro da máquina como porta 2004. A ideia é que o Nginx consiga usar a porta 2004 rodando no host 127.0.0.1 (ou seja, o melhor host, o <em>localhost</em>!) para se comunicar com o PHP-FPM.</li>
</ol>



<p>Note que em nenhum momento eu mencionei que há um link (que usando o <em><a href="https://docs.docker.com/network/links/">legacy linking system</a></em> seria algo tipo <code>-l mysql:mysql</code>) entre o PHP-FPM e o MySQL. Mas, como você pode imaginar, por causa do <a href="https://br.wordpress.org/">WordPress</a> tal conexão se faz necessária, caso contrário esse blog não funcionaria pois o PHP nunca conseguiria se comunicar com o MySQL (afinal, os containers são isolados, certo?). </p>



<p>Para fazer isso, usamos o que o Docker chama de "<a href="https://docs.docker.com/network/#user-defined-networks">Docker User-Defined Network</a>", ou Rede Docker definida pelo usuário, em tradução livre. O que é isso? Imagine que cada container Docker - apesar de rodar um único processo cada - é como se fosse uma rede de computadores. Com base no que sabemos até então, temos a seguinte situação:</p>



<figure class="wp-block-image size-full is-resized"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png?ssl=1"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="841" height="433" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png?resize=841%2C433&#038;ssl=1" alt="Diagrama mostrando você se conectando ao Nginx, que por sua vez se comunica com o PHP-FPM, mas sem se comunicar com o MySQL" class="wp-image-8759" style="width:839px;height:auto" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png?w=841&amp;ssl=1 841w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png?resize=300%2C154&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede.drawio-3.png?resize=768%2C395&amp;ssl=1 768w" sizes="(max-width: 841px) 100vw, 841px" /></a></figure>



<p>Um rede definida pelo usuário, no Docker, nada mais é do que uma rede DENTRO do próprio Docker. No caso desse blog, temos uma rede no Docker chamada <code>fjorgemota-com</code>, e a estrutura fica mais ou menos assim:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="841" height="433" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png?resize=841%2C433&#038;ssl=1" alt="Diagrama mostrando você se conectando ao Nginx, que por sua vez se comunica com o PHP-FPM e este se comunica com o MySQL" class="wp-image-8760" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png?w=841&amp;ssl=1 841w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png?resize=300%2C154&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/rede-fjorgemota-com.drawio-3.png?resize=768%2C395&amp;ssl=1 768w" sizes="(max-width: 841px) 100vw, 841px" /></a></figure>



<p>O que que isso implica, necessariamente? Implica que, assim como no caso da rede LOCAL na sua casa, onde seu celular consegue se comunicar com seu computador e vice-versa, cada container DENTRO da rede <code>fjorgemota-com</code> também consegue se comunicar um com o outro. Porém, da mesma forma que alguém externo à rede local da sua casa NÃO consegue se conectar diretamente ao seu computador ou ao seu celular, um <em>container </em>que esteja FORA da rede <code>fjorgemota-com</code> também não consegue se comunicar nem com o MySQL, e nem com o PHP.</p>



<p>Entretanto, assim como você PODE expor o seu computador conectado na rede interna da sua casa para o mundo exterior, o fato de um container estar dentro de uma rede definida por usuário também não o impossibilita de expor portas da mesma forma, como no caso do container do PHP-FPM cuja porta 9000 é exposta como 2004 dentro do servidor.</p>



<h3 class="wp-block-heading">Tutorial</h3>



<p>Como a configuração do Nginx pode variar DEMAIS de máquina para máquina, vamos fazer uma configuração mais simples aqui, <a href="https://caddyserver.com">usando o Caddy</a>, que é bem mais simples de configurar (bastando um simples arquivo de configuração!). <strong>Vamos ao tutorial</strong>:</p>



<p>1) <a href="https://docs.docker.com/engine/installation/">Baixe e instale o Docker</a> (importante ter uma máquina de 64 bits, pois é o único ambiente no qual o Docker efetivamente roda..)</p>



<p>2) <a href="https://caddyserver.com/download">Baixe e instale o Caddy</a> para sua máquina (basta clicar no botão de Download na página, você não precisa de nenhum plugin extra)</p>



<p>3) Crie uma rede definida por usuário, usando <code>docker network create tutorial-fjorgemota-com</code>. A saída desse comando deve ser um simples <em>hash</em>, conforme mostrado abaixo:</p>



<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
<script type="text/javascript" src="https://asciinema.org/a/yOfuP5h3XHzoRq6matGusmWqA.js" id="asciicast-yOfuP5h3XHzoRq6matGusmWqA" async></script><noscript><a href="https://asciinema.org/a/yOfuP5h3XHzoRq6matGusmWqA" target="_blank"><img decoding="async" src="https://asciinema.org/a/yOfuP5h3XHzoRq6matGusmWqA.svg" /></a></noscript>
</div></figure>



<p>4) Agora, vamos criar os containers! Primeiro, inicialize o MySQL usando <code>docker run --name bd-tutorial-fjorgemota-com --network tutorial-fjorgemota-com --network-alias mysql -e </code><code>MYSQL_DATABASE</code>=tutorial_blog<code> -e MYSQL_ROOT_PASSWORD=12345678 -d mysql</code>. A saida do Docker deve ser algo assim:</p>



<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
<script type="text/javascript" src="https://asciinema.org/a/yQcI4KaMU00CMl4lLFqQQ0btk.js" id="asciicast-yQcI4KaMU00CMl4lLFqQQ0btk" async></script><noscript><a href="https://asciinema.org/a/yQcI4KaMU00CMl4lLFqQQ0btk" target="_blank"><img decoding="async" src="https://asciinema.org/a/yQcI4KaMU00CMl4lLFqQQ0btk.svg" /></a></noscript>
</div></figure>



<p>5) <a href="https://br.wordpress.org/latest-pt_BR.zip">Baixe o WordPress</a> e descompacte-o para uma pasta chamada <code>wordpress</code>. No Linux, você pode usar <code>wget -O wordpress.zip https://br.wordpress.org/latest-pt_BR.zip &amp;&amp; unzip wordpress.zip</code>, conforme mostra a saída abaixo:</p>



<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
<script type="text/javascript" src="https://asciinema.org/a/t8wxbPWqCqHxM8pw9KZesSncC.js" id="asciicast-t8wxbPWqCqHxM8pw9KZesSncC" async></script><noscript><a href="https://asciinema.org/a/t8wxbPWqCqHxM8pw9KZesSncC" target="_blank"><img decoding="async" src="https://asciinema.org/a/t8wxbPWqCqHxM8pw9KZesSncC.svg" /></a></noscript>
</div></figure>



<p>7) Crie um arquivo chamado <code>Dockerfile</code> para preparar a imagem do PHP-FPM para ter as extensões necessárias para rodar o WordPress. O arquivo deve ter o seguinte conteúdo:</p>



<pre class="wp-block-code"><code lang="docker" class="language-docker line-numbers">FROM php:8.3-fpm 
RUN apt-get update &amp;&amp; apt-get install -y \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libxpm-dev \
    libwebp-dev \
    libxslt1-dev \
    libzip-dev \
    libonig-dev \
    libtidy-dev \
    libicu-dev \
    imagemagick \
    libmagickwand-dev \
    less \
    &amp;&amp; pecl install imagick \
    &amp;&amp; pecl install apcu \
    &amp;&amp; docker-php-ext-configure gd --with-freetype --with-jpeg --with-xpm --with-webp \
    &amp;&amp; docker-php-ext-install mbstring mysqli zip bcmath exif xsl intl pdo_mysql gd tidy \
    &amp;&amp; docker-php-ext-enable imagick apcu \
    &amp;&amp; apt-get clean &amp;&amp; rm -rf /var/lib/apt/lists/*
</code></pre>



<p>Para contextualização, aqui estamos apenas algumas dependêcnias necessárias para a execução do WordPress, uma vez que a imagem <code>php:8.3-fpm</code> vem sem as extensões necessárias instaladas/ativadas.</p>



<p>8) Construa a imagem acima usando <code>docker build -t tutorial-php-fjorgemota-com .</code> </p>



<p>O comando deve mostrar algo assim:</p>



<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
<script type="text/javascript" src="https://asciinema.org/a/hBFE89RMUvwbOcEGicBKUKMI6.js" id="asciicast-hBFE89RMUvwbOcEGicBKUKMI6" async></script><noscript><a href="https://asciinema.org/a/hBFE89RMUvwbOcEGicBKUKMI6" target="_blank"><img decoding="async" src="https://asciinema.org/a/hBFE89RMUvwbOcEGicBKUKMI6.svg" /></a></noscript>
</div></figure>



<p>9) Rode o <em>container</em> do PHP-FPM usando essa pasta do wordpress como volume, e mapeando para <code>/wordpress</code>. Sem entrar na pasta <code>wordpress</code>, criada acima, o comando fica assim <code>docker run -v $(pwd)/wordpress:$(pwd)/wordpress --network tutorial-fjorgemota-com  -p 127.0.0.1:2004:9000 -d tutorial-php-fjorgemota-com</code></p>



<p>Esse comando deve ter um simples <em>hash</em> como saída, conforme mostrado abaixo:</p>



<figure class="wp-block-embed is-type-rich is-provider-asciinema wp-block-embed-asciinema"><div class="wp-block-embed__wrapper">
<script type="text/javascript" src="https://asciinema.org/a/LqEjOkCw191JSKqctixl4Kbpj.js" id="asciicast-LqEjOkCw191JSKqctixl4Kbpj" async></script><noscript><a href="https://asciinema.org/a/LqEjOkCw191JSKqctixl4Kbpj" target="_blank"><img decoding="async" src="https://asciinema.org/a/LqEjOkCw191JSKqctixl4Kbpj.svg" /></a></noscript>
</div></figure>



<p>Com isso, você deve ter o container rodando PHP-FPM rodando na mesma rede do container do MySQL. E o PHP-FPM deve estar exposto na porta 2004 no seu computador.</p>



<p>7) Agora, vamos configurar o Caddy para se conectar no PHP-FPM na sua máquina. Na mesma pasta onde está a pasta <code>wordpress</code>, crie um arquivo chamado <code>Caddyfile</code> com o seguinte conteúdo:</p>



<pre class="wp-block-code"><code class="">:8080 {
    root * wordpress
    encode gzip
    php_fastcgi 127.0.0.1:2004
    file_server
}</code></pre>



<p>8) Então, execute <code>caddy run Caddyfile</code> </p>



<p>Se tudo deu certo, você deve ver algo assim:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">[fernando@fernando-ryzen ~]$ caddy run
2024/07/07 22:39:08.186	INFO	using adjacent Caddyfile
2024/07/07 22:39:08.187	WARN	Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies	{"adapter": "caddyfile", "file": "Caddyfile", "line": 2}
2024/07/07 22:39:08.188	INFO	admin	admin endpoint started	{"address": "localhost:2019", "enforce_origin": false, "origins": ["//127.0.0.1:2019", "//localhost:2019", "//[::1]:2019"]}
2024/07/07 22:39:08.188	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc000429880"}
2024/07/07 22:39:08.188	INFO	http.log	server running	{"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2024/07/07 22:39:08.188	INFO	autosaved config (load with --resume flag)	{"file": "/home/fernando/.local/share/caddy/autosave.json"}
2024/07/07 22:39:08.188	INFO	serving initial configuration
2024/07/07 22:39:08.189	WARN	tls	storage cleaning happened too recently; skipping for now	{"storage": "FileStorage:/home/fernando/.local/share/caddy", "instance": "cf543b53-950d-435f-8cfc-59ea67aff4c5", "try_again": "2024/07/08 22:39:08.189", "try_again_in": 86399.99999981}
2024/07/07 22:39:08.189	INFO	tls	finished cleaning storage units</code></pre>



<p>9) Acesse <a href="http://127.0.0.1:8080">http://127.0.0.1:8080</a> no seu navegador. Você verá a tela de instalação do WordPress:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="1024" height="515" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?resize=1024%2C515&#038;ssl=1" alt="" class="wp-image-8746" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?resize=1024%2C515&amp;ssl=1 1024w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?resize=300%2C151&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?resize=768%2C387&amp;ssl=1 768w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?resize=1536%2C773&amp;ssl=1 1536w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image.png?w=1919&amp;ssl=1 1919w" sizes="(max-width: 1000px) 100vw, 1000px" /></a></figure>



<p>Clique em "Vamos lá!"</p>



<p>10) Nessa tela de configuração do banco de dados:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="517" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?resize=1024%2C517&#038;ssl=1" alt="" class="wp-image-8749" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?resize=1024%2C517&amp;ssl=1 1024w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?resize=300%2C151&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?resize=768%2C388&amp;ssl=1 768w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?resize=1536%2C775&amp;ssl=1 1536w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-1.png?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p>Informe os seguintes dados:</p>



<ul class="wp-block-list">
<li><strong>Nome do banco de dados:</strong> tutorial_blog</li>



<li><strong>Nome de usuário:</strong> root</li>



<li><strong>Senha:</strong> 12345678</li>



<li><strong>Servidor do banco de dados:</strong> mysql</li>



<li><strong>Prefixo da tabela:</strong> wp_</li>
</ul>



<p>Clique em "Enviar"</p>



<p>11) O WordPress te pedirá para criar um arquivo <code>wp-config.php</code> com o código que ele passar: </p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="518" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?resize=1024%2C518&#038;ssl=1" alt="" class="wp-image-8750" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?resize=1024%2C518&amp;ssl=1 1024w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?resize=300%2C152&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?resize=768%2C389&amp;ssl=1 768w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?resize=1536%2C778&amp;ssl=1 1536w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-2.png?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p>Entre na pasta <code>wordpress</code> e crie o arquivo <code>wp-config.php</code> com aquele conteúdo informado.</p>



<p>Clique em "Instalar"</p>



<p>12) O WordPress te pedirá mais algumas informações,  agora a respeito do site. Preencha com os  dados que bem entender:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="513" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?resize=1024%2C513&#038;ssl=1" alt="" class="wp-image-8751" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?resize=1024%2C513&amp;ssl=1 1024w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?resize=300%2C150&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?resize=768%2C384&amp;ssl=1 768w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?resize=1536%2C769&amp;ssl=1 1536w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-3.png?w=1918&amp;ssl=1 1918w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p>Clique em "Instalar WordPress"</p>



<p>13) O WordPress estará instalado:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="513" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?resize=1024%2C513&#038;ssl=1" alt="" class="wp-image-8752" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?resize=1024%2C513&amp;ssl=1 1024w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?resize=300%2C150&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?resize=768%2C385&amp;ssl=1 768w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?resize=1536%2C770&amp;ssl=1 1536w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/07/image-4.png?w=1919&amp;ssl=1 1919w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p>Agora você tem o Caddy conectando ao PHP-FPM rodando dentro de um container Docker, e se comunicando com o MySQL em outro container Docker dentro da mesma rede.</p>



<h3 class="wp-block-heading">Conclusão</h3>



<p>Como dá pra ver, mesmo com o uso de <em>containers</em>, não há a necessidade de se preocupar em colocar TUDO dentro do Docker. É possível ter uma certa flexibilidade, ainda mais em termos de serviços de rede (como o MySQL ou o PHP-FPM). </p>



<p>Naturalmente, entretanto, ter mais containers rodando no Docker tende a facilitar mais a vida em alguns cenários. Em ambientes de desenvolvimento, por exemplo, quando você usa algo como o <a href="https://fjorgemota.com/2016/01/27/docker-compose-ou-como-organizar-containers-docker-de-maneira-facil/">Docker Compose</a>, <strong>todo</strong> o processo de instalação e configuração de um projeto se resume a alguns poucos comandos. Não há a necessidade de, por exemplo, pedir pela instalação de softwares adicionais (como o Caddy, no caso desse post), nem de configurações extras. </p>



<p>Portanto, como tudo na vida, decidir como estruturar sua aplicação é uma questão de custo benefício. No meu caso, o blog roda dessa forma (só que usando Nginx em vez do Caddy) pois isso me facilita a instalação e configuração de outros projetos, além do blog. Por exemplo, posso usar o Gitea (que é uma alternativa mais moderna ao <a href="https://fjorgemota.com/2016/01/25/gogs-um-sistema-versatil-para-hospedagem-de-repositorios-git/">Gogs, sobre o qual já falei aqui no blog</a>), <a href="https://fjorgemota.com/2023/03/30/dokku-deploy-simplificado-para-os-seus-projetos/">o Dokku</a> e outros serviços tendo apenas um servidor web como "porta principal" do servidor. Logo, acaba valendo mais a pena ter tudo centralizado em uma única configuração do <em>Nginx</em>. </p>



<p>E você? Como gosta de estruturar os seus projetos? Compartilhe nos comentários!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://fjorgemota.com/2024/07/07/docker-networks-ou-como-configurar-php-fpmmysql-no-docker-com-o-nginx-externo/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5436</post-id>	</item>
		<item>
		<title>Como melhorar a velocidade do phpcs e do phpcbf</title>
		<link>https://fjorgemota.com/2024/06/30/como-melhorar-a-velocidade-do-phpcs-e-do-phpcbf/</link>
					<comments>https://fjorgemota.com/2024/06/30/como-melhorar-a-velocidade-do-phpcs-e-do-phpcbf/#respond</comments>
		
		<dc:creator><![CDATA[Fernando]]></dc:creator>
		<pubDate>Sun, 30 Jun 2024 22:33:13 +0000</pubDate>
				<category><![CDATA[Dicas]]></category>
		<category><![CDATA[Ferramentas e Projetos]]></category>
		<category><![CDATA[desenvolvimento]]></category>
		<category><![CDATA[ferramentas]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[testes]]></category>
		<category><![CDATA[utilidades]]></category>
		<guid isPermaLink="false">https://fjorgemota.com/?p=6871</guid>

					<description><![CDATA[<!-- wp:paragraph -->
<p>Uma tarefa comum quando você está desenvolvendo um projeto é rodar um <em>linter</em>. <em>Linters</em> são ferramentas que analisam o código fonte do seu projeto e buscam detectar diferentes problemas no código, incluindo possíveis falhas na lógica e também questões relacionadas ao estilo do código. Porém, se tem uma coisa que incomoda MUITO é quando você está desenvolvendo, QUASE finalizando o software, e precisa ESPERAR para que ferramentas de verificação assim (que incluem tanto linters quanto <a href="https://fjorgemota.com/tag/testes-2/">testes, que são importantes para qualquer projeto</a>) assim rodem.</p>
<!-- /wp:paragraph -->


<span id="more-6871"></span>


<!-- wp:paragraph -->
<p> Esse é o clássico problema que o XKCD retratou extremamente bem no post "<a href="https://xkcd.com/303/">Compiling</a>":</p>
<!-- /wp:paragraph -->

<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://imgs.xkcd.com/comics/compiling.png" alt="Tirinha do XKCD que traduz livremente para: A desculpa número 1 dos programadores para procrastinar legitimamente: 'meu código está compilando'"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>E isso incomoda AINDA MAIS quando a ferramenta em questão é <em>single-thread </em>ou mal otimizada, pois o seu computador (que assumo ter um processador com múltiplos núcleos hoje em dia, certo?), fica mais ou menos assim:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":8639,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image size-full"><a href="https://fjorgemota.com/wp-content/uploads/2024/06/image.png"><img src="https://fjorgemota.com/wp-content/uploads/2024/06/image.png" alt="Imagem de vários trabalhadores ao redor de uma obra, com só um dos trabalhadores de fato trabalhando em um buraco. Fazendo analogia ao uso de 100% de apenas um núcleo só na maior parte das atividades cotidianas em um computador." class="wp-image-8639"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Bom. Agora vamos ao tópico do post: Já que é bem difícil simplesmente paralelizar o trabalho de uma ferramenta de forma eficiente, vamos tentar tornar a sua atuação mais inteligente: Uma forma de deixar o trabalho de qualquer <em>script</em> - ou qualquer coisa, na verdade - mais eficiente, é fazer com que tal <em>script</em> (ou coisa) faça MENOS trabalho. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>No caso de um <em>linter, </em>uma forma bem fácil de fazer MENOS trabalho é simplesmente... não ficar rechecando arquivos que não são necessários. Isso é MUITO mais eficiente do que simplesmente paralelizar o algoritmo, uma vez que mesmo o número de núcleos em um computador moderno é limitado. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Para exemplificar isso, considere um projeto que tenha, digamos, 5000 arquivos para serem analisados, cada um levando aí algo em torno de 0.04 segundos. Um <em>linter</em> rodando sequencialmente levaria, portanto, 200 segundos (ou 3 minutos e 20 segundos) para analisar tudo.  </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Se você tem um processador com 8 núcleos e 16 <em>threads </em>no seu computador, normalmente um algoritmo paralelo tentaria disparar 16 <em>threads</em> para processar cada arquivo. Digamos que essas 16 threads consigam acelerar em 16 vezes a velocidade de processamento (algo que nunca acontece pois há diversas limitações que impedem que algo assim aconteça). Em vez de demorar 200 segundos, ou 3 minutos e 20 segundos, tal algoritmo paralelo levaria cerca de 12 segundos para processar todos os 5000 arquivos.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Levar 12 segundos em vez de 3 minutos e 20 segundos é uma vitória tremenda, certo? Porém, considere que você NÃO vai modificar todos os 5000 arquivos a todo momento. Pelo contrário, você vai modificar ali 1, 3, 5 arquivos por vez, enquanto trabalha no seu projeto. E é aqui que mesmo a paralelização deixa de fazer sentido: Para que checar todos os arquivos, se apenas alguns poucos foram modificados? Se apenas 5 arquivos foram modificados, e o <em>linter</em> leva 0.04 segundos para processar um arquivo, apenas 0.04 * 5 = 0.2 segundos (ou MENOS de um segundo!) deveriam ser necessários para processar tudo, o que já é 60 vezes mais rápido que o algoritmo paralelo ou 1000 vezes mais rápido que o algoritmo sequencial.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>E é aqui que entra o <em>script</em> que é o assunto desse post.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Esse é o <em>script</em>, em <em>bash</em>:</p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":true} -->
<pre title="script.sh" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">#!/bin/bash

set -e

SCRIPT_NAME=$(basename "$0");

find_script() {
    script_name="$1"
    current_dir=$(pwd)
    parent_dir=$(dirname "$current_dir")
    
    # Check if the path exists in the directory exists in the current directory
    script_path="$current_dir/vendor/bin/$script_name"
    if [ -x "$script_path" ]; then
        echo "$script_path"
        return
    fi
    
    # Traverse up the directory tree and check if the script exists in any parent directory
    while [ "$parent_dir" != "$current_dir" ]; do
        script_path="$parent_dir/vendor/bin/$script_name"
        if [ -x "$script_path" ]; then
            echo "$script_path"
            return
        fi
        
        current_dir="$parent_dir"
        parent_dir=$(dirname "$current_dir")
    done
    
    # Script not found
    echo "Script $SCRIPT_NAME not found." &#62; /dev/stderr
    exit 1
}


SCRIPT_PATH=$(find_script "$SCRIPT_NAME");

MODIFIED_FILES=$(git status --porcelain=v2 . &#124; awk '{print $NF}');

if [ -z "$MODIFIED_FILES" ]; then
  echo "No modified files found in the current directory."
  exit 0
fi

echo "Running $SCRIPT_PATH for the following list of files:";
echo "$MODIFIED_FILES" &#124; xargs -i{} echo "- {}";

echo "$MODIFIED_FILES" &#124; xargs "$SCRIPT_PATH";</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>O que o script faz? É bem simples, vou explicar:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><!-- wp:list-item -->
<li>Primeiramente, rodamos <code>set -e</code> para fazer com que o <em>bash</em> imediatamente interrompa a execução caso qualquer comando retorne erro (com código de status de saída diferenet de <code>0</code>)</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Definimos uma variável chamada <code>SCRIPT_NAME</code> contendo o nome do arquivo atual, já explico mais abaixo o motivo disso</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Definimos uma função <code>find_script</code> para procurar o script. Essa função busca encontrar o script de nome <code>SCRIPT_NAME</code> dentro da pasta <code>vendor/bin</code>, e busca tanto no diretório atual quanto em qualquer superior. Para exemplificar, se você rodar o arquivo dentro de uma pasta <code>/home/usuario/projetos/MeuProjeto</code>, ele procurará um arquivo executável com o nome do script salvo em <code>SCRIPT_NAME</code> (digamos que tal nome seja <code>phpcs</code>) nas seguintes pastas:<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><code>/home/usuario/projetos/MeuProjeto/vendor/bin/phpcs</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>/home/usuario/projetos/vendor/bin/phpcs</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>/home/usuario/vendor/bin/phpcs</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>/home/vendor/bin/phpcs</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>/vendor/bin/phpcs</code></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list --></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Definimos uma variável <code>SCRIPT_PATH</code> contendo o caminho para o script encontrado pela função <code>find_script</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Computamos uma lista de arquivos modificados a partir do <code>git</code>. Apenas arquivos modificados cujas mudanças não foram <em>comittados</em> ainda aparecerão aqui</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Verificamos se a lista de arquivos modificados possui, de fato, arquivos modificados. Se não houver arquivos modificados mostramos uma mensagem e encerramos o <em>script</em></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Mostramos a lista de arquivos modificados, e passamos essa lista  de arquivos modificados para o script em questão, como parâmetros.</li>
<!-- /wp:list-item --></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Para usar esse script em uma computador Linux, basta você</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><!-- wp:list-item -->
<li>Criar uma pasta <code>bin</code> na sua <code>$HOME</code> se você ainda não tiver, assim: <code>mkdir -p $HOME/bin</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Adicionar essa pasta <code>bin</code> no seu environment, adicionando no arquivo de configuração do seu <em>shell </em>(digamos, <code>.bashrc</code>) algo como <code>export PATH=$PATH:$HOME/bin</code> </li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Adicionar esse script nessa pasta <code>bin</code>, com o nome da ferramenta que você quer otimizar. Você pode nomeá-lo como <code>phpcs</code> ou <code>phpcbf</code>, por exemplo</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Em um projeto PHP com o <code>phpcbf</code> ou <code>phpcs</code> instalado via Composer, executar o comando correspondente SEM usar <code>vendor/bin</code> como prefixo</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Pronto!</li>
<!-- /wp:list-item --></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>O comando só rodará de fato a ferramenta em questão SE houver arquivos modificados e não comittados ainda no repositório Git.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Também não executará se a ferramenta em questão não estiver instalada usando <a href="https://fjorgemota.com/2016/02/01/composer-como-gerenciar-dependencias-no-php-facilmente/">Composer, que já apresentei me outro post</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Finalmente, se você não estiver usando Git, o script não executará, pois ele não tem como rastrear quais arquivos modificados. <a href="https://fjorgemota.com/2016/01/20/git-sistema-de-controle-de-versoes-distribuido/">Se você ainda não usa Git, verifque o meu post sobre, também</a>. ;)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>E você, tem alguma outra dica para agilizar tarefas demoradas - mas necessárias - do seu dia-a-dia?  Compartilhe nos comentários! E se ficou alguma dúvida, pode madnar nos comentários que vou tentar fazer o meu melhor para ajudar, também. :D </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Valeu pela leitura!</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[
<p>Uma tarefa comum quando você está desenvolvendo um projeto é rodar um <em>linter</em>. <em>Linters</em> são ferramentas que analisam o código fonte do seu projeto e buscam detectar diferentes problemas no código, incluindo possíveis falhas na lógica e também questões relacionadas ao estilo do código. Porém, se tem uma coisa que incomoda MUITO é quando você está desenvolvendo, QUASE finalizando o software, e precisa ESPERAR para que ferramentas de verificação assim (que incluem tanto linters quanto <a href="https://fjorgemota.com/tag/testes-2/">testes, que são importantes para qualquer projeto</a>) assim rodem.</p>



<span id="more-6871"></span>



<p> Esse é o clássico problema que o XKCD retratou extremamente bem no post "<a href="https://xkcd.com/303/">Compiling</a>":</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/imgs.xkcd.com/comics/compiling.png?ssl=1" alt="Tirinha do XKCD que traduz livremente para: A desculpa número 1 dos programadores para procrastinar legitimamente: 'meu código está compilando'"/></figure>



<p>E isso incomoda AINDA MAIS quando a ferramenta em questão é <em>single-thread </em>ou mal otimizada, pois o seu computador (que assumo ter um processador com múltiplos núcleos hoje em dia, certo?), fica mais ou menos assim:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/06/image.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="558" height="695" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/06/image.png?resize=558%2C695&#038;ssl=1" alt="Imagem de vários trabalhadores ao redor de uma obra, com só um dos trabalhadores de fato trabalhando em um buraco. Fazendo analogia ao uso de 100% de apenas um núcleo só na maior parte das atividades cotidianas em um computador." class="wp-image-8639" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/06/image.png?w=558&amp;ssl=1 558w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2024/06/image.png?resize=241%2C300&amp;ssl=1 241w" sizes="auto, (max-width: 558px) 100vw, 558px" /></a></figure>



<p>Bom. Agora vamos ao tópico do post: Já que é bem difícil simplesmente paralelizar o trabalho de uma ferramenta de forma eficiente, vamos tentar tornar a sua atuação mais inteligente: Uma forma de deixar o trabalho de qualquer <em>script</em> - ou qualquer coisa, na verdade - mais eficiente, é fazer com que tal <em>script</em> (ou coisa) faça MENOS trabalho. </p>



<p>No caso de um <em>linter, </em>uma forma bem fácil de fazer MENOS trabalho é simplesmente... não ficar rechecando arquivos que não são necessários. Isso é MUITO mais eficiente do que simplesmente paralelizar o algoritmo, uma vez que mesmo o número de núcleos em um computador moderno é limitado. </p>



<p>Para exemplificar isso, considere um projeto que tenha, digamos, 5000 arquivos para serem analisados, cada um levando aí algo em torno de 0.04 segundos. Um <em>linter</em> rodando sequencialmente levaria, portanto, 200 segundos (ou 3 minutos e 20 segundos) para analisar tudo.  </p>



<p>Se você tem um processador com 8 núcleos e 16 <em>threads </em>no seu computador, normalmente um algoritmo paralelo tentaria disparar 16 <em>threads</em> para processar cada arquivo. Digamos que essas 16 threads consigam acelerar em 16 vezes a velocidade de processamento (algo que nunca acontece pois há diversas limitações que impedem que algo assim aconteça). Em vez de demorar 200 segundos, ou 3 minutos e 20 segundos, tal algoritmo paralelo levaria cerca de 12 segundos para processar todos os 5000 arquivos.</p>



<p>Levar 12 segundos em vez de 3 minutos e 20 segundos é uma vitória tremenda, certo? Porém, considere que você NÃO vai modificar todos os 5000 arquivos a todo momento. Pelo contrário, você vai modificar ali 1, 3, 5 arquivos por vez, enquanto trabalha no seu projeto. E é aqui que mesmo a paralelização deixa de fazer sentido: Para que checar todos os arquivos, se apenas alguns poucos foram modificados? Se apenas 5 arquivos foram modificados, e o <em>linter</em> leva 0.04 segundos para processar um arquivo, apenas 0.04 * 5 = 0.2 segundos (ou MENOS de um segundo!) deveriam ser necessários para processar tudo, o que já é 60 vezes mais rápido que o algoritmo paralelo ou 1000 vezes mais rápido que o algoritmo sequencial.</p>



<p>E é aqui que entra o <em>script</em> que é o assunto desse post.</p>



<p>Esse é o <em>script</em>, em <em>bash</em>:</p>



<pre title="script.sh" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">#!/bin/bash

set -e

SCRIPT_NAME=$(basename "$0");

find_script() {
    script_name="$1"
    current_dir=$(pwd)
    parent_dir=$(dirname "$current_dir")
    
    # Check if the path exists in the directory exists in the current directory
    script_path="$current_dir/vendor/bin/$script_name"
    if [ -x "$script_path" ]; then
        echo "$script_path"
        return
    fi
    
    # Traverse up the directory tree and check if the script exists in any parent directory
    while [ "$parent_dir" != "$current_dir" ]; do
        script_path="$parent_dir/vendor/bin/$script_name"
        if [ -x "$script_path" ]; then
            echo "$script_path"
            return
        fi
        
        current_dir="$parent_dir"
        parent_dir=$(dirname "$current_dir")
    done
    
    # Script not found
    echo "Script $SCRIPT_NAME not found." &gt; /dev/stderr
    exit 1
}


SCRIPT_PATH=$(find_script "$SCRIPT_NAME");

MODIFIED_FILES=$(git status --porcelain=v2 . | awk '{print $NF}');

if [ -z "$MODIFIED_FILES" ]; then
  echo "No modified files found in the current directory."
  exit 0
fi

echo "Running $SCRIPT_PATH for the following list of files:";
echo "$MODIFIED_FILES" | xargs -i{} echo "- {}";

echo "$MODIFIED_FILES" | xargs "$SCRIPT_PATH";</code></pre>



<p>O que o script faz? É bem simples, vou explicar:</p>



<ol class="wp-block-list">
<li>Primeiramente, rodamos <code>set -e</code> para fazer com que o <em>bash</em> imediatamente interrompa a execução caso qualquer comando retorne erro (com código de status de saída diferenet de <code>0</code>)</li>



<li>Definimos uma variável chamada <code>SCRIPT_NAME</code> contendo o nome do arquivo atual, já explico mais abaixo o motivo disso</li>



<li>Definimos uma função <code>find_script</code> para procurar o script. Essa função busca encontrar o script de nome <code>SCRIPT_NAME</code> dentro da pasta <code>vendor/bin</code>, e busca tanto no diretório atual quanto em qualquer superior. Para exemplificar, se você rodar o arquivo dentro de uma pasta <code>/home/usuario/projetos/MeuProjeto</code>, ele procurará um arquivo executável com o nome do script salvo em <code>SCRIPT_NAME</code> (digamos que tal nome seja <code>phpcs</code>) nas seguintes pastas:
<ul class="wp-block-list">
<li><code>/home/usuario/projetos/MeuProjeto/vendor/bin/phpcs</code></li>



<li><code>/home/usuario/projetos/vendor/bin/phpcs</code></li>



<li><code>/home/usuario/vendor/bin/phpcs</code></li>



<li><code>/home/vendor/bin/phpcs</code></li>



<li><code>/vendor/bin/phpcs</code></li>
</ul>
</li>



<li>Definimos uma variável <code>SCRIPT_PATH</code> contendo o caminho para o script encontrado pela função <code>find_script</code></li>



<li>Computamos uma lista de arquivos modificados a partir do <code>git</code>. Apenas arquivos modificados cujas mudanças não foram <em>comittados</em> ainda aparecerão aqui</li>



<li>Verificamos se a lista de arquivos modificados possui, de fato, arquivos modificados. Se não houver arquivos modificados mostramos uma mensagem e encerramos o <em>script</em></li>



<li>Mostramos a lista de arquivos modificados, e passamos essa lista  de arquivos modificados para o script em questão, como parâmetros.</li>
</ol>



<p>Para usar esse script em uma computador Linux, basta você</p>



<ol class="wp-block-list">
<li>Criar uma pasta <code>bin</code> na sua <code>$HOME</code> se você ainda não tiver, assim: <code>mkdir -p $HOME/bin</code></li>



<li>Adicionar essa pasta <code>bin</code> no seu environment, adicionando no arquivo de configuração do seu <em>shell </em>(digamos, <code>.bashrc</code>) algo como <code>export PATH=$PATH:$HOME/bin</code> </li>



<li>Adicionar esse script nessa pasta <code>bin</code>, com o nome da ferramenta que você quer otimizar. Você pode nomeá-lo como <code>phpcs</code> ou <code>phpcbf</code>, por exemplo</li>



<li>Em um projeto PHP com o <code>phpcbf</code> ou <code>phpcs</code> instalado via Composer, executar o comando correspondente SEM usar <code>vendor/bin</code> como prefixo</li>



<li>Pronto!</li>
</ol>



<p>O comando só rodará de fato a ferramenta em questão SE houver arquivos modificados e não comittados ainda no repositório Git.</p>



<p>Também não executará se a ferramenta em questão não estiver instalada usando <a href="https://fjorgemota.com/2016/02/01/composer-como-gerenciar-dependencias-no-php-facilmente/">Composer, que já apresentei me outro post</a>.</p>



<p>Finalmente, se você não estiver usando Git, o script não executará, pois ele não tem como rastrear quais arquivos modificados. <a href="https://fjorgemota.com/2016/01/20/git-sistema-de-controle-de-versoes-distribuido/">Se você ainda não usa Git, verifque o meu post sobre, também</a>. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>E você, tem alguma outra dica para agilizar tarefas demoradas - mas necessárias - do seu dia-a-dia?  Compartilhe nos comentários! E se ficou alguma dúvida, pode madnar nos comentários que vou tentar fazer o meu melhor para ajudar, também. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> </p>



<p>Valeu pela leitura!</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://fjorgemota.com/2024/06/30/como-melhorar-a-velocidade-do-phpcs-e-do-phpcbf/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">6871</post-id>	</item>
		<item>
		<title>Uma simples dica para economizar tempo ao atualizar pacotes do AUR no Arch Linux</title>
		<link>https://fjorgemota.com/2023/12/28/uma-simples-dica-para-economizar-tempo-ao-atualizar-pacotes-do-aur-no-arch-linux/</link>
					<comments>https://fjorgemota.com/2023/12/28/uma-simples-dica-para-economizar-tempo-ao-atualizar-pacotes-do-aur-no-arch-linux/#respond</comments>
		
		<dc:creator><![CDATA[Fernando]]></dc:creator>
		<pubDate>Thu, 28 Dec 2023 17:34:57 +0000</pubDate>
				<category><![CDATA[Dicas]]></category>
		<category><![CDATA[arch linux]]></category>
		<category><![CDATA[aur]]></category>
		<category><![CDATA[compilação]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[utilidades]]></category>
		<guid isPermaLink="false">https://fjorgemota.com/?p=7656</guid>

					<description><![CDATA[<!-- wp:image {"align":"right","id":7659,"sizeSlug":"medium","linkDestination":"media"} -->
<figure class="wp-block-image alignright size-medium"><a href="https://fjorgemota.com/wp-content/uploads/2023/12/image.png"><img src="https://fjorgemota.com/wp-content/uploads/2023/12/image-300x300.png" alt="Imagem gerada pelo Dall-E representando um usuário mexendo em um computador com um relógio na parede" class="wp-image-7659"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Como usuário da excelente distribuição Arch Linux (<em><a href="https://knowyourmeme.com/memes/btw-i-use-arch">BTW, I use Arch</a></em>), eu só gostaria de fazer aqui um breve lembrete para todos vocês: Antes de você gastar bastante tempo compilando um pacote gigante do AUR (ou Arch User Repository), como por exemplo o <em>qt5-webkit</em>, vale checar se você realmente PRECISA desse pacote OU se ele é dependência para algum outro pacote instalado na sua máquina. </p>
<!-- /wp:paragraph -->


<span id="more-7656"></span>


<!-- wp:paragraph -->
<p>No Arch Linux, você pode checar se outro pacote depende do pacote em questão através do <code>pactree</code>, que é um script disponível no pacote <code><a href="https://archlinux.org/packages/extra/x86_64/pacman-contrib/">pacman-contrib</a></code>. Primeiro, instale o <code><a href="https://archlinux.org/packages/extra/x86_64/pacman-contrib/">pacman-contrib</a></code>:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pacman -S pacman-contrib</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Depois, execute o seguinte comando, sendo <code>pacote</code> o pacote que você quer verificar se é usado de alguma forma:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pactree -r pacote</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>No caso do <code>qt5-webkit</code>, por exemplo, você pode usar:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pactree -r qt5-webkit</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Nesse comando, o <code>-r</code> significa <em>reverse</em>, ou seja, ele monta uma árvore ASCII de pacotes que DEPENDEM do pacote que você especificou no parâmetro. Se nenhum outro pacote no seu computador tiver o pacote  que você informou como dependência, apenas o nome do pacote que você informou aparecerá na tela (como "raiz" da árvore). </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Claro que, se o pacote informado for de algum programa que você use, como o MySQL ou o Google Chrome, por exemplo, é provável que nenhum outro pacote aparecerá para esse comando, afinal, nenhum outro pacote instalado no seu computador depende dele. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Quando encontrar um pacote do <em>AUR</em> que de fato não faz sentido gastar tempo para atualizar, você pode simplesmente...removê-lo. Esse é o comando para fazer isso, e, novamente, <code>pacote</code> é o pacote que você quer remover:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pacman -Rns pacote</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>No caso do <code>qt5-webkit</code>, o comando fica assim: </p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pacman -Rns qt5-webkit</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Note que esse o parâmetro <code>-Rns</code> aqui vai remover não somente o pacote em questão mas também todas as suas dependências não utilizadas (o que pode muito bem incluir outros pacotes grandes do AUR..).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>"Mas, Fernando, por qual motivo tantas menções para o <code>qt5-webkit</code>?!". Bom, nada em especial, é só o fato de que o gênio que vos escreve aqui <strong>gastou mais de uma hora</strong> essa semana esperando a compilação desse pacote só para finalmente descobrir que.. esse pacote não tava sendo utilizado por nenhuma outra dependência do PC. Ou seja, literalmente desperdicei tempo a toa. 🙃</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Um último detalhe...</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Agora, para você que leu até aqui (obrigado!), uma dúvida: Qual a sua opinião sobre textos curtos assim? Eu quero muito voltar a escrever mais para esse blog, e inclusive até comecei a preparar uma versão em inglês (!!!), mas para a surpresa de um total de zero pessoas a vida adulta é bem...caótica, e <a href="https://fjorgemota.com/2016/01/14/docker-containers-para-a-vida-ou-nao/">artigos de sucesso como o que escrevi anos atrás sobre o Docker (que até hoje recebe um razoável número de visitas)</a> levam MUITO tempo para serem propriamente escrito, testados e revisados. Eu gosto da ideia de trazer dicas e comentários simples assim em posts concisos, entretanto, mas queria saber: qual a sua opinião sobre isso? Deixe nos comentários! :)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ah, e feliz ano novo, pessoal! :D </p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image alignright size-medium"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="300" height="300" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=300%2C300&#038;ssl=1" alt="Imagem gerada pelo Dall-E representando um usuário mexendo em um computador com um relógio na parede" class="wp-image-7659" srcset="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=300%2C300&amp;ssl=1 300w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=150%2C150&amp;ssl=1 150w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=768%2C768&amp;ssl=1 768w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=96%2C96&amp;ssl=1 96w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=84%2C84&amp;ssl=1 84w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?resize=600%2C600&amp;ssl=1 600w, https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/12/image.png?w=1024&amp;ssl=1 1024w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Como usuário da excelente distribuição Arch Linux (<em><a href="https://knowyourmeme.com/memes/btw-i-use-arch">BTW, I use Arch</a></em>), eu só gostaria de fazer aqui um breve lembrete para todos vocês: Antes de você gastar bastante tempo compilando um pacote gigante do AUR (ou Arch User Repository), como por exemplo o <em>qt5-webkit</em>, vale checar se você realmente PRECISA desse pacote OU se ele é dependência para algum outro pacote instalado na sua máquina. </p>



<span id="more-7656"></span>



<p>No Arch Linux, você pode checar se outro pacote depende do pacote em questão através do <code>pactree</code>, que é um script disponível no pacote <code><a href="https://archlinux.org/packages/extra/x86_64/pacman-contrib/">pacman-contrib</a></code>. Primeiro, instale o <code><a href="https://archlinux.org/packages/extra/x86_64/pacman-contrib/">pacman-contrib</a></code>:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pacman -S pacman-contrib</code></pre>



<p>Depois, execute o seguinte comando, sendo <code>pacote</code> o pacote que você quer verificar se é usado de alguma forma:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pactree -r pacote</code></pre>



<p>No caso do <code>qt5-webkit</code>, por exemplo, você pode usar:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pactree -r qt5-webkit</code></pre>



<p>Nesse comando, o <code>-r</code> significa <em>reverse</em>, ou seja, ele monta uma árvore ASCII de pacotes que DEPENDEM do pacote que você especificou no parâmetro. Se nenhum outro pacote no seu computador tiver o pacote  que você informou como dependência, apenas o nome do pacote que você informou aparecerá na tela (como "raiz" da árvore). </p>



<p>Claro que, se o pacote informado for de algum programa que você use, como o MySQL ou o Google Chrome, por exemplo, é provável que nenhum outro pacote aparecerá para esse comando, afinal, nenhum outro pacote instalado no seu computador depende dele. </p>



<p>Quando encontrar um pacote do <em>AUR</em> que de fato não faz sentido gastar tempo para atualizar, você pode simplesmente...removê-lo. Esse é o comando para fazer isso, e, novamente, <code>pacote</code> é o pacote que você quer remover:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pacman -Rns pacote</code></pre>



<p>No caso do <code>qt5-webkit</code>, o comando fica assim: </p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo pacman -Rns qt5-webkit</code></pre>



<p>Note que esse o parâmetro <code>-Rns</code> aqui vai remover não somente o pacote em questão mas também todas as suas dependências não utilizadas (o que pode muito bem incluir outros pacotes grandes do AUR..).</p>



<p>"Mas, Fernando, por qual motivo tantas menções para o <code>qt5-webkit</code>?!". Bom, nada em especial, é só o fato de que o gênio que vos escreve aqui <strong>gastou mais de uma hora</strong> essa semana esperando a compilação desse pacote só para finalmente descobrir que.. esse pacote não tava sendo utilizado por nenhuma outra dependência do PC. Ou seja, literalmente desperdicei tempo a toa. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f643.png" alt="🙃" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h3 class="wp-block-heading">Um último detalhe...</h3>



<p>Agora, para você que leu até aqui (obrigado!), uma dúvida: Qual a sua opinião sobre textos curtos assim? Eu quero muito voltar a escrever mais para esse blog, e inclusive até comecei a preparar uma versão em inglês (!!!), mas para a surpresa de um total de zero pessoas a vida adulta é bem...caótica, e <a href="https://fjorgemota.com/2016/01/14/docker-containers-para-a-vida-ou-nao/">artigos de sucesso como o que escrevi anos atrás sobre o Docker (que até hoje recebe um razoável número de visitas)</a> levam MUITO tempo para serem propriamente escrito, testados e revisados. Eu gosto da ideia de trazer dicas e comentários simples assim em posts concisos, entretanto, mas queria saber: qual a sua opinião sobre isso? Deixe nos comentários! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Ah, e feliz ano novo, pessoal! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> </p>
]]></content:encoded>
					
					<wfw:commentRss>https://fjorgemota.com/2023/12/28/uma-simples-dica-para-economizar-tempo-ao-atualizar-pacotes-do-aur-no-arch-linux/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">7656</post-id>	</item>
		<item>
		<title>Como reduzir o tamanho de vídeos no Linux com ffmpeg</title>
		<link>https://fjorgemota.com/2023/04/09/como-reduzir-o-tamanho-de-videos-no-linux-com-ffmpeg/</link>
					<comments>https://fjorgemota.com/2023/04/09/como-reduzir-o-tamanho-de-videos-no-linux-com-ffmpeg/#respond</comments>
		
		<dc:creator><![CDATA[Fernando]]></dc:creator>
		<pubDate>Mon, 10 Apr 2023 01:03:53 +0000</pubDate>
				<category><![CDATA[Ferramentas e Projetos]]></category>
		<category><![CDATA[desenvolvimento]]></category>
		<category><![CDATA[utilidades]]></category>
		<category><![CDATA[vídeos]]></category>
		<guid isPermaLink="false">https://fjorgemota.com/?p=6486</guid>

					<description><![CDATA[<!-- wp:paragraph -->
<p>Sabe quando você tem um vídeo e você quer compartilhar na internet? Pois então, hoje, na maior parte dos casos, isso não é um problema em termos de plataforma, visto que muitas plataformas aceitam vídeos sem problema nenhum. O problema, entretanto, é a velocidade de <em>upload</em> da maior parte das conexões de internet aqui no Brasil: Aqui, apesar de assinar uma conexão com centenas de Mbps, por exemplo, eu possuo apenas 25 Mbps de <em>upload</em>. Não que hoje seja MUITO demorado quando você compara com, por exemplo, a conexão discada (famosos 56 Kbps que na verdade se traduziam em apenas 8 Kbps em dias em que a conexão estava boa), mas, no dia a dia moderno, o <em>upload</em> de um vídeo qualquer pode levar...bastante tempo.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Logo, a possibilidade de otimizar o vídeo de forma a reduzir o seu tamanho enquanto mantendo uma boa qualidade acaba sendo bem atraente. É dificil dizer em números exatos, mas, na minha experiência, recodificar um vídeo localmente e depois enviar acaba tomando bem menos tempo do que só..enviar, daí a razão por trás desse post.</p>
<!-- /wp:paragraph -->


<span id="more-6486"></span>


<!-- wp:paragraph -->
<p>Antes de finalmente apresentar o script, um pequeno aviso:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph {"backgroundColor":"vivid-green-cyan","textColor":"foreground"} -->
<p class="has-foreground-color has-vivid-green-cyan-background-color has-text-color has-background">Os vídeo ao qual me refiro nesse post são, majoritariamente, gravações de tela, que são muito úteis para mostrar um recurso em desenvolvimento, ou então documentar um bug. Nesses vídeos, pode haver um pequeno bloco no qual a imagem da sua webcam aparece, mas os comandos aqui apresentados não são necessariamente otimizados para um vídeo contendo SOMENTE isso. Em virtude disso, o <em>framerate</em> do vídeo é reduzido para apenas 30 FPS, o que reforça a intenção do <em>script</em> de ser mais otimizado para uso em vídeos em que muitos quadros acabam por serem estáticos.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p> Segue o script, que você pode salvar como <code>prepare-video</code> no seu computador:</p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":false} -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
ffmpeg -i "$1" -crf 27 -preset veryfast -movflags +faststart -r 30 -vcodec libx264 -acodec aac "$2"</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Antes de executar, lembre-se de dar permissões de execução (<code>chmod +x prepare-video</code>) para o comando em questão. A partir daí, você pode usar o seguinte comando para converter vídeos:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code class="">prepare-video video-de-entrada.avi video-de-saida.mp4</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Substituindo <code>video-de-entrada.avi</code> pelo vídeo que você quer converter e <code>video-de-saida.mp4</code> pelo arquivo para o qual o vídeo convertido deve ser salvo.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Esse é o <em>script</em> que eu tenho usado há anos, só que com o nome <code>convert-to-whatsapp</code>, pois foi o motivador inicial para criar tal script: O WhatsApp é CHATO no suporte a vídeos, e esse <em>script </em>é quem me permitia codificar um vídeo que fosse suportado pelo WhatsApp nativamente.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Note que um grande problema desse <em>script</em> é que ele roda todo o processo de decodificação e codificação no processador. Em um processador moderna, com 8 núcleos, isso normalmente não é um grande problema, mas em processadores mais antigos isso pode ser um problema. </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Movendo a carga para a placa de vídeo </h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Como documentado acima, esse é o <em>script</em> que eu uso já há alguns bons anos. Entretanto, como tudo na vida, sempre há espaço pra melhorias. Recentemente, eu fiz uma <em>pequena</em> melhoria no meu computador: troquei a minha placa de vídeo, que antes era uma AMD RX 580 8GB, por uma NVIDIA RTX 4090. Em virtude disso, a possibilidade de usar a placa de vídeo para fazer todo o processo de decodificação e codificação se tornou mais...real, uma vez que infelizmente a AMD é bem fraca nesse aspecto (mesmo nas últimas gerações de placa de vídeo).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Se você tem uma placa de vídeo da NVIDIA com suporte a NVENC, uma possibilidade é usar esse comando aqui para conseguir resultados similares à versão com processador, conforme gerado pelo ChatGPT (a ideia é que esse comando seja equivalente ao anterior):</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
ffmpeg -hwaccel cuvid -i "$1" -c:v h264_nvenc -preset:v fast -rc:v vbr -cq:v 19 -profile:v high -level:v 4.2 -b:v 1200k -maxrate:v 2400k -bufsize:v 2400k -c:a aac -b:a 128k -movflags +faststart -r 30 "$2"</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>A parte curiosa? Apesar de ser um pouco mais rápida do que a versão que roda somente em processador, esta versão gera arquivos MUITO maiores. Segue uma tabela comparando os resultados:</p>
<!-- /wp:paragraph -->

<!-- wp:table {"className":"is-style-regular"} -->
<figure class="wp-block-table is-style-regular"><table><thead><tr><th>Configuração do Codificador</th><th>Tamanho final do arquivo</th><th>Tempo para realizar a conversão</th></tr></thead><tbody><tr><td>Arquivo Original</td><td>1.1 GB</td><td>-</td></tr><tr><td>Usando somente o processador</td><td>106 MB</td><td>1 minuto e 50 segundos</td></tr><tr><td>Usando somente a placa de vídeo</td><td>293 MB</td><td>1 minuto e 34 segundos</td></tr></tbody></table></figure>
<!-- /wp:table -->

<!-- wp:paragraph -->
<p>Para fins de documentação, o meu processador é um AMD Ryzen 7 5800X3D, um dos processadores mais poderosos da atualidade...para jogos. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Aí você me pergunta: Tá, mas pra quê eu vou utilizar a versão baseada em GPU, então? Bom, eu não faço ideia, ¯\_(ツ)_/¯. Ao meu ver, a maior vantagem de usar o codificador baseado em GPU é que você acaba movendo para a GPU toda a carga de processamento, o que é bem útil em algumas situações.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Outras alternativa usando somente o processador</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>De acordo com o ChatGPT, uma outra boa alternativa - ainda usando somente o processador - para codificar os vídeos com o propósito desse post, é o seguinte script:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
ffmpeg -y -i "$1" -c:v libx264 -preset medium -crf 28 -r 30 -c:a aac -b:a 192k -movflags +faststart "$2"</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Fica a seu critério qual utilizar. Pelos meus testes, esse comando provê muda algumas configurações para ter um pouco mais de qualidade de imagem, MAS naturalmente isso aumenta um pouco o tamanho do arquivo. Além disso, o comando demora mais para executar, veja a tabela abaixo:</p>
<!-- /wp:paragraph -->

<!-- wp:table {"className":"is-style-regular"} -->
<figure class="wp-block-table is-style-regular"><table><thead><tr><th>Configuração do Codificador</th><th>Tamanho final do arquivo</th><th>Tempo para realizar a conversão</th></tr></thead><tbody><tr><td>Arquivo Original</td><td>1.1 GB</td><td>-</td></tr><tr><td>Meu script</td><td>106 MB</td><td>1 minuto e 50 segundos</td></tr><tr><td>Script do ChatGPT</td><td>128 MB</td><td>2 minutos e 26 segundos</td></tr></tbody></table></figure>
<!-- /wp:table -->

<!-- wp:paragraph -->
<p>Se você valoriza mais qualidade e não está tão preocupado em ter a execução mais demorada nem o tamanho ligeiramente maior, essa pode ser definitivamente uma opção.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Conclusão</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>O <strong>ffmpeg</strong> é uma ferramenta extremamente poderosa para esse tipo de manipulação de vídeo, e esse tipo de <em>script</em>, em torno de ferramentas assim, ajuda MUITO a facilitar o uso de tarefas cotidianas no computador. Hoje em dia, eu não gravo tantos vídeos quanto gostaria, mas ainda assim esse script se torna muito útil para compartilhar vídeos na internet, em especial considerando os limites da velocidade de <em>upload</em> do plano de internet aqui de casa.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>E você, grava vídeos para a internet? Tem algum script maneiro para compartilhar? Deixe nos comentários! :D </p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[
<p>Sabe quando você tem um vídeo e você quer compartilhar na internet? Pois então, hoje, na maior parte dos casos, isso não é um problema em termos de plataforma, visto que muitas plataformas aceitam vídeos sem problema nenhum. O problema, entretanto, é a velocidade de <em>upload</em> da maior parte das conexões de internet aqui no Brasil: Aqui, apesar de assinar uma conexão com centenas de Mbps, por exemplo, eu possuo apenas 25 Mbps de <em>upload</em>. Não que hoje seja MUITO demorado quando você compara com, por exemplo, a conexão discada (famosos 56 Kbps que na verdade se traduziam em apenas 8 Kbps em dias em que a conexão estava boa), mas, no dia a dia moderno, o <em>upload</em> de um vídeo qualquer pode levar...bastante tempo.</p>



<p>Logo, a possibilidade de otimizar o vídeo de forma a reduzir o seu tamanho enquanto mantendo uma boa qualidade acaba sendo bem atraente. É dificil dizer em números exatos, mas, na minha experiência, recodificar um vídeo localmente e depois enviar acaba tomando bem menos tempo do que só..enviar, daí a razão por trás desse post.</p>



<span id="more-6486"></span>



<p>Antes de finalmente apresentar o script, um pequeno aviso:</p>



<p class="has-foreground-color has-vivid-green-cyan-background-color has-text-color has-background">Os vídeo ao qual me refiro nesse post são, majoritariamente, gravações de tela, que são muito úteis para mostrar um recurso em desenvolvimento, ou então documentar um bug. Nesses vídeos, pode haver um pequeno bloco no qual a imagem da sua webcam aparece, mas os comandos aqui apresentados não são necessariamente otimizados para um vídeo contendo SOMENTE isso. Em virtude disso, o <em>framerate</em> do vídeo é reduzido para apenas 30 FPS, o que reforça a intenção do <em>script</em> de ser mais otimizado para uso em vídeos em que muitos quadros acabam por serem estáticos.</p>



<p> Segue o script, que você pode salvar como <code>prepare-video</code> no seu computador:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
ffmpeg -i "$1" -crf 27 -preset veryfast -movflags +faststart -r 30 -vcodec libx264 -acodec aac "$2"</code></pre>



<p>Antes de executar, lembre-se de dar permissões de execução (<code>chmod +x prepare-video</code>) para o comando em questão. A partir daí, você pode usar o seguinte comando para converter vídeos:</p>



<pre class="wp-block-code"><code class="">prepare-video video-de-entrada.avi video-de-saida.mp4</code></pre>



<p>Substituindo <code>video-de-entrada.avi</code> pelo vídeo que você quer converter e <code>video-de-saida.mp4</code> pelo arquivo para o qual o vídeo convertido deve ser salvo.</p>



<p>Esse é o <em>script</em> que eu tenho usado há anos, só que com o nome <code>convert-to-whatsapp</code>, pois foi o motivador inicial para criar tal script: O WhatsApp é CHATO no suporte a vídeos, e esse <em>script </em>é quem me permitia codificar um vídeo que fosse suportado pelo WhatsApp nativamente.</p>



<p>Note que um grande problema desse <em>script</em> é que ele roda todo o processo de decodificação e codificação no processador. Em um processador moderna, com 8 núcleos, isso normalmente não é um grande problema, mas em processadores mais antigos isso pode ser um problema. </p>



<h2 class="wp-block-heading">Movendo a carga para a placa de vídeo </h2>



<p>Como documentado acima, esse é o <em>script</em> que eu uso já há alguns bons anos. Entretanto, como tudo na vida, sempre há espaço pra melhorias. Recentemente, eu fiz uma <em>pequena</em> melhoria no meu computador: troquei a minha placa de vídeo, que antes era uma AMD RX 580 8GB, por uma NVIDIA RTX 4090. Em virtude disso, a possibilidade de usar a placa de vídeo para fazer todo o processo de decodificação e codificação se tornou mais...real, uma vez que infelizmente a AMD é bem fraca nesse aspecto (mesmo nas últimas gerações de placa de vídeo).</p>



<p>Se você tem uma placa de vídeo da NVIDIA com suporte a NVENC, uma possibilidade é usar esse comando aqui para conseguir resultados similares à versão com processador, conforme gerado pelo ChatGPT (a ideia é que esse comando seja equivalente ao anterior):</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
ffmpeg -hwaccel cuvid -i "$1" -c:v h264_nvenc -preset:v fast -rc:v vbr -cq:v 19 -profile:v high -level:v 4.2 -b:v 1200k -maxrate:v 2400k -bufsize:v 2400k -c:a aac -b:a 128k -movflags +faststart -r 30 "$2"</code></pre>



<p>A parte curiosa? Apesar de ser um pouco mais rápida do que a versão que roda somente em processador, esta versão gera arquivos MUITO maiores. Segue uma tabela comparando os resultados:</p>



<figure class="wp-block-table is-style-regular"><table><thead><tr><th>Configuração do Codificador</th><th>Tamanho final do arquivo</th><th>Tempo para realizar a conversão</th></tr></thead><tbody><tr><td>Arquivo Original</td><td>1.1 GB</td><td>-</td></tr><tr><td>Usando somente o processador</td><td>106 MB</td><td>1 minuto e 50 segundos</td></tr><tr><td>Usando somente a placa de vídeo</td><td>293 MB</td><td>1 minuto e 34 segundos</td></tr></tbody></table></figure>



<p>Para fins de documentação, o meu processador é um AMD Ryzen 7 5800X3D, um dos processadores mais poderosos da atualidade...para jogos. </p>



<p>Aí você me pergunta: Tá, mas pra quê eu vou utilizar a versão baseada em GPU, então? Bom, eu não faço ideia, ¯\_(ツ)_/¯. Ao meu ver, a maior vantagem de usar o codificador baseado em GPU é que você acaba movendo para a GPU toda a carga de processamento, o que é bem útil em algumas situações.</p>



<h2 class="wp-block-heading">Outras alternativa usando somente o processador</h2>



<p>De acordo com o ChatGPT, uma outra boa alternativa - ainda usando somente o processador - para codificar os vídeos com o propósito desse post, é o seguinte script:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
ffmpeg -y -i "$1" -c:v libx264 -preset medium -crf 28 -r 30 -c:a aac -b:a 192k -movflags +faststart "$2"</code></pre>



<p>Fica a seu critério qual utilizar. Pelos meus testes, esse comando provê muda algumas configurações para ter um pouco mais de qualidade de imagem, MAS naturalmente isso aumenta um pouco o tamanho do arquivo. Além disso, o comando demora mais para executar, veja a tabela abaixo:</p>



<figure class="wp-block-table is-style-regular"><table><thead><tr><th>Configuração do Codificador</th><th>Tamanho final do arquivo</th><th>Tempo para realizar a conversão</th></tr></thead><tbody><tr><td>Arquivo Original</td><td>1.1 GB</td><td>-</td></tr><tr><td>Meu script</td><td>106 MB</td><td>1 minuto e 50 segundos</td></tr><tr><td>Script do ChatGPT</td><td>128 MB</td><td>2 minutos e 26 segundos</td></tr></tbody></table></figure>



<p>Se você valoriza mais qualidade e não está tão preocupado em ter a execução mais demorada nem o tamanho ligeiramente maior, essa pode ser definitivamente uma opção.</p>



<h2 class="wp-block-heading">Conclusão</h2>



<p>O <strong>ffmpeg</strong> é uma ferramenta extremamente poderosa para esse tipo de manipulação de vídeo, e esse tipo de <em>script</em>, em torno de ferramentas assim, ajuda MUITO a facilitar o uso de tarefas cotidianas no computador. Hoje em dia, eu não gravo tantos vídeos quanto gostaria, mas ainda assim esse script se torna muito útil para compartilhar vídeos na internet, em especial considerando os limites da velocidade de <em>upload</em> do plano de internet aqui de casa.</p>



<p>E você, grava vídeos para a internet? Tem algum script maneiro para compartilhar? Deixe nos comentários! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> </p>
]]></content:encoded>
					
					<wfw:commentRss>https://fjorgemota.com/2023/04/09/como-reduzir-o-tamanho-de-videos-no-linux-com-ffmpeg/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">6486</post-id>	</item>
		<item>
		<title>Dokku - Deploy simplificado para os seus projetos</title>
		<link>https://fjorgemota.com/2023/03/30/dokku-deploy-simplificado-para-os-seus-projetos/</link>
					<comments>https://fjorgemota.com/2023/03/30/dokku-deploy-simplificado-para-os-seus-projetos/#comments</comments>
		
		<dc:creator><![CDATA[Fernando]]></dc:creator>
		<pubDate>Fri, 31 Mar 2023 01:00:00 +0000</pubDate>
				<category><![CDATA[Dicas]]></category>
		<category><![CDATA[Ferramentas e Projetos]]></category>
		<category><![CDATA[containers]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[desenvolvimento]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[ferramentas]]></category>
		<category><![CDATA[git]]></category>
		<guid isPermaLink="false">https://fjorgemota.com/?p=6337</guid>

					<description><![CDATA[<!-- wp:image {"align":"right","id":6390,"sizeSlug":"full","linkDestination":"media","className":"is-style-default"} -->
<figure class="wp-block-image alignright size-full is-style-default"><a href="https://fjorgemota.com/wp-content/uploads/2023/03/image-1.png"><img src="https://fjorgemota.com/wp-content/uploads/2023/03/image-1.png" alt="Logotipo do Dokku" class="wp-image-6390"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Como programador, uma coisa que eu aprecio demais na nossa profissão é a possibilidade de criar <em>side projects</em>. Claro, relaxar é super importante, eu não nego, ainda mais para nós que trabalhamos basicamente pensando muito o dia inteiro.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Mas poder criar projetos que resolvem AQUELE problema ou necessidade chato que você tem - e ainda de quebra poder ajudar outras pessoas (ou até faturar algum $$$ extra, em alguns casos) - também é algo muito bem vindo.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>O problema, como sempre, é que isso é basicamente...trabalho, e por mais interessante que seja poder customizar cada parte do seu próprio projeto, o fato é que quanto mais você demora para lançá-lo - por qualquer motivo que seja - maiores são as chances de você acabar desistindo e/ou partindo para outro projeto.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>E é nesse ponto que entra o <strong>Dokku</strong>: um projeto que, após ser instalado em um servidor (VPS ou dedicado, conforme o seu bolso deixar), lhe permite facilmente criar novas aplicações e fazer deploy delas, usando um <em>workflow</em> muito parecido com o do Heroku, mas sem os custos extras (além do custo do servidor e do seu tempo, é claro).</p>
<!-- /wp:paragraph -->


<span id="more-6337"></span>


<!-- wp:heading {"gbResponsiveSettings":{}} -->
<h2 class="wp-block-heading">O que é </h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>O <em>Dokku</em> é um projeto que implementa um <em>PaaS</em> - Platform as a Service, ou Plataforma como Serviço, em inglês - e usa o <a href="https://fjorgemota.com/docker-containers-para-a-vida-ou-nao/" data-type="post" data-id="1366">Docker - que já apresentamos em outro post</a> - para fazer suas "magias". Sua administração decorre de um simples comando chamado "dokku", que permite a criação de novos aplicativos (que é como o projeto chama os seus projetos) e também configuração dos mesmos.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Além disso, possui um ecossistema muito rico, com <em>plugins </em>que facilitam, entre outras coisas, a instalação e configuração de projetos como <em>MySQL</em>, <em>PostgreSQL</em> e <em>RabbitMQ</em>, e até mesmo facilitam a configuração de certificados SSL usando <em>Let's Encrypt</em>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Depois de configurar o Dokku completamente, se torna possível publicar seu projeto com apenas alguns poucos comandos (a depender do que você usa no seu projeto), portanto tornando possível publicar o seu projeto muito rapidamente. Para que isso seja possível, entretanto, é necessário seguir algumas regras durante o desenvolvimento do seu projeto, chamado <a href="https://12factor.net/pt_br/"><em>Twelve-Factor App</em></a>, em especial no que diz respeito à configuração do projeto, mas isso é algo que qualquer <em>framework</em> moderno já suporta facilmente, então não chega a ser um grande problema.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"gbResponsiveSettings":{}} -->
<h2 class="wp-block-heading">Como instalar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Para instalar o Dokku, você precisa primeiramente de um servidor VPS ou dedicado, ou seja, não dá para usar uma hospedagem compartilhada com ele. Também é necessário que você possua um domínio, e que o servidor em questão rode uma distribuição Linux. Para simplificar o processo de instalação, vou mostrar aqui apenas os comandos para quem usa Ubuntu ou Debian no servidor. É plenamente possível usar o Dokku também com outras distribuições, mas, <a href="https://dokku.com/docs/getting-started/advanced-installation/">o processo será potencialmente mais complicado</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Se você quiser apenas usar o Dokku em seu próprio computador, digamos, para ver como funciona, também é possível usar o <a href="https://fjorgemota.com/vagrant-maquinas-virtuais-automatizadas-para-desenvolvimento/" data-type="post" data-id="1351">Vagrant - que apresentei em outro post</a> - para rodá-lo. Apenas esteja ciente de que dessa forma os seus projetos NÃO serão publicados na internet. <a href="https://dokku.com/docs/getting-started/install/vagrant/">Segue aqui as instruções</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Com tudo isso dito, segue os comandos para instalar a última versão do Dokku - 0.30.2 - conforme disponível no momento de escrita desse post. Eu sugiro fortemente para que você verifique a última versão disponível do Dokku e ajuste o comando de forma correspondente abaixo, portanto, os comandos abaixo são apenas uma referência:</p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":true} -->
<pre class="wp-block-code"><code lang="bash" class="language-bash line-numbers">wget https://dokku.com/bootstrap.sh
sudo DOKKU_TAG=v0.30.2 bash bootstrap.sh</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph {"backgroundColor":"luminous-vivid-amber","textColor":"foreground"} -->
<p class="has-foreground-color has-luminous-vivid-amber-background-color has-text-color has-background"><strong>ATENÇÃO: </strong>Antes de rodar esses comandos de forma imediata, eu sugiro para que os rode individualmente, e, se possível, analise o conteúdo do arquivo baixado após a execução do primeiro comando. O Dokku é um projeto bastante confiável, mas, sempre vale ter essa prática por segurança, com todo e qualquer comando do tipo que você vê por aí.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Depois de rodar esses comandos e de instalar o Dokku, chegou a hora de configurar o domínio global que o Dokku usará. Uma questão importante sobre esse domínio é que, em um cenário ideal, o domínio deve ser configurado de forma que todo sub-domínio ainda não definido aponte para o servidor no qual o Dokku está instalado. Em termos técnico, isso significa que o DNS precisa ter uma entrada "<em>wildcard</em>" apontando para o seeu servidor. Isso NÃO é um requisito para o uso do Dokku, mas, facilita e muito a configuração de novos aplicativos, visto que você acaba não precisando configurar o DNS manualmente a cada vez que você vai criar um novo aplicativo (bom, pelo menos não se você quiser que sua aplicação rode em um..sub-domínio). Para referência, <a href="https://developers.cloudflare.com/dns/manage-dns-records/reference/wildcard-dns-records/">nesse artigo é mostrado como configurar uma entrada <em>wildcard</em> no Cloudflare</a>. Consulte a documentação do servidor DNS que você usa para mais informações.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Com isso dito, segue o comando para configurar o domínio global no Dokku, onde <code>SEU_DOMINIO</code> é o dominio que o Dokku deve usar como global:</p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":true} -->
<pre class="wp-block-code"><code lang="bash" class="language-bash line-numbers">dokku domains:set-global SEU_DOMINIO</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Depois de configurar o Dokku no seu servidor, uma última etapa que eu considero bastante importante é configurar um cliente do Dokku no seu próprio computador. Naturalmente, o processo varia bastante de acordo com a sua preferência, <a href="https://dokku.com/docs/community/clients/">mas aqui está a lista de clientes que podem ser usados para se comunicar com o Dokku</a>. Pessoalmente, eu gosto bastante do <a href="https://dokku.com/docs/deployment/remote-commands/#official-client">cliente oficial do Dokku, que é bastante simples e funciona por SSH</a>, tornando toda a comunicação bastante segura e simples.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"gbResponsiveSettings":{}} -->
<h2 class="wp-block-heading">Como publicar sua primeira aplicação</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Depois de configurado, publicar sua primeira aplicação é bem simples. Digamos que você tenha um simples repositório <a href="https://fjorgemota.com/git-sistema-de-controle-de-versoes-distribuido/" data-type="post" data-id="1435">Git - que você pode ler mais sobre nesse post</a> - com o seguinte arquivo - chamado <strong>index.php</strong> -  comittado:</p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":true} -->
<pre class="wp-block-code"><code lang="php" class="language-php line-numbers">&#60;?php
// Pega o nome da URL, ou assume o padrão "Mundo", e converte caracteres HTML de forma que não seja possível injetar JS/CSS na página:
$nome = htmlspecialchars( $_GET["name"] ?? "Mundo" );
// Imprime "Olá, " seguido do valor da variável acima
echo "Olá, {$nome}";</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>E também tenha no repositório os arquivos "composer.json" e "composer.lock" criados pelo <a href="https://fjorgemota.com/composer-como-gerenciar-dependencias-no-php-facilmente/" data-type="post" data-id="1585">Composer, sobre o qual já falei aqui</a> (você pode rodar <code>composer init</code> e responder todas as perguntas para configurar o Composer corretamente).  </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph {"backgroundColor":"light-green-cyan","textColor":"foreground"} -->
<p class="has-foreground-color has-light-green-cyan-background-color has-text-color has-background">Apesar da criação dos arquivos <code>composer.json</code> e <code>composer.lock</code> não ser SUPER necessária - visto que o Dokku consegue detectar que se trata de um projeto que usa PHP à partir da existência do arquivo <code>index.php</code> - é algo que é recomendado, visto que o modo de detecção a partir da existência de arquivos PHP é considerado depreciado.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Antes de fazer o deploy dessa aplicação, que vamos chamar aqui de <strong>hello</strong>, você primeiramente precisa criar a aplicação no Dokku. Para isso, você pode usar o seguinte comando, que usa o cliente oficial do Dokku mencionado anteriormente:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku apps:create hello</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Depois de criado, você pode simplesmente rodar o seguinte comando para fazer o deploy do projeto, assumindo que a branch principal do repositório em questão é a branch <code>main</code>, e que você fez o commit nessa branch:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">git push dokku main</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Depois de rodar o comando, o Dokku analisará o conteúdo do repositório e rapidamente constatará que se trata de uma aplicação em PHP, usando um projeto chamado <a href="https://github.com/gliderlabs/herokuish">Herokuish</a>. A partir daí, será usado o <a href="https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-php">buildpack do Heroku para PHP</a> para fazer o deploy da sua aplicação, que deverá estar disponível em <code>hello.SEU_DOMINIO</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Como eu possuo Dokku instalado nesse mesmo servidor, você pode ver a aplicação rodando aqui: <a href="http://hello.fjorgemota.com/?name=World">http://hello.fjorgemota.com/?nome=Teste</a> - sinta-se a vontade para mudar o parâmetro <code>nome</code> para qualquer outra coisa apenas para experimento. :) </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"gbResponsiveSettings":{}} -->
<h2 class="wp-block-heading">Conectando um banco de dados</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Naturalmente, fazer uma simples aplicação assim não mostra o potencial completo da ferramenta. Em virtude disso, vamos complicar um pouquinho o exemplo: Em vez de um simples código PHP que printa um parâmetro recebido na URL, vamos fazer um contador de visitas...bem simples, mas enfim.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Para isso, no repositório Git criado anteriormente, adicione o seguinte código no final do arquivo <strong>index.php: </strong></p>
<!-- /wp:paragraph -->

<!-- wp:code {"lineNumbers":true} -->
<pre class="wp-block-code"><code lang="php" class="language-php line-numbers">// Captura a URL da variável de ambiente e divide em partes
$parametros = parse_url( getenv( "DATABASE_URL" ) );
// Gera a URL para passar para o PDO, contendo os dados de configuração do banco de dados
$url = sprintf( "pgsql:host=%s;port=%d;dbname=%s;user=%s;password=%s", $parametros['host'], $parametros['port'],  substr( $parametros['path'], 1 ), $parametros['user'], $parametros['pass'] );
// Conecta oa banco de dados
$conexao = new PDO( $url );
// Faz a consulta para contar o número de visitas e retornar o número atualizado
$consulta = $conexao-&#62;query( "INSERT INTO visits ( id, num_visits ) VALUES( 1, 1 ) ON CONFLICT (id) DO UPDATE SET num_visits = visits.num_visits + EXCLUDED.num_visits RETURNING num_visits");
// Captura o número de visitas retornado pelo banco de dados
$visitas = $consulta-&#62;fetchColumn( 0 );
// Imprime o resultado na página
echo "&#60;br /&#62; Número de visitas: {$visits}";</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Depois de adicionar esse script ao arquivo, lembre-se de comittar e enviar o resultado para o Dokku, usando <code>git push dokku main</code> como definido acima.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Como você pode imaginar, isso não vai ser suficiente: Estamos aqui usando o <code><a href="https://www.php.net/manual/pt_BR/intro.pdo.php">PDO</a></code> com o <code><a href="https://www.php.net/manual/pt_BR/ref.pdo-pgsql.php">PDO_PGSQL</a></code> para conectar a um banco de dados PostgreSQL, que é um <a href="https://fjorgemota.com/sgbds-sistemas-gerenciadores-de-bancos-de-dados-o-que-sao-como-vivem-e-onde-podem-ser-encontrados/" data-type="post" data-id="1081">SGBD bastante completo</a>. Só que, no momento, o Dokku não faz a mínima ideia dessa dependência do PostgreSQL pra começo de conversa. Portanto, vamos por partes: Vamos configurar o PostgreSQL no Dokku. Felizmente, graças ao fato de que o PHP que o Dokku usa vem com o PDO e o PDO_PGSQL (<a href="https://devcenter.heroku.com/articles/php-support">conforme listado aqui</a>) ativado por padrão, não vamos precisar nos preocupar com a configuração do mesmo.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Para configurar o PostgreSQL no Dokku, primeiramente você precisa instalar o <em>plugin</em> <code>dokku-postgres</code>, que permite criar e gerenciar "serviços" PostgreSQL, e também integrá-los com sua aplicação. Para fazer isso, basta rodar o comando abaixo:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Agora, vamos criar o "serviço", que nada mais é do que o <a href="https://fjorgemota.com/docker-containers-para-a-vida-ou-nao/" data-type="post" data-id="1366">container Docker</a> rodando o PostgreSQL. Esse serviço se chamará <code>pgdb</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku postgres:create pgdb</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Finalmente, vamos conectar o serviço criado com a nossa aplicação <code>hello</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku postgres:link pgdb hello</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Com isso feito, deveremos ter uma variável de ambiente (ou <em>environment variable</em>, em inglês) chamada <code>DATABASE_URL</code> com as informações necessárias para se conectar ao serviço <code>pgdb</code>, que é basicamente o nosso servidor PostgreSQL. Entretanto, falta uma coisa importante: criar a tabela <code>visits</code>, que o nosso script em PHP usa para contar as visitas. Para fazer isso, primeiro, conecte ao PostgreSQL usando o comando abaixo:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku postgres:connect pgdb</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>E então execute o seguinte SQL para criar a tabela <code>visits</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="sql" class="language-sql">CREATE TABLE visits(id INT PRIMARY KEY NOT NULL, num_visits INT NOT NULL);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Agora, acesse sua aplicação e verifique que, a cada vez que você atualiza a página, o contador é devidamente incrementado, como se espera de um contador de visitas.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Configurando sua aplicação</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>O Dokku fornece uma forma fácil de configurar sua aplicação através do uso de variáveis de ambiente, que são úteis para definir parâmetros diversos da sua aplicação. Alguns exemplos que me vem à mente são configurações do servidor de e-mail, configurações de log (para usos mais robustos além do tradicional <code>dokku logs</code>) e outras configurações mais específicas da sua aplicação, como...fuso horário padrão.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Para configurar uma variável de ambiente, você pode usar o comando <code>dokku config</code>. No script acima, se você mudar a linha:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="php" class="language-php">$nome = htmlspecialchars( $_GET["nome"] ?? "Mundo" );</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Por:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="php" class="language-php">$nome = htmlspecialchars( $_GET["nome"] ?? getenv("DEFAULT_NAME") ?? "Mundo" );</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Você se torna apto a usar a variável de ambiente <code>DEFAULT_NAME</code> para mudar o nome que deve aparecer por padrão caso o parâmetro não seja definido na URL. Com o Dokku, você pode configurar tal variável de ambiente usando o seguinte comando, que configurará o valor para "User":</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku config:set DEFAULT_NAME=Usuário</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"gbResponsiveSettings":{}} -->
<h2 class="wp-block-heading">Escalonando a aplicação</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Vamos dizer que sua aplicação é um sucesso absoluto! E que, graças a isso, não é mais suficiente rodar sua aplicação com apenas um processo. O Dokku fornece um comando simples para ajudar nisso, inclusive configurando balanceamento de carga para você. Por exemplo, para ter 4 instâncias da sua aplicação rodando, você pode rodar o seguinte comando:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku ps:scale hello web=4</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Note, entretanto, que as 4 instâncias da aplicação ainda estarão rodando dentro do mesmo servidor. Na maior parte dos casos, isso pode ser suficiente, em especial se o seu servidor possuir vários núcleos. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Entretanto, em um dado momento, se torna interessante ter vários servidores operando. Para fazer isso, o processo é BEM mais complicado, e envolve o uso de sistemas como o <a href="https://dokku.com/docs/deployment/schedulers/kubernetes/">Kubernetes, com o qual é possível integrar usando um plugin do Dokku</a>. Em virtude disso, eu não vou cobrir esse assunto aqui, mas, é algo que é interesante saber de qualquer forma. :) </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Conclusão</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Como é possível ver, o Dokku facilita e muito todo o processo de deploy e configuração da sua aplicação. No geral, todo o uso da ferramenta é muito inspirado pelo <a href="https://heroku.com/" data-type="URL" data-id="https://heroku.com/">Heroku</a>, que foi pioneiro nessa abordagem de deploy e configuração. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Apesar disso, o fato é que, honestamente, a grande maior parte dos projetos NÃO precisam de algo tão robusto e nem tão caro quanto o Heroku, e aí o Dokku começa a se tornar muito mais interessante, visto que com um simples VPS (que hoje você consegue contratar por menos de 5 dólares ao mês), você consegue hospedar diversas aplicações E ainda ter todas essas facilidades de forma bem tranquila, o que é útil em especial se as suas aplicações não tem como meta retorno financeiro (que é o meu caso).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>"Mas, Fernando, eu trabalho para uma empresa pequena, vale a pena usar Dokku?" - Bom, eu diria que depende muito. Se vocês tem condições de ter um VPS (e há, por exemplo, há uma pessoa trabalhando com a infraestrutura da empresa), a resposta é... Talvez. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Na prática, entretanto, se você tem um projeto que possui retorno financeiro, quase sempre vale considerar fortemente o uso de um serviço como o Heroku (ou um de seus concorrentes), simplesmente pela paz de espírito que se tem ao poder dormir à noite ou passar o tempo livre, e também por todo o suporte que você tem ao usar algo especializado do tipo. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Bom, espero que tenham gostado da leitura, e deixem nos comentários: como é o processo de deploy do seu último projeto?</p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image alignright size-full is-style-default"><a href="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/03/image-1.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="89" height="62" src="https://i0.wp.com/fjorgemota.com/wp-content/uploads/2023/03/image-1.png?resize=89%2C62&#038;ssl=1" alt="Logotipo do Dokku" class="wp-image-6390"/></a></figure>



<p>Como programador, uma coisa que eu aprecio demais na nossa profissão é a possibilidade de criar <em>side projects</em>. Claro, relaxar é super importante, eu não nego, ainda mais para nós que trabalhamos basicamente pensando muito o dia inteiro.</p>



<p>Mas poder criar projetos que resolvem AQUELE problema ou necessidade chato que você tem - e ainda de quebra poder ajudar outras pessoas (ou até faturar algum $$$ extra, em alguns casos) - também é algo muito bem vindo.</p>



<p>O problema, como sempre, é que isso é basicamente...trabalho, e por mais interessante que seja poder customizar cada parte do seu próprio projeto, o fato é que quanto mais você demora para lançá-lo - por qualquer motivo que seja - maiores são as chances de você acabar desistindo e/ou partindo para outro projeto.</p>



<p>E é nesse ponto que entra o <strong>Dokku</strong>: um projeto que, após ser instalado em um servidor (VPS ou dedicado, conforme o seu bolso deixar), lhe permite facilmente criar novas aplicações e fazer deploy delas, usando um <em>workflow</em> muito parecido com o do Heroku, mas sem os custos extras (além do custo do servidor e do seu tempo, é claro).</p>



<span id="more-6337"></span>



<h2 class="wp-block-heading">O que é </h2>



<p>O <em>Dokku</em> é um projeto que implementa um <em>PaaS</em> - Platform as a Service, ou Plataforma como Serviço, em inglês - e usa o <a href="https://fjorgemota.com/docker-containers-para-a-vida-ou-nao/" data-type="post" data-id="1366">Docker - que já apresentamos em outro post</a> - para fazer suas "magias". Sua administração decorre de um simples comando chamado "dokku", que permite a criação de novos aplicativos (que é como o projeto chama os seus projetos) e também configuração dos mesmos.</p>



<p>Além disso, possui um ecossistema muito rico, com <em>plugins </em>que facilitam, entre outras coisas, a instalação e configuração de projetos como <em>MySQL</em>, <em>PostgreSQL</em> e <em>RabbitMQ</em>, e até mesmo facilitam a configuração de certificados SSL usando <em>Let's Encrypt</em>.</p>



<p>Depois de configurar o Dokku completamente, se torna possível publicar seu projeto com apenas alguns poucos comandos (a depender do que você usa no seu projeto), portanto tornando possível publicar o seu projeto muito rapidamente. Para que isso seja possível, entretanto, é necessário seguir algumas regras durante o desenvolvimento do seu projeto, chamado <a href="https://12factor.net/pt_br/"><em>Twelve-Factor App</em></a>, em especial no que diz respeito à configuração do projeto, mas isso é algo que qualquer <em>framework</em> moderno já suporta facilmente, então não chega a ser um grande problema.</p>



<h2 class="wp-block-heading">Como instalar</h2>



<p>Para instalar o Dokku, você precisa primeiramente de um servidor VPS ou dedicado, ou seja, não dá para usar uma hospedagem compartilhada com ele. Também é necessário que você possua um domínio, e que o servidor em questão rode uma distribuição Linux. Para simplificar o processo de instalação, vou mostrar aqui apenas os comandos para quem usa Ubuntu ou Debian no servidor. É plenamente possível usar o Dokku também com outras distribuições, mas, <a href="https://dokku.com/docs/getting-started/advanced-installation/">o processo será potencialmente mais complicado</a>.</p>



<p>Se você quiser apenas usar o Dokku em seu próprio computador, digamos, para ver como funciona, também é possível usar o <a href="https://fjorgemota.com/vagrant-maquinas-virtuais-automatizadas-para-desenvolvimento/" data-type="post" data-id="1351">Vagrant - que apresentei em outro post</a> - para rodá-lo. Apenas esteja ciente de que dessa forma os seus projetos NÃO serão publicados na internet. <a href="https://dokku.com/docs/getting-started/install/vagrant/">Segue aqui as instruções</a>.</p>



<p>Com tudo isso dito, segue os comandos para instalar a última versão do Dokku - 0.30.2 - conforme disponível no momento de escrita desse post. Eu sugiro fortemente para que você verifique a última versão disponível do Dokku e ajuste o comando de forma correspondente abaixo, portanto, os comandos abaixo são apenas uma referência:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash line-numbers">wget https://dokku.com/bootstrap.sh
sudo DOKKU_TAG=v0.30.2 bash bootstrap.sh</code></pre>



<p class="has-foreground-color has-luminous-vivid-amber-background-color has-text-color has-background"><strong>ATENÇÃO: </strong>Antes de rodar esses comandos de forma imediata, eu sugiro para que os rode individualmente, e, se possível, analise o conteúdo do arquivo baixado após a execução do primeiro comando. O Dokku é um projeto bastante confiável, mas, sempre vale ter essa prática por segurança, com todo e qualquer comando do tipo que você vê por aí.</p>



<p>Depois de rodar esses comandos e de instalar o Dokku, chegou a hora de configurar o domínio global que o Dokku usará. Uma questão importante sobre esse domínio é que, em um cenário ideal, o domínio deve ser configurado de forma que todo sub-domínio ainda não definido aponte para o servidor no qual o Dokku está instalado. Em termos técnico, isso significa que o DNS precisa ter uma entrada "<em>wildcard</em>" apontando para o seeu servidor. Isso NÃO é um requisito para o uso do Dokku, mas, facilita e muito a configuração de novos aplicativos, visto que você acaba não precisando configurar o DNS manualmente a cada vez que você vai criar um novo aplicativo (bom, pelo menos não se você quiser que sua aplicação rode em um..sub-domínio). Para referência, <a href="https://developers.cloudflare.com/dns/manage-dns-records/reference/wildcard-dns-records/">nesse artigo é mostrado como configurar uma entrada <em>wildcard</em> no Cloudflare</a>. Consulte a documentação do servidor DNS que você usa para mais informações.</p>



<p>Com isso dito, segue o comando para configurar o domínio global no Dokku, onde <code>SEU_DOMINIO</code> é o dominio que o Dokku deve usar como global:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash line-numbers">dokku domains:set-global SEU_DOMINIO</code></pre>



<p>Depois de configurar o Dokku no seu servidor, uma última etapa que eu considero bastante importante é configurar um cliente do Dokku no seu próprio computador. Naturalmente, o processo varia bastante de acordo com a sua preferência, <a href="https://dokku.com/docs/community/clients/">mas aqui está a lista de clientes que podem ser usados para se comunicar com o Dokku</a>. Pessoalmente, eu gosto bastante do <a href="https://dokku.com/docs/deployment/remote-commands/#official-client">cliente oficial do Dokku, que é bastante simples e funciona por SSH</a>, tornando toda a comunicação bastante segura e simples.</p>



<h2 class="wp-block-heading">Como publicar sua primeira aplicação</h2>



<p>Depois de configurado, publicar sua primeira aplicação é bem simples. Digamos que você tenha um simples repositório <a href="https://fjorgemota.com/git-sistema-de-controle-de-versoes-distribuido/" data-type="post" data-id="1435">Git - que você pode ler mais sobre nesse post</a> - com o seguinte arquivo - chamado <strong>index.php</strong> -  comittado:</p>



<pre class="wp-block-code"><code lang="php" class="language-php line-numbers">&lt;?php
// Pega o nome da URL, ou assume o padrão "Mundo", e converte caracteres HTML de forma que não seja possível injetar JS/CSS na página:
$nome = htmlspecialchars( $_GET["name"] ?? "Mundo" );
// Imprime "Olá, " seguido do valor da variável acima
echo "Olá, {$nome}";</code></pre>



<p>E também tenha no repositório os arquivos "composer.json" e "composer.lock" criados pelo <a href="https://fjorgemota.com/composer-como-gerenciar-dependencias-no-php-facilmente/" data-type="post" data-id="1585">Composer, sobre o qual já falei aqui</a> (você pode rodar <code>composer init</code> e responder todas as perguntas para configurar o Composer corretamente).  </p>



<p class="has-foreground-color has-light-green-cyan-background-color has-text-color has-background">Apesar da criação dos arquivos <code>composer.json</code> e <code>composer.lock</code> não ser SUPER necessária - visto que o Dokku consegue detectar que se trata de um projeto que usa PHP à partir da existência do arquivo <code>index.php</code> - é algo que é recomendado, visto que o modo de detecção a partir da existência de arquivos PHP é considerado depreciado.</p>



<p>Antes de fazer o deploy dessa aplicação, que vamos chamar aqui de <strong>hello</strong>, você primeiramente precisa criar a aplicação no Dokku. Para isso, você pode usar o seguinte comando, que usa o cliente oficial do Dokku mencionado anteriormente:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku apps:create hello</code></pre>



<p>Depois de criado, você pode simplesmente rodar o seguinte comando para fazer o deploy do projeto, assumindo que a branch principal do repositório em questão é a branch <code>main</code>, e que você fez o commit nessa branch:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">git push dokku main</code></pre>



<p>Depois de rodar o comando, o Dokku analisará o conteúdo do repositório e rapidamente constatará que se trata de uma aplicação em PHP, usando um projeto chamado <a href="https://github.com/gliderlabs/herokuish">Herokuish</a>. A partir daí, será usado o <a href="https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-php">buildpack do Heroku para PHP</a> para fazer o deploy da sua aplicação, que deverá estar disponível em <code>hello.SEU_DOMINIO</code>.</p>



<p>Como eu possuo Dokku instalado nesse mesmo servidor, você pode ver a aplicação rodando aqui: <a href="http://hello.fjorgemota.com/?name=World">http://hello.fjorgemota.com/?nome=Teste</a> - sinta-se a vontade para mudar o parâmetro <code>nome</code> para qualquer outra coisa apenas para experimento. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> </p>



<h2 class="wp-block-heading">Conectando um banco de dados</h2>



<p>Naturalmente, fazer uma simples aplicação assim não mostra o potencial completo da ferramenta. Em virtude disso, vamos complicar um pouquinho o exemplo: Em vez de um simples código PHP que printa um parâmetro recebido na URL, vamos fazer um contador de visitas...bem simples, mas enfim.</p>



<p>Para isso, no repositório Git criado anteriormente, adicione o seguinte código no final do arquivo <strong>index.php: </strong></p>



<pre class="wp-block-code"><code lang="php" class="language-php line-numbers">// Captura a URL da variável de ambiente e divide em partes
$parametros = parse_url( getenv( "DATABASE_URL" ) );
// Gera a URL para passar para o PDO, contendo os dados de configuração do banco de dados
$url = sprintf( "pgsql:host=%s;port=%d;dbname=%s;user=%s;password=%s", $parametros['host'], $parametros['port'],  substr( $parametros['path'], 1 ), $parametros['user'], $parametros['pass'] );
// Conecta oa banco de dados
$conexao = new PDO( $url );
// Faz a consulta para contar o número de visitas e retornar o número atualizado
$consulta = $conexao-&gt;query( "INSERT INTO visits ( id, num_visits ) VALUES( 1, 1 ) ON CONFLICT (id) DO UPDATE SET num_visits = visits.num_visits + EXCLUDED.num_visits RETURNING num_visits");
// Captura o número de visitas retornado pelo banco de dados
$visitas = $consulta-&gt;fetchColumn( 0 );
// Imprime o resultado na página
echo "&lt;br /&gt; Número de visitas: {$visits}";</code></pre>



<p>Depois de adicionar esse script ao arquivo, lembre-se de comittar e enviar o resultado para o Dokku, usando <code>git push dokku main</code> como definido acima.</p>



<p>Como você pode imaginar, isso não vai ser suficiente: Estamos aqui usando o <code><a href="https://www.php.net/manual/pt_BR/intro.pdo.php">PDO</a></code> com o <code><a href="https://www.php.net/manual/pt_BR/ref.pdo-pgsql.php">PDO_PGSQL</a></code> para conectar a um banco de dados PostgreSQL, que é um <a href="https://fjorgemota.com/sgbds-sistemas-gerenciadores-de-bancos-de-dados-o-que-sao-como-vivem-e-onde-podem-ser-encontrados/" data-type="post" data-id="1081">SGBD bastante completo</a>. Só que, no momento, o Dokku não faz a mínima ideia dessa dependência do PostgreSQL pra começo de conversa. Portanto, vamos por partes: Vamos configurar o PostgreSQL no Dokku. Felizmente, graças ao fato de que o PHP que o Dokku usa vem com o PDO e o PDO_PGSQL (<a href="https://devcenter.heroku.com/articles/php-support">conforme listado aqui</a>) ativado por padrão, não vamos precisar nos preocupar com a configuração do mesmo.</p>



<p>Para configurar o PostgreSQL no Dokku, primeiramente você precisa instalar o <em>plugin</em> <code>dokku-postgres</code>, que permite criar e gerenciar "serviços" PostgreSQL, e também integrá-los com sua aplicação. Para fazer isso, basta rodar o comando abaixo:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres</code></pre>



<p>Agora, vamos criar o "serviço", que nada mais é do que o <a href="https://fjorgemota.com/docker-containers-para-a-vida-ou-nao/" data-type="post" data-id="1366">container Docker</a> rodando o PostgreSQL. Esse serviço se chamará <code>pgdb</code>:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku postgres:create pgdb</code></pre>



<p>Finalmente, vamos conectar o serviço criado com a nossa aplicação <code>hello</code>:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku postgres:link pgdb hello</code></pre>



<p>Com isso feito, deveremos ter uma variável de ambiente (ou <em>environment variable</em>, em inglês) chamada <code>DATABASE_URL</code> com as informações necessárias para se conectar ao serviço <code>pgdb</code>, que é basicamente o nosso servidor PostgreSQL. Entretanto, falta uma coisa importante: criar a tabela <code>visits</code>, que o nosso script em PHP usa para contar as visitas. Para fazer isso, primeiro, conecte ao PostgreSQL usando o comando abaixo:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku postgres:connect pgdb</code></pre>



<p>E então execute o seguinte SQL para criar a tabela <code>visits</code>:</p>



<pre class="wp-block-code"><code lang="sql" class="language-sql">CREATE TABLE visits(id INT PRIMARY KEY NOT NULL, num_visits INT NOT NULL);</code></pre>



<p>Agora, acesse sua aplicação e verifique que, a cada vez que você atualiza a página, o contador é devidamente incrementado, como se espera de um contador de visitas.</p>



<h2 class="wp-block-heading">Configurando sua aplicação</h2>



<p>O Dokku fornece uma forma fácil de configurar sua aplicação através do uso de variáveis de ambiente, que são úteis para definir parâmetros diversos da sua aplicação. Alguns exemplos que me vem à mente são configurações do servidor de e-mail, configurações de log (para usos mais robustos além do tradicional <code>dokku logs</code>) e outras configurações mais específicas da sua aplicação, como...fuso horário padrão.</p>



<p>Para configurar uma variável de ambiente, você pode usar o comando <code>dokku config</code>. No script acima, se você mudar a linha:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">$nome = htmlspecialchars( $_GET["nome"] ?? "Mundo" );</code></pre>



<p>Por:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">$nome = htmlspecialchars( $_GET["nome"] ?? getenv("DEFAULT_NAME") ?? "Mundo" );</code></pre>



<p>Você se torna apto a usar a variável de ambiente <code>DEFAULT_NAME</code> para mudar o nome que deve aparecer por padrão caso o parâmetro não seja definido na URL. Com o Dokku, você pode configurar tal variável de ambiente usando o seguinte comando, que configurará o valor para "User":</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku config:set DEFAULT_NAME=Usuário</code></pre>



<h2 class="wp-block-heading">Escalonando a aplicação</h2>



<p>Vamos dizer que sua aplicação é um sucesso absoluto! E que, graças a isso, não é mais suficiente rodar sua aplicação com apenas um processo. O Dokku fornece um comando simples para ajudar nisso, inclusive configurando balanceamento de carga para você. Por exemplo, para ter 4 instâncias da sua aplicação rodando, você pode rodar o seguinte comando:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">dokku ps:scale hello web=4</code></pre>



<p>Note, entretanto, que as 4 instâncias da aplicação ainda estarão rodando dentro do mesmo servidor. Na maior parte dos casos, isso pode ser suficiente, em especial se o seu servidor possuir vários núcleos. </p>



<p>Entretanto, em um dado momento, se torna interessante ter vários servidores operando. Para fazer isso, o processo é BEM mais complicado, e envolve o uso de sistemas como o <a href="https://dokku.com/docs/deployment/schedulers/kubernetes/">Kubernetes, com o qual é possível integrar usando um plugin do Dokku</a>. Em virtude disso, eu não vou cobrir esse assunto aqui, mas, é algo que é interesante saber de qualquer forma. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> </p>



<h2 class="wp-block-heading">Conclusão</h2>



<p>Como é possível ver, o Dokku facilita e muito todo o processo de deploy e configuração da sua aplicação. No geral, todo o uso da ferramenta é muito inspirado pelo <a href="https://heroku.com/" data-type="URL" data-id="https://heroku.com/">Heroku</a>, que foi pioneiro nessa abordagem de deploy e configuração. </p>



<p>Apesar disso, o fato é que, honestamente, a grande maior parte dos projetos NÃO precisam de algo tão robusto e nem tão caro quanto o Heroku, e aí o Dokku começa a se tornar muito mais interessante, visto que com um simples VPS (que hoje você consegue contratar por menos de 5 dólares ao mês), você consegue hospedar diversas aplicações E ainda ter todas essas facilidades de forma bem tranquila, o que é útil em especial se as suas aplicações não tem como meta retorno financeiro (que é o meu caso).</p>



<p>"Mas, Fernando, eu trabalho para uma empresa pequena, vale a pena usar Dokku?" - Bom, eu diria que depende muito. Se vocês tem condições de ter um VPS (e há, por exemplo, há uma pessoa trabalhando com a infraestrutura da empresa), a resposta é... Talvez. </p>



<p>Na prática, entretanto, se você tem um projeto que possui retorno financeiro, quase sempre vale considerar fortemente o uso de um serviço como o Heroku (ou um de seus concorrentes), simplesmente pela paz de espírito que se tem ao poder dormir à noite ou passar o tempo livre, e também por todo o suporte que você tem ao usar algo especializado do tipo. </p>



<p>Bom, espero que tenham gostado da leitura, e deixem nos comentários: como é o processo de deploy do seu último projeto?</p>
]]></content:encoded>
					
					<wfw:commentRss>https://fjorgemota.com/2023/03/30/dokku-deploy-simplificado-para-os-seus-projetos/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">6337</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Object Caching 53/88 objects using APC
Page Caching using Disk: Enhanced 
Lazy Loading (feed)
Minified using Disk

Served from: fjorgemota.com @ 2026-04-04 13:13:58 by W3 Total Cache
-->