Jekyll2019-09-10T06:07:33-05:00https://www.rafaelhdr.com.br/rafaelhdrPersonal website for rafaelhdr. Developer since 15 years old. Always learning. Likes Linux, DevOps, Python, node.js, Docker and much more.Learning docker compose2019-09-09T06:00:00-05:002019-09-09T06:00:00-05:00https://www.rafaelhdr.com.br/blog/learning-docker-compose<h1 id="aprendendo-docker-compose">Aprendendo docker compose</h1>
<p>Nesse post, vou explicar um pouco como fazer uma aplicação simples usando docker-compose. Farei uma aplicação web com Flask utilizando banco de dados MariaDB.</p>
<p>Ela será simples, sem dados ou algum migration com o banco de dados. O foco do post será entender o docker-compose.</p>
<h2 id="aplicação-flask">Aplicação Flask</h2>
<p>Usarei o Flask para essa aplicação simples. Ela terá apenas 2 endpoints. Um será apenas uma mensagem estática e o outro fará uma requisição para o banco de dados.</p>
<p>A estrutura será a seguinte:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>├── application
│ ├── Dockerfile
│ └── src
│ ├── app.py
│ └── requirements.txt
└── docker-compose.yml
</code></pre></div></div>
<ul>
<li><em>Dockerfile</em> contém a nossa imagem Docker.</li>
<li><em>app.py</em> é a nossa aplicação.</li>
<li><em>requirements.txt</em> contém as dependências do nosso projeto.</li>
<li><em>docker-compose.yml</em> é para orquestrar os nossos serviços (a aplicação e o banco de dados).</li>
</ul>
<p>O código de exemplo está no <a href="https://gitlab.com/rafaelhdr/docker-compose-example">GitLab</a></p>
<h3 id="apppy">app.py</h3>
<p>Nossa aplicação possui esses 2 endpoints: <code class="highlighter-rouge">/</code> e <code class="highlighter-rouge">/db</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">pymysql.cursors</span>
<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="n">connection</span> <span class="o">=</span> <span class="n">pymysql</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">'database'</span><span class="p">,</span>
<span class="n">user</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">'MYSQL_USER'</span><span class="p">),</span>
<span class="n">password</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">'MYSQL_PASSWORD'</span><span class="p">),</span>
<span class="n">db</span><span class="o">=</span><span class="s">'application_db'</span><span class="p">,</span>
<span class="n">charset</span><span class="o">=</span><span class="s">'utf8mb4'</span><span class="p">,</span>
<span class="n">cursorclass</span><span class="o">=</span><span class="n">pymysql</span><span class="o">.</span><span class="n">cursors</span><span class="o">.</span><span class="n">DictCursor</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
<span class="k">return</span> <span class="n">f</span><span class="s">'Application /'</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/db'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">db</span><span class="p">():</span>
<span class="n">cur</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"SELECT VERSION() AS db_version"</span><span class="p">)</span>
<span class="n">version</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
<span class="k">return</span> <span class="p">(</span><span class="n">f</span><span class="s">'Database /db<br /></span><span class="se">\n</span><span class="s">'</span>
<span class="n">f</span><span class="s">'Version of database: {version["db_version"]}'</span><span class="p">)</span>
</code></pre></div></div>
<p>A aplicação usa os primeiros exemplos que encontrei para flaks e pymysql.</p>
<p>O endpoint <code class="highlighter-rouge">/</code> é apenas para imprimir um texto simples e <code class="highlighter-rouge">/db</code> se conecta ao banco de dados e escreve a versão.</p>
<h3 id="requirementstxt">requirements.txt</h3>
<pre><code class="language-txt">Flask==1.1.1
PyMySQL==0.9.3
</code></pre>
<p>Esse arquivo contém as dependências do projeto.</p>
<h3 id="dockerfile">Dockerfile</h3>
<p>O Dockerfile tem comentários para ajudar a entender o que ele está fazendo. Ele está copiando a pasta <code class="highlighter-rouge">src</code> para a imagem, instalando os requerimentos e definindo o comando para inicializar.</p>
<pre><code class="language-Dockerfile">FROM python:3.7
# Copy full application to the image
# For real environments, consider customize .dockerignore
COPY src /opt/application
# This is to make it easier. The defaul PWD where you
# start when using your application
WORKDIR /opt/application
RUN pip install -r requirements.txt
# Run default flask, but allow remote access
CMD flask run --host=0.0.0.0
</code></pre>
<h3 id="docker-composeyml">docker-compose.yml</h3>
<p>Esse arquivo vai listar os serviços e suas variáveis.</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">3.7"</span>
<span class="na">services</span><span class="pi">:</span>
<span class="na">application</span><span class="pi">:</span>
<span class="na">build</span><span class="pi">:</span> <span class="s">application</span>
<span class="na">links</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">database</span>
<span class="na">ports</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s2">"</span><span class="s">5000:5000"</span>
<span class="na">environment</span><span class="pi">:</span>
<span class="na">FLASK_DEBUG</span><span class="pi">:</span> <span class="s2">"</span><span class="s">1"</span>
<span class="na">MYSQL_USER</span><span class="pi">:</span> <span class="s2">"</span><span class="s">application"</span>
<span class="na">MYSQL_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">password"</span>
<span class="na">MYSQL_DATABASE</span><span class="pi">:</span> <span class="s2">"</span><span class="s">application_db"</span>
<span class="na">volumes</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">./application/src:/opt/application</span>
<span class="na">database</span><span class="pi">:</span>
<span class="na">image</span><span class="pi">:</span> <span class="s">mariadb:10.4</span>
<span class="na">environment</span><span class="pi">:</span>
<span class="na">MYSQL_RANDOM_ROOT_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">yes"</span>
<span class="na">MYSQL_DATABASE</span><span class="pi">:</span> <span class="s2">"</span><span class="s">application_db"</span>
<span class="na">MYSQL_USER</span><span class="pi">:</span> <span class="s2">"</span><span class="s">application"</span>
<span class="na">MYSQL_PASSWORD</span><span class="pi">:</span> <span class="s2">"</span><span class="s">password"</span>
</code></pre></div></div>
<p>O serviço de banco de dados está definindo a imagem a ser utilizada e as variáveis de ambiente. Nós não fazemos modificações na imagem.</p>
<p>Mas nossa aplicação precisa de customização (definida em nosso Dockerfile).</p>
<ul>
<li><code class="highlighter-rouge">build: application</code> define onde o nosso Dockerfile está. Nossa imagem será criada com base nele.</li>
<li><code class="highlighter-rouge">links:</code> é a lista de conexões entre nossos serviços. Nossa aplicação precisa se conectar ao banco de dados.</li>
<li><code class="highlighter-rouge">ports:</code> é a lista de portas conectadas com o host (seu computador). Nesse exemplo, se acessar <code class="highlighter-rouge">localhost:5000</code> no meu navegador local, ele irá responder com o <code class="highlighter-rouge">localhost:5000</code> do container.</li>
<li><code class="highlighter-rouge">environment:</code> é a lista com a variáveis de ambiente passadas para o container.</li>
<li><code class="highlighter-rouge">volumes:</code> é a lista de volumes utilizados. Aqui, estou montando o código-fonte na imagem. A razão para isso é que se eu realizar mudanças no host, elas serão atualizadas no container. Também porque configurei no flask <code class="highlighter-rouge">FLASK_DEBUG: "1"</code>.</li>
</ul>
<h2 id="rodando">Rodando</h2>
<p>Agora você precisa apenas rodar com o comando <code class="highlighter-rouge">docker-compose up</code>.</p>
<p>Página estática</p>
<p><img src="/assets/posts/2019-09-05-learning-docker-compose/application.png" alt="application" /></p>
<p>Página fazendo conexão com o banco de dados</p>
<p><img src="/assets/posts/2019-09-05-learning-docker-compose/database.png" alt="database" /></p>
<h2 id="alguns-truques">Alguns truques</h2>
<h3 id="rodar-em-background">Rodar em background</h3>
<p>Para rodar em background basta adicionar uma flag <code class="highlighter-rouge">docker-compose up -d</code>. Seu terminal não estará preso ao docker. Se você quiser ver os logs, rode <code class="highlighter-rouge">docker-compose logs</code> (para ver todos os logs), <code class="highlighter-rouge">docker-compose logs -f</code> (para ver todos os logs e seguir os seguintes) ou <code class="highlighter-rouge">docker-compose logs application</code> (para filtrar os logs de um determinado serviço).</p>
<h3 id="compose-network">Compose network</h3>
<p>Não sei se você percebeu, mas não precisei mapear o hostname do banco de dados. O Docker já o criou para mim.</p>
<p>Isso aconteceu porque ligamos os serviços:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> links:
- database
</code></pre></div></div>
<p>No caso, usamos o mesmo nome do serviço como db hostname da aplicação.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>host='database',
</code></pre></div></div>
<h3 id="debug-container">Debug container</h3>
<p>Você também pode inspecionar o container roando o comando <code class="highlighter-rouge">docker-compose exec application bash</code>.</p>
<h3 id="mudar-portas">Mudar portas</h3>
<p>Você não precisa usar a porta 5000 de seu host. Você pode escoolher qualquer outra. (exemplo: no arquivo <code class="highlighter-rouge">docker-compose.yml</code>, você poderia mudar para <code class="highlighter-rouge">8000:5000</code>)</p>
<h3 id="mudando-o-dockerfile">Mudando o Dockerfile</h3>
<p>Se você fizer mudanças que alterem a imagem gerada, será necessário build da imagem.</p>
<p>Por exemplo, se você começar seu projeto (<code class="highlighter-rouge">docker-compose up</code>) e depois atualizar o <code class="highlighter-rouge">requirements.txt</code>.</p>
<p>Você pode fazer isso rodando <code class="highlighter-rouge">docker-compose build</code>.</p>Aprendendo docker composeComeçando com Docker2019-08-28T06:00:00-05:002019-08-28T06:00:00-05:00https://www.rafaelhdr.com.br/blog/starting-with-docker<h1 id="como-fazer-um-pr">Como fazer um PR</h1>
<p>Nesse post, explicarei um pouco como usar o Docker. Basicamente, vou abordar o comando <code class="highlighter-rouge">run</code> a alguns truques.</p>
<h2 id="run">Run</h2>
<p>Esse comando vai rodar um container com uma imagem já existente.</p>
<p>Se você quiser rodar o Ubuntu localmente, deve rodar apenas <code class="highlighter-rouge">docker run ubuntu</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run -it ubuntu
root@aacdec8ea1e8:/# echo test
test
root@aacdec8ea1e8:/#
</code></pre></div></div>
<p>A primeira linha (<code class="highlighter-rouge">docker run -it ubuntu</code>) rodou no meu host (meu Sistema Operacional, não no container docker).
A segunda linha (<code class="highlighter-rouge">echo test</code>) rodou no container Ubuntu.</p>
<p>P.S.: A flag <code class="highlighter-rouge">-it</code> é para conectar o seu terminao com o container (para ver o que acontece dentro do container).</p>
<p>Poderiamos user outras imagens (debian, centos, python…). No <a href="https://hub.docker.com/">Docker Hub</a> você pode encontrar diversas outras imagens.</p>
<h3 id="usar-outra-versão">Usar outra versão</h3>
<p>Também é possível usar diferentes versões do Ubuntu. Nós precisamos apenas usar uma tag diferente para a versão.</p>
<p>Podemos usar o Ubuntu 19.04 usando o comando <code class="highlighter-rouge">docker run ubuntu:19.04</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run -it ubuntu:19.04
root@bc620ad9745b:/# cat /etc/*release | grep VERSION_ID
VERSION_ID="19.04"
root@bc620ad9745b:/# exit
exit
$ docker run -it ubuntu
root@6acfdb1bff1d:/# cat /etc/*release | grep VERSION_ID
VERSION_ID="18.04"
</code></pre></div></div>
<p>Por padrão, usa-se a tag <code class="highlighter-rouge">latest</code>, ou seja, rodar o comando <code class="highlighter-rouge">docker run ubuntu</code> é o mesmo que rodar <code class="highlighter-rouge">docker run ubuntu:latest</code>. Hoje, o <code class="highlighter-rouge">latest</code> é o mesmo que <code class="highlighter-rouge">18.04</code>. No lançamento do próximo Ubuntu LTS a versão latest será a <code class="highlighter-rouge">20.04</code>.</p>
<h3 id="mudar-o-comando-padrão">Mudar o comando padrão</h3>
<p>Cada imagem tem um comando padrão para rodar. Quando usamos <code class="highlighter-rouge">docker run -it ubuntu</code>, ele automaticamente roda <code class="highlighter-rouge">bash</code>. Mas quando usamos uma imagem python, ele roda o comando <code class="highlighter-rouge">python</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run --rm -it python
Python 3.7.4 (default, Aug 14 2019, 12:09:51)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('hello')
hello
</code></pre></div></div>
<p>Você pode mudar o comando padrão. Por exemplo, caso queira instalar algo antes do comando padrão.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run --rm -it python bash
root@1db1de2e11cc:/# pip install awscli
Collecting awscli
Downloading https://files.pythonhosted.org/packages/97/72/bafa0c932416fb91c87f172cd4b0fdff5be32e4d01a3c89c8ae03549d7c3/awscli-1.16.229-py2.py3-none-any.whl (2.0MB)
|████████████████████████████████| 2.0MB 2.2MB/s
...
Building wheels for collected packages: PyYAML
Building wheel for PyYAML (setup.py) ... done
Created wheel for PyYAML: filename=PyYAML-5.1.2-cp37-cp37m-linux_x86_64.whl size=468680 sha256=df0859d47787aaf4e7b2b2e1f5720ab061297d9b3c2519b32f5254217b77fd51
Stored in directory: /root/.cache/pip/wheels/d9/45/dd/65f0b38450c47cf7e5312883deb97d065e030c5cca0a365030
Successfully built PyYAML
Installing collected packages: pyasn1, rsa, docutils, six, python-dateutil, urllib3, jmespath, botocore, s3transfer, colorama, PyYAML, awscli
Successfully installed PyYAML-5.1.2 awscli-1.16.229 botocore-1.12.219 colorama-0.3.9 docutils-0.15.2 jmespath-0.9.4 pyasn1-0.4.6 python-dateutil-2.8.0 rsa-3.4.2 s3transfer-0.2.1 six-1.12.0 urllib3-1.25.3
root@1db1de2e11cc:/# python
Python 3.7.4 (default, Aug 14 2019, 12:09:51)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import awscli
>>> # Do things with awscli
</code></pre></div></div>
<h3 id="conectar-de-um-terminal-diferente">Conectar de um terminal diferente</h3>
<p>Vamos rodar o servidor em um terminal e criar arquivos em outro.</p>
<p>Terminal 1</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run -it -p 8000:8000 python bash
root@1e171a55d01f:/# python -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
</code></pre></div></div>
<p>Terminal 2</p>
<p>Execute o comando <code class="highlighter-rouge">ps</code> para obter o container ID e se conectar ao container usando o comando <code class="highlighter-rouge">exec</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e171a55d01f python "bash" 42 seconds ago Up 41 seconds 0.0.0.0:8000->8000/tcp stupefied_heyrovsky
$ docker exec -it 1e171a55d01f bash
root@1e171a55d01f:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@1e171a55d01f:/# echo 'My site' > index.html
</code></pre></div></div>
<p>Se você acessar <a href="http://localhost:8000/">localhost:8000</a> verá a página simples que acabou de ser criada.</p>
<p><img src="/assets/posts/2019-08-28-starting-with-docker/my-site.png" alt="My site example" /></p>
<h2 id="dicas">Dicas</h2>
<h3 id="usar-a-flag-rm">Usar a flag –rm</h3>
<p>Quando você roda esses comandos os containers são criados mas não apagados depois de utilizá-los. No fim, você terá diversos containers antigos ocupando espaço.</p>
<p>Você pode encontrar esses containers rodando <code class="highlighter-rouge">docker ps -a</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e171a55d01f python "bash" 10 minutes ago Up 10 minutes 0.0.0.0:8000->8000/tcp stupefied_heyrovsky
6acfdb1bff1d ubuntu "/bin/bash" 2 hours ago Exited (0) 22 minutes ago cranky_booth
bc620ad9745b ubuntu:19.04 "/bin/bash" 2 hours ago Exited (0) 2 hours ago gracious_hopper
</code></pre></div></div>
<p>Se você rodar a flag <code class="highlighter-rouge">--rm</code> isso não acontecerá. Por exemplo: <code class="highlighter-rouge">docker run -it --rm ubuntu</code>.</p>
<h3 id="limpar-imagens">Limpar Imagens</h3>
<p>Você também pode limpar espaço rodando o comando <code class="highlighter-rouge">prune</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker system prune -a
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all images without at least one container associated to them
- all build cache
Are you sure you want to continue? [y/N] y
...
</code></pre></div></div>
<p>Por agora, esse comando não tempo problema pois não criamos muitas coisas. Mas precisa tomar cuidado para não apagar nada importante (se por acaso algo importante estiver rodando, ele não será apagado).</p>
<h2 id="resumo">Resumo</h2>
<p>Esse é apenas o básico de tarefas com o docker. Espero que você tenha entendido um pouco mais sobre ele.</p>
<p>Outra possibilidade é rodar 2 containers (por exemplo, um site PHP e um banco de dados). Eu expliquei no <a href="https://stackoverflow.com/questions/43127599/connect-to-mysql-server-from-php-with-docker/43128428#43128428">StackOverflow</a> como fazer isso.</p>
<p>Isso é interessante para o aprendizado, mas eu prefiro usar o docker-compose para isso.</p>
<p>Veja o post sobre <a href="/blog/learning-docker-compose">docker-compose</a>.</p>Como fazer um PRHow to make a PR2018-12-23T05:00:00-06:002018-12-23T05:00:00-06:00https://www.rafaelhdr.com.br/blog/how-to-make-a-pr<h1 id="como-fazer-um-pr">Como fazer um PR</h1>
<p>Esse tutotial ensina como fazer um PR (Pull Request, que é integrar seu código git)</p>
<h2 id="pegue-o-código">Pegue o código</h2>
<p>Usarei o meu repositório <a href="https://gitlab.com/rafaelhdr/pr-example">pr tutorial repository</a> como examplo. Você pode usá-lo, mas eu recomendo que você use o seu próprio.</p>
<p><code class="highlighter-rouge">git clone git@gitlab.com:rafaelhdr/pr-example.git</code></p>
<h3 id="use-código-recente">Use código recente</h3>
<p><em>(você pode pular esse passo, se clonou o repositório)</em></p>
<p>A maioria do tempo você não estará clonando um repositório, mas usando um já existente. Nesse caso, vá para a branch master e atualize o código.</p>
<p><code class="highlighter-rouge">git checkout master</code> para ir a branch master</p>
<p><code class="highlighter-rouge">git pull origin master</code> para atualizar com o código mais recente</p>
<h2 id="branch">Branch</h2>
<p>Vamos criar um novo branch com as mudanças. Criaremos o novo branch, e faremos um Pull Reqquest para integrar o código com suas mudanças à branch master (normalmente master, mas pode ser outra).</p>
<p><code class="highlighter-rouge">git branch make-chapter-2</code> para criar a nova branch make-chapter-2</p>
<p><code class="highlighter-rouge">git checkout make-chapter-2</code> para ir a essa nova branch</p>
<blockquote>
<p>Dica: Os dois comandos acima poderiam ser substituídos por <code class="highlighter-rouge">git branch -b make-chapter-2</code></p>
</blockquote>
<p>Mude algo no código (examplo: adicione um parágrapho lorem ipsum a content.txt).</p>
<p><code class="highlighter-rouge">git add content.txt</code> para adicionar o código ao commit</p>
<p><code class="highlighter-rouge">git commit -m "make chapter 2"</code> para criar um commit com essas mudanças</p>
<p>Agora, seu código local está atualizado. We precisamos apenas colocar no servidor (no meu caso, GitLab).</p>
<p><code class="highlighter-rouge">git push origin make-chapter-2</code></p>
<h2 id="pronto">Pronto</h2>
<p>O código está pronto. Você pode vê-lo no GitLab (e integrar de lá).</p>Como fazer um PRDeploy de aplicação hello world no Kubernetes GKE2018-06-08T06:00:00-05:002018-06-08T06:00:00-05:00https://www.rafaelhdr.com.br/blog/deploying-hello-world-application-to-gke<h1 id="deploy-de-aplicação-hello-world-no-kubernetes-gke">Deploy de aplicação hello world no Kubernetes GKE</h1>
<p>Esse tutorial é para deploy de uma aplicação simple no <a href="https://cloud.google.com/kubernetes-engine/">Google Kubernetes Engine</a>.</p>
<p>Mas para começar, você precisa de:</p>
<ul>
<li><a href="https://cloud.google.com/sdk/">gcloud</a> linha de comando instalada e configurada</li>
<li><a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/">kubectl</a> linha de comando instalada</li>
</ul>
<p>É melhor se você já souber os básico de Docker. Eu criei uma imagem <code class="highlighter-rouge">rafaelhdr/server-hello</code> para isso. Essa imagem apenas responde <code class="highlighter-rouge">Hello, World!</code> para <code class="highlighter-rouge">GET /</code>.</p>
<h2 id="crie-o-cluster">Crie o cluster</h2>
<p><code class="highlighter-rouge">gcloud container clusters create hello-cluster</code></p>
<p>Esse comando irá criar seu cluster kubernetes. Depois de um tempo irá aparecer:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
hello-cluster us-central1-a 1.8.10-gke.0 35.226.200.163 n1-standard-1 1.8.10-gke.0 3 RUNNING
</code></pre></div></div>
<h2 id="deploy-da-aplicação">Deploy da aplicação</h2>
<p>Nós temos nosso cluster mas nenhuma aplicação rodando. Veja com os comandos abaixo.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl get deployment
No resources found.
<span class="nv">$ </span>kubectl get pods
No resources found.
</code></pre></div></div>
<p>Então vamos colocar nossa aplicação. Crie o arquivo de configuração <code class="highlighter-rouge">sh-service-lb.yaml</code>:</p>
<blockquote>
<p>Se quiser usar sua própria aplicação, mude <strong>image</strong> e <strong>cointanerPort</strong>.</p>
</blockquote>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">extensions/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">sh-deployment</span>
<span class="na">labels</span><span class="pi">:</span>
<span class="na">app</span><span class="pi">:</span> <span class="s">sh-deployment</span>
<span class="na">spec</span><span class="pi">:</span>
<span class="na">replicas</span><span class="pi">:</span> <span class="s">2</span>
<span class="na">template</span><span class="pi">:</span>
<span class="na">metadata</span><span class="pi">:</span>
<span class="na">labels</span><span class="pi">:</span>
<span class="na">app</span><span class="pi">:</span> <span class="s">sh-deployment</span>
<span class="na">spec</span><span class="pi">:</span>
<span class="na">containers</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">sh-deployment</span>
<span class="na">image</span><span class="pi">:</span> <span class="s">rafaelhdr/server-hello</span>
<span class="na">ports</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="s">5000</span>
</code></pre></div></div>
<p>Para deploy em nosso cluster, rode:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl apply <span class="nt">-f</span> sh-deployment.yaml
deployment.extensions <span class="s2">"sh-deployment"</span> created
</code></pre></div></div>
<p>Fizémos o deploy de nossa aplicação. Você pode checar rodando:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
sh-deployment 2 2 2 2 39s
<span class="nv">$ </span>kubectl get pods
NAME READY STATUS RESTARTS AGE
sh-deployment-6db6b8856d-q9j95 1/1 Running 0 53s
sh-deployment-6db6b8856d-tgmmh 1/1 Running 0 53s
</code></pre></div></div>
<p><strong>O que fizémos?</strong> - Criamos duas replicas de nossa aplicação em nosso cluster (<code class="highlighter-rouge">replicas: 2</code>). É por isso que temos 2 pods e um deployment.</p>
<blockquote>
<p><strong>O que é um Pod?</strong> É a menos unidade que colocamos no Kubernetes. Nós poderíamos ter dois containers rodando juntos, de forma que compartilhariam o mesmo volume.</p>
</blockquote>
<p>O problema é que ele ainda não está exposto. Vamos criar o Load Balancer.</p>
<h2 id="serviço-load-balancer">Serviço Load Balancer</h2>
<p>Nós vamos seguir os mesmos passos (criar arquivo de configuração e <code class="highlighter-rouge">apply</code> usando <code class="highlighter-rouge">kubectl</code>). Crie o arquivo <code class="highlighter-rouge">sh-service-lb.yaml</code>.</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">sh-service</span>
<span class="na">labels</span><span class="pi">:</span>
<span class="na">app</span><span class="pi">:</span> <span class="s">sh-service</span>
<span class="na">spec</span><span class="pi">:</span>
<span class="na">type</span><span class="pi">:</span> <span class="s">LoadBalancer</span>
<span class="na">ports</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">port</span><span class="pi">:</span> <span class="s">80</span>
<span class="na">targetPort</span><span class="pi">:</span> <span class="s">5000</span>
<span class="na">selector</span><span class="pi">:</span>
<span class="na">app</span><span class="pi">:</span> <span class="s">sh-deployment</span>
</code></pre></div></div>
<p>Agora nós rodamos o mesmo comando para esse arquivo:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl apply <span class="nt">-f</span> sh-service-lb.yaml
service <span class="s2">"sh-service"</span> created
</code></pre></div></div>
<p><strong>O que fizémos?</strong> Criamos nosso Load Balancer redirecionando requests de acesso externo (porta 80) para nosso container (porta 5000).</p>
<p>Certo. Nosso serviço foi criado, mas precisa de um tempo para iniciar. Espere o EXTERNAL-IP mudar de PENDING para um valor real:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT<span class="o">(</span>S<span class="o">)</span> AGE
kubernetes ClusterIP 10.15.240.1 <none> 443/TCP 25m
sh-service LoadBalancer 10.15.241.155 <pending> 80:30138/TCP 1s
<span class="c"># Wait some time</span>
<span class="nv">$ </span>kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT<span class="o">(</span>S<span class="o">)</span> AGE
kubernetes ClusterIP 10.15.240.1 <none> 443/TCP 27m
sh-service LoadBalancer 10.15.241.155 35.192.86.102 80:30138/TCP 1m
</code></pre></div></div>
<p>Meu IP externo é 35.192.86.102. Pegue o seu IP externo e acesse de seu navegador (http://YOUR_EXTERNAL_IP/).</p>
<h2 id="acessando-a-interface-web">Acessando a interface web</h2>
<p>Pegue o token de acesso rodando <code class="highlighter-rouge">kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | awk '/^deployment-controller-token-/{print $1}') | awk '$1=="token:"{print $2}'</code>.</p>
<p>Acesse a interface localmente por um proxy rodando <code class="highlighter-rouge">kubectl config view</code> e abrindo <a href="http://127.0.0.1:8001/ui/">http://127.0.0.1:8001/ui/</a>. Para Sign In, use o token obtido anteriormente.</p>
<h2 id="apague-tudo">Apague tudo</h2>
<p>Certo, fizémos nossos testes. Podemos remover tudo apagando nosso cluster.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcloud container clusters delete hello-cluster
The following clusters will be deleted.
- <span class="o">[</span>hello-cluster] <span class="k">in</span> <span class="o">[</span>us-central1-a]
Do you want to <span class="k">continue</span> <span class="o">(</span>Y/n<span class="o">)</span>? Y
...
</code></pre></div></div>
<h2 id="resumo">Resumo</h2>
<p>Nesse tutorial, criamos um cluster, colocamos nossa aplicação e um load balancer nele, acessamos a interface web e então deletamos esse cluster.</p>
<p>Esse é apenas o começo para o Kubernetes, mas fizémos apenas o básico. Tentarei fazer mais posts sobre Kubernetes. Enquanto isso, você poderia ver <a href="https://medium.freecodecamp.org/learn-kubernetes-in-under-3-hours-a-detailed-guide-to-orchestrating-containers-114ff420e882">Learn Kubernetes in Under 3 Hours: A Detailed Guide to Orchestrating Containers</a>. É um tutorial mais completo que esse, aprendendo os conceitos que testamos aqui mais profundamente, mas em um cluster local.</p>
<h2 id="referências">Referências:</h2>
<ul>
<li><a href="https://stackoverflow.com/questions/46664104/how-to-sign-in-kubernetes-dashboard">How to sign in kubernetes dashboard?</a></li>
<li><a href="https://cloud.google.com/kubernetes-engine/docs/quickstart">Quickstart - GKE</a></li>
<li><a href="https://kubernetes-v1-4.github.io/docs/hellonode/">Hello World Walkthrough</a></li>
</ul>Deploy de aplicação hello world no Kubernetes GKEEntendendo os parâmetros de python2018-06-05T06:00:00-05:002018-06-05T06:00:00-05:00https://www.rafaelhdr.com.br/blog/understanding-python-parameters<h1 id="entendendo-os-parâmetros-de-python">Entendendo os parâmetros de python</h1>
<p>Nesse post, vou escrever uma função simples <code class="highlighter-rouge">full_profile</code> explicando alguns conceitos sobre os parâmetros de Python. Con isso, poderemos entender como a famosa função <code class="highlighter-rouge">my_function(*args, **kwargs)</code> funciona.</p>
<h2 id="argumento-de-posição-positional-argument">Argumento de posição (Positional argument)</h2>
<p>Esse é o primeiro tipo de parâmetro que vemos. A sequência de argumentos dada é usada:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"rafael"</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Id: 1
Name: rafael
Age: 30
</code></pre></div></div>
<h2 id="argumento-de-palavra-chave-keyword-argument">Argumento de palavra-chave (Keyword argument)</h2>
<p>Algumas vezes é melhor usarmos argumento de palavra-chave para ficar mais legível.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">"rafael"</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Id: 1
Name: rafael
Age: 30
</code></pre></div></div>
<p>Em minha opinião, prefiro argumento de palavra chave pois é mais explícito (mas nem sempre, como por exemplo em <code class="highlighter-rouge">soma(1, 2)</code> por não fazer diferença a ordem).</p>
<h2 id="forçar-argumento-de-palavra-chave">Forçar argumento de palavra-chave</h2>
<p>Se você trocar a ordem dos argumentos, pode ter o seguinte problema:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="c"># If you change the order for some reason, the result will be wrong</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="s">"rafael"</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Id: 1
Name: 30
Age: rafael
</code></pre></div></div>
<p>Você pode forçar o argumento ser de palavra chave usando <code class="highlighter-rouge">*</code>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="c"># This will not work anymore</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="s">"rafael"</span><span class="p">)</span>
<span class="c"># This will work</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">"rafael"</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
<span class="c"># This result is the same</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">"rafael"</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<stdin>"</span>, line 2, <span class="k">in</span> <module>
TypeError: full_profile<span class="o">()</span> takes 1 positional argument but 3 were given
Id: 1
Name: rafael
Age: 30
Id: 1
Name: rafael
Age: 30
</code></pre></div></div>
<h2 id="adicionar-argumentos-de-posição-não-definidos">Adicionar argumentos de posição não definidos</h2>
<p>Se quisermos adicionar mais informações passadas pelo usuário, mas não definidas na função, podemos usar args.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"I am a developer"</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">"rafael"</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Id: 1
Name: rafael
Age: 30
I am a developer
</code></pre></div></div>
<p>Agora entendemos os <code class="highlighter-rouge">*args</code> do padrão <code class="highlighter-rouge">my_function(*args, **kwargs)</code>.</p>
<blockquote>
<p>Nós não precisamos usar o nome <code class="highlighter-rouge">args</code>. Poderia ser algum outro nome, como <code class="highlighter-rouge">extra</code>. É apenas umas convenção.</p>
</blockquote>
<h2 id="adicionando-argumentos-de-palavras-chave-não-definidos">Adicionando argumentos de palavras-chave não definidos</h2>
<p>Se precisarmos de mais informações passadas pelo usuário, mas não definidos pela função, podemos usar kwargs.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"{key}: {value}"</span><span class="p">)</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"I am a developer"</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">"rafael"</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">Company</span><span class="o">=</span><span class="s">"rafaelhdr"</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Id: 1
Name: rafael
Age: 30
I am a developer
Company: rafaelhdr
</code></pre></div></div>
<p>E agora entendemos o <code class="highlighter-rouge">**kwargs</code> do padrão <code class="highlighter-rouge">my_function(*args, **kwargs)</code>.</p>
<blockquote>
<p>Novamente, <code class="highlighter-rouge">kwargs</code> é a convenção, mas você pode escolher outro nome.</p>
</blockquote>
<p>Se usarmos o padrão <code class="highlighter-rouge">my_function(*args, **kwargs)</code> ele aceitará todos os casos. Mas os argumentos são todos opcionais. Se definirmos ele na função e o usuário não fornecê-lo, será levantado um erro:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">full_profile</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Id: {id}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Name: {name}"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"Age: {age}"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"{key}: {value}"</span><span class="p">)</span>
<span class="c"># age is removed of the arguments</span>
<span class="n">full_profile</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"I am a developer"</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">"rafael"</span><span class="p">,</span> <span class="n">Company</span><span class="o">=</span><span class="s">"rafaelhdr"</span><span class="p">)</span>
</code></pre></div></div>
<p>Resultado:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: full_profile() missing 1 required keyword-only argument: 'age'
</code></pre></div></div>
<h1 id="args-e-kwargs">args e kwargs</h1>
<p>Podemos pensar em <code class="highlighter-rouge">*args</code> como uma lista de <strong>argumentos de posição</strong> não definidos e <code class="highlighter-rouge">**kwargs</code> é um Dicionário de <strong>argumentos de palavra-chave</strong> não definidos.</p>
<h2 id="referência">Referência</h2>
<p><a href="https://docs.python.org/3/glossary.html#term-parameter">Python Glossary - term parameter</a></p>Entendendo os parâmetros de pythonvim para limpar tags HTML2018-05-21T16:00:00-05:002018-05-21T16:00:00-05:00https://www.rafaelhdr.com.br/blog/vim-regex-for-cleaning-html-tags<h1 id="vim-para-limpar-tags-html">VIM para limpar tags HTML</h1>
<p>Você tem um arquivo muito grande, e quer extrair algum valor em específico. Você pode usar substituição com expressão regular.</p>
<blockquote>
<p>Certo, não é apenas com VIM. Você poderia usar o grep também. Estou usando VIM pela facilidade no post.</p>
</blockquote>
<blockquote>
<p>Sim, você poderia usar um crawler para isso. No meu caso, eu só queria extrair esses valores de um único arquivo.</p>
</blockquote>
<p><strong>TL;DR</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:%g!/useful-class/d
:%s/<a.*href="\([^"]*\).*\n/\1\r/g
</code></pre></div></div>
<h2 id="arquivo-de-teste">Arquivo de teste</h2>
<p>Para testar, você pode abrir o seguinte arquivo no VIM:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SOME BIG HTML
<span class="nt"><a</span> <span class="na">class=</span><span class="s">"useful-class"</span> <span class="na">href=</span><span class="s">"http://example/1"</span><span class="nt">></span>Example 1<span class="nt"></a></span>
NOT USEFUL LINE
<span class="nt"><a</span> <span class="na">class=</span><span class="s">"useful-class"</span> <span class="na">href=</span><span class="s">"http://example/2"</span><span class="nt">></span>Example 2<span class="nt"></a></span>
END OF BIG HTML
</code></pre></div></div>
<p>Em nosso exemplo, queremos remover as linhas inúteis e deixar apenas a URL.</p>
<h2 id="comandos">Comandos</h2>
<p>Limpar as linhas inúteis:</p>
<p><code class="highlighter-rouge">:%g!/useful-class/d</code></p>
<ul>
<li><strong>%g!</strong> Fazer algo em todas as linhas que não contenham certa expressão</li>
<li><strong>useful-class</strong> A expressão que estamos procurando. No caso, queremos encontrar useful-class</li>
<li><strong>d</strong> Definimos que queremos deletar quando não encontrar a expressão</li>
</ul>
<p>Remover conteúdo inútil:</p>
<p><code class="highlighter-rouge">:%s/<a.*href="\([^"]*\).*\n/\1\r/g</code></p>
<ul>
<li><strong>%s</strong> Substituir todas as linhas que possuam certa expressão</li>
<li>Expressão (esse é longo):
<ul>
<li><strong><a</strong> Que começa com <code class="highlighter-rouge"><a</code></li>
<li><strong>.*</strong> Com qualquer caracter até…</li>
<li><strong>href=”</strong> …até que encontre <code class="highlighter-rouge">href="</code></li>
<li><strong>\([^”]*\)</strong> e a primeira parte (chamada de “atom”) é qualquer coisa que não contenha aspas(<code class="highlighter-rouge">[^"]*</code> sem aspas). O “atom” é o conteúdo entre os parênteses(<code class="highlighter-rouge">(...)</code>)</li>
<li><strong>.*</strong> e qualquer caracter até…</li>
<li><strong>\n</strong> …até que encontre uma nova linha <code class="highlighter-rouge">\n</code></li>
</ul>
</li>
<li><strong>\1\r</strong> e substituir pelo primeiro “atom” e uma nova linha</li>
<li><strong>g</strong> rodar o comando</li>
</ul>
<h2 id="done">Done</h2>
<p>O resultado é esse:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://example/1
http://example/2
</code></pre></div></div>
<p>Não é simples, mas da segunda vez é mais fácil de lembrar.</p>
<p>Eu usei hoje para limpar um simples arquivo longo (copiei o DOM <code class="highlighter-rouge"><ul><li><a>...</a></li></ul></code>) e rodei os comandos (ao mesmo tempo que ia aprendendo também).</p>
<h2 id="referências">Referências</h2>
<ul>
<li><a href="http://vim.wikia.com/wiki/Delete_all_lines_containing_a_pattern">Delete all lines containing a pattern</a></li>
<li><a href="https://stackoverflow.com/questions/11624166/replace-while-keeping-certain-words-in-vi-vim">Replace while keeping certain “words” in vi/vim</a></li>
<li><a href="https://stackoverflow.com/questions/71323/how-to-replace-a-character-by-a-newline-in-vim">How to replace a character by a newline in Vim?</a></li>
</ul>VIM para limpar tags HTMLrafaelhdr freelancer skills2018-05-17T06:00:00-05:002018-05-17T06:00:00-05:00https://www.rafaelhdr.com.br/blog/rafaelhdr-freelancer-skills<h1 id="rafaelhdr-desenvolvedor-freelancer">rafaelhdr desenvolvedor freelancer</h1>
<p>Olá, meu nome é Rafael e sou desenvolvedor web desde 2003. Se você está aqui, talvez esteja interessado em me contratar como desenvolvedor, então gostaria de falar um pouco mais sobre minhas habilidades.</p>
<blockquote>
<p>No texto, estou adicionando alguns links a projetos open-source relacionados.</p>
</blockquote>
<p><strong>Minha principal habilidade é de backend.</strong> Eu gosto das linguagens Node.js e Python. Você poderia me contratar também para desenvolver em <a href="https://gitlab.com/shereland/graphql">Golang</a>, mas ainda sou iniciante em Go. Tenho experiência desenvolvendo aplicações monolíticas com Django e também Microserviços usando <a href="https://gitlab.com/shereland/web">Express</a>, Flask e <a href="https://github.com/rafaelhdr/portfolio-wall-app">Django</a>.</p>
<p><strong>Também sei frontend.</strong> Possuo as habilidades básicas de HTML/CSS/js e também desenvolvo usando React, tanto para <a href="https://github.com/rafaelhdr/portfolio-wall-app">single-page application (<code class="highlighter-rouge">create-react-app my-app</code>)</a> como adicionando componentes em <a href="https://gitlab.com/shereland/web">uma aplicação já existente</a>.</p>
<p><strong>DevOps é algo que gosto bastante.</strong> Comecei aprendendo Linux alguns anos atrás (~desde 2013) e Docker desde 2016. Hoje em dia, tento sempre desenvolver minhas aplicações utilizando <a href="https://gitlab.com/shereland">GitLab CI e Docker Swarm</a>.</p>
<p><a href="/portfolio">Veja meu portfolio completo</a></p>
<p>Já trabalhei com Startups (Dagood, buscador de bares, baladas e restaurantes, e Helpin, para contratar prestadores de serviços) e na área de Inovação (LARC/Scopus, um laboratório da USP desenvolvendo e pesquisando para a Scopus, que é uma empresa parceira do Bradesco).</p>
<p>E-mail: <a href=""mailto:contato@rafaelhdr.com.br"">contato@rafaelhdr.com.br</a>.</p>rafaelhdr desenvolvedor freelancerEditar commit antigo do git2018-05-13T16:00:00-05:002018-05-13T16:00:00-05:00https://www.rafaelhdr.com.br/blog/edit-previous-git-commit<h1 id="editar-commit-antigo-do-git">Editar commit antigo do git</h1>
<p>Se você cometeu algum erro em um commit anterior do git e quer editá-lo, você pode usar o git rebase para isso.</p>
<p><em>Não é recomendado se você já subiu com</em> <code class="highlighter-rouge">git push</code></p>
<p><strong>tl;dr</strong> <code class="highlighter-rouge">git rebase -i COMMITHASH</code></p>
<p>Vou explicar como fazer com um exemplo completo:</p>
<h2 id="criando-o-cenário">Criando o cenário</h2>
<p>Com os comandos abaixo, você terá três commits.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git init
<span class="nb">echo</span> <span class="s2">"first commit"</span> <span class="o">></span> file0.txt
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"first commit"</span>
<span class="nb">echo</span> <span class="s2">"some code
password forgotten
more code"</span> <span class="o">></span> file1.txt
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"commit 1"</span>
<span class="nb">echo</span> <span class="s2">"more code"</span> <span class="o">></span> file2.txt
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"commit 2"</span>
</code></pre></div></div>
<p>Temos três arquivos (file0.txt, file1.txt e file2.txt), mas um deles tem a senha escrita que foi adicionado no “commit 1”.</p>
<h2 id="git-rebase">git rebase</h2>
<p>Podemos usar o git rebase com hash ou então há 2 commits atrás.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git rebase <span class="nt">-i</span> HEAD^2
<span class="c"># OR</span>
git rebase <span class="nt">-i</span> COMMIT_1_HASH
</code></pre></div></div>
<p>Você verá algo assim (com hash diferente);</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pick 3aa4948 commit 1
pick 9e5aadf commit 2
<span class="c"># More code, even explaining the options</span>
</code></pre></div></div>
<p>Nós queremos editar o “commit 1”, então vamos mudar de <strong>pick</strong> para <strong>edit</strong> no “commit 1”:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>edit 3aa4948 commit 1
pick 9e5aadf commit 2
</code></pre></div></div>
<blockquote>
<p>Poderíamos ter utilizado apenas <code class="highlighter-rouge">e</code> ao invés de <code class="highlighter-rouge">edit</code>.</p>
</blockquote>
<p>E agora estamos no “commit 1”. Vamos remover a linha <code class="highlighter-rouge">password forgotten</code> e refazer o commit.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"some code
more code"</span> <span class="o">></span> file1.txt
git add <span class="nb">.</span>
git commit <span class="nt">--amend</span> <span class="c"># We are editing an existent commit</span>
</code></pre></div></div>
<p>E está pronto. Nós precisamos deixar o git continuar o processo com o comando <code class="highlighter-rouge">git rebase --continue</code>.</p>
<p>Você verá a seguinte mensagem: <code class="highlighter-rouge">Successfully rebased and updated refs/heads/master.</code></p>
<p>E agora está pronto para o <code class="highlighter-rouge">push</code>.</p>
<h2 id="cuidado">Cuidado</h2>
<p>Se você já fez <code class="highlighter-rouge">push</code> antes, provevalmente terá problemas. É melhor editar o arquivo (e mudar sua própria senha).</p>
<h2 id="nota-sobre-o-primeiro-commit">Nota sobre o primeiro commit</h2>
<p>O primeiro commit não é importante. Por que eu o adicionei? Porque o git rebase seria um pouco diferente.</p>
<p>Se você tentar <code class="highlighter-rouge">git rebase -i HEAD~3</code> terá o seguinte erro:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fatal: Needed a single revision
invalid upstream <span class="s1">'HEAD~3'</span>
</code></pre></div></div>
<p>Precisaria no caso usar <code class="highlighter-rouge">git rebase -i --root</code>.</p>
<h2 id="referência">Referência</h2>
<p><a href="https://git-scm.com/book/en/v2/Git-Branching-Rebasing">Git Rebasing</a></p>Editar commit antigo do gitShereland open-source2018-03-11T10:00:00-05:002018-03-11T10:00:00-05:00https://www.rafaelhdr.com.br/blog/shereland-open-source<h1 id="shereland-open-source">Shereland open-source</h1>
<p>Shereland é um site de compartilhamento de livros. É útil para encontrar os livros que seus amigos poderiam lhe emprestar.</p>
<p>Ele foi desenvolvido com Python Django, sendo um playground para praticar novas tecnologias e aprender.</p>
<p>Mas depois de aprender novas coisas na última empresa que trabalhei, resolvi mudar, usando micro-serviços, graphql e Go.</p>
<h2 id="por-quê">Por quê</h2>
<p><strong>Micro-serviços</strong> - Eu gosto de infraestrutura e microserviços me ajudarão a ter uma melhor infra para meus projetos.</p>
<p><strong>Graphql</strong> - É muito bacana. Além de fácil de usar e atualizar meus serviços.</p>
<p><strong>Go</strong> - Na verdade, ainda estou aprendendo. Eu poderia fazer meu site mais rápido com node.js e Python. Então me forcei a desenvolver em Go para aprendê-lo.</p>
<h2 id="status">Status</h2>
<p>É composto de 8 imagens Docker:</p>
<ol>
<li>Caddy Server - Servidor http com Let’s Encrypt (não é meu: <a href="https://github.com/abiosoft/caddy-docker">source</a>)</li>
<li>Graphql - Serviço de frente como api (<a href="https://gitlab.com/shereland/graphql">source</a>). Está muito grande, agrupando toda a lógica do projeto, mas deve ser quebrado em mais microserviços.</li>
<li>Monolithic DB - A base de dados com todo o projeto. Na realidade, pretendo quebrá-lo em diversas partes, uma para cada microserviço (MariaDB).</li>
<li>MySQL Docker Backuper - Serviço para fazer o backup da base de dados (<a href="https://github.com/rafaelhdr/mysql-docker-backuper">source</a>).</li>
<li>Shereland - O projeto Python Django que criei (closed-source).</li>
<li>Redis DB - Armazena as sessões de usuário e no futuro será usado como cache.</li>
<li>Thumbnail - Apenas para os albuns do blog, usando imaginary (not mine: <a href="https://github.com/h2non/imaginary">source</a>). Na realidade, é temporário. Pretendo gerar o thumbnail apenas no upload da foto, e não quando o usuário acessar.</li>
<li>Web - Front-end para o HTML (<a href="https://gitlab.com/shereland/web">source</a>).</li>
</ol>
<p>Ele está acessível como <a href="https://beta.shereland.com/blog/">beta</a>. Depois de bugfixes e mais testes colocarei como padrão.</p>
<h2 id="arrependimentos">Arrependimentos</h2>
<p>Eu queria a primeira versão bem simples. Todas as requisições para <code class="highlighter-rouge">/blog/*</code> são redirecionadas para o novo serviço. Eu queria melhorá-la primeiro pois possui muitos acessos (SEO).</p>
<p>Mas se fosse voltar atrás, eu começaria por algo ainda mais simples, apenas com graphql e usando o HTML do site legado.</p>
<h2 id="nota-sobre-os-testes">Nota sobre os testes</h2>
<p>O microserviço <strong>web</strong> tem bons testes (Unitários e de Integração com Pact). Mas eu não coloquei os testes em <strong>graphql</strong>. Por quê?</p>
<p>Pouco depois de desenvolver o microserviço <strong>web</strong> eu vi um <a href="https://medium.com/@copyconstruct/testing-microservices-the-sane-way-9bb31d158c16">post interessante sobre monitoramento “Testing Microservices, the sane way”</a>. També vi “Service Reliability Hierarchy” do <a href="https://landing.google.com/sre/book/chapters/part3.html">Google SRE Book</a>. Então decidi que vou focar inicialmente em monitoramento.</p>
<h2 id="futuro">Futuro</h2>
<p>Tem muito trabalho para fazer no Shereland. Meu foco será automação e em seguida monitoramento. O Primeiro e Segundo caminho (ver <a href="https://itrevolution.com/the-three-ways-principles-underpinning-devops/">The Three Ways</a>).</p>
<p>Automação: Fazer o pipeline de <code class="highlighter-rouge">graphql</code> e <code class="highlighter-rouge">web</code>.</p>
<p>Monitoramento: Colocar Prometheus para métricas de performance.</p>Shereland open-sourceSite estático com AWS S3 e CloudFlare2018-01-01T19:00:00-06:002018-01-01T19:00:00-06:00https://www.rafaelhdr.com.br/blog/static-website-with-aws-s3-and-cloudflare<h1 id="site-estático-com-aws-s3-e-cloudflare">Site estático com AWS S3 e CloudFlare</h1>
<blockquote>
<p>Atenção, os nomes CloudFlare (serviço próprio) e CloudFront (serviço da Amazon) são muito parecidos e então fácil de ser confundido no texto.</p>
</blockquote>
<h2 id="cloudflare-com-aws-s3">Cloudflare com AWS S3</h2>
<p>Acabei de atualizar o site rafaelhdr usando o Jekyll. Ele foi configurado para ser usado com o CloudFlare.</p>
<p>Estou usando-o para todos os meus sites, por isso não uso o AWS Route 53. Se quiser desenvolver seu site com o AWS Route 53, está documentado em <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html">AWS Documentation</a>.</p>
<h2 id="por-que-cloudflare">Por que Cloudflare</h2>
<p>Usar AWS Route 53 seria mais fácil, mas não possuo apenas o rafaelhdr. Alguns sites não estão hospedados na AWS, então escolhi usar um servidor DNS para todos eles fora da AWS.</p>
<h2 id="requerimentos">Requerimentos</h2>
<p>Para esse tutorial, estou assumindo que você sabe o básico de AWS S3, como subir arquivos, e o básico de CloudFlare, como adicionar um domínio.</p>
<h2 id="introdução">Introdução</h2>
<p>Vamos fazer esse site com poucas páginas HTML. Não vou usar um gerador HTML (como o Jekyll) porque o objetivo aqui é aprender sobre a infraestrutura. Se quiser desenvolver com o Jekyll, você pode adaptar o código daqui com o <a href="https://github.com/laurilehmijoki/s3_website">plugin s3_website</a>.</p>
<p>Depois que criarmos nosso site na AWS S3, iremos configurá-lo com o CloudFlare (e também com o CloudFront).</p>
<h2 id="aws-s3-website">AWS S3 Website</h2>
<h3 id="criar-o-bucket">Criar o bucket</h3>
<p>Faremos o upload via console de nosso novo bucket.</p>
<p>O nome do bucket deve ser o mesmo nome de seu website. Então, se você estiver criando um site chamado <em>example.com</em>, o nome de seu bucket deve ser <em>example.com</em>. Use os parâmetros padrão, exceto <strong>Manage public permissions</strong> selecionando <strong>Grant public read access to this bucket</strong>.</p>
<p>Na verdade, esse acesso público é apenas para esse tutorial. Em produção, você não precisa dele.</p>
<h3 id="subir-os-arquivos">Subir os arquivos</h3>
<p>Vamos criar um site simples com três arquivos. <code class="highlighter-rouge">index.html</code>, <code class="highlighter-rouge">page</code> e <code class="highlighter-rouge">subdir/index.html</code> (você pode baixá-los <a href="https://www.rafaelhdr.com.br/assets/posts/2018-01-02-static-website-with-aws-s3-and-cloudflare/pages.zip">aqui</a>, para economizar tempo).</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!-- index.html --></span>
<span class="nt"><h1></span>Home<span class="nt"></h1></span>
<span class="nt"><ul></span>
<span class="nt"><li></span>Home - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/"</span><span class="nt">></span>/<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/index.html"</span><span class="nt">></span>/index.html<span class="nt"></a></li></span>
<span class="nt"><li></span>Page - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/page"</span><span class="nt">></span>/page<span class="nt"></a></li></span>
<span class="nt"><li></span>Sub-index - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir"</span><span class="nt">></span>/subdir<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir/"</span><span class="nt">></span>/subdir/<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir/index.html"</span><span class="nt">></span>/subdir/index.html<span class="nt"></a></li></span>
<span class="nt"></ul></span>
</code></pre></div></div>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!-- page --></span>
<span class="nt"><h1></span>Page<span class="nt"></h1></span>
<span class="nt"><ul></span>
<span class="nt"><li></span>Home - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/"</span><span class="nt">></span>/<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/index.html"</span><span class="nt">></span>/index.html<span class="nt"></a></li></span>
<span class="nt"><li></span>Page - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/page"</span><span class="nt">></span>/page<span class="nt"></a></li></span>
<span class="nt"><li></span>Sub-index - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir"</span><span class="nt">></span>/subdir<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir/"</span><span class="nt">></span>/subdir/<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir/index.html"</span><span class="nt">></span>/subdir/index.html<span class="nt"></a></li></span>
<span class="nt"></ul></span>
</code></pre></div></div>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!-- subdir/index.html --></span>
<span class="nt"><h1></span>Sub-index<span class="nt"></h1></span>
<span class="nt"><ul></span>
<span class="nt"><li></span>Home - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/"</span><span class="nt">></span>/<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/index.html"</span><span class="nt">></span>/index.html<span class="nt"></a></li></span>
<span class="nt"><li></span>Page - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/page"</span><span class="nt">></span>/page<span class="nt"></a></li></span>
<span class="nt"><li></span>Sub-index - <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir"</span><span class="nt">></span>/subdir<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir/"</span><span class="nt">></span>/subdir/<span class="nt"></a></span> or <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/subdir/index.html"</span><span class="nt">></span>/subdir/index.html<span class="nt"></a></li></span>
<span class="nt"></ul></span>
</code></pre></div></div>
<p>Acesse seu bucket, e suba esses três arquivos (com acesso público).</p>
<blockquote>
<p>Para esse tutorial, você precisa editar o metadata de <code class="highlighter-rouge">page</code>. Clique em <code class="highlighter-rouge">page</code>, selecione Metadata e edite Content-type para <code class="highlighter-rouge">text/html</code>.</p>
</blockquote>
<p>Pegue a URL de seu bucket e teste seu novo site. Por agora, cliquei no arquivo e em seu link.</p>
<p>As páginas funcionam bem, mas não os links. Para consertar, vamos utilizar <strong>Static website hosting</strong>.</p>
<ol>
<li>Vá na raiz de seu bucket;</li>
<li>Selecione <strong>Properties</strong>;</li>
<li>Selecione <strong>Static website hosting</strong>;</li>
<li>Selecione <strong>Use this bucket to host a website</strong>;</li>
<li>Preencha <strong>index.html</strong> em <strong>Index document</strong>;</li>
<li>Copie o endpoint (em cima);</li>
<li>Salve.</li>
</ol>
<p>Você pode testar e ver todos os links funcionando bem. O problema aqui é que não queremos esse link imenso de endpoint da amazon. Ajustamos isso com o CloudFlare.</p>
<h2 id="configurando-o-cloudflare">Configurando o CloudFlare</h2>
<p>Configure seu domínio (em meu caso, é rafaelhdr.com.br) em <strong>Add site</strong>, ou apenas selecione seu domínio.</p>
<p>Na aba DNS, adicione o CNAME com seu domínio (rafaelhdr.com.br) e adicione o endpoint que você copiou do AWS S3 website (que você copiou no último passo) excluindo o protocolo, por exemplo <code class="highlighter-rouge">YOUR_DOMAIN.s3-website-us-west-2.amazonaws.com</code>.</p>
<p>E pronto. Seu site está funcionando com AWS S3 e CloudFlare.</p>
<h2 id="usando-o-cloudfront">Usando o CloudFront</h2>
<p>Então, por agora, você está usando Full SSL with CloudFlare, mas não Full (Strict). Isso significa que a conexão entre o cliente e o CloudFlare está encriptada, mas não a conexão entre o CloudFlare e AWS. Você pode resolver isso com o AWS CloudFront.</p>
<p>Vá no Console da AWS, em CloudFront.</p>
<ol>
<li>Clique em <strong>Create a Distribution</strong>;</li>
<li>Clique em <strong>Get started</strong>;</li>
<li>Selecione o seu domínio em <strong>Origin Domain Name</strong>. Mantenha todas as opções padrão, exceto:
<ul>
<li><strong>Viewer Protocol Policy</strong> selecione <strong>Redirect HTTP to HTTPS</strong>;</li>
<li><strong>Price Class</strong> selecione <strong>Use only US, Canada and Europe</strong>;</li>
<li><strong>Alternate Domain Names (CNAMEs)</strong> adicione o seu domínio;</li>
<li><strong>Default Root Object</strong> coloque <code class="highlighter-rouge">index.html</code>;</li>
<li>Depois, cheque todas as opções que melhor se encaixam para você;</li>
</ul>
</li>
<li>Clique em <strong>Create distribution</strong>.</li>
</ol>
<p>Você pode ver o progresso, e depois de um tempo, irá mudar o status de <strong>In progress</strong> para <strong>Deployed</strong>.</p>
<p>Em <strong>Domain name</strong>, você verá o nome de domínio. Você pode testá-lo.</p>
<p>E por fim, você pode editar o DNS do CloudFlare. Mude o CNAME que tinha o seu <strong>AWS S3 Static Website address</strong> para <strong>AWS CloudFront Domain Name</strong> (<code class="highlighter-rouge">SOMETHING.cloudfront.net</code>).</p>
<p>Agora seu site está funcionando com AWS S3 e CloudFronto usando o CDN do CloudFlare.</p>Site estático com AWS S3 e CloudFlare