<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bernardo</title>
    <description>The latest articles on Forem by Bernardo (@bgalvao).</description>
    <link>https://forem.com/bgalvao</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F23329%2F473e95d1-b45b-4fd4-913f-190fa7473814.jpg</url>
      <title>Forem: Bernardo</title>
      <link>https://forem.com/bgalvao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bgalvao"/>
    <language>en</language>
    <item>
      <title>Mini guide, access your k8s service local development</title>
      <dc:creator>Bernardo</dc:creator>
      <pubDate>Thu, 22 Sep 2022 19:47:33 +0000</pubDate>
      <link>https://forem.com/bgalvao/mini-guide-access-your-k8s-service-local-development-4o54</link>
      <guid>https://forem.com/bgalvao/mini-guide-access-your-k8s-service-local-development-4o54</guid>
      <description>&lt;p&gt;In a kind/minikube/etc. cluster, start a deployment (a workload resource that manages a pod replicaset)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deployment home &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;b4bz/homer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;expose the deployment, i.e. make it receive comms from other containers or the outside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl expose deploy/home &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;-&amp;gt; make sure the port exposed is actually the one the container exposes, e.g. for postgres this would 5432, for b4bz/homer it is 8080. There is no default here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The command above creates a service of the type ClusterIP, which makes it accessible to other services only within cluster.&lt;/p&gt;

&lt;p&gt;To make it accessible outside the cluster, the service has to be of type &lt;code&gt;NodePort&lt;/code&gt;, like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl expose deploy/home --type=NodePort --port 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, how to you open it in a browser using &lt;del&gt;kind&lt;/del&gt;, k8s? Well, you can port-forward from the localhost to the container port using &lt;code&gt;kubectl port-forward&lt;/code&gt; - checking out &lt;code&gt;kubectl port-forward --help&lt;/code&gt; clarifies a lot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl port-forward services/home :8080
# assigns a random localhost port to the port 8080 of the container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>learn</category>
    </item>
    <item>
      <title>Troubleshooting Traefik + Let's Encrypt + CloudFlare</title>
      <dc:creator>Bernardo</dc:creator>
      <pubDate>Wed, 26 Jan 2022 12:58:08 +0000</pubDate>
      <link>https://forem.com/bgalvao/traefik-lets-encrypt-cloudflare-36fj</link>
      <guid>https://forem.com/bgalvao/traefik-lets-encrypt-cloudflare-36fj</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://brnrdo.hashnode.dev/traefik-lets-encrypt-cloudflare" rel="noopener noreferrer"&gt;brnrdo.hashnode.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I am writing this post
&lt;/h2&gt;

&lt;p&gt;Hi. I'm a data scientist and I am currently developing a platform for MLOps using Docker Compose. This is to say, now that I am playing the role of an engineer, there are a lot of concepts that I am learning fast, and it can feel overwhelming and even scary. If you're new to deploying applications with CloudFlare and configuring a reverse-proxy with Traefik, I wrote this guide for you.&lt;/p&gt;

&lt;p&gt;The goal of this post is also to show you how you can get that sweet green lock for SSL certificates by having Traefik fetch Let's Encrypt (LE) certificates for you and how to place your application behind a CloudFlare proxy. For sake of preview, here are some pain points that I've faced as a starting engineer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloudflare as your DNS server.&lt;/li&gt;
&lt;li&gt;CloudFlare flexible, full and strict modes.

&lt;ul&gt;
&lt;li&gt;Watch out for https redirects in Traefik.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Exposing your server in CloudFlare: Development mode and temporarily disabling CloudFlare to bypass its proxy.

&lt;ul&gt;
&lt;li&gt;Traefik configuration to fetch Let's Encrypt.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This post is not supposed a complete tutorial to Docker Compose, Traefik, CloudFlare and Let's Encrypt - there is already a lot of resources out there for that purpose. Rather, it is almost a personal log of the obstacles I encountered that I hope helps other people overcome them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CloudFlare, Traefik and Let's Encrypt?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloudflare.com" rel="noopener noreferrer"&gt;&lt;strong&gt;CloudFlare&lt;/strong&gt;&lt;/a&gt; (CF) is mainly a DNS server with extra features - these extra features are attributed to CloudFlare's (reverse-)proxy functions, which you can enable and disable whenever you want.&lt;/p&gt;

