<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Patrik Cyvoct</title><link>https://ptrk.io/posts/</link><description>Recent content in Posts on Patrik Cyvoct</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 14 May 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://ptrk.io/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Tweaking an EFK stack on Kubernetes</title><link>https://ptrk.io/posts/2018/05/tweaking-an-efk-stack-on-kubernetes/</link><pubDate>Mon, 14 May 2018 00:00:00 +0000</pubDate><guid>https://ptrk.io/posts/2018/05/tweaking-an-efk-stack-on-kubernetes/</guid><description>This is the continuation of my last post regarding EFK on Kubernetes. In this post we will mainly focus on configuring Fluentd/Fluent Bit but there will also be a Kibana tweak with the Logtrail plugin.
Configuring Fluentd This part and the next one will have the same goal but one will focus on Fluentd and the other on Fluent Bit. Our goal is to create a configuration that will separate the logs of different namespaces and select which containers we want to log depending on their label.</description><content type="html"><![CDATA[<p>This is the continuation of <a href="https://blog.ptrk.io/how-to-deploy-an-efk-stack-to-kubernetes/">my last post regarding EFK on Kubernetes</a>. In this post we will mainly focus on configuring <a href="https://www.fluentd.org">Fluentd</a>/<a href="https://fluentbit.io">Fluent Bit</a> but there will also be a <a href="https://www.elastic.co/products/kibana">Kibana</a> tweak with the Logtrail plugin.</p>
<h1 id="configuring-fluentd">Configuring Fluentd</h1>
<p>This part and the next one will have the same goal but one will focus on Fluentd and the other on Fluent Bit. Our goal is to create a configuration that will separate the logs of different namespaces and select which containers we want to log depending on their label.</p>
<h2 id="configure-the-daemonset">Configure the DaemonSet</h2>
<p>The first thing we need to do is change Fluentd&rsquo;s DaemonSet. In fact, if we use <a href="https://github.com/fluent/fluentd-kubernetes-daemonset">the one provided by Fluentd</a>, the configuration file is hardcoded into the image and it is not very simple to change it. So we will create a Kubernetes ConfigMap and mount it in the <code>/fluentd/etc</code> folder. If you have RBAC enabled, and you should, don&rsquo;t forget to configure it for Fluentd:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># fluentd-rbac.yml</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># If you have RBAC enabled</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ServiceAccount</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">kube-system</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">rbac.authorization.k8s.io/v1beta1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ClusterRole</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">kube-system</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">rules</span>:
</span></span><span style="display:flex;"><span>- <span style="color:#f92672">apiGroups</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">resources</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#ae81ff">pods</span>
</span></span><span style="display:flex;"><span>  - <span style="color:#ae81ff">namespaces</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">verbs</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#ae81ff">get</span>
</span></span><span style="display:flex;"><span>  - <span style="color:#ae81ff">list</span>
</span></span><span style="display:flex;"><span>  - <span style="color:#ae81ff">watch</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ClusterRoleBinding</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">rbac.authorization.k8s.io/v1beta1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">roleRef</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ClusterRole</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">apiGroup</span>: <span style="color:#ae81ff">rbac.authorization.k8s.io</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">subjects</span>:
</span></span><span style="display:flex;"><span>- <span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ServiceAccount</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">kube-system</span>
</span></span></code></pre></div><p>Now regarding the DaemonSet:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># fluentd-daemonset.yml</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">extensions/v1beta1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">DaemonSet</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">k8s-app</span>: <span style="color:#ae81ff">fluentd-logging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">version</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">kubernetes.io/cluster-service</span>: <span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">k8s-app</span>: <span style="color:#ae81ff">fluentd-logging</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">version</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes.io/cluster-service</span>: <span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">serviceAccount</span>: <span style="color:#ae81ff">fluentd</span> <span style="color:#75715e"># if RBAC is enabled</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">serviceAccountName</span>: <span style="color:#ae81ff">fluentd</span> <span style="color:#75715e"># if RBAC is enabled</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">tolerations</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">node-role.kubernetes.io/master</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">effect</span>: <span style="color:#ae81ff">NoSchedule</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">fluent/fluentd-kubernetes-daemonset:v1.1-debian-elasticsearch</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>:  <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_HOST</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;elasticsearch&#34;</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>:  <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_PORT</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;9200&#34;</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_SCHEME</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;http&#34;</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_USER</span> <span style="color:#75715e"># even if not used they are necessary</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;foo&#34;</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_PASSWORD</span> <span style="color:#75715e"># even if not used they are necessary</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;bar&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">resources</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">limits</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">memory</span>: <span style="color:#ae81ff">200Mi</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">requests</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">cpu</span>: <span style="color:#ae81ff">100m</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">memory</span>: <span style="color:#ae81ff">200Mi</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">volumeMounts</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlog</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/log</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlibdockercontainers</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/lib/docker/containers</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd-config</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/fluentd/etc</span> <span style="color:#75715e"># path of fluentd config file</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">terminationGracePeriodSeconds</span>: <span style="color:#ae81ff">30</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlog</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/log</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlibdockercontainers</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/lib/docker/containers</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd-config</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">configMap</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd-config</span> <span style="color:#75715e"># name of the config map we will create</span>
</span></span></code></pre></div><blockquote>
<p>Note that we are using Fluentd v1. Some configurations will not work on v0.12!</p>
</blockquote>
<p>You may wonder why I added <code>FLUENT_ELASTICSEARCH_PASSWORD</code> and <code>FLUENT_ELASTICSEARCH_USER</code>. It is because the Docker image <a href="https://hub.docker.com/r/fluent/fluentd-kubernetes-daemonset/">fluent/fluentd-kubernetes-daemonset</a> uses <code>sed</code> on the configuration file if these environment variables are not set, and since the ConfigMap is read-only the container will fail to start. We could change the base image of the DaemonSet but adding these two lines is simpler and doesn&rsquo;t hurt.</p>
<p>With the DaemonSet created we can now focus on our <code>fluentd-config</code> ConfigMap.</p>
<h2 id="creating-the-configmap">Creating the ConfigMap</h2>
<p>Here is a basic Fluentd configuration for Kubernetes (You can learn more on configuring Fluentd in <a href="https://docs.fluentd.org/v1.0/articles/quickstart">their documentation</a>):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># fluentd-config-map.yml</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd-config</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">fluent.conf</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;match fluent.**&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        # this tells fluentd to not output its log on stdout
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        @type null
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;/match&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    # here we read the logs from Docker&#39;s containers and parse them
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;source&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      @type tail
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      path /var/log/containers/*.log
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      pos_file /var/log/fluentd-containers.log.pos
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      tag kubernetes.*
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      read_from_head true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      &lt;parse&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        @type json
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        time_format %Y-%m-%dT%H:%M:%S.%NZ
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      &lt;/parse&gt;      
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;/source&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    # we use kubernetes metadata plugin to add metadatas to the log
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;filter kubernetes.**&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        @type kubernetes_metadata
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;/filter&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    # we send the logs to Elasticsearch
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;match kubernetes.**&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        @type elasticsearch
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        include_tag_key true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        host &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_HOST&#39;]}&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        port &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_PORT&#39;]}&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        scheme &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_SCHEME&#39;] || &#39;http&#39;}&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        ssl_verify &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_SSL_VERIFY&#39;] || &#39;true&#39;}&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        user &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_USER&#39;]}&#34; # remove these lines if not needed
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        password &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_PASSWORD&#39;]}&#34; # remove these lines if not needed
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        reload_connections true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        logstash_prefix logstash
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        logstash_format true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &lt;buffer&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            flush_thread_count 8
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            flush_interval 5s
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            chunk_limit_size 2M
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            queue_limit_length 32
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            retry_max_interval 30
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            retry_forever true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &lt;/buffer&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &lt;/match&gt;</span>    
</span></span></code></pre></div><blockquote>
<p>The <a href="https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter">Kubernetes metadata plugin</a> is already installed in the Docker image we use.</p>
</blockquote>
<p>This configuration does about the same as the one provided by Fluentd. Now if you want for instance to not send the <code>kube-system</code> containers&rsquo; logs, you can add these lines before the Elasticsearch output:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">&lt;match kubernetes.var.log.containers.**kube-system**.log&gt;                                                                            
    @type null
&lt;/match&gt;
</code></pre><h3 id="split-the-logs-regarding-to-the-namespaces">Split the logs regarding to the namespaces</h3>
<p>Let&rsquo;s assume you want to separate your logs depending on the container&rsquo;s namespace. For instance you could send the logs from the <code>dev</code> namespace to one Elasticsearch cluster and the logs from the <code>production</code> namespace to another one. In order to achieve it we will use the <a href="https://github.com/fluent/fluent-plugin-rewrite-tag-filter">rewrite tag filter</a>. After the metadata plugin, we could add:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf"># this add the namespace name at the begining of the tag
&lt;match kubernetes.**&gt;
    @type rewrite_tag_filter
    &lt;rule&gt;
        key $[&#39;kubernetes&#39;][&#39;namespace_name&#39;]
        pattern ^(.+)$
        tag $1.${tag}
    &lt;/rule&gt;
&lt;/match&gt;
</code></pre><p>And then we could have something like that for the output:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf"># match the dev logs
&lt;match dev.kubernetes.**&gt;
    @type elasticsearch
    include_tag_key true
    host &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_HOST_DEV&#39;]}&#34;
    port &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_PORT_DEV&#39;]}&#34;
    scheme &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_SCHEME_DEV&#39;] || &#39;http&#39;}&#34;
    ...
&lt;/match&gt;
# match the production logs
&lt;match production.kubernetes.**&gt;
    @type elasticsearch
    include_tag_key true
    host &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_HOST_PROD&#39;]}&#34;
    port &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_PORT_PROD&#39;]}&#34;
    scheme &#34;#{ENV[&#39;FLUENT_ELASTICSEARCH_SCHEME_PROD&#39;] || &#39;http&#39;}&#34;
    ...
&lt;/match&gt;
</code></pre><blockquote>
<p>It&rsquo;s just an example, let your imagination make the better of it :) !</p>
</blockquote>
<h3 id="select-which-containers-you-want-to-log">Select which containers you want to log</h3>
<p>Now we want to select which containers we want to log or which not to log. It is possible with the <a href="https://docs.fluentd.org/v1.0/articles/filter_grep">grep filter</a> (This will only work on Fluentd v1 since nested keys does not seem to work on v0.12).</p>
<p>The idea here is to add a label to the containers you want to log or to the ones you don&rsquo;t want to log. There is two approaches: either we label all the containers we want to log; or the ones that we don&rsquo;t want to log.</p>
<p>For instance if we add <code>fluentd: &quot;true&quot;</code> as a label for the containers we want to log we then need to add:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">&lt;filter kubernetes.**&gt;
    @type grep
    &lt;regexp&gt;
        key $.kubernetes.labels.fluentd
        pattern true
    &lt;/regexp&gt;
&lt;/filter&gt;
</code></pre><p>Or similarly, if we add <code>fluentd: &quot;false&quot;</code> as a label for the containers we don&rsquo;t want to log we would add:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">&lt;filter kubernetes.**&gt;
    @type grep
    &lt;exclude&gt;
        key $.kubernetes.labels.fluentd
        pattern false
    &lt;/exclude&gt;
&lt;/filter&gt;
</code></pre><p>And that&rsquo;s it for Fluentd configuration. Again if you want some more configuration options, check the documentation of Fluentd and of the plugins we used.</p>
<h1 id="configuring-fluent-bit">Configuring Fluent Bit</h1>
<p>Unfortunately configuring Fluent Bit to work just like we just did for Fluentd is not (yet?) possible. One way to achieve it would be to connect Fluent Bit to a Fluentd aggregator but I will not cover it here. You can find some information about it on the <a href="https://github.com/fluent/fluent-bit-docs/blob/master/output/forward.md">fluent Github repo</a>.</p>
<h1 id="lets-tweak-kibana-a-bit-with-the-logtrail-plugin">Let&rsquo;s tweak Kibana a bit with the Logtrail plugin</h1>
<p><img alt="Logtrail screenshot" src="https://raw.githubusercontent.com/sivasamyk/logtrail/master/screenshot.png"></p>
<blockquote>
<p><a href="hhttps://github.com/sivasamyk/logtrail">Logtrail</a> is a plugin for Kibana to view, analyze, search and tail log events from multiple hosts in realtime with devops friendly interface inspired by <a href="https://papertrailapp.com/">Papertrail</a>.</p>
</blockquote>
<p>First we need to install the plugin (Kibana 5.X &amp; 6.X only).
To install the plugin you&rsquo;ll need the URL of a Logtrail release. You can check them <a href="https://github.com/sivasamyk/logtrail/releases">here</a>.</p>
<blockquote>
<p>You must take the URL corresponding to your Kibana version.</p>
</blockquote>
<p>Now, you can build the image with the Logtrail plugin like this (assuming you want Kibana 6.2.4):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> docker.elastic.co/kibana/kibana-oss:6.2.4</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> kibana-plugin install https://github.com/sivasamyk/logtrail/releases/download/v0.1.27/logtrail-6.2.4-0.1.27.zip<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /config</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">USER</span><span style="color:#e6db74"> root</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mv /usr/share/kibana/plugins/logtrail/logtrail.json /config/logtrail.json <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    ln -s /config/logtrail.json /usr/share/kibana/plugins/logtrail/logtrail.json<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">USER</span><span style="color:#e6db74"> kibana</span><span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Or pull the image from my Dockerhub: <a href="https://hub.docker.com/r/sh4d1/kibana-logtrail/">sh4d1/kibana-logtrail</a></p>
<blockquote>
<p>I only have the <code>6.2.4</code> tag.</p>
</blockquote>
<p>Next step is to configure Logtrail and we will use a ConfigMap. Here is the ConfigMap and the Deployment for Kibana:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">logtrail-config</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">logtrail.json</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;version&#34; : 1,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;index_patterns&#34; : [
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        {      
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;es&#34;: {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                &#34;default_index&#34;: &#34;logstash-*&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            },
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;tail_interval_in_seconds&#34;: 10,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;es_index_time_offset_in_seconds&#34;: 0,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;display_timezone&#34;: &#34;local&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;display_timestamp_format&#34;: &#34;MMM DD HH:mm:ss&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;max_buckets&#34;: 500,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;default_time_range_in_days&#34; : 0,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;max_hosts&#34;: 100,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;max_events_to_keep_in_viewer&#34;: 5000,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;fields&#34; : {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                &#34;mapping&#34; : {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    &#34;timestamp&#34; : &#34;@timestamp&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    &#34;hostname&#34; : &#34;kubernetes.host&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    &#34;program&#34;: &#34;kubernetes.pod_name&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    &#34;message&#34;: &#34;log&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                },
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                &#34;message_format&#34;: &#34;{{{log}}}&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            },
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            &#34;color_mapping&#34; : {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">            }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        }]
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    } </span>    
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1beta1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">matchLabels</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">sh4d1/kibana-logtrail:6.2.4</span> <span style="color:#75715e"># or your image</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">volumeMounts</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">logtrail-config</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">CLUSTER_NAME</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#ae81ff">myesdb</span> <span style="color:#75715e"># the name of your ES cluster</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">resources</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">limits</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">cpu</span>: <span style="color:#ae81ff">1000m</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">requests</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">cpu</span>: <span style="color:#ae81ff">100m</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">containerPort</span>: <span style="color:#ae81ff">5601</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">logtrail-config</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">configMap</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">name</span>: <span style="color:#ae81ff">logtrail-config</span>
</span></span></code></pre></div><p>So let&rsquo;s take look at Logtrail&rsquo;s configuration. The first point is the <code>default-index</code>; it must be set to the index used by Elasticsearch.
Then the important part is the <code>fields</code> section. It will display like:</p>
<pre tabindex="0"><code>timestamp hostname program:message
</code></pre><p>The <code>message</code> is defined in <code>message_format</code>. We could put something like <code>{{{docker.container_id}}}: {{{log}}}</code>.
For further configuration you can check the repository of <a href="https://github.com/sivasamyk/logtrail">sivasamyk</a>.</p>
<p>If you have any questions feel free to <a href="mailto:patrik@ptrk.io">send me a email</a> or contact me on the <a href="https://dockercommunity.slack.com/">Docker Slack community</a> @Sh4d1</p>
]]></content></item><item><title>How to deploy an EFK stack to Kubernetes</title><link>https://ptrk.io/posts/2018/04/how-to-deploy-an-efk-stack-to-kubernetes/</link><pubDate>Wed, 18 Apr 2018 00:00:00 +0000</pubDate><guid>https://ptrk.io/posts/2018/04/how-to-deploy-an-efk-stack-to-kubernetes/</guid><description>EFK stack? Like ELK? You may have heard of ELK (Elasticsearch, Logstash, Kibana). EFK is the same stack where we replace Logstash by Fluentd. So why replace Logstash with Fluentd?
First of all, Fluentd is now hosted by the Cloud Native Computing Foundation, the same which hosts Kubernetes. Also, I find it very easy to configure, there is a lot of plugins and its memory footprint is very low.
We could also replace Fluentd by Fluent Bit, which is a lighter log forwarder but has fewer functionalities than the first one.</description><content type="html"><![CDATA[<h1 id="efk-stack-like-elk">EFK stack? Like ELK?</h1>
<p>You may have heard of ELK (<a href="https://www.elastic.co/products/elasticsearch">Elasticsearch</a>, <a href="https://www.elastic.co/products/logstash">Logstash</a>, <a href="https://www.elastic.co/products/kibana">Kibana</a>). EFK is the same stack where we replace Logstash by <a href="https://www.fluentd.org/">Fluentd</a>.
So why replace Logstash with Fluentd?</p>
<p>First of all, Fluentd is now hosted by the <a href="https://cncf.io/">Cloud Native Computing Foundation</a>, the same which hosts <a href="https://kubernetes.io">Kubernetes</a>. Also, I find it very easy to configure, there is a lot of plugins and its memory footprint is very low.</p>
<p>We could also replace Fluentd by <a href="https://fluentbit.io">Fluent Bit</a>, which is a lighter log forwarder but has  fewer functionalities than the first one.</p>
<h2 id="how-does-it-work">How does it work</h2>
<p>A picture is worth a thousand words, so here is a simple schema.</p>
<p><img alt="Simplified schema of an EFK" src="/images/elk.png"></p>
<p>Basically, each Fluentd container reads the <code>/var/lib/docker</code> to get the logs of each container on the node and send them to Elasticsearch. Finally, when we access Kibana, it requests the logs from Elasticsearch.</p>
<h2 id="what-for">What for?</h2>
<p>You may ask yourselves why bother setting up such a stack? I can just run <code>docker logs ...</code>, and there I have my logs.</p>
<p>Well, yes, you could. However, if you have several replicas you&rsquo;ll have to go through each one of the containers to find what you are looking for. Here you can go through all the logs at once.
Also, with Kibana you can create dashboards and very nice visualizations.</p>
<p>Take a look:</p>
<p><img alt="A very nice dashboard" src="https://www.elastic.co/assets/bltd2d6eaf0e294f4d2/basics-v3.jpg"></p>
<blockquote>
<p>From <a href="https://www.elastic.co">elastic.co</a></p>
</blockquote>
<p>Another interesting point is the manipulation of the logs. With Fluentd you can filter, modify and backup your logs very easily. But we&rsquo;ll look into that in another post.</p>
<p>Enough with the introduction, let&rsquo;s build this stack!</p>
<h1 id="elasticsearch">Elasticsearch</h1>
<blockquote>
<p>Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. As the heart of the Elastic Stack, it centrally stores your data so you can discover the expected and uncover the unexpected.</p>
</blockquote>
<p>In the E*K stack, we use Elasticsearch to store and search the logs forwarded by Fluentd. To deploy it into our Kubernetes cluster, we can use the GitHub repository of <a href="https://github.com/pires/">pires</a>: <a href="https://github.com/pires/kubernetes-elasticsearch-cluster">pires/kubernetes-elasticsearch-cluster</a></p>
<p>You can modify the values in <code>es-master.yaml</code>, <code>es-client.yaml</code> and in <code>es-data.yaml</code>, for changing the number of replicas, the names, etc.</p>
<blockquote>
<p>By default, <code>ES_JAVA_OPTS</code> is set to <code>-Xms256m -Xmx256m</code>. This is a very low value but many users, i.e. minikube users, were having issues with pods getting killed because hosts were out of memory. One can change this in the deployment descriptors available in this repository.
<em><a href="https://github.com/pires/kubernetes-elasticsearch-cluster/blob/master/README.md">README.md </a></em></p>
</blockquote>
<p>It is also recommended to change the storage from <code>emptyDir</code> to the storage of your choosing to get persistent storage of the data.</p>
<p>Once you have setup your files you can run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ kubectl -n logging create -f es-discovery-svc.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging create -f es-svc.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging create -f es-master.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging rollout status -f es-master.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging create -f es-client.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging rollout status -f es-client.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging create -f es-data.yaml
</span></span><span style="display:flex;"><span>$ kubectl -n logging rollout status -f es-data.yaml
</span></span></code></pre></div><blockquote>
<p>Note: I will run the EFK stack in the <code>logging</code> namespace, use <code>kubectl create ns logging</code> to create it.</p>
</blockquote>
<p>Check that your Elasticsearch is up and running by following <a href="https://github.com/pires/kubernetes-elasticsearch-cluster/blob/master/README.md#access-the-service">pires instructions</a>.</p>
<p>If everything is okay, we can now set up Fluentd (or Fluent Bit)!</p>
<h1 id="fluentd">Fluentd</h1>
<blockquote>
<p>Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data.
<em><a href="https://www.fluentd.org/architecture">https://www.fluentd.org/architecture</a></em></p>
</blockquote>
<p>Fluentd can be run directly on the host, or in a Docker container. Here we will use a <code>DaemonSet</code> to ensure that Fluentd is running on every node. The code is from <a href="https://github.com/fluent/fluentd-kubernetes-daemonset">fluent/fluentd-kubernetes-daemonset</a>.</p>
<p>If you have RBAC enabled on your cluster (and I hope you have), check the <code>ClusterRole</code>, <code>ClusterRoleBinding</code> and <code>ServiceAccount</code> of <a href="https://github.com/fluent/fluentd-kubernetes-daemonset/blob/master/fluentd-daemonset-elasticsearch-rbac.yaml">fluentd-daemonset-elasticsearch-rbac.yaml</a>.</p>
<p>Don&rsquo;t forget to change the namespace to the one used when deploying Elasticsearch, it should be the same.
Then we can apply the <code>DaemonSet</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">DaemonSet</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">logging</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">component</span>: <span style="color:#ae81ff">fluentd-logging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">version</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">kubernetes.io/cluster-service</span>: <span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">matchLabels</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">component</span>: <span style="color:#ae81ff">fluentd-logging</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">component</span>: <span style="color:#ae81ff">fluentd-logging</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">version</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes.io/cluster-service</span>: <span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">serviceAccount</span>: <span style="color:#ae81ff">fluentd</span> <span style="color:#75715e"># if you have RBAC enabled</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">serviceAccountName</span>: <span style="color:#ae81ff">fluentd</span> <span style="color:#75715e"># if you have RBAC enabled</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">tolerations</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">node-role.kubernetes.io/master</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">effect</span>: <span style="color:#ae81ff">NoSchedule</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluentd</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">fluent/fluentd-kubernetes-daemonset:elasticsearch</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#f92672">name</span>:  <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_HOST</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;elasticsearch&#34;</span> <span style="color:#75715e"># the name of the previous es-svc.yml </span>
</span></span><span style="display:flex;"><span>          - <span style="color:#f92672">name</span>:  <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_PORT</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;9200&#34;</span> <span style="color:#75715e"># port of the previous es-svc.yml</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_SCHEME</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;http&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">resources</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">limits</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">memory</span>: <span style="color:#ae81ff">200Mi</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">requests</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">cpu</span>: <span style="color:#ae81ff">100m</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">memory</span>: <span style="color:#ae81ff">200Mi</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">volumeMounts</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlog</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/log</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlibdockercontainers</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/lib/docker/containers</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">terminationGracePeriodSeconds</span>: <span style="color:#ae81ff">30</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlog</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/log</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlibdockercontainers</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/lib/docker/containers</span>
</span></span></code></pre></div><h1 id="fluent-bit">Fluent Bit</h1>
<p>We will use the code of <a href="https://github.com/fluent/fluent-bit-kubernetes-logging">fluent/fluent-bit-kubernetes-logging</a>.
As for Fluentd, if you use RBAC, create the <code>ClusterRole</code>, <code>ClusterRoleBinding</code> and <code>ServiceAccount</code> with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ kubectl create -f https://raw.githubusercontent.com/fluent/fluent-bit-kubernetes-logging/master/fluent-bit-service-account.yaml
</span></span><span style="display:flex;"><span>$ kubectl create -f https://raw.githubusercontent.com/fluent/fluent-bit-kubernetes-logging/master/fluent-bit-role.yaml
</span></span><span style="display:flex;"><span>$ kubectl create -f https://raw.githubusercontent.com/fluent/fluent-bit-kubernetes-logging/master/fluent-bit-role-binding.yaml
</span></span></code></pre></div><p>We also need to create a <code>ConfigMap</code> for the configuration. You can either modify <a href="https://github.com/fluent/fluent-bit-kubernetes-logging/blob/master/output/elasticsearch/fluent-bit-configmap.yaml">this one</a> and apply it or use the default one:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ kubectl create -f https://raw.githubusercontent.com/fluent/fluent-bit-kubernetes-logging/master/output/elasticsearch/fluent-bit-configmap.yaml
</span></span></code></pre></div><p>Once the <code>ConfigMap</code> is applied, here is the code for the <code>DaemonSet</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">DaemonSet</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluent-bit</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">logging</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">component</span>: <span style="color:#ae81ff">fluent-bit-logging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">version</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">kubernetes.io/cluster-service</span>: <span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">matchLabels</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">component</span>: <span style="color:#ae81ff">fluent-bit-logging</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">component</span>: <span style="color:#ae81ff">fluent-bit-logging</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">version</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes.io/cluster-service</span>: <span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluent-bit</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">fluent/fluent-bit:0.12.17</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_HOST</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;elasticsearch&#34;</span> <span style="color:#75715e"># the name of the previous es-svc.yml </span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">FLUENT_ELASTICSEARCH_PORT</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;9200&#34;</span> <span style="color:#75715e"># the port of the previous es-svc.yml </span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">volumeMounts</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlog</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/log</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlibdockercontainers</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/lib/docker/containers</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluent-bit-config</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/fluent-bit/etc/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">terminationGracePeriodSeconds</span>: <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlog</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/log</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">varlibdockercontainers</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/lib/docker/containers</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluent-bit-config</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">configMap</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fluent-bit-config</span> <span style="color:#75715e"># name of the previously created ConfigMap</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">serviceAccountName</span>: <span style="color:#ae81ff">fluent-bit</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">tolerations</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">node-role.kubernetes.io/master</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">Exists</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">effect</span>: <span style="color:#ae81ff">NoSchedule</span>
</span></span></code></pre></div><h1 id="kibana">Kibana</h1>
<p>Once you have some logs into Elasticsearch, we can add a tool for exploring and analyze them like Kibana.</p>
<blockquote>
<p>Kibana lets you visualize your Elasticsearch data and navigate the Elastic Stack.</p>
</blockquote>
<p>So we will deploy Kibana as a deployment. We&rsquo;ll use the 6.2 OSS version because it does not have X-Pack enabled. (If you want X-Pack, you can, of course, adjust the image name).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">logging</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">matchLabels</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.elastic.co/kibana/kibana-oss:6.2.2</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">CLUSTER_NAME</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">value</span>: <span style="color:#ae81ff">myesdb</span> <span style="color:#75715e"># name of the Elasticsearch cluster defined in the first part</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">resources</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">limits</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">cpu</span>: <span style="color:#ae81ff">1000m</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">requests</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">cpu</span>: <span style="color:#ae81ff">100m</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">containerPort</span>: <span style="color:#ae81ff">5601</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http</span>
</span></span></code></pre></div><p>When the pod is up and running, we can make it accessible via a <code>Service</code> and an <code>Ingress</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">logging</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">component</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">port</span>: <span style="color:#ae81ff">5601</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">extensions/v1beta1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Ingress</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">logging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">annotations</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes.io/ingress.class</span>: <span style="color:#ae81ff">traefik</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">ingress.kubernetes.io/auth-type</span>: <span style="color:#e6db74">&#34;basic&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">ingress.kubernetes.io/auth-secret</span>: <span style="color:#ae81ff">kibana-basic-auth</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">rules</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">host</span>: <span style="color:#e6db74">&#34;&lt;your-url&gt;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">http</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">paths</span>:
</span></span><span style="display:flex;"><span>                - <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/</span>
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">backend</span>:
</span></span><span style="display:flex;"><span>                      <span style="color:#f92672">serviceName</span>: <span style="color:#ae81ff">kibana</span>
</span></span><span style="display:flex;"><span>                      <span style="color:#f92672">servicePort</span>: <span style="color:#ae81ff">http</span>
</span></span></code></pre></div><p>For protecting Kibana with a user/password, we will use <a href="https://traefik.io/">Traefik</a> as an Ingress controller.
To create the secret:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ htpasswd -c ./auth &lt;your-user&gt;
</span></span><span style="display:flex;"><span>$ kubectl -n logging create secret generic kibana-basic-auth --from-file auth
</span></span><span style="display:flex;"><span>$ rm auth
</span></span></code></pre></div><p>When you will access to Kibana for the first time, you need to configure your first index.
If you did not change Fluentd&rsquo;s default configuration, the index name/pattern is <code>logstash-YYYY-MM-DD</code>. You can use a wildcard to catch all index beginning with <em>logstash-</em> by using <code>logstash-*</code>.</p>
<p>And now you have a functional EFK stack!</p>
<p><img alt="Some logs in Kibana" src="/images/efk.png"></p>
<p>In the next part, we will dive into the configuration of Fluentd and Kibana.</p>
<blockquote>
<p>Thanks to <a href="https://jmaitrehenry.ca/">@jmaitrehenry</a> for his feedback on this post.</p>
</blockquote>
]]></content></item><item><title>Using Drone and Traefik on Kubernetes to deploy a basic application</title><link>https://ptrk.io/posts/2017/12/using-drone-and-traefik-on-kubernetes-to-deploy-a-basic-application/</link><pubDate>Mon, 18 Dec 2017 00:00:00 +0000</pubDate><guid>https://ptrk.io/posts/2017/12/using-drone-and-traefik-on-kubernetes-to-deploy-a-basic-application/</guid><description>Drone is a Continuous Delivery system built on container technology. Drone uses a simple YAML configuration file, a superset of docker-compose, to define and execute Pipelines inside Docker containers.
That seems awesome, a CD built with containers in mind. Drone is written in Go, supports a lot of plugins, and is very easy to configure.
If you don&amp;rsquo;t know Traefik, you can check out my previous posts.
We will deploy Drone on a Kubernetes cluster, here using Google Cloud Platform (You can get free credits for one year).</description><content type="html"><![CDATA[<blockquote>
<p>Drone is a Continuous Delivery system built on container technology. Drone uses a simple YAML configuration file, a superset of docker-compose, to define and execute Pipelines inside Docker containers.</p>
</blockquote>
<p>That seems awesome, a CD built with containers in mind. <a href="https://drone.io">Drone</a> is written in Go, supports a lot of plugins, and is very easy to configure.</p>
<p>If you don&rsquo;t know <a href="https://traefik.io/">Traefik</a>, you can check out <a href="https://blog.ptrk.io/multi-https-sub-domain-with-traefik-and-docker/">my previous posts</a>.</p>
<p>We will deploy Drone on a <a href="https://kubernetes.io/">Kubernetes cluster</a>, here using <a href="https://cloud.google.com/">Google Cloud Platform</a> (You can get free credits for one year). You can choose the provider you prefer, but the instructions may change.</p>
<h2 id="creation-of-the-cluster">Creation of the cluster</h2>
<p>So first thing first, we need a running cluster. With <a href="https://cloud.google.com/kubernetes-engine/">Google Kubernetes Engine</a>, it can be done with a simple command. I assume you have <code>gcloud</code> installed and a working Google Cloud account, if not check the <a href="https://cloud.google.com/sdk/gcloud/">doc here</a>.
In order to create the cluster we just have to type:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ gcloud container clusters create &lt;cluster-name&gt; --cluster-version<span style="color:#f92672">=</span>1.8.3-gke.0
</span></span><span style="display:flex;"><span>Creating cluster &lt;cluster-name&gt;...done.                                      
</span></span><span style="display:flex;"><span>Created <span style="color:#f92672">[</span>https://container.googleapis.com/v1/projects/&lt;gcloud-project-name&gt;/zones/&lt;zone-name&gt;/clusters/&lt;cluster-name&gt;<span style="color:#f92672">]</span>.
</span></span><span style="display:flex;"><span>kubeconfig entry generated <span style="color:#66d9ef">for</span> &lt;cluster-name&gt;.
</span></span><span style="display:flex;"><span>NAME  LOCATION        MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
</span></span><span style="display:flex;"><span>&lt;cluster-name&gt;  &lt;zone-name&gt;  1.8.3-gke.0     &lt;master-ip&gt;  n1-standard-1  1.8.3-gke.0   <span style="color:#ae81ff">3</span>          RUNNING
</span></span></code></pre></div><p>We will be using Kubernetes 1.8+ so be sure to have the correct <a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/"><code>kubectl</code> version</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl version
</span></span><span style="display:flex;"><span>Client Version: version.Info<span style="color:#f92672">{</span>Major:<span style="color:#e6db74">&#34;1&#34;</span>, Minor:<span style="color:#e6db74">&#34;8&#34;</span>, GitVersion:<span style="color:#e6db74">&#34;v1.8.3+f0efb3cb88375&#34;</span>, GitCommit:<span style="color:#e6db74">&#34;f0efb3cb883751c5ffdbe6d515f3cb4fbe7b7acd&#34;</span>, GitTreeState:<span style="color:#e6db74">&#34;not a git tree&#34;</span>, BuildDate:<span style="color:#e6db74">&#34;2017-11-09T12:38:03Z&#34;</span>, GoVersion:<span style="color:#e6db74">&#34;go1.9.2&#34;</span>, Compiler:<span style="color:#e6db74">&#34;gc&#34;</span>, Platform:<span style="color:#e6db74">&#34;linux/amd64&#34;</span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>Server Version: version.Info<span style="color:#f92672">{</span>Major:<span style="color:#e6db74">&#34;1&#34;</span>, Minor:<span style="color:#e6db74">&#34;8+&#34;</span>, GitVersion:<span style="color:#e6db74">&#34;v1.8.3-gke.0&#34;</span>, GitCommit:<span style="color:#e6db74">&#34;86d3ac5eaf57223302c95e7d9fc1aeff55fb0c15&#34;</span>, GitTreeState:<span style="color:#e6db74">&#34;clean&#34;</span>, BuildDate:<span style="color:#e6db74">&#34;2017-11-08T21:42:58Z&#34;</span>, GoVersion:<span style="color:#e6db74">&#34;go1.8.3b4&#34;</span>, Compiler:<span style="color:#e6db74">&#34;gc&#34;</span>, Platform:<span style="color:#e6db74">&#34;linux/amd64&#34;</span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="using-helm-to-install-traefik">Using Helm to install Traefik</h2>
<p>To use Traefik with Let&rsquo;s Encrypt, the easiest way to install it is via <a href="https://github.com/kubernetes/helm">Helm</a>: the Kubernetes Package Manager. You can install it from <a href="https://docs.helm.sh/using_helm/#installing-helm">here</a>.</p>
<p>Once Helm is installed, you can run <code>helm init</code>. It will install Tiller (the cluster-side service) on your cluster.
If you have several clusters, check that <code>kubectl config current-context</code> returns the wanted cluster, if not you can use the <code>--kube-context</code> option from <code>helm</code> to install it on a different one.</p>
<p>Let&rsquo;s create our Traefik chart configuration. Here is my <code>traefik-helm.yml</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">imageTag</span>: <span style="color:#ae81ff">1.5</span>                                    
</span></span><span style="display:flex;"><span><span style="color:#f92672">ssl</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">enforced</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">acme</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">email</span>: <span style="color:#e6db74">&#34;&lt;your email&gt;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">staging</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">persistence.enabled</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">dashboard</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">domain</span>: <span style="color:#e6db74">&#34;&lt;adress of the dashboard&gt;&#34;</span>
</span></span></code></pre></div><p><code>imageTag</code> allows us to specify Traefik&rsquo;s version, here the latest one. <code>ssl.enabled</code>, well, enables HTTPS while <code>ssl.enforced</code> enables the HTTP to HTTPS redirection.
Next, the <code>acme</code> section is about Let&rsquo;s Encrypt certificates generation, and the last section is whether or not you would like to set up Traefik&rsquo;s dashboard. More configuration options can be found <a href="https://github.com/kubernetes/charts/tree/master/stable/traefik">here</a>, such as Volume types for persistent storage or connection to <a href="https://prometheus.io/">Prometheus</a>. Also, I did not specify it, but by default, the <code>replicas</code> count will be one, which is the best option when using Let&rsquo;s Encrypt for the moment.</p>
<p>We are now ready to run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ helm install --namespace kube-system --name traefik --values traefik-helm.yml stable/traefik
</span></span><span style="display:flex;"><span>Error: release traefik failed: namespaces <span style="color:#e6db74">&#34;kube-system&#34;</span> is forbidden: User <span style="color:#e6db74">&#34;system:serviceaccount:kube-system:default&#34;</span> cannot get namespaces in the namespace <span style="color:#e6db74">&#34;kube-system&#34;</span>: Unknown user <span style="color:#e6db74">&#34;system:serviceaccount:kube-system:default&#34;</span>
</span></span></code></pre></div><p>So that did not work as expected. We need to add a ClusterRoleBinding to add the Role <code>cluster-admin</code> to the ServiceAccount <code>kube-system:default</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl create clusterrolebinding add-on-cluster-admin --clusterrole<span style="color:#f92672">=</span>cluster-admin --serviceaccount<span style="color:#f92672">=</span>kube-system:default
</span></span><span style="display:flex;"><span>clusterrolebinding <span style="color:#e6db74">&#34;add-on-cluster-admin&#34;</span> created
</span></span></code></pre></div><p>Now if we retry:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$helm install --namespace kube-system --name traefik --values traefik-helm.yml stable/traefik                                                  
</span></span><span style="display:flex;"><span>NAME:   traefik                                                                                                                                 
</span></span><span style="display:flex;"><span>LAST DEPLOYED: Sat Dec <span style="color:#ae81ff">16</span> 11:05:39 <span style="color:#ae81ff">2017</span>                                                                                                         
</span></span><span style="display:flex;"><span>NAMESPACE: kube-system                                                                                                                          
</span></span><span style="display:flex;"><span>STATUS: DEPLOYED                                                                                                                                
</span></span><span style="display:flex;"><span>                                                                                                                                                
</span></span><span style="display:flex;"><span>RESOURCES:                                                                                                                                      
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1/ConfigMap                                                                                                                                
</span></span><span style="display:flex;"><span>NAME             DATA  AGE                                                                                                                      
</span></span><span style="display:flex;"><span>traefik-traefik  <span style="color:#ae81ff">1</span>     1s                                                                                                                       
</span></span><span style="display:flex;"><span>                                                                                                                                                
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1/PersistentVolumeClaim                                                                                                                    
</span></span><span style="display:flex;"><span>NAME                  STATUS   VOLUME    CAPACITY  ACCESS MODES  STORAGECLASS  AGE                                                              
</span></span><span style="display:flex;"><span>traefik-traefik-acme  Pending  standard  1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1/Service
</span></span><span style="display:flex;"><span>NAME                       TYPE          CLUSTER-IP     EXTERNAL-IP  PORT<span style="color:#f92672">(</span>S<span style="color:#f92672">)</span>                     AGE
</span></span><span style="display:flex;"><span>traefik-traefik-dashboard  ClusterIP     10.43.254.78   &lt;none&gt;       80/TCP                      1s
</span></span><span style="display:flex;"><span>traefik-traefik            LoadBalancer  10.43.249.218  &lt;pending&gt;    80:30922/TCP,443:30670/TCP  1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1beta1/Deployment
</span></span><span style="display:flex;"><span>NAME             DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
</span></span><span style="display:flex;"><span>traefik-traefik  <span style="color:#ae81ff">1</span>        <span style="color:#ae81ff">1</span>        <span style="color:#ae81ff">1</span>           <span style="color:#ae81ff">0</span>          1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1beta1/Ingress
</span></span><span style="display:flex;"><span>NAME                       HOSTS        ADDRESS  PORTS  AGE
</span></span><span style="display:flex;"><span>traefik-traefik-dashboard  &lt;dashboard-address&gt;  <span style="color:#ae81ff">80</span>       1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1/Pod<span style="color:#f92672">(</span>related<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>NAME                              READY  STATUS   RESTARTS  AGE
</span></span><span style="display:flex;"><span>traefik-traefik-6fc99c65d7-qm44j  0/1    Pending  <span style="color:#ae81ff">0</span>         1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>&gt; v1/Secret
</span></span><span style="display:flex;"><span>NAME                          TYPE    DATA  AGE
</span></span><span style="display:flex;"><span>traefik-traefik-default-cert  Opaque  <span style="color:#ae81ff">2</span>     1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>NOTES:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>1. Get Traefik<span style="color:#e6db74">&#39;s load balancer IP/hostname:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">     NOTE: It may take a few minutes for this to become available.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">     You can watch the status by running:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">         $ kubectl get svc traefik-traefik --namespace
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">kube-system -w
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">     Once &#39;</span>EXTERNAL-IP<span style="color:#e6db74">&#39; is no longer &#39;</span>&lt;pending&gt;<span style="color:#e6db74">&#39;:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">         $ kubectl describe svc traefik-traefik --namespace kube-system | grep Ingress | awk &#39;</span><span style="color:#f92672">{</span>print $3<span style="color:#f92672">}</span><span style="color:#960050;background-color:#1e0010">&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>2. Configure DNS records corresponding to Kubernetes ingress resources to point to the load balancer IP/hostname found in step <span style="color:#ae81ff">1</span>
</span></span></code></pre></div><p>It worked! We can get the external IP pointing to Traefik by this command (you may need to wait a few seconds):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl describe svc traefik-traefik --namespace kube-system | grep Ingress | awk <span style="color:#e6db74">&#39;{print $3}&#39;</span>
</span></span><span style="display:flex;"><span>35.198.124.40
</span></span></code></pre></div><p>Now we just need to edit our DNS records to match our dashboard&rsquo;s URL to this IP. Let&rsquo;s say you have the example.com domain: You will need one A record from this IP to dashboard.example.com, one A record to drone.example.com, and a last to app.example.com. Here is what I get when accessing the dashboard:
<img alt="Traefik&rsquo;s dashboard" src="/images/traefik-dashboard.png"></p>
<h2 id="testing-traefik-with-an-example">Testing Traefik with an example</h2>
<p>Now that we have Traefik up and running, and before getting started with Drone, we are just going to deploy a simple application to check if Traefik works as intended.
Here is my <code>basic-deployment.yml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1beta2                              </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">matchLabels</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">app</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">app</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>              - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">image</span>: <span style="color:#ae81ff">stenote/nginx-hostname:latest</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">apps</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">app</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">port</span>: <span style="color:#ae81ff">80</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http</span>
</span></span></code></pre></div><p>It will create two replicas of a <a href="https://hub.docker.com/r/stenote/nginx-hostname/">basic NGINX server</a> which prints the hostname.
We apply it with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl apply -f basic-deployment.yml          
</span></span><span style="display:flex;"><span>deployment <span style="color:#e6db74">&#34;nginx&#34;</span> created
</span></span><span style="display:flex;"><span>service <span style="color:#e6db74">&#34;nginx&#34;</span> created
</span></span></code></pre></div><p>Now we need to create an Ingress to tell Traefik to use this service as the endpoint for the <code>app.example.com</code> URL. Here is my <code>basic-ingress.yml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">extensions/v1beta1                        </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Ingress</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">annotations</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes.io/ingress.class</span>: <span style="color:#ae81ff">traefik</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">rules</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">host</span>: <span style="color:#e6db74">&#34;&lt;your-desired-URL&gt;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">http</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">paths</span>:
</span></span><span style="display:flex;"><span>              - <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">backend</span>: 
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">serviceName</span>: <span style="color:#ae81ff">nginx</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">servicePort</span>: <span style="color:#ae81ff">http</span>
</span></span></code></pre></div><p>And we apply it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl apply -f basic-ingress.yml                  
</span></span><span style="display:flex;"><span>ingress <span style="color:#e6db74">&#34;drone&#34;</span> created
</span></span></code></pre></div><p>If we visit and refresh several times this URL, we can see that the hostname is changing. Traefik is working and is correctly redirecting to one of the two replicas created, perfect!</p>
<h2 id="deploying-and-configuring-drone">Deploying and configuring Drone</h2>
<p>Traefik is working so let&rsquo;s get to Drone. I will set up Drone with GitHub, but you can do it with GitLab, Gogs, Bitbucket,&hellip;Only the environment variables will change. You can find the instructions <a href="http://docs.drone.io/installation/">here</a>.</p>
<h3 id="configuring-a-github-oauth">Configuring a GitHub OAuth</h3>
<p>You must go to GitHub &gt; Settings &gt; Developer settings &gt; OAuth Apps and click on <code>New OAuth App</code>. You must complete the form like this (replacing <code>https://drone.foo.com</code> with your URL):
<img alt="GitHub OAuth App Page" src="/images/drone-auth.png"></p>
<p>Keep this page open since we will soon need the client and secret key.</p>
<h3 id="deploying-drone">Deploying Drone</h3>
<p>We will deploy Drone on the K8s cluster, I will group all the necessary Kubernetes objects in one YAML file, but of course you can split it in several files. Here is my drone-k8s.yml.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1beta2                               </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment                                       </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:                                              
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone                                        </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:                                                  
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">selector</span>:                                          
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">matchLabels</span>:                                   
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">app</span>: <span style="color:#ae81ff">drone                                 </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span>                                        
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">template</span>:                                          
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">metadata</span>:                                      
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">labels</span>:                                    
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">app</span>: <span style="color:#ae81ff">drone                             </span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">spec</span>:                                          
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">containers</span>:                                
</span></span><span style="display:flex;"><span>              - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone                              </span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">image</span>: <span style="color:#ae81ff">drone/drone:0.8                   </span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_OPEN                       </span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;false&#34;</span>                         
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_ADMIN                      </span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;&lt;your-git-username&gt;&#34;</span>                         
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_HOST                       </span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;&lt;your-drone-URL&gt;&#34;</span>         
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_GITHUB                     </span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;true&#34;</span>                          
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_GITHUB_CLIENT              </span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;&lt;your-github-client-id&gt;&#34;</span>          
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_GITHUB_SECRET              </span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;&lt;your-github-client-secret&gt;&#34;</span>
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_SECRET</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;&lt;random-string&gt;&#34;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>                - <span style="color:#f92672">containerPort</span>: <span style="color:#ae81ff">8000</span>
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-web-port</span>
</span></span><span style="display:flex;"><span>                - <span style="color:#f92672">containerPort</span>: <span style="color:#ae81ff">9000</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">volumeMounts</span>:
</span></span><span style="display:flex;"><span>                - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/lib/drone</span>
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-db</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-db</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/lib/drone</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1 </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service                                          </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:                                              
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone                                        </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">labels</span>:                                            
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">apps</span>: <span style="color:#ae81ff">drone                                    </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:                                                  
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:                                             
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http                                       </span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">port</span>: <span style="color:#ae81ff">80</span>                                         
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">drone-web-port                       </span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP                                    </span>
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">agent                                      </span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9000</span>                                       
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">selector</span>:                                          
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">app</span>: <span style="color:#ae81ff">drone                                       </span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1beta2</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-agent</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">selector</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">matchLabels</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">app</span>: <span style="color:#ae81ff">drone-agent</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">template</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">app</span>: <span style="color:#ae81ff">drone-agent</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">containers</span>:
</span></span><span style="display:flex;"><span>              - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-agent</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">image</span>: <span style="color:#ae81ff">drone/agent:0.8</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">args</span>: [<span style="color:#e6db74">&#34;agent&#34;</span>]
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_SERVER</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;drone:9000&#34;</span>
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">DRONE_SECRET</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">value</span>: <span style="color:#e6db74">&#34;&lt;same-random-string-as-above&gt;&#34;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">volumeMounts</span>:
</span></span><span style="display:flex;"><span>                  - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/var/run/docker.sock</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">docker-socket</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>              - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">docker-socket</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">hostPath</span>:
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/var/run/docker.sock</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">extensions/v1beta1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Ingress</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">annotations</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes.io/ingress.class</span>: <span style="color:#ae81ff">traefik</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">rules</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">host</span>: <span style="color:#e6db74">&#34;&lt;your-drone-URL&gt;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">http</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">paths</span>:
</span></span><span style="display:flex;"><span>              - <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">backend</span>:
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">serviceName</span>: <span style="color:#ae81ff">drone</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">servicePort</span>: <span style="color:#ae81ff">http</span>
</span></span></code></pre></div><p>We have one Deployment and one Service for Drone&rsquo;s server and one Deployment for Drone&rsquo;s agent. We don&rsquo;t need any Service for the agent since it does not expose any port. Finally, we have an Ingress for Traefik.</p>
<p>Okay, so now let&rsquo;s apply it!</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl apply -f drone-k8s.yml
</span></span><span style="display:flex;"><span>deployment <span style="color:#e6db74">&#34;drone&#34;</span> created
</span></span><span style="display:flex;"><span>service <span style="color:#e6db74">&#34;drone&#34;</span> created
</span></span><span style="display:flex;"><span>deployment <span style="color:#e6db74">&#34;drone-agent&#34;</span> created
</span></span><span style="display:flex;"><span>ingress <span style="color:#e6db74">&#34;drone&#34;</span> configured
</span></span></code></pre></div><p>And, ta-da, you can access Drone at the URL you chose!</p>
<h2 id="using-drone">Using Drone</h2>
<p>Now that Drone is working, I will show you how to use it. Drone will build the Dockerfile of my chosen repo, upload it to Dockerhub, tagged with the commit&rsquo;s hash, and update the deployment on Kubernetes with the new upload image.</p>
<p>First, let&rsquo;s create the <code>.drone.yml</code> in the repo you want to build.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">pipeline</span>:                                             
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">docker</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">plugins/docker</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">repo</span>: <span style="color:#ae81ff">&lt;your-username&gt;/&lt;your-repo&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">tags</span>: <span style="color:#ae81ff">${DRONE_COMMIT_SHA:0:8}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">username</span>: <span style="color:#ae81ff">&lt;your-username&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">secrets</span>: [ <span style="color:#ae81ff">docker_password ] </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">deploy</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">quay.io/honestbee/drone-kubernetes</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes_server</span>: <span style="color:#ae81ff">${KUBERNETES_SERVER}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes_cert</span>: <span style="color:#ae81ff">${KUBERNETES_CERT}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">kubernetes_token</span>: <span style="color:#ae81ff">${KUBERNETES_TOKEN}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">deployment</span>: <span style="color:#ae81ff">&lt;name-of-the-deployment&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">repo</span>: <span style="color:#ae81ff">&lt;your-username&gt;/&lt;your-repo&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">container</span>: <span style="color:#ae81ff">&lt;name-of-your-container&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">tag</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">${DRONE_COMMIT_SHA:0:8}</span>
</span></span></code></pre></div><p>This file uses two plugins: <a href="http://plugins.drone.io/drone-plugins/drone-docker/">one to push to Dockerhub</a> and <a href="https://github.com/honestbee/drone-kubernetes">one to update the deployment</a>.</p>
<p>To make it work, we need to add the right secrets.
You will need to install the <a href="http://docs.drone.io/cli-installation/">Drone CLI</a>. On Linux, you just have to enter:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ curl -L https://github.com/drone/drone-cli/releases/download/v0.7.0/drone_linux_amd64.tar.gz | tar zx
</span></span><span style="display:flex;"><span>$ sudo install -t /usr/local/bin drone
</span></span></code></pre></div><p>Next step is to get the right tokens: go to your newly created Drone and on the top right click on the menu icon and click on <code>Token</code>.
Copy and paste the first two lines of the <code>Example CLI Usage</code> into your terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DRONE_SERVER<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&lt;your-drone-URL&gt;&#34;</span>
</span></span><span style="display:flex;"><span>export DRONE_TOKEN<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&lt;your-drone-token&gt;&#34;</span>
</span></span></code></pre></div><p>If it worked, you should get the right output when you type <code>drone info</code>.</p>
<h3 id="adding-secrets-to-drone">Adding secrets to Drone</h3>
<p>Before adding any secret to a repo, this one needs to be added through Drone&rsquo;s UI.
For the first plugin to work, we need to add the <code>docker_password</code> secret:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>drone secret add -repository &lt;your-username&gt;/&lt;your-repo&gt; -image plugins/docker -name docker_password -value <span style="color:#e6db74">&#34;&lt;your-dockerhub-password&gt;&#34;</span>
</span></span></code></pre></div><p>The next plugins uses three different secrets: <code>kubernetes_server</code>, <code>kubernetes_cert</code>, and <code>kubernetes_token</code>.</p>
<p>However, we need to create an RBAC in order the plugin to deploy.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1                                        </span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ServiceAccount</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">default</span>
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">rbac.authorization.k8s.io/v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Role</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">default</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">rules</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">apiGroups</span>: [<span style="color:#e6db74">&#34;extensions&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">resources</span>: [<span style="color:#e6db74">&#34;deployments&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">verbs</span>: [<span style="color:#e6db74">&#34;get&#34;</span>,<span style="color:#e6db74">&#34;list&#34;</span>,<span style="color:#e6db74">&#34;patch&#34;</span>,<span style="color:#e6db74">&#34;update&#34;</span>]
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">rbac.authorization.k8s.io/v1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">RoleBinding</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">default</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">subjects</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ServiceAccount</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">default</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">roleRef</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Role</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">drone-deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">apiGroup</span>: <span style="color:#ae81ff">rbac.authorization.k8s.io</span>
</span></span></code></pre></div><p>And apply it : <code>kubectl apply -f drone-rbac.yml</code>
If you are running K8s on GKE, you need to first add the Role <code>cluster-admin</code> to your gcloud user (see this <a href="https://github.com/coreos/prometheus-operator/issues/357">issue</a>).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl create clusterrolebinding &lt;your-user-cluster-admin-binding&gt; --clusterrole<span style="color:#f92672">=</span>cluster-admin --user<span style="color:#f92672">=</span>your.google.cloud.email@example.org
</span></span></code></pre></div><p>Then we need to extract the <code>ca.crt</code> and the <code>token</code> from the service account.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kubectl -n &lt;namespace&gt; get secrets
</span></span><span style="display:flex;"><span>NAME                       TYPE                                  DATA      AGE
</span></span><span style="display:flex;"><span>default-token-ms8cl        kubernetes.io/service-account-token   <span style="color:#ae81ff">3</span>         3h
</span></span><span style="display:flex;"><span>drone-deploy-token-4zv8j   kubernetes.io/service-account-token   <span style="color:#ae81ff">3</span>         10m 
</span></span><span style="display:flex;"><span>$ kubectl -n &lt;namespace&gt; get secret/drone-deploy-token-4zv8j -o yaml | grep <span style="color:#e6db74">&#39;ca.crt:&#39;</span>
</span></span><span style="display:flex;"><span>  ca.crt: &lt;your-crt&gt;
</span></span><span style="display:flex;"><span>$ kubectl describe secret drone-deploy-token-4zv8j | grep <span style="color:#e6db74">&#39;token:&#39;</span>
</span></span><span style="display:flex;"><span>  token: &lt;your-token&gt;
</span></span></code></pre></div><p>Once this is done, we can create our secrets.</p>
<ul>
<li>To get the IP of your master node, you can use the <code>kubectl cluster-info</code> command. And we create the secret with <code>drone secret add --image=quay.io/honestbee/drone-kubernetes -repository &lt;your-username&gt;/&lt;your-repo&gt; -name kubernetes_server -value &quot;https://&lt;master-ip&gt;&quot;</code></li>
<li>To create the token secret, we run <code>drone secret add --image=quay.io/honestbee/drone-kubernetes -repository &lt;your-username&gt;/&lt;your-repo&gt; -name kubernetes_token -value &lt;your-token&gt;</code></li>
<li>To create the cert token, we run <code>drone secret add --image=quay.io/honestbee/drone-kubernetes -repository &lt;your-username&gt;/&lt;your-repo&gt; -name kubernetes_cert -value &lt;your-crt&gt;</code></li>
</ul>
<p>However, for this plugin to work, the deployment has to be already created. You can check this <a href="https://github.com/vallard/drone-kube">plugin</a>, if you want Drone to run <code>kubectl apply -f deploy.yml</code> instead of just changing the image of the deployment.</p>
<p>Now, once you push some new code on GitHub, it will trigger Drone and start your build/deployment. Cheers!</p>
]]></content></item><item><title>Multi HTTPS sub domain with Traefik and Docker - Part 2</title><link>https://ptrk.io/posts/2017/10/multi-https-sub-domain-with-traefik-and-docker-part-2/</link><pubDate>Sun, 08 Oct 2017 00:00:00 +0000</pubDate><guid>https://ptrk.io/posts/2017/10/multi-https-sub-domain-with-traefik-and-docker-part-2/</guid><description>In this (small) second part, we&amp;rsquo;ll set up Traefik Web UI on its own sub domain with a basic HTTP authentication.
Basic dashboard In the traefik.toml we add the following just before the [entryPoints] label:
[web] # Port for the status page address = &amp;#34;:8080&amp;#34; We also need to map the port 8080 in the docker-compose.yml so you have to add this line in the ports section:
- 8080:8080 Now we can access Traefik Web UI at yourdomain.</description><content type="html"><![CDATA[<p>In this (small) second part, we&rsquo;ll set up Traefik Web UI on its own sub domain with a basic HTTP authentication.</p>
<h2 id="basic-dashboard">Basic dashboard</h2>
<p>In the <code>traefik.toml</code> we add the following just before the <code>[entryPoints]</code> label:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">web</span>]
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Port for the status page</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">address</span> = <span style="color:#e6db74">&#34;:8080&#34;</span>
</span></span></code></pre></div><p>We also need to map the port 8080 in the <code>docker-compose.yml</code> so you have to add this line in the ports section:</p>
<pre tabindex="0"><code>- 8080:8080
</code></pre><p>Now we can access Traefik Web UI at <code>yourdomain.com:8080</code>. It will look like this:</p>
<p><img alt="Traefik&rsquo;s dashboard" src="/images/dashboard-1.png"></p>
<h2 id="lets-add-a-sub-domain">Let&rsquo;s add a sub domain</h2>
<p>Now we need to modify the <code>docker-compose.yml</code> in order to redirect to a sub domain. The only thing we are going to add is the Docker labels:</p>
<ul>
<li><code>&quot;traefik.enabled=true&quot;</code></li>
<li><code>&quot;traefik.backend=dashboard&quot;</code></li>
<li><code>&quot;traefik.frontend.rule=Host:dashboard.yourdomain.com&quot;</code></li>
<li><code>&quot;traefik.port=8080&quot;</code></li>
</ul>
<p>Moreover, we don&rsquo;t need to map the port 8080 since we will not access the dashboard through this port.</p>
<p>So our file will look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;2&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">traefik</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">traefik</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">command</span>: --<span style="color:#ae81ff">web --docker</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;80:80&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;443:443&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.enabled=true&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.backend=dashboard&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.frontend.rule=Host:dashboard.yourdomain.com&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.port=8080&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;/var/run/docker.sock:/var/run/docker.sock&#34;</span> 
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;./traefik.toml:/traefik.toml&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;./acme.json:/acme.json&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">default </span>
</span></span></code></pre></div><p>Now you can access your dashboard through the desired URL!</p>
<h2 id="a-basic-http-authentication">A basic HTTP authentication</h2>
<p>If you need to protect your application with a user/password authentication, Traefik can do it for you. Again it&rsquo;s configurable via the Docker labels of the service:
<code>traefik.frontend.auth.basic=user:passwordHash</code>
You can get the hash with the htpasswd command like this</p>
<pre tabindex="0"><code>$ htpasswd -nB user
New password:
Re-type new password:
user:$2y$05$NiscFUPxmLub5vW1gL6cF.4R1ElHKeMgBQKNPIY.1V.CW802nXhwG
</code></pre><p>When you add the hash in the <code>docker-compose.yml</code> you must escape the <code>$</code> character with another <code>$</code>. In this case we will have :
<code>traefik.frontend.auth.basic=user:$$2y$$05$$NiscFUPxmLub5vW1gL6cF.4R1ElHKeMgBQKNPIY.1V.CW802nXhwG</code>. Your application will then be protected by a user/password authentication.</p>
<p>You can now easily access your public and private Docker applications through different sub domains.</p>
]]></content></item><item><title>Multi HTTPS sub domain with Traefik and Docker - Part 1</title><link>https://ptrk.io/posts/2017/10/multi-https-sub-domain-with-traefik-and-docker-part-1/</link><pubDate>Wed, 04 Oct 2017 00:00:00 +0000</pubDate><guid>https://ptrk.io/posts/2017/10/multi-https-sub-domain-with-traefik-and-docker-part-1/</guid><description>Today I&amp;rsquo;ll show you how to make several Docker containers accessible via automatic HTTPS with Let&amp;rsquo;s Encrypt on different sub domains. I assume you are already familiar with Docker, if not I recommend you to read the following getting started guide, especially the first three parts.
Traefik We will use Traefik. So first what is Traefik? According to its website:
Traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.</description><content type="html"><![CDATA[<p>Today I&rsquo;ll show you how to make several Docker containers accessible via automatic HTTPS with <a href="https://letsencrypt.org/">Let&rsquo;s Encrypt</a> on different sub domains.
I assume you are already familiar with <a href="https://www.docker.com/">Docker</a>, if not I recommend you to read the following <a href="https://docs.docker.com/get-started/">getting started guide</a>, especially the first three parts.</p>
<h2 id="traefik">Traefik</h2>
<p>We will use <a href="https://traefik.io"><em>Traefik</em></a>. So first what is <em>Traefik</em>? According to its website:</p>
<blockquote>
<p>Traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. It supports several backends (Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS, and a lot more) to manage its configuration automatically and dynamically.</p>
</blockquote>
<p><img alt="Architecture of Traefik" src="/images/architecture-2.png"></p>
<p>In our case, we will principally use the reverse proxy feature, and the automatic configuration. That means the right redirection from the sub domain to the right Docker.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>In order to follow this guide, you will need a server and a domain name. You can of course test Traefik on your local computer, but this is intended to real sub domains.</p>
<p>So I will consider that you have already:</p>
<ul>
<li>a running and accessible server</li>
<li>a domain name and some sub domain names all pointing to your server IP</li>
<li>a working installation of Docker</li>
</ul>
<h2 id="lets-dive-into-it">Let&rsquo;s dive into it</h2>
<p>For the first example I&rsquo;ll just create a basic web server using nginx.
We&rsquo;ll create the necessary directories</p>
<pre tabindex="0"><code>$ mkdir -p server/{traefik,nginx}
</code></pre><p>In the <code>traefik</code> folder, we can now create the <code>docker-compose.yml</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;2&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">traefik</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">traefik:raclette</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">command</span>: --<span style="color:#ae81ff">docker</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;80:80&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;443:443&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;/var/run/docker.sock:/var/run/docker.sock&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;./traefik.toml:/traefik.toml&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;./acme.json:/acme.json&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">default</span>
</span></span></code></pre></div><p>Basically what it does is:</p>
<ul>
<li>Pull the raclette (1.3) Traefik docker image</li>
<li>Start the command with the <code>docker</code> argument, which enable the Docker backend</li>
<li>Map the port HTTP and HTTPS ports to the host</li>
<li>Mount the Docker sock (to communicate with the Docker daemon)</li>
<li>Mount the configuration file and the Let&rsquo;s Encrypt file
Now we can create the <code>traefik.toml</code> and the <code>acme.toml</code></li>
</ul>
<h2 id="lets-encrypt">Let&rsquo;s Encrypt</h2>
<p>Traefik uses Let&rsquo;s Encrypt to generate automated HTTPS certificate for free. For more technical information you can visit the <a href="https://letsencrypt.org/">Let&rsquo;s Encrypt website</a>.</p>
<p>It will generate a certificate for each service we will create, and manage the renewal. The <code>acme.json</code> is here to store these certificates. We could keep it inside the Docker since if it reboots it will regenerate the certificates, however keeping it outside our container is a bit more efficient. (It could also avoid us to reach Let&rsquo;s Encrypt limits).
The file needs to have only read-write permissions for the current user so let&rsquo;s create it and set the right permissions:</p>
<pre tabindex="0"><code>$ touch acme.json &amp;&amp; chmod 600 acme.json
</code></pre><h2 id="traefiktoml">traefik.toml</h2>
<p>The Traefik config file is in the toml format. Here is a short example with HTTP redirection to HTTPS and Let&rsquo;s Encrypt certificate:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#75715e"># defaultEntryPoints must be at the top </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># because it should not be in any table below</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">defaultEntryPoints</span> = [<span style="color:#e6db74">&#34;http&#34;</span>, <span style="color:#e6db74">&#34;https&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Entrypoints, http and https</span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">entryPoints</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># http should be redirected to https</span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">entryPoints</span>.<span style="color:#a6e22e">http</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">address</span> = <span style="color:#e6db74">&#34;:80&#34;</span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">entryPoints</span>.<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">redirect</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">entryPoint</span> = <span style="color:#e6db74">&#34;https&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># https is the default</span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">entryPoints</span>.<span style="color:#a6e22e">https</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">address</span> = <span style="color:#e6db74">&#34;:443&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">entryPoints</span>.<span style="color:#a6e22e">https</span>.<span style="color:#a6e22e">tls</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Enable ACME (Let&#39;s Encrypt): automatic SSL</span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">acme</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">email</span> = <span style="color:#e6db74">&#34;your.email@domain.com&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">storage</span> = <span style="color:#e6db74">&#34;/acme.json&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">entryPoint</span> = <span style="color:#e6db74">&#34;https&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">onDemand</span> = <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">OnHostRule</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">docker</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">endpoint</span> = <span style="color:#e6db74">&#34;unix:///var/run/docker.sock&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">domain</span> = <span style="color:#e6db74">&#34;yourdomain.com&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">watch</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">exposedbydefault</span> = <span style="color:#66d9ef">false</span>
</span></span></code></pre></div><p>You have to change your email, and the domain name. In this case, I disabled the <code>exposedbydefault</code> so we&rsquo;ll have to manually tell that a container have to be exposed.</p>
<h2 id="run-it">Run it!</h2>
<p>Now that we have all the configuration file:</p>
<pre tabindex="0"><code>$ ls # in server/traefik
acme.json  docker-compose.yml traefik.toml
</code></pre><p>we can execute <code>docker-compose up -d</code>.
It will create the Docker container for Traefik and a new network <code>traefik_default</code>.
If we curl the sub domain desired for nginx we get a <code>404 page not found</code> which indicates that Traefik received the requests but did not found any backend to proxy the request. Let&rsquo;s set up our nginx container next!</p>
<h2 id="our-first-service">Our first service</h2>
<p>We succeeded to set up Traefik, we now have to use it. In order to use the Docker backend, we will use the Docker labels. Here are a few labels:</p>
<ul>
<li><code>traefik.backend=example</code> gives the name example to the generated backend</li>
<li><code>traefik.port=80</code> which indicates which port Traefik will proxy the requests to</li>
<li><code>traefik.enable=true</code> enable Traefik on the specified container</li>
<li><code>traefik.frontend.rule=Host:subdomain.example.com</code> tells Traefik to route all the requests from this sub domain to this container</li>
</ul>
<p>The full list can be found <a href="https://docs.traefik.io/configuration/backends/docker/">here</a>.</p>
<p>Here is the <code>docker-compose.yml</code> for the simple nginx container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;2&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">nginx</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx:stable</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.enabled=true&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.backend=nginx&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.frontend.rule=Host:subdomain.example.com&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.port=80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">traefik_default</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">traefik_default</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">external</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">name</span>: <span style="color:#ae81ff">traefik_default</span>
</span></span></code></pre></div><p>We don&rsquo;t need the expose the port 80 since Traefik redirects the traffic in the container. And we have to add another network to have the Traefik container and the nginx container in the same network, so they can communicate. Another way would be the add the label <code>traefik.docker.network</code> with the right network name.</p>
<p>Finally you just have to <code>docker-compose up -d</code> and voilà! If you now try to open <code>subdomain.example.com</code> you will be redirected to <code>https://subdomain.example.com</code> with a valid certificate and you can see the nginx page.</p>
<h2 id="a-practical-example">A practical example</h2>
<p>I&rsquo;ll show you a quick example with two Docker containers running <a href="http://flask.pocoo.org/">Flask</a> on <code>test1.ptrk.io</code> and <code>test2.ptrk.io</code>. We need to create a directory <code>test</code> and the following files:</p>
<ul>
<li><code>docker-compose.yml</code></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;2&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">test1</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">build</span>: <span style="color:#ae81ff">.</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.enabled=true&#34;</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.backend=test1&#34;</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.frontend.rule=Host:test1.ptrk.io&#34;</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.port=5000&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik_default&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">test2</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">build</span>: <span style="color:#ae81ff">.</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.enabled=true&#34;</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.backend=test2&#34;</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.frontend.rule=Host:test2.ptrk.io&#34;</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik.port=5000&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#e6db74">&#34;traefik_default&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">traefik_default</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">external</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">name</span>: <span style="color:#ae81ff">traefik_default</span>
</span></span></code></pre></div><ul>
<li><code>Dockerfile</code></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> python:2.7</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /app</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> . /app<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> pip install flask<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ENTRYPOINT</span> [<span style="color:#e6db74">&#34;python&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> [<span style="color:#e6db74">&#34;start.py&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><ul>
<li><code>start.py</code></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> flask <span style="color:#f92672">import</span> Flask, request
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app <span style="color:#f92672">=</span> Flask(__name__)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@app.route</span>(<span style="color:#e6db74">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">hello</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;Hello &#34;</span> <span style="color:#f92672">+</span> request<span style="color:#f92672">.</span>host
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> __name__ <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    app<span style="color:#f92672">.</span>run(debug<span style="color:#f92672">=</span><span style="color:#66d9ef">False</span>,host<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;0.0.0.0&#39;</span>)
</span></span></code></pre></div><p>Now if I run <code>docker-compose up -d</code> I can check <a href="https://test1.ptrk.io">test1.ptrk.io</a> and <a href="https://test2.ptrk.io">test2.ptrk.io</a> to see that we are correctly redirected to the right container.</p>
<h2 id="conclusion">Conclusion</h2>
<p>You can found out more on the <a href="https://docs.traefik.io/">Traefik docs</a>, and in my next post I&rsquo;ll explain how to access to the Traefik web UI on another sub domain, and with basic HTTP authentication.</p>
]]></content></item></channel></rss>