&lt;p&gt;For example, you set your DNS records to point your domain and subdomains to the IP of the server where your application is running. When you set these records to 'proxied' (i.e. orange cloud) you benefit from the proxy functions that CloudFlare carries out, such as &lt;strong&gt;concealing the real IP address of your server&lt;/strong&gt; and DDoS protection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.traefik.io" rel="noopener noreferrer"&gt;&lt;strong&gt;Traefik&lt;/strong&gt;&lt;/a&gt; is a &lt;a href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/" rel="noopener noreferrer"&gt;reverse-proxy&lt;/a&gt; that sits at the edge of your application on the server. This reverse-proxy is Wait, what? Another "proxy"?! Well yes, but this Traefik is configured in your docker compose application and has no overlap in functionality with CloudFlare. Traefik will intercept requests to a given route, say &lt;code&gt;a-route.your-domain.com&lt;/code&gt; and match with any existing rules that you have set to a service running in Compose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Let's Encrypt&lt;/strong&gt;&lt;/a&gt; (LE) is a Certificate Authority (CA) that signs and ensures that your certificates are genuine to encrypt the connection between the clients and your server. The best part is that by using LE, you are taking advantage of the ACME protocol that provides you with autorenewals of your certificates. You could use a self-signed certificate, but there are &lt;a href="https://www.ssldragon.com/blog/self%20signed-ssl-certificates-disadvantages/" rel="noopener noreferrer"&gt;disadvantages to that&lt;/a&gt;. You can use Let's Encrypt from Traefik to minimize set up effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Traefik
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up proxy entrypoints
&lt;/h3&gt;

&lt;p&gt;It's best to test things locally as much as one can before deploying it to a live server. Your setup should have two entrypoints, which I have chosen to name &lt;code&gt;web&lt;/code&gt; and &lt;code&gt;websecure&lt;/code&gt; for the sake of having distinct names than &lt;code&gt;http&lt;/code&gt; and &lt;code&gt;https&lt;/code&gt;, so that we know which fields are arbitrary names given by us.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.address=:80'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.websecure.address=:443'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The entrypoints are part of the dynamic configuration of Traefik. This setup is less than ideal as it allows for unecrypted http connections. In Traefik, a &lt;a href="https://doc.traefik.io/traefik/routing/entrypoints/#redirection" rel="noopener noreferrer"&gt;redirection to https&lt;/a&gt; can be done in the following way.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.address=:80'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.http.redirections.entryPoint.to=websecure'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.http.redirections.entryPoint.scheme=https'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.websecure.address=:443'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;One of the options available from CloudFlare is none other that HTTPS redirection, so the headers are already rewritten at CloudFlare's proxy. The redirection configured in Traefik (~'origin server' as per CloudFlare's terminology) acts as a failsafe should you disable CF's proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Let's Encrypt (from Traefik)
&lt;/h3&gt;

&lt;p&gt;This step is entirely optional if you're just developing on your machine. TLS can be enabled without LE, in which case, Traefik issues its own certificates.&lt;/p&gt;

&lt;p&gt;Of course, what is desirable in production is to have CA certificates. Under the hood, Traefik uses &lt;a href="https://go-acme.github.io/lego/" rel="noopener noreferrer"&gt;&lt;code&gt;lego&lt;/code&gt;&lt;/a&gt;, an LE CLI client, to connect to LE servers and fetch certificates. You only need to supply Traefik with an email and some options and Traefik will handle the rest for you. Here's an example of a setup.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.email=${ACME_EMAIL}'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json'&lt;/span&gt;
      &lt;span class="c1"&gt;# TLS challenge serves the certificates back to the CA in order to renew them&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.tlschallenge=true'&lt;/span&gt;
      &lt;span class="c1"&gt;# Optionally use the staging server to prevent exhausting rate limits&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bare minimum is comprised of the first two lines: the email and the TLS challenge. This challenge is the simplest one to setup, as the only thing to do is to enable a boolean flag. However, taking into account CloudFlare, &lt;a href="https://community.cloudflare.com/t/renew-letsencrypt-certificate-does-not-work-with-cloudflare-proxied-on/268403/4" rel="noopener noreferrer"&gt;CF does not work with the TLS challenge&lt;/a&gt;, and either the &lt;a href="https://support.cloudflare.com/hc/en-us/articles/214820528-Validating-a-Let-s-Encrypt-Certificate-on-a-Site-Already-Active-on-Cloudflare" rel="noopener noreferrer"&gt;DNS challenge or the HTTP challenge must be configured&lt;/a&gt; in order to be able to have the edge proxy enabled.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a note, the default method used for ACME authentication by the Let's Encrypt client utilizes the DVSNI method. This will fail for a domain which has Cloudflare enabled as we terminate SSL (TLS) at our edge and the ACME server will never see the certificate the client presents at the origin. Using alternate ACME validation methods, such as DNS or HTTP will complete successfully when Cloudflare is enabled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that &lt;a href="https://traefik.io/blog/traefik-2-tls-101-23b4fbee81f1/" rel="noopener noreferrer"&gt;challenges are mutually exclusive per certificate resolver&lt;/a&gt;, and each router can only use one certificate resolver at a time. Effectively, a router can only use one type of ACME challenge at a time. The snippets below are illustrative of choosing just one ACME challenge for the &lt;code&gt;le&lt;/code&gt; certificate provider that is being configured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting up Let's Encrypt with HTTP challenge&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.httpchallenge=true'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.httpchallenge.entrypoint=web'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Setting up Let's Encrypt with DNS challenge&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.dnschallenge=true'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.le.acme.dnschallenge.provider=cloudflare'&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# you may choose to use secrets instead of environment variables like this&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CF_API_EMAIL=${CF_API_EMAIL}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CF_API_KEY=${CF_API_KEY}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this example, the &lt;code&gt;cloudflare&lt;/code&gt; provider is being used because that's where the DNS records are set up - i.e. the nameservers of the domain are pointing to CloudFlare. If you are using another DNS server, then you must &lt;a href="https://doc.traefik.io/traefik/https/acme/#providers" rel="noopener noreferrer"&gt;set the environment variables specific to your provider&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable the use of Let's Encrypt in a router
&lt;/h3&gt;

&lt;p&gt;Refer to the section &lt;a href="https://traefik.io/blog/traefik-2-tls-101-23b4fbee81f1/#using-the-certificate-resolver" rel="noopener noreferrer"&gt;Using the certificate resolver&lt;/a&gt;, this blog post will be more clear than me on how to use Traefik :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up CloudFlare
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DNS records and subdomains
&lt;/h3&gt;

&lt;p&gt;You only need one A record for the root of the platform you're developing. For any subdomain, you can set CNAMEs that point to that A record. The A record should point at the IP where Traefik is being served. Traefik will handle routing to the correct machines itself i.e. load balancing - should you have your application running in Swarm mode.&lt;/p&gt;

&lt;p&gt;For example, DNS records on CloudFlare could look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1643107269989%2F6cb9f4iiN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1643107269989%2F6cb9f4iiN.png" alt="image-20220125103230059.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a general rule, you only need to set A records (&lt;code&gt;@&lt;/code&gt; and &lt;code&gt;www&lt;/code&gt;) that point to the real IP of your server. If the services you defined in Traefik follow the template &lt;code&gt;a-service.yourdomain.com&lt;/code&gt;, then you only need to set CNAME records with the Name &lt;code&gt;a-service&lt;/code&gt; pointing to the Content &lt;code&gt;yourdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note the orange clouds: they indicate that that requests to the specificied (sub)domain are being proxied by CloudFlare's edge proxy. They can be disabled one by one, but that is not of interest to what I write in this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudFlare options
&lt;/h3&gt;

&lt;p&gt;In general, and from my experience, the default configurations work well. I only call your attention to the CF's encryption modes (which I mention in the Troubleshooting section) and the HSTS option, that could be problematic for your case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tips
&lt;/h3&gt;

&lt;p&gt;A very useful tip is to enable CF "Development Mode" so that web requests bypass any cache that CF may have created and allows you to check for changes without interference of a cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you have set up LE only with the TLS challenge&lt;/strong&gt;: use the option "Pause CloudFlare on Site" before doing &lt;code&gt;docker-compose up&lt;/code&gt; in your server. This will allow Let's Encrypt to find the real IP of your server without CF hiding it. Related with this is the use of a DNS client (or &lt;a href="https://dnschecker.org" rel="noopener noreferrer"&gt;dnschecker.org&lt;/a&gt;) to check where the nameservers are pointing your names to. Using &lt;a href="https://github.com/ogham/dog" rel="noopener noreferrer"&gt;&lt;code&gt;dog&lt;/code&gt;&lt;/a&gt; (a CLI DNS client), you should get a record pointing to the real IP of your live server:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dog some-domain.com
&lt;span class="go"&gt;A some-domain.com. 38s   xx.yyy.xx.yyy


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once the TLS challenge is complete and the certificates are issued, you should be able to check that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the certificates are stored in the &lt;code&gt;acme.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;in the browser window, at the page of the service being served at the specified route rule, you should click on the lock icon in the address bar, open "certificates" and verify that they are in fact issued by Let's Encrypt. This means you set up Traefik + LE correctly!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once everything is working as it should, you can click on the option "Enable CloudFlare on site" and let CF hide your IP again. The output of the DNS check should be something like this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dog auth.some-domain.com
&lt;span class="go"&gt;A auth.some-domain.com. 5m00s   104.21.28.234
A auth.some-domain.com. 5m00s   172.67.147.200


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Those IP's belong to CF proxy and the output confirms that CF is enabled again. &lt;/p&gt;

&lt;h2&gt;
  
  
  Some troubleshooting
&lt;/h2&gt;

&lt;p&gt;The list below describes issues that I have experienced with CloudFlare and Traefik. It may not be exactly your case, but they are noted down in case you face them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser throws &lt;code&gt;ERR_TOO_MANY_REDIRECTS&lt;/code&gt; when accessing a service&lt;/strong&gt;: If you deployed using CloudFlare's DNS servers and set CF to 'Flexible mode' then you will incurr in this error. This is because you have https from the client to the CF proxy, and forced http between the CF proxy and the server (forced by CF). As Traefik was configured with an http-to-https redirection itself, this will cause an infinite loop of redirects. In order to solve this issue, you need to set CF to Full encryption mode, and even without LE (using Traefik's self signed certificate) your website/application is now accessible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Browser throws &lt;code&gt;ERR_SSL_VERSION_OR_CIPHER_MISMATCH&lt;/code&gt; when accessing a service&lt;/strong&gt;: I ran into this error because the "edge certificates" (the certificates sitting at CloudFlare's proxy) did not have the same coverage for the routes I was setting up with Traefik.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I was setting up routes with the structure &lt;code&gt;service.platform.your-domain.com&lt;/code&gt;. This is called a 4th level subdomain.&lt;/li&gt;
&lt;li&gt;The "edge" certificates provided by CloudFlare (the "edge" being CF's proxy) only provide SSL up to 3rd level subdomains, specifically, to &lt;code&gt;your-domain.com&lt;/code&gt; and &lt;code&gt;*.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Thus the LE certificates fetch by Traefik did not match the names "made available" by CloudFlare, and the error above was produced.&lt;/li&gt;
&lt;li&gt;The only solution is to upgrade to a Enterprise subscription to CloudFlare 💸, as this allows you to issue edge certificates for any level of subdomains you want.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;I hope that you have found at least one solution to your problems if you're working with this particular set of tools (Docker Compose, Traefik, CloudFlare and Let's Encrypt). I may update this post as I add more functionalities to the platform I am developing.&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>proxy</category>
      <category>dockercompose</category>
      <category>traefik</category>
    </item>
    <item>
      <title>A docker appreciation post and use case with tensorflow</title>
      <dc:creator>Bernardo</dc:creator>
      <pubDate>Tue, 02 Jan 2018 21:12:16 +0000</pubDate>
      <link>https://forem.com/bgalvao/a-docker-appreciation-post-and-use-case-with-tensorflow-3dg4</link>
      <guid>https://forem.com/bgalvao/a-docker-appreciation-post-and-use-case-with-tensorflow-3dg4</guid>
      <description>&lt;p&gt;Recently I had to work with a code base that used tensorflow, not the current version 1.4, but version 1.2.1. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An open-source software library for Machine Intelligence&lt;br&gt;
&lt;a href="//tensorflow.org"&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, tensorflow is a library that allows you to implement machine learning algorithms, namely neural network architectures. It allows you to train a neural network using the CPU (less cores with more clock speed) or using the GPU (more cores with less clock speed). Because neural networks are highly parallelizable in the GPU, it was in my interest to run tensorflow using the GPU: less training time, more iteration for parameter tuning.&lt;/p&gt;

&lt;p&gt;However, tensorflow has some specific requirements with regards to some nvidia libraries, in order to run on the GPU:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cuda 8.0&lt;/li&gt;
&lt;li&gt;cudnn 6.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;which are legacy and some other software I use for work requires cuda 9.0... I've had my share of installing and uninstalling stuff on my system at work and didn't want to have so much hassle just for a smaller project assignment.&lt;/p&gt;

&lt;p&gt;So I thought to myself "if only there was, like, a tiny environment I could run tensorflow on the GPU... like, a docker image or something". My thoughts were heard and I could not believe my eyes when I found out that tensorflow could be run from a docker container and on the GPU :)&lt;/p&gt;

&lt;p&gt;If you don't know what docker is or how to use it, I recommend you watch the video below or the &lt;a href="https://jonnylangefeld.github.io/learning/Docker/How%2Bto%2BDocker.html" rel="noopener noreferrer"&gt;written tutorial&lt;/a&gt; by the same guy Jonny L. I will try my best to summarize it  here though.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/JprTjTViaEA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Docker is a containerization system. It allows you to take slimmed down versions of operating systems (such as ubuntu with 111mb) and to build a specific image just for a specific application. It is like running someone else's computer system &amp;amp; configuration except you run it inside your own computer because the container is light enough for such.&lt;/p&gt;

&lt;p&gt;To clarify, allow me to introduce quickly some concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;image&lt;/strong&gt; is like a snapshot of an operating system. It is not something that runs.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;container&lt;/strong&gt; is an instance of an image. You start a container from an image, and you can leave it running or stop it. A container has its own filesystem, just like your machine does.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;volume&lt;/strong&gt;, for the purposes of this post, is a directory that you specify to be shared between the host system (i.e. your machine) and the container that is running.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, I was trying to solve sort of a "runs not on my machine" problem.^1 So, tensorflow (the organization) provides images on &lt;a href="https://hub.docker.com/r/tensorflow/tensorflow/" rel="noopener noreferrer"&gt;docker hub&lt;/a&gt;. For my case, it was a matter of finding the legacy image tag &lt;code&gt;1.2.1-gpu-py3&lt;/code&gt;. So to start with, I did&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull tensorflow/tensorflow:1.2.1-gpu-py3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now, when you run &lt;code&gt;docker images&lt;/code&gt; you can see this specific image listed. To start a container from this image I ran&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvidia-docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8888:8888 &lt;span class="nt"&gt;--name&lt;/span&gt; followme &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/notebooks tensorflow/tensorflow:1.2.1-gpu-py3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's dissect this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/NVIDIA/nvidia-docker" rel="noopener noreferrer"&gt;&lt;code&gt;nvidia-docker&lt;/code&gt;&lt;/a&gt; is just a special case for this particular problem to provide GPU access to the docker container, as is instructed by tensorflow. Otherwise, most use cases will simply use &lt;code&gt;docker&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run&lt;/code&gt; is the docker subcommand to start a container&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-it&lt;/code&gt; is a flag enabling an interactive tty, or simply put, a terminal of the container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; is a flag instructing to automatically remove the container after exiting it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 8888:8888&lt;/code&gt; is a flag instructing to connect port 8888 of the container to port 8888 of the host. I tried to look up which one corresponds to which but I could not find this one out, sorry. The port 8888 is the default port of jupyter notebook server, which is included in the image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--name followme&lt;/code&gt;, names the container "followme", which looking back is completely stupid given that the container is immediately removed. Well, the more you know, the better, though.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v $(pwd):/notebooks&lt;/code&gt; connects the &lt;code&gt;/notebooks&lt;/code&gt; directory of the container to the current working directory &lt;code&gt;$(pwd)&lt;/code&gt; of the host system. Whatever you do in the container that writes out, is written to the host system.&lt;/li&gt;
&lt;li&gt;finally &lt;code&gt;tensorflow/tensorflow:1.2.1-gpu-py3&lt;/code&gt; is the image from which this instance is started.&lt;/li&gt;
&lt;li&gt;in this particular example, this command kicks off a jupyter notebook server by default. But if you need more control over the container "session", you could add &lt;code&gt;bash&lt;/code&gt; to the end of the above command to start a bash session on the terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with that, I was able to train neural networks faster on the GPU using somebody else's legacy code. I find it to be a great example of what docker can do. And I can't wait to start building specific images, controlling and separating my development environments with docker, and living a happier life as a developer more focused on code :)&lt;/p&gt;

&lt;p&gt;^1 Another use case may include one or similar or the entirety of the following issues: older os versions using an older linux kernel; camera drivers that are only compatible with older kernel versions; custom kernel patches that will break your beloved machine. In such case, it is desirable to test all this installation mess within a docker container and leave your system intact :)&lt;/p&gt;

</description>
      <category>docker</category>
      <category>machinelearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Conda &amp; Dealing with Conflicting Python(s) in your system</title>
      <dc:creator>Bernardo</dc:creator>
      <pubDate>Thu, 09 Nov 2017 15:23:34 +0000</pubDate>
      <link>https://forem.com/bgalvao/conda--dealing-with-conflicting-pythons-in-your-system-62n</link>
      <guid>https://forem.com/bgalvao/conda--dealing-with-conflicting-pythons-in-your-system-62n</guid>
      <description>&lt;p&gt;&lt;a href="https://thepracticaldev.s3.amazonaws.com/i/qtl6ebcb2c2njv5blnc0.jpg" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;br&gt;
(Disclaimer: talking about a unix (me on linux) system here)&lt;/p&gt;
&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;I took up a course on robotics using &lt;a href="http://www.ros.org/about-ros/" rel="noopener noreferrer"&gt;Robot Operating System&lt;/a&gt; (ROS). However, I always keep a &lt;code&gt;miniconda3&lt;/code&gt; installation to handle my data science adventures and respective dependencies. To clarify, it installs &lt;code&gt;conda&lt;/code&gt;, a general purpose package manager - although really I only use it to install python libraries - and &lt;strong&gt;python 3.6&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What happens is that ROS uses the system python - i.e. &lt;strong&gt;python 2.7&lt;/strong&gt;. The problem arises if you set your "python path" to default to that of &lt;code&gt;miniconda3&lt;/code&gt;, a procedure which is automated when you accept that the &lt;code&gt;miniconda3&lt;/code&gt; installer adds the following line to your &lt;code&gt;.bashrc&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/miniconda3/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words, everytime you open a shell, your system sets the python interpreter to that of &lt;code&gt;miniconda3&lt;/code&gt;, which is version 3.6. So everytime I ran something from ROS, it would crash running python scripts that were written in version 2.7, namely due to syntax differences on the &lt;code&gt;print&lt;/code&gt; command between the two versions.&lt;/p&gt;

&lt;h1&gt;
  
  
  The solution - meet symlinks
&lt;/h1&gt;

&lt;p&gt;After reading conda's &lt;a href="https://conda.io/docs/user-guide/troubleshooting.html#programs-fail-due-to-invoking-conda-python-instead-of-system-python" rel="noopener noreferrer"&gt;documentation on the subject&lt;/a&gt;, I decided to test my ability to implement their suggested solution, which is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;remove &lt;code&gt;miniconda3&lt;/code&gt; from the &lt;code&gt;PATH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;create symlinks to three components of &lt;code&gt;miniconda3&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;conda&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;activate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deactivate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;add these symlinks to the &lt;code&gt;PATH&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To remove &lt;code&gt;miniconda3&lt;/code&gt; from the &lt;code&gt;PATH&lt;/code&gt;, one simply has to comment out or delete the aforementioned line in the &lt;code&gt;.bashrc&lt;/code&gt; file, using some text editor like &lt;code&gt;nano&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;Now that that is done, let us create &lt;a href="https://www.howtogeek.com/287014/how-to-create-and-use-symbolic-links-aka-symlinks-on-linux/" rel="noopener noreferrer"&gt;symlinks&lt;/a&gt;. A symlink, for the purpose of this post, is like a pointer to some other executable file and will function as a command. I created a specific folder (&lt;code&gt;.symlinks&lt;/code&gt;) just for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; .symlinks
&lt;span class="nb"&gt;cd&lt;/span&gt; .symlinks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we're in the &lt;code&gt;.symlinks&lt;/code&gt; folder, let's actually create symlinks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /home/user/miniconda3/bin/conda conda
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /home/user/miniconda3/bin/activate activate
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /home/user/miniconda3/bin/deactivate deactivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify that they were created, run &lt;code&gt;ls -l&lt;/code&gt; (list files) in the &lt;code&gt;.symlinks&lt;/code&gt; folder, you'll be able to see the pointers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lrwxrwxrwx 1 user user 34 Nov  9 14:08 activate -&amp;gt; /home/user/miniconda3/bin/activate
lrwxrwxrwx 1 user user 31 Nov  9 14:10 conda -&amp;gt; /home/user/miniconda3/bin/conda
lrwxrwxrwx 1 user user 36 Nov  9 14:08 deactivate -&amp;gt; /home/user/miniconda3/bin/deactivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At last, we add the &lt;code&gt;.symlinks&lt;/code&gt; folder to the path. But we want to have these symlink commands automatically available every time we open a new shell. The answer is to "add" them to the script which is run everytime a shell is opened: the &lt;code&gt;.bashrc&lt;/code&gt; file. So, add this line to the said file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/.symlinks:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the changes to take effect, you may close and reopen the terminal, but to feel like a pro without doing that move, run &lt;code&gt;source .bashrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, if you run &lt;code&gt;python --version&lt;/code&gt; you will get the system python back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user@ryzen:~$ python --version
Python 2.7.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use python 3.6 from the root &lt;a href="https://conda.io/docs/user-guide/tasks/manage-environments.html" rel="noopener noreferrer"&gt;conda environment&lt;/a&gt;, do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user@ryzen:~$ source activate root
(root) user@ryzen:~$ python --version
Python 3.6.3 :: Anaconda, Inc.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from the &lt;code&gt;python --version&lt;/code&gt; bit, we're now using the 3.6 interpreter. If I want to activate the environment where I installed &lt;strong&gt;d&lt;/strong&gt;ata &lt;strong&gt;s&lt;/strong&gt;cience libraries&lt;sup&gt;1&lt;/sup&gt; I'd run &lt;code&gt;source activate ds&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that the newer interpreter is activated, you can run scripts that were written for that interpreter. Anyways, if you need to revert back to the system interpreter (2.7) on the current shell, then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(root) user@ryzen:~$ source deactivate
user@ryzen:~$ python --version
Python 2.7.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we're back to 2.7. So you can run software that runs on this version with no problems, and switch back to your 3.6 antics whenever you want. ðŸ˜&lt;/p&gt;

&lt;p&gt;Have a good one. ðŸ˜&lt;/p&gt;

&lt;p&gt;&lt;a&gt;1&lt;/a&gt;: &lt;em&gt;I think&lt;/em&gt; &lt;code&gt;conda&lt;/code&gt; &lt;em&gt;does not allow to install packages to root anymore and forces users to create their own environments so as to incentivise good practices. Not that I checked, just personal experience.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>conda</category>
      <category>environments</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
