

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
        <channel>
                <title>ops.tips</title>
                <description>Articles on AWS, Golang, Containers, Linux, Infrastructure and more.</description>
                <lastBuildDate>Fri, 11 Dec 2020 00:00:00 +0000</lastBuildDate>
                <link>https://ops.tips/</link>
                <category>Programming, Linux, and Cloud-native technologies</category>

                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                

                        
                        <item>
                                <title>A Raspberry PI Concourse Worker</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve recently bought a &lt;a href=&#34;https://www.raspberrypi.org/products/raspberry-pi-3-model-b-plus/&#34;&gt;Raspberry Pi 3B+&lt;/a&gt;, and that seemed like a great target for a &lt;a href=&#34;https://concourse-ci.org&#34;&gt;Concourse&lt;/a&gt; worker run at.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/concourse-raspberry-pi-diagram.svg&#34;
       alt=&#34;concourse cluster with the raspberry pi included &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;It turns out that just the process of building and adapting the Concourse binary itself was already an interesting thing to do, so here I share the lessons learned and how that process looked like.&lt;/p&gt;
&lt;p&gt;To provide &lt;a href=&#34;https://en.wikipedia.org/wiki/ARM_architecture&#34;&gt;ARM&lt;/a&gt;-compiled binaries for &lt;a href=&#34;https://github.com/cirocosta/node_extra_exporter&#34;&gt;&lt;code&gt;node_extra_exporter&lt;/code&gt;&lt;/a&gt; (a Rust-based &lt;a href=&#34;https://prometheus.io/&#34;&gt;Prometheus&lt;/a&gt; exporter for exposing some metrics that the traditional &lt;code&gt;node_exporter&lt;/code&gt; doesn&amp;rsquo;t expose), it felt like having an ARM-based machine in my Concourse cluster would be a great idea - have an extra job for building the ARM binary and there you go!&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to know what does it take to get a Concourse worker ready to take workloads on ARM, make sure you stick to the end.&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#concourse-workers&#34;&gt;Concourse workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#compiling-the-concourse-binary&#34;&gt;Compiling the Concourse binary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cross-compiling-go-code&#34;&gt;Cross compiling Go code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#compiling-cgo-code&#34;&gt;Compiling CGO code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cross-compiling-cgo-code&#34;&gt;Cross compiling CGO code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#building-guardian-the-containerizer&#34;&gt;Building Guardian, the containerizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#building-baggageclaim-the-volumizer&#34;&gt;Building Baggageclaim, the volumizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#running-the-concourse-worker&#34;&gt;Running the Concourse worker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#generating-the-modified-registry-image-resource&#34;&gt;Generating the modified registry-image-resource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#automating-the-process-of-building-an-arm-based-concourse-distribution&#34;&gt;Automating the process of building an ARM-based Concourse distribution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#summarizing&#34;&gt;Summarizing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#some-surprises&#34;&gt;Some surprises&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;concourse-workers&#34;&gt;Concourse workers&lt;/h3&gt;
&lt;p&gt;Regardless of your knowledge of &lt;a href=&#34;https://concourse-ci.org&#34;&gt;Concourse&lt;/a&gt;, the &lt;em&gt;tl;dr&lt;/em&gt; is that being a &amp;ldquo;continuous thing-doer&amp;rdquo;, it needs some form of compute nodes to do the things you want - these nodes are the workers.&lt;/p&gt;
&lt;p&gt;To perform the job of &amp;ldquo;doing things&amp;rdquo;, in any platform, these workers are made of three components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &amp;ldquo;containerizer&amp;rdquo;, that manages containers&lt;/li&gt;
&lt;li&gt;a &amp;ldquo;volumizer&amp;rdquo;, that manages volumes&lt;/li&gt;
&lt;li&gt;&amp;ldquo;beacon&amp;rdquo;, the piece that registers the worker against the cluster and manages its lifecycle&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/concourse-architecture.svg&#34;
       alt=&#34;minimal architecture showing the internal concourse components &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In the case of Linux, of those three components, two&lt;sup&gt;1&lt;/sup&gt; (the &amp;ldquo;volumizer&amp;rdquo; and &amp;ldquo;beacon&amp;rdquo;) are already part of the &lt;code&gt;concourse&lt;/code&gt; binary. This means that we not only need to build &lt;code&gt;concourse&lt;/code&gt;, but we also need to build the &amp;ldquo;containerizer&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;sup&gt;1&lt;/sup&gt; there&amp;rsquo;s an expection, but that won&amp;rsquo;t be covered here.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;compiling-the-concourse-binary&#34;&gt;Compiling the Concourse binary&lt;/h3&gt;
&lt;p&gt;Being Concourse a project entirely written in Go (actually, there&amp;rsquo;s also the UI, which is in &lt;a href=&#34;https://elm-lang.org/&#34;&gt;Elm&lt;/a&gt;), all that we need at this stage is the Go toolchain.&lt;/p&gt;
&lt;p&gt;As almost all of the Go code necessary for building Concourse is now under a single repository (&lt;a href=&#34;https://github.com/concourse/concourse&#34;&gt;&lt;code&gt;github.com/concourse/concourse&lt;/code&gt;&lt;/a&gt;), and &lt;a href=&#34;https://github.com/golang/go/wiki/Modules&#34;&gt;Go modules&lt;/a&gt; is the way that dependencies are handled there, this is what should be the most straightforward part.&lt;/p&gt;
&lt;p&gt;Given that installing Go is quite straightforward, I decided to do that right in my Raspberry PI (why not?).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/concourse-built-on-raspberry-pi.svg&#34;
       alt=&#34;illustration of the concourse repository being built in a raspberry pi producing armv7 concourse &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;This means that just the following two steps are required:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# clone the main concourse repository&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
git clone https://github.com/concourse/concourse .


&lt;span class=&#34;c1&#34;&gt;# build the main Concourse binary and put the result of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the compilation into `$GOPATH/bin/`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
go install -v ./cmd/concourse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem though, is that the Raspberry PI is not as powerful as one would imagine: despite the 4 core &lt;a href=&#34;https://en.wikipedia.org/wiki/System_on_a_chip&#34;&gt;SoC&lt;/a&gt;, it takes no less than seven minutes once all of the dependencies are already in place. Yeah, SEVEN MINUTES already having fetched all of the dependencies. Without the dependencies: 20 minutes.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #F7F8FA; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/concourse-build-arm.svg&#34;
       alt=&#34;graph showing the cpu utilization of the raspberry pi during the build process &#34; &gt;

    
&lt;/figure&gt;

&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;For a full picture of the dashboard, &lt;a href=&#34;https://snapshot.raintank.io/dashboard/snapshot/URPBthXh5SGLi3HnxxLel1wkmwDQn06X?orgId=2&#34;&gt;click here&lt;/a&gt; to check out the interactive snapshot).&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;As a side note, it was quite interesting for me to see how there are clearly very different phases that the compiler toolchain goes trough when performing the build (not including the dependency fetching that is not in this panel).&lt;/p&gt;
&lt;h3 id=&#34;cross-compiling-go-code&#34;&gt;Cross compiling Go code&lt;/h3&gt;
&lt;p&gt;Knowing that if I&amp;rsquo;d need to recompile this multiple times, it&amp;rsquo;d be crazy slow and, thus, super time consuming, I decided to go with &lt;a href=&#34;http://baruch.siach.name/blog/posts/introduction_to_cross_compilation_part_1/&#34;&gt;cross compiling&lt;/a&gt; - this way we could just use all of the speed we have available and, in the end, just ship the binaries.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/cross-compile.svg&#34;
       alt=&#34;illustration of a macbook pro machine running darwin producing artifacts for other architectures and operating systems &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Another benefit is that it&amp;rsquo;d be easy for anyone to build it too! No need for an actual Raspberry PI (or any ARMv7) to build Concourse.&lt;/p&gt;
&lt;p&gt;The good news is that Go makes that whole job easy for us, making the whole cross compilation dependant on just few flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GOOS&lt;/code&gt; the name of the target operating system&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GOARCH&lt;/code&gt; the name of the target architecture&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GOARM&lt;/code&gt; the version of ARM that want to target&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 85rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/go-compilation.svg&#34;
       alt=&#34;illustration of a golang file going through the compilation steps that gets it towards a compiled binary file &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;For Go code that is free of any calls to C code (via &lt;a href=&#34;https://blog.golang.org/c-go-cgo&#34;&gt;&lt;code&gt;CGO&lt;/code&gt;&lt;/a&gt;), this &amp;ldquo;Just Works™&amp;rdquo; by the magic of the default Go toolchain - the go compilation infrastructure has all the necessary bits to perform the right translation to the right architectures and OSes that it supports.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;re curious about the intermediate representation that the Go compiler generates and how that becomes machine-dependant code, checkout the following example views of &lt;a href=&#34;https://godoc.org/golang.org/x/tools/go/ssa&#34;&gt;Go&amp;rsquo;s SSA&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ops.tips/blog/-/general/ssa-linux-amd64.html&#34;&gt;Linux AMD64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ops.tips/blog/-/general/ssa-linux-arm64.html&#34;&gt;Linux ARM64&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ps.: to compile reproduce: &lt;code&gt;GOSSAFUNC=main go build -gcflags &amp;quot;-S&amp;quot; main.go&lt;/code&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;However, being free of calls to C code is not a property of all projects  - in the case of Concourse itself, &lt;a href=&#34;https://github.com/dexidp/dex&#34;&gt;&lt;code&gt;dex&lt;/code&gt;&lt;/a&gt;, one of our dependencies, depends on &lt;a href=&#34;https://github.com/mattn/go-sqlite3&#34;&gt;&lt;code&gt;go-sqlite3&lt;/code&gt;&lt;/a&gt;, which has bindings to C, which means that we now depend on CGO.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;├ github.com/concourse/concourse/skymarshal/storage
  ├ github.com/concourse/dex/storage
  ├ github.com/concourse/dex/storage/sql
    ├ database/sql
    ├ database/sql/driver
    ...
    └ github.com/mattn/go-sqlite3
      ├ database/sql
      ├ database/sql/driver
      ..
      ├ unsafe
      └ C                       &amp;lt;&amp;lt; CGO!!
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;re curious about an example in &lt;code&gt;go-sqlite3&lt;/code&gt; where CGO gets used, check out &lt;a href=&#34;https://github.com/mattn/go-sqlite3/blob/2a192bf7823799e082cfa3380aab9f02e4d312c0/sqlite3.go#L179-L203&#34;&gt;sqlite3.go&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;To see what I mean by &amp;ldquo;CGO doesn&amp;rsquo;t &amp;lsquo;just works&amp;rsquo;&amp;rdquo;, let&amp;rsquo;s try doing cross compilation with just those flags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;GOARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;arm &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;GOARM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;GOOS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;linux &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                go build ./cmd/concourse/
&lt;span class=&#34;c1&#34;&gt;# runtime/cgo&lt;/span&gt;
gcc: error: unrecognized &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; line option &lt;span class=&#34;s1&#34;&gt;&amp;#39;-marm&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
            did you mean &lt;span class=&#34;s1&#34;&gt;&amp;#39;-mabm&amp;#39;&lt;/span&gt;?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the reason why it wouldn&amp;rsquo;t work out of the box makes sense: when it comes to CGO, you&amp;rsquo;re not only in the realm of the Go toolchain, but you&amp;rsquo;re also relying on the infrastructure to build the C code as well, and there, things are slightly different. Let&amp;rsquo;s expand on it.&lt;/p&gt;
&lt;h3 id=&#34;compiling-cgo-code&#34;&gt;Compiling CGO code&lt;/h3&gt;
&lt;p&gt;As an example of how cross compilation with CGO looks like, let&amp;rsquo;s assume that we have a super extra very efficient library in C that is optimized to print strings to &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/go-calling-c.svg&#34;
       alt=&#34;illustration of building CGO code &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;First, starting with the declaration of the function we want to consume from Go (in the &lt;code&gt;printer.h&lt;/code&gt; file):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;super_optimized_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, in the definition (&lt;code&gt;printer.c&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;printer.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;super_optimized_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now, finally, our Go code that uses CGO (&lt;code&gt;main.go&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// #include &amp;#34;printer.h&amp;#34;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// #include &amp;lt;stdlib.h&amp;gt;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;unsafe&amp;#34;&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;super_optimized_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can then try to build all of that code to our own OS and ARCH, and nothing really needs to be changed: you give the package to the &lt;code&gt;go&lt;/code&gt; compiler, and let it do its job:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;go build -v .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As, in this case, our C code is definitely portable, and we&amp;rsquo;re targetting our own machine architecture, all works. Let&amp;rsquo;s now try to build to a different platform though.&lt;/p&gt;
&lt;h3 id=&#34;cross-compiling-cgo-code&#34;&gt;Cross compiling CGO code&lt;/h3&gt;
&lt;p&gt;However, if, again, we try the cross compilation, it&amp;rsquo;ll fail with the very same error we saw before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;GOOS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;linux &lt;span class=&#34;nv&#34;&gt;GOARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;arm &lt;span class=&#34;nv&#34;&gt;GOARM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; go build -v .
gcc: error: unrecognized &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; line 
     option &lt;span class=&#34;s1&#34;&gt;&amp;#39;-marm&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; did you mean &lt;span class=&#34;s1&#34;&gt;&amp;#39;-mabm&amp;#39;&lt;/span&gt;?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The good news is that without even looking at the Go code, we can see how that separation of &amp;ldquo;who compiles what&amp;rdquo; happens by tracing all of the &lt;a href=&#34;https://linux.die.net/man/2/execve&#34;&gt;&lt;code&gt;execve&lt;/code&gt;&lt;/a&gt;s that happen:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PCOMM     PID      PPID     ARGS
--------------------------------------------------------
go        29352    26142    go build .
cgo       29361    29352    cgo -V=full
compile   29362    29352    compile -V=full
compile   29365    29352    compile -V=full
compile   29367    29352    compile -V=full
compile   29376    29352    compile -V=full
asm       29381    29352    asm -V=full
asm       29382    29352    asm -V=full
cgo       29394    29352    cgo -objdir /tmp/go-build123931463/b003/...
gcc       29399    29394    gcc -E -dM -marm -I /tmp/go-build1239314...
&lt;/code&gt;&lt;/pre&gt;&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/cgo-gcc-execsnoop.svg&#34;
       alt=&#34;diagram with the steps taken by the compiler to cross-compile CGO &#34; &gt;

    
&lt;/figure&gt;

&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;For the output above, &lt;a href=&#34;https://github.com/iovisor/bcc/blob/e8dd701f675af95583caf49fc274f11a099bc473/tools/execsnoop_example.txt&#34;&gt;&lt;code&gt;execsnoop&lt;/code&gt;&lt;/a&gt; from &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;&lt;code&gt;iovisor/bcc&lt;/code&gt;&lt;/a&gt; was used.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;And that seems perfectly reasonable - to build &lt;code&gt;C&lt;/code&gt; code, one needs to have a C compiler, which is something totally out of the realm of where the Go team should be focusing on, reason why it calls out to a C compiler.&lt;/p&gt;
&lt;p&gt;The failure that we see there though comes from the fact that to have &lt;a href=&#34;https://gcc.gnu.org/&#34;&gt;GCC&lt;/a&gt; performing the cross compilation, we need to install separate packages before, and properly adjust the C compiler to point to the right compiler.&lt;/p&gt;
&lt;p&gt;Luckly, letting Go know which compiler to use when performing the build comes down to setting the &lt;code&gt;CC&lt;/code&gt; environment variable (see &lt;a href=&#34;https://github.com/golang/go/blob/master/src/cmd/cgo/gcc.go#L1514-L1528&#34;&gt;&lt;code&gt;golang/go#gccBaseCmd()&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;GOOS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;linux &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;GOARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;arm &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;GOARM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;arm-linux-gnueabihf-gcc &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        go build -v
&lt;span class=&#34;c1&#34;&gt;# workkss!!&lt;/span&gt;

PCOMM     PID    PPID   ARGS
go        &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;26142&lt;/span&gt;  go build -v .
cgo       &lt;span class=&#34;m&#34;&gt;30834&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  cgo -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
compile   &lt;span class=&#34;m&#34;&gt;30835&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  compile -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
compile   &lt;span class=&#34;m&#34;&gt;30840&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  compile -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
compile   &lt;span class=&#34;m&#34;&gt;30841&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  compile -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
compile   &lt;span class=&#34;m&#34;&gt;30842&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  compile -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
asm       &lt;span class=&#34;m&#34;&gt;30857&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  asm -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
asm       &lt;span class=&#34;m&#34;&gt;30862&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  asm -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
asm       &lt;span class=&#34;m&#34;&gt;30863&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  asm -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
asm       &lt;span class=&#34;m&#34;&gt;30872&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  asm -V&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;full
cgo       &lt;span class=&#34;m&#34;&gt;30877&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30825&lt;/span&gt;  cgo -objdir /tmp/go-build130487924/b003/ ...
arm-linux-30882  &lt;span class=&#34;m&#34;&gt;30877&lt;/span&gt;  /usr/bin/arm-linux-gnueabihf-gcc -E -dM ...
cc1       &lt;span class=&#34;m&#34;&gt;30883&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;30882&lt;/span&gt;  /usr/lib/gcc-cross/arm-linux-gnueabihf/7/cc1 -E ...
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/cgo-gcc-cross-compile.svg&#34;
       alt=&#34;diagram with the steps taken to properly cross compile CGO &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Now, with the Concourse binary built, we can move to its dependencies.&lt;/p&gt;
&lt;h3 id=&#34;building-guardian-the-containerizer&#34;&gt;Building Guardian, the containerizer&lt;/h3&gt;
&lt;p&gt;As Concourse steps and resource checks run in Containers&lt;sup&gt;1&lt;/sup&gt;, and there&amp;rsquo;s a piece of the Concourse worker that is responsible for that, but Concourse as a team is not necessarily in the business of creating container runtimes, Concourse uses a separate component for doing so: &lt;a href=&#34;https://github.com/cloudfoundry/guardian&#34;&gt;Guardian&lt;/a&gt;(&lt;code&gt;gdn&lt;/code&gt;), an implementation of the &lt;a href=&#34;https://github.com/cloudfoundry/garden&#34;&gt;Garden&lt;/a&gt; interface for container management.&lt;/p&gt;
&lt;p&gt;With the process of creating Linux containers being all standardized now (see &lt;a href=&#34;https://github.com/opencontainers/runtime-spec&#34;&gt;opencontainers/runtime-spec&lt;/a&gt;), Guardian takes the approach of leveraging what&amp;rsquo;s already there, wrapping &lt;a href=&#34;https://github.com/opencontainers/runc&#34;&gt;&lt;code&gt;runc&lt;/code&gt;&lt;/a&gt;, the &lt;em&gt;de facto&lt;/em&gt; implementation of the Runtime Spec, allowing consumers of the Garden interface to have containers created by Runc, without leaking the implementation details to the Garden interface.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/please-create-a-container.svg&#34;
       alt=&#34;illustration of Concourse interatinig with Garden to create a container &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The detail here though, is that while most of &lt;code&gt;gdn&lt;/code&gt; is pure Go, there are many bits from &lt;code&gt;runc&lt;/code&gt; (&lt;code&gt;gdn&lt;/code&gt;&amp;rsquo;s dependency) that are C based, and Guardian itself depends on other binaries (one being a C program).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/gdn-dependencies.svg&#34;
       alt=&#34;Guardian dependencies &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Another detail in the process os building &lt;code&gt;gdn&lt;/code&gt; is that, by default, &lt;code&gt;gdn&lt;/code&gt; is not suitable for multiple architectures due to the way the way that it interacts with &lt;code&gt;runc&lt;/code&gt; when it comes to asking &lt;code&gt;runc&lt;/code&gt; to block specific syscalls.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 90rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/seccomp-limitting.svg&#34;
       alt=&#34;seccomp in action, limiting the system calls that a process can use &#34; &gt;

    
&lt;/figure&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Seccomp represents syscall restrictions
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// By default, only the native architecture of the kernel is allowed to be used
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// for syscalls. Additional architectures can be added by specifying them in
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Architectures.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Seccomp&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;DefaultAction&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Action&lt;/span&gt;     &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;default_action&amp;#34;`&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;Architectures&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;   &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;architectures&amp;#34;`&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;Syscalls&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Syscall&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;syscalls&amp;#34;`&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That means that, in &lt;code&gt;gdn&lt;/code&gt; itself, we needed to have in the &lt;code&gt;architectures&lt;/code&gt; slice, ARM included:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt; var seccomp = &amp;amp;specs.LinuxSeccomp{
         DefaultAction: specs.ActErrno,
         Architectures: []specs.Arch{
                 specs.ArchX86_64,
                 specs.ArchX86,
                 specs.ArchX32,
&lt;span class=&#34;gi&#34;&gt;+                specs.ArchARM,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;         },
         Syscalls: []specs.LinuxSyscall{
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we know how to build all of those in a cross-platform way, we just need to follow the same recipe: set the right compiler, and there you go.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;sup&gt;1&lt;/sup&gt;: in platforms that support containers.&lt;/i&gt;&lt;/p&gt;
&lt;h3 id=&#34;building-baggageclaim-the-volumizer&#34;&gt;Building Baggageclaim, the volumizer&lt;/h3&gt;
&lt;p&gt;As mentioned before, the &amp;ldquo;volumizer&amp;rdquo; is already part of the worker, thus, by building &lt;code&gt;concourse&lt;/code&gt; (the binary), we already have &lt;code&gt;baggageclaim&lt;/code&gt; built.&lt;/p&gt;
&lt;p&gt;The only detail for &lt;code&gt;baggageclaim&lt;/code&gt; is that if the backing filesystem for it is set to be &lt;code&gt;btrfs&lt;/code&gt;, then the machine that runs the worker needs to have the &lt;code&gt;btrfs&lt;/code&gt; CLI on it (built to the right platform).&lt;/p&gt;
&lt;h3 id=&#34;running-the-concourse-worker&#34;&gt;Running the Concourse worker&lt;/h3&gt;
&lt;p&gt;At this point, we can already have our Concourse worker in a state that it could run - it has all of its dependencies, even though it has no base &lt;a href=&#34;https://concourse-ci.org/resource-types.html&#34;&gt;resource types&lt;/a&gt;, meaning that it wouldn&amp;rsquo;t be able to have any steps or even checks running.&lt;/p&gt;
&lt;p&gt;The reason for that is that the root filesystem that ends up being fetched by Concourse to run a container needs to come from somewhere - the resource type that is configured to retrieve those bits. As there are none to do so, nothing fetch the base, thus, nothing can run.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/rootfs-retrieval.svg&#34;
       alt=&#34;illustration of the interaction between web and worker components in Concourse &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;To break out of that, we have to create a resource type to ship with our cross platform build that is able to retrieve root filesystems that are built for the specific platform that we target.&lt;/p&gt;
&lt;p&gt;As we&amp;rsquo;re targetting non Linux AMD64, that meant that we&amp;rsquo;d need to go through the cross compilation dance again, now for the &lt;a href=&#34;https://github.com/concourse/registry-image-resource&#34;&gt;&lt;code&gt;registry-image&lt;/code&gt; resource&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem though, is that not only compiling would be sufficient - when a registry client asks for a container image that lives in a registry, it has to specify what&amp;rsquo;s the platform that such image is created for.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/registry-image-resource-interaction.svg&#34;
       alt=&#34;illustration of the registry-image-resource interaction with container creation and a container images registry &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;By default, the underlying library that &lt;code&gt;registry-image-resource&lt;/code&gt; uses assuming the &lt;code&gt;linux&lt;/code&gt; &lt;code&gt;amd64&lt;/code&gt; tuple, thus, I created a pull request (PR) to address that: &lt;a href=&#34;https://github.com/concourse/registry-image-resource/pull/36&#34;&gt;https://github.com/concourse/registry-image-resource/pull/36&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;generating-the-modified-registry-image-resource&#34;&gt;Generating the modified registry-image-resource&lt;/h3&gt;
&lt;p&gt;As a base resource type is defined by having a &lt;code&gt;rootfs&lt;/code&gt; and &lt;code&gt; resource_metadata.json&lt;/code&gt; (see &lt;a href=&#34;https://concourse-ci.org/tasks.html#task-image-resource),&#34;&gt;https://concourse-ci.org/tasks.html#task-image-resource),&lt;/a&gt; the easiest way of getting to a &lt;code&gt;rootfs&lt;/code&gt; would be to have a container image generated from a Dockerfile and then extracting the final rootfs, and placing that into a tarball.&lt;/p&gt;
&lt;p&gt;Having that &lt;code&gt;rootfs.tgz&lt;/code&gt; that contains the root filesystem for the modified &lt;code&gt;registry-image-resource&lt;/code&gt;, that would mean that I could then distribute this resource in the tarball that contains all of the necessary bits for Concourse, effectively bootstrapping the whole thing!&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/concourse-tarball-distribution.svg&#34;
       alt=&#34;a view into how the final tarball looks like &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;While that sounds great, we have to remember that the &lt;code&gt;registry-image-resource&lt;/code&gt; makes requests to external systems.&lt;/p&gt;
&lt;p&gt;The problem here is that to have the &lt;code&gt;rootfs&lt;/code&gt; properly created, we need to execute some commands within that container that creates the rootfs to get &lt;code&gt;ca-certificates&lt;/code&gt; so that we can make requests to HTTPS endpoints.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;c&#34;&gt;# the final representation of the registry-image &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Concourse resource type.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; rootfs-${arch} AS registry-image-resource&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COPY&lt;/span&gt; --from&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;registry-image-resource-build &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /assets/ &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /opt/resource/&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; apt update -y &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        apt install -y ca-certificates &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        rm -rf /var/lib/apt/lists/*&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As the base image of that container must be an ARM-based image, it means that any binaries that we try executing there, will be executing instructions that only ARM machines can run. Damn!&lt;/p&gt;
&lt;p&gt;To overcome that, we have at least two options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;create a bootstrapping container image once in the target architecture, or&lt;/li&gt;
&lt;li&gt;emulate the target architecture.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While &lt;code&gt;1&lt;/code&gt; sounds like something that could work, &lt;code&gt;2&lt;/code&gt; is now quite simple to achieve, if you&amp;rsquo;re using a MacOS or Windows 10 machine.&lt;/p&gt;
&lt;p&gt;Since not too long ago, Docker for Desktop has been shipping their internal VM with the right hooks to be able to emulate other architectures in a very transparent way for the developer (see the recent announcement: &lt;a href=&#34;https://engineering.docker.com/2019/04/multi-arch-images/&#34;&gt;Building Multi-Arch Image for Arm and X86 with Docker Desktop&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&#34;automating-the-process-of-building-an-arm-based-concourse-distribution&#34;&gt;Automating the process of building an ARM-based Concourse distribution&lt;/h3&gt;
&lt;p&gt;As manually building all of those binaries is not fun at all, I made the whole process buildable by creating a &lt;a href=&#34;https://docs.docker.com/develop/develop-images/multistage-build/&#34;&gt;multi-stage Dockerfile&lt;/a&gt; (see &lt;a href=&#34;https://github.com/cirocosta/concourse-arm/blob/master/Dockerfile&#34;&gt;&lt;code&gt;cirocosta/concourse-arm#Dockerfile&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Given that to build such Dockerfile we&amp;rsquo;d need to have a task that is able to do so, the Dockerfile builds a version of the &lt;a href=&#34;https://github.com/concourse/builder-task&#34;&gt;&lt;code&gt;builder-task&lt;/code&gt;&lt;/a&gt;, which wraps &lt;a href=&#34;https://github.com/genuinetools/img&#34;&gt;&lt;code&gt;genuinetools/img&lt;/code&gt;&lt;/a&gt;, which is able to build container images from Dockerfiles (using &lt;a href=&#34;https://github.com/moby/buildkit&#34;&gt;buildkit&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Yeah, that&amp;rsquo;s a &lt;em&gt;lot&lt;/em&gt; of names in a single article!&lt;/p&gt;
&lt;h3 id=&#34;summarizing&#34;&gt;Summarizing&lt;/h3&gt;
&lt;p&gt;In the end, we build a bunch of stuff!&lt;/p&gt;
&lt;p&gt;For instance, consider the building of the binaries:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 120rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/binaries.svg&#34;
       alt=&#34;diagram of all of the steps taken to build the binaries container image &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;And, for the &lt;code&gt;registry-image-resource&lt;/code&gt; rootfs:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 120rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/registry-image-resource.svg&#34;
       alt=&#34;diagram with the steps taken to build the registry-image-resource bts &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The good news is that it&amp;rsquo;s all declared in that very same Dockerfile I mentioned, making the build mostly reproducible.&lt;/p&gt;
&lt;h3 id=&#34;some-surprises&#34;&gt;Some surprises&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;While trying to figure out what was going wrong with Guardian, I wanted &lt;strong&gt;so much&lt;/strong&gt; to use &lt;a href=&#34;https://github.com/go-delve/delve&#34;&gt;&lt;code&gt;dlv&lt;/code&gt;&lt;/a&gt; to troubleshoot what was going on, but, unfortunatelly, it doesn&amp;rsquo;t support any 32bit systems at the moment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I didn&amp;rsquo;t know that in some Linux distros you&amp;rsquo;d have to run &lt;code&gt;modprobe config&lt;/code&gt; to have the &lt;code&gt;/proc/config.gz&lt;/code&gt; file accessible to check the configuration used to build that Kernel - interesting to know!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing Thoughts&lt;/h3&gt;
&lt;p&gt;In the end, it turns out that it&amp;rsquo;s not super complicated to achieve building a Go project that depends on some dependencies (having some C code involved too) to other architectures - set the right variables here and there, make use of some emulation if needed, and there you go.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s quite cool what you can do using cross compilation, and how a combination of Go and container images with a well defined set of build steps can make the whole process of building for multi platforms work great even when you don&amp;rsquo;t have access to those platforms.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m very curious about the whole movement of supporting other architectures other than amd64, so it&amp;rsquo;s nice to start having a foot in this space.&lt;/p&gt;
&lt;p&gt;Even though we made use of cross compilation, there were steps where we were still needing to run some details in such architecture, which makes me think that it might be worth investing in having Concourse workers running smoothly on these other platforms too.&lt;/p&gt;
&lt;p&gt;Please let me know what you think! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;See you!&lt;/p&gt;
</description>
                                <pubDate>Sun, 19 May 2019 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/raspberry-pi-concourse-ci-worker/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/raspberry-pi-concourse-ci-worker/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How Linux creates sockets and counts them</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been working with web servers for a little while, you certainly have already hit the classic &amp;ldquo;&lt;em&gt;address already in use&lt;/em&gt;&amp;rdquo; (EADDRINUSE).&lt;/p&gt;
&lt;p&gt;Here in this article, we go through not only how to see whether such condition as conditioned to happen (by looking at the list of open sockets), but also verify in the actual Kernel code paths where that check happens.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/socket-how-does-it-work.svg&#34;
       alt=&#34;Illustration of someone wondering about how does the socket syscall work &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In case you&amp;rsquo;ve been wondering about how the &lt;a href=&#34;http://man7.org/linux/man-pages/man2/socket.2.html&#34;&gt;&lt;code&gt;socket(2)&lt;/code&gt;&lt;/a&gt; syscall works where are these sockets stored, make sure you stick to the end!&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;This is the sixth article in a series of 30 articles around &lt;em&gt;procfs&lt;/em&gt;: &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;A Month of /proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to keep up to date with it, make sure you &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#what-are-these-sockets-about&#34;&gt;What are these sockets about?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#where-to-look-for-the-list-of-sockets-in-my-system&#34;&gt;Where to look for the list of sockets in my system?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#what-happens-under-the-hood-when-the-socket-syscall-gets-called&#34;&gt;What happens under the hood when the socket syscall gets called?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sockets-and-resource-limits&#34;&gt;Sockets and resource limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#counting-the-number-of-sockets-in-the-system&#34;&gt;Counting the number of sockets in the system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#what-about-namespaces&#34;&gt;What about namespaces?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;what-are-these-sockets-about&#34;&gt;What are these sockets about?&lt;/h3&gt;
&lt;p&gt;Sockets are the constructs that allow processes on different machines to communicate through an underlying network, being also possibly used as a way of communicating with other processes in the same host (through Unix sockets).&lt;/p&gt;
&lt;p&gt;The analogy that really stuck with me is the one presented in the book &lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;&lt;strong&gt;Computer Networking: A top-down approach&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At a &lt;em&gt;very&lt;/em&gt; high-level, we can think of the server machine as this &amp;ldquo;house&amp;rdquo; with a set of doors.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/house-sockets-overview.svg&#34;
       alt=&#34;A house that represents a server with a door that represents the socket &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;With each door corresponding to a socket, the client can arrive at the door of the house and &amp;ldquo;knock&amp;rdquo; at it.&lt;/p&gt;
&lt;p&gt;Right after knocking (sending the &lt;code&gt;SYN&lt;/code&gt; packet), the house then automatically responds back with a response (&lt;code&gt;SYN+ACK&lt;/code&gt;), which is then acknowledged by the house (yep, smart house with a &amp;ldquo;smart door&amp;rdquo;).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/client-server-boundary.svg&#34;
       alt=&#34;The interaction between the client and the house when the client is still being greeted by the house &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Meanwhile, while the process just sits there within the house, the clients get organized by the &amp;ldquo;smart house&amp;rdquo;, which creates two lines: one for those that the house is still greeting, and another one for those that it finished greeting.&lt;/p&gt;
&lt;p&gt;Whenever new clients land in the second line, the process can then let it come in.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/server-accepting.svg&#34;
       alt=&#34;The server process accepting incoming connections from the two queues formed &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Once this connection gets accepted (the client is told to come in), the server is then able to communicate with it, transmitting and receiving data at wish.&lt;/p&gt;
&lt;p&gt;One detail to note is that the client doesn&amp;rsquo;t really &amp;ldquo;get in&amp;rdquo; - the server creates a &amp;ldquo;private door&amp;rdquo; in the house (a client socket) and then communicates with the client from there.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;d like to follow the step by step of implementing a TCP server in C, make sure you check this article! &lt;a href=&#34;https://ops.tips/blog/a-tcp-server-in-c/&#34;&gt;&lt;strong&gt;Implementing a TCP server&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;where-to-look-for-the-list-of-sockets-in-my-system&#34;&gt;Where to look for the list of sockets in my system?&lt;/h3&gt;
&lt;p&gt;Having the mental model of how the TCP connection establishment looks like, we can now &amp;ldquo;get into the house&amp;rdquo; and explore how the machine is creating these &amp;ldquo;doors&amp;rdquo; (the sockets), how many doors our house has and in which state they are (are they closed? are they opened?).&lt;/p&gt;
&lt;p&gt;For doing so, let&amp;rsquo;s consider the example of a server that just creates a socket (the door!) and does nothing with it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// socket.c - creates a socket and then sleeps.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Creates a TCP IPv4 socket and then just
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * waits.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// The `socket(2)` syscall creates an endpoint for communication
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// and returns a file descriptor that refers to that endpoint.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// It takes three arguments (the last being just to provide greater
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// specificity):
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// -    domain (communication domain)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//      AF_INET              IPv4 Internet protocols
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// -    type (communication semantics)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//      SOCK_STREAM          Provides sequenced, reliable,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//                           two-way, connection-based byte
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//                           streams.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOCK_STREAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;socket&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Just wait ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3600&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Under the hood, such simple syscall ends up triggering a whole bunch of internal methods (more on that in the next session) that at some point allows us to seek for information about active sockets under three different files: &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/net/tcp&lt;/code&gt;, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/fd&lt;/code&gt;, and &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/net/sockstat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While the &lt;code&gt;fd&lt;/code&gt; directory presents us a list of files opened by the process, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/net/tcp&lt;/code&gt; file gives us information regarding currently active TCP connections (in their various states) under the process network namespace. &lt;code&gt;sockstat&lt;/code&gt;, on the other hand, acts more like a summary.&lt;/p&gt;
&lt;p&gt;Starting with the &lt;code&gt;fd&lt;/code&gt; directory, we can see that after the &lt;code&gt;socket(2)&lt;/code&gt; call we can see the socket file descriptor in the list of file descriptors:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run socket.out (gcc -Wall -o socket.out socket.c)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and leave it running in the background&lt;/span&gt;
./socket.out &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;2&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;21113&lt;/span&gt;
 
&lt;span class=&#34;c1&#34;&gt;# Check out that are the open files that the process has.&lt;/span&gt;
ls -lah /proc/21113/fd
dr-x------ &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; ubuntu ubuntu  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; 12:27 .
dr-xr-xr-x &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; ubuntu ubuntu  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; 12:27 ..
lrwx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; ubuntu ubuntu &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; 12:27 &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/0
lrwx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; ubuntu ubuntu &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; 12:27 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /dev/pts/0
lrwx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; ubuntu ubuntu &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; 12:27 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /dev/pts/0
lrwx------ &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; ubuntu ubuntu &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; 12:27 &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; -&amp;gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;socket:[301666]&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that from a simple call to &lt;code&gt;socket(2)&lt;/code&gt; we don&amp;rsquo;t have a TCP connection, there&amp;rsquo;s no relevant information to be gathered from &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/net/tcp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the summary (&lt;code&gt;sockstat&lt;/code&gt;), we can guess that we&amp;rsquo;re increasing the number of allocated TCP sockets:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check the summary regarding socket.&lt;/span&gt;
cat /proc/21424/net/sockstat
sockets: used &lt;span class=&#34;m&#34;&gt;296&lt;/span&gt;
TCP: inuse &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; orphan &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; tw &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; alloc &lt;span class=&#34;m&#34;&gt;106&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
UDP: inuse &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
UDPLITE: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
RAW: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
FRAG: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; memory &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To make sure that we&amp;rsquo;re really increasing the &lt;code&gt;alloc&lt;/code&gt; number, we can modify the source code above and allocate 100 sockets instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gi&#34;&gt;+ for (int i = 0; i &amp;lt; 100; i++) {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;      int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
      if (err == -1) {
          perror(&amp;#34;socket&amp;#34;);
          return err;
      }
&lt;span class=&#34;gi&#34;&gt;+ }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, checking that again, we can see the &lt;code&gt;alloc&lt;/code&gt; at a higher number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;cat /proc/21456/net/sockstat

                   bigger than before!
                                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
sockets: used &lt;span class=&#34;m&#34;&gt;296&lt;/span&gt;          .----------.
TCP: inuse &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; orphan &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; tw &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; alloc 207&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
UDP: inuse &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         *----------*
UDPLITE: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
RAW: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
FRAG: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; memory &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, the question is - how does the socket gets created under the hood?&lt;/p&gt;
&lt;h3 id=&#34;what-happens-under-the-hood-when-the-socket-syscall-gets-called&#34;&gt;What happens under the hood when the socket syscall gets called?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;socket(2)&lt;/code&gt; is pretty much a factory that produces the underlying structures for handling operations on such socket.&lt;/p&gt;
&lt;p&gt;Making use of &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;&lt;code&gt;iovisor/bcc&lt;/code&gt;&lt;/a&gt;, we can trace the deepest invocation that happens in the &lt;code&gt;sys_socket&lt;/code&gt; call stack and from there understand each step.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;|  socket()
|--------------- (kernel boundary)
|  sys_socket    
|       (socket, type, protocol)
|  sock_create   
|       (family, type, protocol, res)
|  __sock_create 
|       (net, family, type, protocol, res, kern)
|  sock_alloc    
|       ()
˘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Starting from &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/net/socket.c#L1317&#34;&gt;&lt;code&gt;sys_socket&lt;/code&gt;&lt;/a&gt; itself, this syscall wrapper is the first thing to be touched at kernelspace, being responsible for performing various checks and preparing some flags to pass down to subsequent invocations.&lt;/p&gt;
&lt;p&gt;Once preliminary validations have been performed, it allocates in its stack a pointer to a &lt;code&gt;struct socket&lt;/code&gt;, the struct that will end up holding the non-protocol specific information about the socket:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Defined `socket` as a syscall with the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * following arguments:
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - int family;        - the communication domain
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - int type; and      - the communication semantics
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - int protocol.      - a specific protocol within a
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *                        certain domain and semantics.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *                       
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;SYSCALL_DEFINE3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// A pointer that is meant to be pointed to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// a `struct sock` that contains the whole
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// socket definition after it gets properly
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// allocated by the socket family.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


	&lt;span class=&#34;c1&#34;&gt;// ... Checks some stuff and prepare some flags ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Create the underlying socket structures.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock_create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Allocate the file descriptor for the process so
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// that it can consume the underlying socket from
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// userspace.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sock_map_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;O_CLOEXEC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_NONBLOCK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * High level wrapper of the socket structures.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;socket_state&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt;                   &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;           &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;sk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proto_ops&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ops&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that at the moment that we create the socket we can choose between different types and protocol families (like, UDP, UNIX, and TCP), the &lt;code&gt;struct socket&lt;/code&gt; contains an interface (&lt;code&gt;struct proto_ops*&lt;/code&gt;) that defines the basic constructs that sockets implement (regardless of their families/type), which gets initiated on the next method called: &lt;code&gt;sock_create&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Initializes `struct socket`, allocating the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * necessary memory for it, as well as filling
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * the necessary information associated with
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * the socket.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * It:
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - Performs some argument checking;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - Runs a security check hook for `socket_create`
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - Initializes the actual allocation of the `struct socket`
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   (letting the `family` do it according to its own rules)
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__sock_create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;net&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;net_proto_family&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Checks if the protocol range.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NPROTO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EAFNOSUPPORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOCK_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


	&lt;span class=&#34;c1&#34;&gt;// Triggers custom security hooks for socket_create.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;security_socket_create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


	 &lt;span class=&#34;c1&#34;&gt;// Allocates a `struct socket` object and ties it to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// a file under the `sockfs` filesystem.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;net_warn_ratelimited&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;socket: no more sockets&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENFILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Not exactly a match, but its the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;				   closest posix thing */&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Tries to retrieve the protocol family methods
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// for performing the family-specific socket creation.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;pf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu_dereference&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net_families&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EAFNOSUPPORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out_release&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Executes the protocol family specific 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// socket creation method.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// For instance, if our family is AF_INET (ipv4)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and we&amp;#39;re creating a TCP socket (SOCK_STREAM),
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// a specific method for handling such type of socket
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// is called.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// If we were specifying a local socket (UNIX),
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// then another method would be called (given that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// such method would implement the `proto_ops` interface
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and have been loaded).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out_module_put&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Continuing with our deep dive, we can now look closely at how the actual &lt;code&gt;struct socket&lt;/code&gt; gets allocated by &lt;code&gt;sock_alloc()&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 75rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/net-internal-socket.svg&#34;
       alt=&#34;Illustration of how the Linux kernel creates sockets &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;What that method does is allocate two things: a new &lt;code&gt;inode&lt;/code&gt;, and a &lt;code&gt;socket&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;These two are bound together via the &lt;code&gt;sockfs&lt;/code&gt; filesystem, which is then responsible for not only keeping track of socket information in the system, but also providing the translation layer between regular filesystem calls (like &lt;code&gt;write(2)&lt;/code&gt;) and the network stack (regardless of the underlying communication domain).&lt;/p&gt;
&lt;p&gt;By tracing &lt;code&gt;sock_alloc_inode&lt;/code&gt;, the method responsible for allocating the inode in &lt;code&gt;sockfs&lt;/code&gt;, we&amp;rsquo;re able to see how that gets set up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cc&#34; data-lang=&#34;cc&#34;&gt;&lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock_alloc_inode&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;22384&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;22384&lt;/span&gt;   &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;sock_alloc_inode&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;sock_alloc_inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;new_inode_pseudo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x11&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;sock_alloc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x1c&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;__sock_create&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x80&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;sys_socket&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x55&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;do_syscall_64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x73&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;entry_SYSCALL_64_after_hwframe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x3d&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *	sock_alloc	-	allocate a socket
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *	Allocate a new inode and socket object. The two are bound together
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *	and initialized. The socket is then returned. If we are out of inodes
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *	NULL is returned.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;inode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Given that the filesystem is in-memory,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// perform the allocation using the kernel
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// memory.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_inode_pseudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock_mnt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mnt_sb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Retrieves the `socket` struct from
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the `inode` that lives in `sockfs`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOCKET_I&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Sets some filesystem aspects so that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_ino&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_next_ino&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S_IFSOCK&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S_IRWXUGO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_uid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_fsuid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_gid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_fsgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_op&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sockfs_inode_ops&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Update the per-cpu counter (which can then be
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// used by `sockstat` to and other systems
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// to quickly know the socket count).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;this_cpu_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sockets_in_use&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;inode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sock_alloc_inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;super_block&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;socket_alloc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;socket_wq&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Create an entry in the kernel cache 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// taking the necessary memory for it.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kmem_cache_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock_inode_cachep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GFP_KERNEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;wq&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kmalloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GFP_KERNEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;kmem_cache_free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock_inode_cachep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        
        &lt;span class=&#34;c1&#34;&gt;// Performs the most basic initialization
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// possible
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SS_UNCONNECTED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ops&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sk&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Returns the underlying vfs inode.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ei&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vfs_inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sockets-and-resource-limits&#34;&gt;Sockets and resource limits&lt;/h3&gt;
&lt;p&gt;Given that a filesystem inode can be referred from the userspace from a file descriptor, after we have the underlying Kernel structs all set up, &lt;code&gt;sys_socket&lt;/code&gt; is then responsible for generating a file descriptor for the user (going through the resource limits validations as presented in &lt;a href=&#34;https://ops.tips/blog/proc-pid-limits-under-the-hood/&#34;&gt;Process resource limits under the hood&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve wondered why it is the case that you might receive a &amp;ldquo;too many open files&amp;rdquo; error for &lt;code&gt;socket(2)&lt;/code&gt;, that&amp;rsquo;s the reason - it goes through the same resource limits checks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;sock_map_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Do you recall this one? This is the method
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the kernel ends up performing a check against
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// resource limits and making sure that we don&amp;#39;t
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// get past the limits!
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;          &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_unused_fd_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unlikely&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;sock_release&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;newfile&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock_alloc_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;likely&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;IS_ERR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fd_install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;put_unused_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTR_ERR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;counting-the-number-of-sockets-in-the-system&#34;&gt;Counting the number of sockets in the system&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;ve paid attention to the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/net/socket.c#L566&#34;&gt;&lt;code&gt;sock_alloc&lt;/code&gt;&lt;/a&gt; call, there was a part of it that took care of increasing the number of sockets that are &amp;ldquo;in-use&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sock_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ....
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Update the per-cpu counter (which can then be
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// used by `sockstat` to and other systems
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// to quickly know the socket count).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;this_cpu_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sockets_in_use&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/include/linux/percpu-defs.h#L511&#34;&gt;&lt;code&gt;this_cpu_add&lt;/code&gt;&lt;/a&gt; a macro, we can look at its definition and understand a bit more about it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * this_cpu operations (C) 2008-2013 Christoph Lameter &amp;lt;cl@linux.com&amp;gt;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Optimized manipulation for memory allocated through the per cpu
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * allocator or for addresses of per cpu variables.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * These operation guarantee exclusivity of access for other operations
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * on the *same* processor. The assumption is that per cpu data is only
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * accessed by a single processor instance (the current one).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * [...]
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, given that we&amp;rsquo;re always adding to &lt;code&gt;sockets_in_use&lt;/code&gt;, we can at least guess that if we go through the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/net/ipv4/proc.c#L54&#34;&gt;method that is registered for &lt;code&gt;/proc/net/sockstat&lt;/code&gt;&lt;/a&gt; is going to use that value, which it really does (with also performing an addition over the values registered for each CPU):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *	Report socket allocation statistics [mea@utu.fi]
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sockstat_seq_show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seq_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;net&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;frag_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;orphans&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Retrieve the counters related to TCP sockets.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;orphans&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;percpu_counter_sum_positive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tcp_orphan_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;sockets&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proto_sockets_allocated_sum_positive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tcp_prot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Show the stats!
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// As we saw in the beginning of the article,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// `alloc` show all of those that were allocated
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and might not be in an &amp;#34;in-use&amp;#34; state yet.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;socket_seq_show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;seq_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;TCP: inuse %d orphan %d tw %d alloc %d mem %ld&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		   &lt;span class=&#34;n&#34;&gt;sock_prot_inuse_get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tcp_prot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;orphans&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		   &lt;span class=&#34;n&#34;&gt;atomic_read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ipv4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tcp_death_row&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tw_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		   &lt;span class=&#34;n&#34;&gt;proto_memory_allocated&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tcp_prot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;seq_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;FRAG: inuse %u memory %u&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frag_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;frag_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;what-about-namespaces&#34;&gt;What about namespaces?&lt;/h3&gt;
&lt;p&gt;As you might&amp;rsquo;ve noticed, there&amp;rsquo;s no logic in the code related to namespaces when it comes to counting how many sockets where allocated.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s something that at first really surprised me given that I thought the networking stack was something that was the most namespaced, but it turns out that there are still some points that are not.&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;interesting - `/proc/&amp;lt;pid&amp;gt;/net/tcp` is namespaced, but `/proc/&amp;lt;pid&amp;gt;/net/sockstat` is not (it still isn&amp;#39;t, the patch wasn&amp;#39;t accept) &lt;a href=&#34;https://t.co/BcaVCAOczY&#34;&gt;pic.twitter.com/BcaVCAOczY&lt;/a&gt;&lt;/p&gt;&amp;mdash; Ciro S. Costa (@cirowrc) &lt;a href=&#34;https://twitter.com/cirowrc/status/1052181698874490880?ref_src=twsrc%5Etfw&#34;&gt;October 16, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;p&gt;If you&amp;rsquo;d like to see that by yourself, make sure you follow the article &lt;a href=&#34;https://ops.tips/blog/using-network-namespaces-and-bridge-to-isolate-servers/&#34;&gt;&lt;strong&gt;Using network namespaces and a virtual switch to isolate servers&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The gist of it is that you can create a bunch of sockets, see &lt;code&gt;sockstat&lt;/code&gt;, then create a network namespace, get into it, and then see that although you can&amp;rsquo;t see the TCP sockets from the whole system over there (namespaces in action!), you can see the total number of allocated sockets in the system (not namespaced).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a bunch of sockets using our&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# example in C&lt;/span&gt;
./sockets.out


&lt;span class=&#34;c1&#34;&gt;# Check that we have a bunch of sockets&lt;/span&gt;
cat /proc/net/sockstat
sockets: used &lt;span class=&#34;m&#34;&gt;296&lt;/span&gt;
TCP: inuse &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; orphan &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; tw &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; alloc &lt;span class=&#34;m&#34;&gt;108&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
UDP: inuse &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
UDPLITE: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
RAW: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
FRAG: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; memory &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Create a network namespace&lt;/span&gt;
ip netns add namespace1


&lt;span class=&#34;c1&#34;&gt;# Get into it&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 /bin/bash


&lt;span class=&#34;c1&#34;&gt;# Check how `/proc/net/sockstat` shows the same&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# number of allocated sockets.&lt;/span&gt;
TCP: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; orphan &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; tw &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; alloc &lt;span class=&#34;m&#34;&gt;108&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
UDP: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; mem &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
UDPLITE: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
RAW: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
FRAG: inuse &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; memory &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s interesting to see how after exploring the inner workings of the Kernel by just being curious about &lt;code&gt;/proc&lt;/code&gt; is leading to answers to why some specific behaviors that I&amp;rsquo;ve seen in daily operations work in such way.&lt;/p&gt;
&lt;p&gt;Given that this is just the first article that is about &lt;code&gt;/proc/net&lt;/code&gt; and I&amp;rsquo;ve already learned a lot, I can&amp;rsquo;t wait to start digging deeper into the rest of it!&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to follow along with me, make sure you subscribe to the mailing list.&lt;/p&gt;
&lt;p&gt;In case you have any questions or thoughts you&amp;rsquo;d like to share, please let me know!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, and I&amp;rsquo;d love to chat with you!&lt;/p&gt;
&lt;p&gt;Have a good one,
Ciro&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
                                <pubDate>Tue, 16 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/how-linux-creates-sockets/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/how-linux-creates-sockets/</guid>

                                
                                        <category>linux</category>
                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                

                        
                        <item>
                                <title>Using /proc to get a process&#39; current stack trace</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;The file covered in this article, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stack&lt;/code&gt;, is the one that motivated me to learn more about &lt;code&gt;/proc&lt;/code&gt; and get &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc&#34;&gt;&lt;code&gt;The Month of Proc&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s such a useful thing when you&amp;rsquo;re unaware of what is the state of a given process. Meanwhile, I&amp;rsquo;ve noticed that it&amp;rsquo;s not very well known by people getting started with Linux.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/procfs-capturing-stack.svg&#34;
       alt=&#34;Illustration of how the process stack can be inspected &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Here in this post, you&amp;rsquo;ll get to know more about how procfs can gather a process&#39; stack trace, as well as get an idea of its usefulness.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;This is the fifth article in a series of 30 articles around &lt;em&gt;procfs&lt;/em&gt;: &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;A Month of /proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to keep up to date with it, make sure you &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#a-process-that-blocks&#34;&gt;A process that blocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#viewing-the-process-kernel-stack-trace&#34;&gt;Viewing the process kernel stack trace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#when-the-stack-does-not-help-much&#34;&gt;When the stack does not help much&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;a-process-that-blocks&#34;&gt;A process that blocks&lt;/h3&gt;
&lt;p&gt;To kick things off, let&amp;rsquo;s start with the tailoring of a process that blocks - a TCP server.&lt;/p&gt;
&lt;p&gt;In its most simplistic form, we can have a single-threaded TCP server that just receives traffic in a given thread and then processes its results.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/tcp-server-blocking-main-thread.svg&#34;
       alt=&#34;Illustration of TCP server blocking the main thread &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Naturally, there are two places where we can see the server blocking: at the &lt;code&gt;accept(2)&lt;/code&gt; phase, of the &lt;code&gt;read(2)&lt;/code&gt; phase - the first blocks until a client finishes the TCP handshake; the second, until data is available for read.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how a simplistic implementation in C would look like considering just the first blocking part (&lt;code&gt;accept&lt;/code&gt;ing):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * server_listen takes care of setting up the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * passive socket that receives incoming TCP
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * connections.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Returns the file descriptor corresponding to
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * the passive socket, of -1 in the case of
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * error.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * See https://ops.tips/blog/a-tcp-server-in-c/#creating-a-socket
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * for a reference implementation.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;server_listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * server_accept_and_close accepts connections that
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * finish their TCP handshake through the provided
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * @listen_fd argument.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Once the connection is `accept`ed, it gets closed
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * immediately.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;server_accept_and_close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;                &lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;                &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;socklen_t&lt;/span&gt;          &lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Accepting connections ...&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Accept connections from the completed
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// connection queue (pops the latest conn
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// that succesfully finished the 3-way
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// handshake).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Given that the queue might be empty, it
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// waits (i.e., blocks) until there&amp;#39;s a connection
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// there.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	         &lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Client connected! Going to close now.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Mark the connection as closed so that we
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// can get back to accepting new connections.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * main execution - creates a passive socket
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * bound to a specific port that keeps receiving
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * incoming connections, accepting them and then
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * marking them as closed immediately.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_accept_and_close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;re not into how a TCP server can be implemented in C, make sure you check &lt;a href=&#34;https://ops.tips/blog/a-tcp-server-in-c&#34;&gt;&lt;strong&gt;A TCP Server in C&lt;/strong&gt;&lt;/a&gt; for a complete description of it.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Run the server, and then see it blocking!&lt;/p&gt;
&lt;h3 id=&#34;viewing-the-process-kernel-stack-trace&#34;&gt;Viewing the process kernel stack trace&lt;/h3&gt;
&lt;p&gt;Once the server is blocked, we can jump into &lt;code&gt;/proc&lt;/code&gt; and check out what&amp;rsquo;s going on in the Kernel and figure out that it&amp;rsquo;s blocked on the &lt;code&gt;accept&lt;/code&gt; syscall:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Gather the in-kernel stack trace of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the `accept.out` process (the simplistic&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# TCP server that we&amp;#39;re running).&lt;/span&gt;
cat /proc/&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pidof accept.out&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; inet_csk_accept+0x246/0x380
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; inet_accept+0x45/0x170
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SYSC_accept4+0xff/0x210
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SyS_accept+0x10/0x20
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; do_syscall_64+0x73/0x130
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; entry_SYSCALL_64_after_hwframe+0x3d/0xa2
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 0xffffffffffffffff
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although it might look like a weird stack trace at first, the structure is very straightforward to reason about.&lt;/p&gt;
&lt;p&gt;Each line represents a function that was called (from looking at the stack calls), having the first part, that &lt;code&gt;[&amp;lt;0&amp;gt;]&lt;/code&gt; thing, being the kernel address of the function, while the second, that &lt;code&gt;do_syscall_64+...&lt;/code&gt; being the symbol name with the corresponding offset.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;[&amp;lt;0&amp;gt;]&lt;/code&gt; looks weird (like, not an actual address at all), it&amp;rsquo;s because it&amp;rsquo;s intended to be like that.&lt;/p&gt;
&lt;p&gt;When &lt;a href=&#34;https://github.com/torvalds/linux/blob/d8a5b80568a9cb66810e75b182018e9edb68e8ff/fs/proc/base.c#L424-L453&#34;&gt;&lt;code&gt;fs/proc/base.c#proc_pid_stack&lt;/code&gt;&lt;/a&gt; (the method that gets called by the &lt;code&gt;/proc&lt;/code&gt; implementation of the virtual filesystem) iterates over the stack frames, we can see that it hardcodes &lt;code&gt;[&amp;lt;0&amp;gt;]&lt;/code&gt; as the address to be displayed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Iterates through the kernel stack frames of
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * the current task, displaying the kernel 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * addresses of each function, as well as
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * their symbol name and offset.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_pid_stack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seq_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid_namespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			  &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stack_trace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Allocate some memory so that we can have
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// in our execution the whole stack of the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// process (up to a given depth).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// The first argument to the kmalloc
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// is the size of the block to be allocated.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// The second argument is allocation flag.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// GFP_KERNEL means that allocation is performed on
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// behalf of a process running in the kernel space.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// This means that the calling function is executing
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// a system call on behalf of a process.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Using GFP_KERNEL means that kmalloc can put the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// current process to sleep waiting for a page when
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// called in low-memory situations.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// See https://elixir.bootlin.com/linux/v4.15/source/include/linux/gfp.h#L219
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kmalloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_STACK_TRACE_DEPTH&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GFP_KERNEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENOMEM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// With the space properly allocated, we can now
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// prepare the `stack_trace` struct and pass
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// it down to the function that will get that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// for us.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nr_entries&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;max_entries&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_STACK_TRACE_DEPTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;skip&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Make sure that we have mutual exclusion in
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// place.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lock_trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// Capture the stack trace!
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// https://elixir.bootlin.com/linux/v4.15/source/arch/x86/kernel/stacktrace.c#L69
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;save_stack_trace_tsk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// Iterate over each frame captured.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// *************************
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// HERE is where the `[&amp;lt;0&amp;gt;]` is hardcoded.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// *************************
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nr_entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;seq_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;[&amp;lt;0&amp;gt;] %pB&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;unlock_trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;kfree&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entries&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at the file where the function is defined, we can &lt;code&gt;git blame&lt;/code&gt; that &lt;code&gt;seq_printf&lt;/code&gt; and see who&amp;rsquo;s there to blame for putting that hardcoded &lt;code&gt;[&amp;lt;0&amp;gt;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Guess what - Torvalds did the change!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;Author: Linus Torvalds &amp;lt;torvalds@linux-foundation.org&amp;gt;
Date:   Mon Nov 27 16:45:56 2017 -0800

    proc: don&amp;#39;t report kernel addresses in /proc/&amp;lt;pid&amp;gt;/stack

    This just changes the file to report them as zero, although maybe even
    that could be removed.  I checked, and at least procps doesn&amp;#39;t actually
    seem to parse the &amp;#39;stack&amp;#39; file at all.

    And since the file doesn&amp;#39;t necessarily even exist (it requires
    CONFIG_STACKTRACE), possibly other tools don&amp;#39;t really use it either.

    That said, in case somebody parses it with tools, just having that zero
    there should keep such tools happy.

    Signed-off-by: Linus Torvalds &amp;lt;torvalds@linux-foundation.org&amp;gt;

&lt;span class=&#34;gh&#34;&gt;diff --git a/fs/proc/base.c b/fs/proc/base.c
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 31934cb9dfc8..28fa85276eec 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/fs/proc/base.c
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/fs/proc/base.c
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -443,8 +443,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                save_stack_trace_tsk(task, &amp;amp;trace);

                for (i = 0; i &amp;lt; trace.nr_entries; i++) {
&lt;span class=&#34;gd&#34;&gt;-                       seq_printf(m, &amp;#34;[&amp;lt;%pK&amp;gt;] %pB\n&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;-                                  (void *)entries[i], (void *)entries[i]);
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                       seq_printf(m, &amp;#34;[&amp;lt;0&amp;gt;] %pB\n&amp;#34;, (void *)entries[i]);
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;                }
                unlock_trace(task);
        }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not being a Kernel expert (at all!), I tried to understand what that &lt;code&gt;%pB&lt;/code&gt; and &lt;code&gt;%pK&lt;/code&gt; are all about - I&amp;rsquo;ve never used such kind of formatting with &lt;code&gt;printf&lt;/code&gt; after all.&lt;/p&gt;
&lt;p&gt;Looking at the &lt;a href=&#34;https://www.kernel.org/doc/Documentation/printk-formats.txt&#34;&gt;docs for &lt;code&gt;printk&lt;/code&gt; format specifiers&lt;/a&gt;, we can see what that very specialized formatting is all about:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;B&lt;/code&gt; specifier results in the symbol name with offsets and should be used when printing stack backtraces.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[The &lt;code&gt;K&lt;/code&gt; specifier is used &amp;hellip;] For printing kernel pointers which should be hidden from unprivileged users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Meaning that yeah, previously you &lt;em&gt;could&lt;/em&gt; retrieve the kernel addresses, but not anymore, for the reasons presented by Linus.&lt;/p&gt;
&lt;h3 id=&#34;when-the-stack-does-not-help-much&#34;&gt;When the stack does not help much&lt;/h3&gt;
&lt;p&gt;While it&amp;rsquo;s very clear why knowing the in-kernel stack trace in the example above was useful, it&amp;rsquo;s not all that much when it comes to servers that make use of async io (like most of the modern web servers do).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how a code that is very similar to the TCP acceptor we wrote above in C looks like in Go:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;net&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Create the necessary underlying data
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// structures for listening on port 1337
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// on all interfaces.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;:1337&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nb&#34;&gt;panic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Release all the resources when leaving
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// Accept a connection from the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// backlog of connections that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// finalized the 3-way handshake
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nb&#34;&gt;panic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// Close them right away
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although in the code above we spawn no goroutines other than the main one, under the hood, the Go runtime ends up setting a single event pool file that allows us to monitor multiple file descriptors and not block on them individually.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/epoll-notifying.svg&#34;
       alt=&#34;Illustration of the process of Epoll notifying events &#34; &gt;

    
&lt;/figure&gt;

&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;By the way, &lt;a href=&#34;https://twitter.com/b0rk&#34;&gt;Julia Evans&lt;/a&gt; has a &lt;strong&gt;great&lt;/strong&gt; blog post on async IO - make sure you check it out! It&amp;rsquo;s called &lt;a href=&#34;https://jvns.ca/blog/2017/06/03/async-io-on-linux--select--poll--and-epoll/&#34;&gt;Async IO on Linux: select, poll, and epoll&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;We can notice that by looking at which syscall the Kernel is blocked at when our process runs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Display the stack of every thread that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# pertains to the `go_accept` command that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is running.&lt;/span&gt;
find /proc/&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pidof go_accept&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/task -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;stack&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        xargs -I&lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt; /bin/sh -c &lt;span class=&#34;s1&#34;&gt;&amp;#39;echo {} ; cat {}&amp;#39;&lt;/span&gt;

/proc/17019/task/17019/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; ep_poll+0x29c/0x3a0
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SyS_epoll_pwait+0x19e/0x220
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; do_syscall_64+0x73/0x130
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; entry_SYSCALL_64_after_hwframe+0x3d/0xa2
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 0xffffffffffffffff

/proc/17019/task/17020/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; futex_wait_queue_me+0xc4/0x120
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; futex_wait+0x10a/0x250
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; do_futex+0x325/0x500
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SyS_futex+0x13b/0x180
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; do_syscall_64+0x73/0x130
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; entry_SYSCALL_64_after_hwframe+0x3d/0xa2
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 0xffffffffffffffff

/proc/17019/task/17021/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; futex_wait_queue_me+0xc4/0x120
...

/proc/17019/task/17022/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; futex_wait_queue_me+0xc4/0x120
...

/proc/17019/task/17023/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; futex_wait_queue_me+0xc4/0x120
...

/proc/17019/task/17024/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; futex_wait_queue_me+0xc4/0x120
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that differently from the C code, here I&amp;rsquo;m looking at the stack of each task under the task group identified by the PID of the &lt;code&gt;go_accept&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Given that Go will run more than one thread when it starts (so that we can schedule goroutines to run across the poll of actual threads), we can take a look at the stack across all of the threads and see their stack (in the end, each thread is a &lt;code&gt;task&lt;/code&gt;, so we can take the stack of each of them).&lt;/p&gt;
&lt;p&gt;If we use &lt;a href=&#34;https://github.com/derekparker/delve&#34;&gt;&lt;code&gt;dlv&lt;/code&gt;&lt;/a&gt;, we can see why it&amp;rsquo;s the case that we have those 5 threads just waiting with a &lt;code&gt;futex_wait&lt;/code&gt;, while there&amp;rsquo;s another one blocked on &lt;code&gt;ep_poll&lt;/code&gt; (the actual block on async IO):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Attach to the currently running Go&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process with delve so that we can&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# check from the userspace perspective&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# what is going on with the Go runtime&lt;/span&gt;
dlv attach &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pidof go_accept&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Check the thread pool&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dlv&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; threads
* Thread &lt;span class=&#34;m&#34;&gt;17019&lt;/span&gt; at .../sys_linux_amd64.s:671 runtime.epollwait
  Thread &lt;span class=&#34;m&#34;&gt;17020&lt;/span&gt; at .../sys_linux_amd64.s:532 runtime.futex
  Thread &lt;span class=&#34;m&#34;&gt;17021&lt;/span&gt; at .../sys_linux_amd64.s:532 runtime.futex
  Thread &lt;span class=&#34;m&#34;&gt;17022&lt;/span&gt; at .../sys_linux_amd64.s:532 runtime.futex
  Thread &lt;span class=&#34;m&#34;&gt;17023&lt;/span&gt; at .../sys_linux_amd64.s:532 runtime.futex
  Thread &lt;span class=&#34;m&#34;&gt;17024&lt;/span&gt; at .../sys_linux_amd64.s:532 runtime.futex


&lt;span class=&#34;c1&#34;&gt;# Check the pool of goroutines&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dlv&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; goroutines
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; goroutines&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  Goroutine &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; - ...netpoll.go:173 internal/poll.runtime_pollWait &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x427146&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
  Goroutine &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; - ...proc.go:303 runtime.gopark &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x42c74b&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
  Goroutine &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; - ...proc.go:303 runtime.gopark &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x42c74b&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
  Goroutine &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; - ...proc.go:303 runtime.gopark &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x42c74b&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Switch to goroutine 1&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dlv&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; goroutine 


&lt;span class=&#34;c1&#34;&gt;# See the userspace stack that got us&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to being parked at `epoll wait`&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dlv&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; stack
 &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  0x000000000042c74b in runtime.gopark
    at /usr/local/go/src/runtime/proc.go:303
 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  0x0000000000427a99 in runtime.netpollblock
    at /usr/local/go/src/runtime/netpoll.go:366
 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  0x0000000000427146 in internal/poll.runtime_pollWait
    at /usr/local/go/src/runtime/netpoll.go:173
 &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;  0x000000000048e81a in internal/poll.&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;*pollDesc&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.wait
    at /usr/local/go/src/internal/poll/fd_poll_runtime.go:85
 &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;  0x000000000048e92d in internal/poll.&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;*pollDesc&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.waitRead
    at /usr/local/go/src/internal/poll/fd_poll_runtime.go:90
 &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;  0x000000000048fc20 in internal/poll.&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;*FD&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.Accept
    at /usr/local/go/src/internal/poll/fd_unix.go:384
 &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt;  0x00000000004b6572 in net.&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;*netFD&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.accept
    at /usr/local/go/src/net/fd_unix.go:238
 &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt;  0x00000000004c972e in net.&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;*TCPListener&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.accept
    at /usr/local/go/src/net/tcpsock_posix.go:139
 &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;  0x00000000004c86c7 in net.&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;*TCPListener&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.Accept
    at /usr/local/go/src/net/tcpsock.go:260
 &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt;  0x00000000004d55f4 in main.main
    at /tmp/tcp/main.go:16
&lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;  0x000000000042c367 in runtime.main
    at /usr/local/go/src/runtime/proc.go:201
&lt;span class=&#34;m&#34;&gt;11&lt;/span&gt;  0x0000000000456391 in runtime.goexit
    at /usr/local/go/src/runtime/asm_amd64.s:1333
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having now both the userspace and kernelspace stacks, we can properly identify what&amp;rsquo;s going on with the Go application.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;The conclusion? IMO, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stack&lt;/code&gt; (or the equivalent &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/task/&amp;lt;task_id&amp;gt;/stack&lt;/code&gt;) is great, but it only takes us so far.&lt;/p&gt;
&lt;p&gt;In the end, we need a mix of userspace and kernel space tools that can help us debug the state in which a system is present.&lt;/p&gt;
&lt;p&gt;Luckily, from time to time new tools like &lt;code&gt;dlv&lt;/code&gt; show up, &lt;code&gt;pprof&lt;/code&gt; improves, and even more powerful tools to inspect the Kernel emerge.&lt;/p&gt;
&lt;p&gt;I hope this article was useful for you! Please let me know if you have any questions.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter, and I&amp;rsquo;d love to chat!&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Sun, 14 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/using-procfs-to-get-process-stack-trace/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/using-procfs-to-get-process-stack-trace/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Process resource limits under the hood</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;When dealing with web servers, it&amp;rsquo;s not uncommon to face the problem of &amp;ldquo;too many files open&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Usually, people solve that by modifying a number using &lt;code&gt;ulimit -n&lt;/code&gt;, and then, sometimes that doesn&amp;rsquo;t work as such setting is per-process, and not system-wide.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/ulimits-example.svg&#34;
       alt=&#34;Illustration of ulimits not working as expected &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In this article, I go through how that &lt;code&gt;ulimit&lt;/code&gt; setting works under the hood, and how you can make use of &lt;code&gt;/proc&lt;/code&gt; to inspect other processes limits without the need for additional tools.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;This is the fourth article in a series of 30 articles around &lt;em&gt;procfs&lt;/em&gt;: &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;A Month of /proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to keep up to date with it, make sure you &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#what-are-resource-limits&#34;&gt;What are resource limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#how-does-the-kernel-limit-the-number-of-files-open-by-a-process&#34;&gt;How does the kernel limit the number of files open by a process?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#under-the-hood-of-the-ulimit-command&#34;&gt;Under the hood of the ulimit &amp;ldquo;command&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#a-sample-ulimit-implementation&#34;&gt;A sample ulimit implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#setting-and-getting-resource-limits-at-the-kernel-level&#34;&gt;Setting and getting resource limits at the Kernel level&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gathering-process-limits-via-proc&#34;&gt;Gathering process limits via /proc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#why-expose-limits-through-procfs-if-prlimit-already-exists&#34;&gt;Why expose limits through procfs if prlimit already exists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;what-are-resource-limits&#34;&gt;What are resource limits&lt;/h3&gt;
&lt;p&gt;Resource limits can be thought as ceilings that can be set for specific resources from the Kernel that a given process might end up consuming.&lt;/p&gt;
&lt;p&gt;These limits are made up of two values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;soft&lt;/strong&gt;: limits the number of resources that the process may consume; and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hard&lt;/strong&gt;: a ceiling on the value to which the soft limit may be adjusted by an unprivileged process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Throughout this article, I&amp;rsquo;ll be covering only one resource - the number of open files -, but there are many other resources that can have their consumption limited via resource limits.&lt;/p&gt;
&lt;p&gt;So, to set a quick example, let&amp;rsquo;s consider the following program that opens &lt;code&gt;n&lt;/code&gt; files and leaves them open:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;flag&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;io/ioutil&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Take as user input the number of files
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * that we want to create and keep open.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;flag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;files&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;number of files to open&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * open-files - opens files and leaves them open.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Usage: ./open-files -files=&amp;lt;number_of_files&amp;gt;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;flag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;number of files must be &amp;gt; 0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * Show the PID of the current process so
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * that we can mess with it in another
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * terminal.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 */&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;pid: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

	&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * Starts the process of creating N files
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * and leaving them open.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 */&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;files open&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;tmpfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ioutil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TempFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;example&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;failed to create and &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
                                &lt;span class=&#34;s&#34;&gt;&amp;#34;open tmp file: %v\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Remove&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tmpfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running them on a shell with a high limit of open files, we can see it properly working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;./open-files
pid:  &lt;span class=&#34;m&#34;&gt;726&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;8&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; files open
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we make that limit very small - 10 -, we can see it failing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Set the maximum number of open files to 10.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;ulimit&lt;/span&gt; -n &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Try to open 10 files.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Naturally, it should fail, given that &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the execution of `open-files` will also open&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# some shared libraries before opening the other&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# 10 files.&lt;/span&gt;
./open-files
pid:  &lt;span class=&#34;m&#34;&gt;732&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; files open
&lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; files open
failed to create and open tmp file: 
  open /tmp/example484763765: too many open files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;how-does-the-kernel-limit-the-number-of-files-open-by-a-process&#34;&gt;How does the kernel limit the number of files open by a process?&lt;/h3&gt;
&lt;p&gt;In the case of open files, we can see in the Kernel code how that&amp;rsquo;s strictly enforced by following the methods invoked in the code path for an &lt;a href=&#34;http://man7.org/linux/man-pages/man2/open.2.html&#34;&gt;&lt;code&gt;open(2)&lt;/code&gt;&lt;/a&gt; syscall:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;          ^   __alloc_fd
          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   get_unused_fd_flags
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;kernel&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   do_sys_open
          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   sys_openat
          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   do_syscall_64
          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   entry_SYSCALL_64_after_hwframe
----------+--------------------------
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;user&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   open&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;2&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having everything started at &lt;code&gt;do_syscall&lt;/code&gt; and going towards &lt;code&gt;do_sys_open&lt;/code&gt;, nothing particularly interesting happens when it comes to resource limits.&lt;/p&gt;
&lt;p&gt;Things get interesting when it comes to &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/file.c#L547&#34;&gt;&lt;code&gt;get_unused_fd_flags&lt;/code&gt;&lt;/a&gt;, which then calls &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/file.c#L484&#34;&gt;&lt;code&gt;__alloc_fd&lt;/code&gt;&lt;/a&gt; with the resource limit boundaries:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Sets up the ranges for __alloc_fd
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * so that when trying to allocate a
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * file descriptor, it performs some
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * bounds checking.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_unused_fd_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__alloc_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
                &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RLIMIT_NOFILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;               
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Tries to allocate a file descriptor
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * for the process, marking it as busy.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__alloc_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	       &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fdtable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fdt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// tries to gather the next available
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// file descriptor
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fdt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;max_fds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;find_next_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fdt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Verifies if the file descriptor that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// we have available falls within the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// boundaries set by the open files
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// resource limit.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EMFILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Knowing where all these checks take place, we can tailor a specific &lt;a href=&#34;https://github.com/iovisor/bpftrace&#34;&gt;&lt;code&gt;bpftrace&lt;/code&gt;&lt;/a&gt; program that targets &lt;code&gt;__alloc_file&lt;/code&gt; and then lets us know what is the result from it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span class=&#34;k&#34;&gt;BEGIN&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Looking for EMFILE when opening\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;sr&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Place&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;probe&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;sb&#34;&gt;`__alloc_fd`&lt;/span&gt;
&lt;span class=&#34;sr&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;so&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;that&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;we&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;can&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;verify&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;whether&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;is&lt;/span&gt;
&lt;span class=&#34;sr&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;returned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;kretprobe:__alloc_fd&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/comm == &amp;#34;open-files&amp;#34;/&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;returned: %d\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Leaving the tracing running in a terminal while we run &lt;code&gt;open-files&lt;/code&gt; in another with a low limit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the trace program and then&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# see the values returned.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# What we expect: file descriptors being&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# properly created up until `9`, then `-EMFILE`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (24) at the 10th try.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# #define EMFILE 24 /* Too many open files */&lt;/span&gt;

sudo bpftrace ./limit-check.d
Attaching &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; probes...
Looking &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; EMFILE when opening
returned: &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
returned: &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
returned: &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;
returned: &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt;
returned: &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt;
returned: &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;
returned: &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt;
returned: -24
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;under-the-hood-of-the-ulimit-command&#34;&gt;Under the hood of the ulimit &amp;ldquo;command&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Now that we know how the Kernel is able to check for the limits whenever our process tries to create a program, it&amp;rsquo;s time to discover what that &lt;code&gt;ulimit -n&lt;/code&gt; command is all about.&lt;/p&gt;
&lt;p&gt;The first thing one might notice is that &lt;code&gt;ulimit&lt;/code&gt; is not really a binary that the shell is calling - it&amp;rsquo;s usually a builtin command that your shell provides.&lt;/p&gt;
&lt;p&gt;For instance, looking at &lt;code&gt;ash&lt;/code&gt;, the shell that &lt;a href=&#34;https://busybox.net/about.html&#34;&gt;&lt;code&gt;busybox&lt;/code&gt;&lt;/a&gt; provides, we can see it in &lt;a href=&#34;https://elixir.bootlin.com/busybox/1.29.2/source/shell/shell_common.c#L453&#34;&gt;&lt;code&gt;ash&lt;/code&gt;&amp;rsquo;s code&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Implementation of all of the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * ulimit builtin functionality.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * No `execve` calling a `/usr/bin/ulimit`
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * or somethign like that.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Pure code implemented from ground up.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FAST_FUNC&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;shell_builtin_ulimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

         &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;l&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limits_tbl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
                &lt;span class=&#34;n&#34;&gt;l&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limits_tbl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ARRAY_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limits_tbl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)];&lt;/span&gt; 
                &lt;span class=&#34;n&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                        &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OPT_hard&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OPT_soft&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OPT_hard&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                        &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OPT_soft&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                        &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setrlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                        &lt;span class=&#34;n&#34;&gt;bb_perror_msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;error setting limit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
                        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: the same is valid for &lt;code&gt;bash&lt;/code&gt; - see &lt;a href=&#34;http://git.savannah.gnu.org/cgit/bash.git/tree/builtins/ulimit.def&#34;&gt;bash/builtins/ulimit.def&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Being a builtin or not, it doesn&amp;rsquo;t matter - at some point, it touches the Kernel with a syscall.&lt;/p&gt;
&lt;p&gt;For doing so, three syscalls can be used (see &lt;a href=&#34;https://linux.die.net/man/2/prlimit&#34;&gt;man 2 prlimit&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setrlimit&lt;/code&gt; and &lt;code&gt;getrlimit&lt;/code&gt;: respectively, sets and gets resource limits corresponding to the currently running process (and its future children); and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prlimit&lt;/code&gt;, which allows settings and gettings resource limits corresponding to an arbitrary process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As we can see from the description, in the end, &lt;code&gt;prlimit&lt;/code&gt; is what really matters.&lt;/p&gt;
&lt;p&gt;If we look under the hood of &lt;code&gt;setrlimit&lt;/code&gt; and &lt;code&gt;getrlimit&lt;/code&gt;, we even discover that they&amp;rsquo;re just wrapping parts of the &lt;code&gt;prlimit&lt;/code&gt; functionality (see &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/kernel/sys.c#L1330&#34;&gt;&lt;code&gt;kernel/sys.c&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;n&#34;&gt;SYSCALL_DEFINE2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getrlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;do_prlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;copy_to_user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;EFAULT&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;SYSCALL_DEFINE2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setrlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;copy_from_user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EFAULT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;do_prlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, how does &lt;code&gt;prlimit&lt;/code&gt; work?&lt;/p&gt;
&lt;h3 id=&#34;a-sample-ulimit-implementation&#34;&gt;A sample ulimit implementation&lt;/h3&gt;
&lt;p&gt;We can see its functionality in place by creating a quick program in C that is able to change the resource limits regarding the number of open files associated with a given process id:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/resource.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// A hardcoded number that sets the maximum number
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// of open files that the supplied PID can handle.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define MAX_OPEN_FILES 10
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// Hardcode the resource that we&amp;#39;ll be changing.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// RLIMIT_NOFILE - number of files that can be
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//                 opened by this process.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define RESOURCE RLIMIT_NOFILE
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * limit-open-files - limits the number of open files that
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *                    a given PID can hold to 10.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Usage: ./limit-open-files.out &amp;lt;PID&amp;gt;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// parse the arguments supplied via
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// flags (code omitted for brevity).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;cli_parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Initialize the data structures that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// carry information about the process
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// resource limits.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// `old` is supposed to have its values
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// filled by the kernel at the `get` 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// phase of `prlimit`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// `new` is supposed to contain the values
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// that we want to change.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;soft&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hard&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Perform a &amp;#34;get-and-set&amp;#34; operation.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// By passing non-NULL `new` and `old` values,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the values supplied at `new` will be used as
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the new values for such resource.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// The `old` will get filled with the previous
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// values.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// int prlimit(
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//   pid_t pid,      --&amp;gt; process ID to affect
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//   int resource,   --&amp;gt; resource to tweak / gather info
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//   const struct rlimit *new_limit, --&amp;gt; if set; new limit 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//                                       to place.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//   struct rlimit *old_limit   --&amp;gt; if non-nil, gathers info 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//                                  about the previous soft 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//                                  and hard limits.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// );
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;prlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIMIT_NOFILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;prlimit - get and set:&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;before: soft=%lld; hard=%lld&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Perform a `get` operation to retrieve the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// current values set for the resource.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;prlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIMIT_NOFILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;prlimit - get:&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;now:    soft=%lld; hard=%lld&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run it against a particular process and then see it changing its resources limits:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Modify the limit of open files that process&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# 29871 can hold to soft=12 and hard=12.&lt;/span&gt;
./limit-open-files.out -p &lt;span class=&#34;m&#34;&gt;29871&lt;/span&gt; -s &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; -h &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;
before: &lt;span class=&#34;nv&#34;&gt;soft&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1024&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;hard&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1048576&lt;/span&gt;
now: &lt;span class=&#34;nv&#34;&gt;soft&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;12&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;hard&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Trying to modify it again, we can see that &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the process was previously set to `12` &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (given that we had just changed to 12).&lt;/span&gt;
./limit-open-files.out -p &lt;span class=&#34;m&#34;&gt;29871&lt;/span&gt; -s &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; -h &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;
before: &lt;span class=&#34;nv&#34;&gt;soft&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;12&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;hard&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;
now: &lt;span class=&#34;nv&#34;&gt;soft&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;12&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;hard&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Try to increase the hard limit from 12 to 13.&lt;/span&gt;
./limit-open-files.out -p &lt;span class=&#34;m&#34;&gt;29871&lt;/span&gt; -s &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; -h &lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;
prlimit - get and set:: Operation not permitted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice how in the end we were not able to complete our desired operation of increasing hard limit.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because some of the operations that &lt;code&gt;prlimit&lt;/code&gt; performs (like increasing the hard limit) require elevated privileges, which we didn&amp;rsquo;t have when running it as an unprivileged user.&lt;/p&gt;
&lt;p&gt;Making use of a &lt;a href=&#34;https://github.com/iovisor/bpftrace&#34;&gt;&lt;code&gt;bpftrace&lt;/code&gt;&lt;/a&gt; tool called &lt;a href=&#34;https://github.com/iovisor/bpftrace/blob/master/tools/capable_example.txt&#34;&gt;&lt;code&gt;capable&lt;/code&gt;&lt;/a&gt; we&amp;rsquo;re able to see how &lt;code&gt;prlimit&lt;/code&gt; checks for &lt;code&gt;CAP_SYS_RESOURCE&lt;/code&gt; when trying to elevate the hard limit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;sudo capable
UID    PID    COMM             CAP  NAME                 AUDIT
&lt;span class=&#34;m&#34;&gt;1001&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;29882&lt;/span&gt;  limit-open-file  &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt;   CAP_SYS_RESOURCE     &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we&amp;rsquo;re aware of the &lt;code&gt;prlimit&lt;/code&gt; syscall, can we see the Kernel code that sets and gets these limits?&lt;/p&gt;
&lt;h3 id=&#34;setting-and-getting-resource-limits-at-the-kernel-level&#34;&gt;Setting and getting resource limits at the Kernel level&lt;/h3&gt;
&lt;p&gt;Tracing down the methods invoked by &lt;code&gt;prlimit&lt;/code&gt;, we can see that all ends up in the method &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/kernel/sys.c#L1472&#34;&gt;&lt;code&gt;do_prlimit&lt;/code&gt; at &lt;code&gt;kernel/sys.c&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a break down of it, full of comments of my own (and mutual exclusion - through locks - stripped out):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `do_prlimit` constitutes the underlying functionality
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * of `prlimit` (which is also partly used by `getrlimit`
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * and `setrlimit`).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;do_prlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Checks if the resource is a valid one (given that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// we can provide whatever we want from the syscall
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// interface).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIM_NLIMITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// If we specified a non-NULL `new_rlim`, it means
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// that we&amp;#39;re planning to set some limits on a given
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// resource.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;c1&#34;&gt;// Check if the values even make sense.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Check if it&amp;#39;d be getting above the system-wide limit
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// already set (sysctl)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIMIT_NOFILE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                                &lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sysctl_nr_open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EPERM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Grab the current resource limits for
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the desired resource.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// - Maybe we&amp;#39;ll be able to see that /proc/pid/limits
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//   looks at the very same thing (tsk-&amp;gt;signal-&amp;gt;rlim)?
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tsk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// If we&amp;#39;re going to set new values,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// that is, if we&amp;#39;re going to change limits, then ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// If we&amp;#39;re increasing the hard limit, make
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// sure that the user has the proper capabilities.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
				&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;capable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CAP_SYS_RESOURCE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EPERM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Go ahead and perform the update, but first,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// apply a security check.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;security_task_setrlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// If everything went right so far,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// update `old_rlim` with the values of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// what has been captured as the current
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// limits as of before updating.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_rlim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cool! So now we know that the limits (per-task) are set at &lt;code&gt;task-&amp;gt;signal-&amp;gt;rlim + &amp;lt;rlimit_offset&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You might&amp;rsquo;ve noticed that we didn&amp;rsquo;t explicitly look at &lt;code&gt;task-&amp;gt;signal-&amp;gt;rlim&lt;/code&gt; in the section &lt;a href=&#34;#how-does-the-kernel-limits-the-number-of-files-open-by-a-process&#34;&gt;&amp;ldquo;How does the kernel limits the number of files open by a process&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To remember you, this is what we saw:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Sets up the ranges for __alloc_fd
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * so that when trying to allocate a
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * file descriptor, it performs some
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * bounds checking.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_unused_fd_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__alloc_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
                &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RLIMIT_NOFILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;               
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking deeper into it, we can start inspecting what is that &lt;code&gt;rlimit(RLIMIT_NOFILE)&lt;/code&gt; thing, which leads to the fact that under the hood, it looks at the current task and inspects &lt;code&gt;-&amp;gt;signal-&amp;gt;rlim&lt;/code&gt; in the next function that gets called (&lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15/source/include/linux/sched/signal.h#L591&#34;&gt;task_rlimit&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Looks at the current task&amp;#39;s resource
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * limit.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * ps.: notice how it doesn&amp;#39;t look at the **hard**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *      limit, but the **soft** limit.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;task_rlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;READ_ONCE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, now that we know how limits can be updated, as well as read, we can start imagining how &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt; works under the hood.&lt;/p&gt;
&lt;h3 id=&#34;gathering-process-limits-via-proc&#34;&gt;Gathering process limits via /proc&lt;/h3&gt;
&lt;p&gt;Not only we&amp;rsquo;re able to retrieve information about what are the limits set for a given process via the &lt;code&gt;prlimit(2)&lt;/code&gt; syscall, we can also do that by inspecting &lt;code&gt;/proc&lt;/code&gt;, more specifically, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt; (where &lt;code&gt;&amp;lt;pid&amp;gt;&lt;/code&gt; corresponds to the process ID of the process we want to know the limits).&lt;/p&gt;
&lt;p&gt;For instance, we can check the limits of the current process either via &lt;code&gt;ulimit -n&lt;/code&gt; or &lt;code&gt;/proc/self/limits&lt;/code&gt; (&lt;code&gt;/proc/self&lt;/code&gt; is a link to &lt;code&gt;/proc/&amp;lt;pid&amp;gt;&lt;/code&gt; where &lt;code&gt;&amp;lt;pid&amp;gt;&lt;/code&gt; is the current process&#39; &lt;code&gt;pid&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check the limit of open files&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# using `ulimit` (`prlimit` under the hood).&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;ulimit&lt;/span&gt; -n
&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Check the limit of open files&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# using the `proc` filesystem under `/proc`.&lt;/span&gt;
cat /proc/self/limits  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s1&#34;&gt;&amp;#39;open files&amp;#39;&lt;/span&gt;
Limit           Soft Limit  Hard Limit   Units
Max open files  &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;1048576&lt;/span&gt;      files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Knowing from the past articles (see &lt;a href=&#34;https://ops.tips/blog/what-is-slash-proc/&#34;&gt;What is /proc?&lt;/a&gt;) how procfs is able to register methods to respond to Virtual Filesystem (VFS) calls, we can start digging into how the method registered for handling calls to &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt; work.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Display limits for a process 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_pid_limits&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seq_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid_namespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			   &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RLIM_NLIMITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Make sure we have exclusive access
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// to the task struct while reading
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// it.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock_task_sighand&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Copy to our current execution all of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the limits that are set for the task
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// provided as argument.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
                &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlimit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIM_NLIMITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Release the exclusive access
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;unlock_task_sighand&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Print the header
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;seq_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%-25s %-20s %-20s %-10s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		  &lt;span class=&#34;s&#34;&gt;&amp;#34;Limit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Soft Limit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Hard Limit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Units&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Iterate over each limit and then display it.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIM_NLIMITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RLIM_INFINITY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;seq_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%-25s %-20s &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				   &lt;span class=&#34;n&#34;&gt;lnames&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;unlimited&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;seq_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%-25s %-20lu &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				   &lt;span class=&#34;n&#34;&gt;lnames&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rlim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rlim_cur&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;why-expose-limits-through-procfs-if-prlimit-already-exists&#34;&gt;Why expose limits through procfs if prlimit already exists&lt;/h3&gt;
&lt;p&gt;I don&amp;rsquo;t know!&lt;/p&gt;
&lt;p&gt;While the kernel doesn&amp;rsquo;t provide convenient ways of accessing some of its internal resources, for &lt;code&gt;limits&lt;/code&gt; it&amp;rsquo;s definitely not the case - prlimit can supply all of its functionality.&lt;/p&gt;
&lt;p&gt;Do you know why? Please let me know!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It was interesting to see how a resource limit is actually applied by the kernel, and in the end, discover that &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt; is very redundant when looking at the functionality that a syscall (&lt;code&gt;prlimit&lt;/code&gt;) already provides.&lt;/p&gt;
&lt;p&gt;If you have any further questions, or just want to connect, let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;p&gt;Here are some interesting books to learn more about some of the concepts highlighted here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2CIpde2&#34;&gt;Linux System Programming: Talking Directly to the Kernel and C Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2DAORD5&#34;&gt;Systems Performance: Enterprise and the Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2zE5jOV&#34;&gt;The C Programming Language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
                                <pubDate>Sat, 13 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/proc-pid-limits-under-the-hood/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/proc-pid-limits-under-the-hood/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Why top and free inside containers don&#39;t show the correct container memory</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Something that is very common to get wrong when starting with Linux containers is to think that &lt;code&gt;free&lt;/code&gt; and other tools like &lt;code&gt;top&lt;/code&gt; should report the memory limits.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/meminfo-uncontained.svg&#34;
       alt=&#34;Illustration of the access to procfs from a container &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Here you&amp;rsquo;ll not only go through why that happens and how to get it right, but also take a look at where is the Kernel looking for information when you ask it for memory statistics.&lt;/p&gt;
&lt;p&gt;Also, if you&amp;rsquo;re curious about how the code for keeping track of per-cgroup page counter looks, stick to the end!&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;This is the third article in a series of 30 articles around &lt;em&gt;procfs&lt;/em&gt;: &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;A Month of /proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to keep up to date with it, make sure you &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#running-top-within-a-container&#34;&gt;Running top within a container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#how-the-top-and-free-tools-gather-memory-statistics&#34;&gt;How the top and free tools gather memory statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#setting-container-limits&#34;&gt;Setting container limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#memory-limits-set-by-cgroups-are-not-namespaced&#34;&gt;Memory limits set by cgroups are not namespaced&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#whos-controlling-the-allocation-of-memory&#34;&gt;Who&amp;rsquo;s controlling the allocation of memory?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tracing-a-cgroup-running-out-of-memory&#34;&gt;Tracing a cgroup running out of memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;running-top-within-a-container&#34;&gt;Running top within a container&lt;/h3&gt;
&lt;p&gt;To get a testbed for the rest of the article, consider the case of running a single container with a memory limit of 10MB in a system that has 2GB of RAM available:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check the amount of memory available&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# outside the container (i.e., in the host)&lt;/span&gt;
free -h
      total   used   free   available
Mem:   1.9G   312M   385M        1.5G

&lt;span class=&#34;c1&#34;&gt;# Define the total number of bytes that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# will dictate the memory limit of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# container.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;MEM_MAX&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Run a container using the ubuntu image&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as its base image, with the memory limit&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# set to 10MB, and a tty as well as interactive&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# support.&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --interactive &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --tty &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --memory &lt;span class=&#34;nv&#34;&gt;$MEM_MAX&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ubuntu
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the container running, we can now check what are the results from executing &lt;code&gt;top&lt;/code&gt; over there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;top -bn1

Tasks:   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; total,   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; running,   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; sleeping,   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; stopped,   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; zombie
%Cpu&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;:  0.2 us,  0.1 sy,  0.0 ni, 99.7 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
         .----------------.
         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
KiB Mem :&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2040940&lt;/span&gt; total, &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;117612&lt;/span&gt; free,   &lt;span class=&#34;m&#34;&gt;651204&lt;/span&gt; used,  &lt;span class=&#34;m&#34;&gt;1272124&lt;/span&gt; buff/cache
KiB Swap:&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; total, &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; free,        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; used.  &lt;span class=&#34;m&#34;&gt;1196972&lt;/span&gt; avail Mem
         *--+-------------*
  PID USER  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;18508&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;3432&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;3016&lt;/span&gt; S   0.0  0.2   0:00.02 bash
   &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; root  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;36484&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;3104&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2748&lt;/span&gt; R   0.0  0.2   0:00.00 top
            &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
            *---&amp;gt; Not really what we 
                  expect, that is 2GB!!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we outlined before, not what one would typically expect (it reports the total available memory as seen in the host - not showing the 10MB limit at all).&lt;/p&gt;
&lt;p&gt;What about &lt;code&gt;free&lt;/code&gt;?  Same thing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;free -h
        total    used     free   available
Mem:     1.9G    612M     131M        1.2G
Swap:      0B      0B       0B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;how-the-top-and-free-tools-gather-memory-statistics&#34;&gt;How the top and free tools gather memory statistics&lt;/h3&gt;
&lt;p&gt;If we go inspect what are the syscalls being used by both &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;free&lt;/code&gt;, we can see that they&amp;rsquo;re making use of plain &lt;code&gt;open(2)&lt;/code&gt; and &lt;code&gt;read(2)&lt;/code&gt; calls:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check what are the syscalls being&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# used by `free`&lt;/span&gt;
strace -f free
...
openat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AT_FDCWD, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/proc/meminfo&amp;#34;&lt;/span&gt;, O_RDONLY&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;

                        .-------.
                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       v
read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, &lt;span class=&#34;s2&#34;&gt;&amp;#34;MemTotal:      | 2040940 kB\nMemF&amp;#34;&lt;/span&gt;..., 8191&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1307&lt;/span&gt;
...                     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       
                     That is 2GB!



&lt;span class=&#34;c1&#34;&gt;# Check what are the syscalls being used&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by `top`&lt;/span&gt;
strace -f top -p &lt;span class=&#34;m&#34;&gt;19282&lt;/span&gt;  -bn1
...
openat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AT_FDCWD, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/proc/meminfo&amp;#34;&lt;/span&gt;, O_RDONLY&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;
lseek&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;5, 0, SEEK_SET&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;5, &lt;span class=&#34;s2&#34;&gt;&amp;#34;MemTotal:        2040940 kB\nMemF&amp;#34;&lt;/span&gt;..., 8191&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1307&lt;/span&gt;
...                             ^
                                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
             2GB again  --------*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at those return values (what it&amp;rsquo;s read), we can spot that the &amp;ldquo;problem&amp;rdquo; is coming from &lt;code&gt;/proc/meminfo&lt;/code&gt;, which &lt;code&gt;free&lt;/code&gt; and &lt;code&gt;top&lt;/code&gt; are just blindly trusting.&lt;/p&gt;
&lt;p&gt;Before we go check what the Kernel is doing when reporting those values, let&amp;rsquo;s quickly remember how a container gets memory limits set.&lt;/p&gt;
&lt;h3 id=&#34;setting-container-limits&#34;&gt;Setting container limits&lt;/h3&gt;
&lt;p&gt;The way that Docker (ok, &lt;code&gt;runc&lt;/code&gt;) ends up setting the container limits is via the use of &lt;code&gt;cgroups&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As very well documented in the man page (see &lt;a href=&#34;http://man7.org/linux/man-pages/man7/cgroups.7.html&#34;&gt;&lt;code&gt;man 7 cgroups&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Control cgroups, usually referred to as cgroups, are a Linux kernel feature which allows processes to be organized into hierarchical groups whose usage of various types of resources can then be limited and monitored.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To see that in action, consider the following program that allocates memory in chunks of 1MB:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#define MEGABYTE (1 &amp;lt;&amp;lt; 20)
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define ALLOCATIONS 20
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * alloc - a &amp;#34;leaky&amp;#34; program that just allocated
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *         a predefined amount of memory and then
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *         exits.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;allocating: %dMB&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ALLOCATIONS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;


	&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;   &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ALLOCATIONS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


	&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;c1&#34;&gt;// Allocate 1MB (not initializing it
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// though).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MEGABYTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;malloc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Explicitly initialize the area that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// has been allocated.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;65&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MEGABYTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;remaining&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can see that without any limits, we can keep allocating past 20MB without problems.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Keep allocating memory until the 20MB&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# mark gets reached.&lt;/span&gt;
./alloc.out
allocating: 20MB
remaining	&lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;
...
remaining	&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That changes after we put our process under a cgroup with memory limits set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create our custom cgroup&lt;/span&gt;
mkdir /sys/fs/cgroup/memory/custom-group

&lt;span class=&#34;c1&#34;&gt;# Configure the maximum amount of memory&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that all of the processes in such cgroup&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# will be able to allocate&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /sys/fs/cgroup/memory/custom-group/memory.limit_in_bytes

&lt;span class=&#34;c1&#34;&gt;# Put the current process tree under such&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# cgroup&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$$&lt;/span&gt; &amp;gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /sys/fs/cgroup/memory/custom-group/tasks

&lt;span class=&#34;c1&#34;&gt;# Try to allocate the 20MB&lt;/span&gt;
./alloc.out
allocating: 20MB
remaining	&lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;15&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;14&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;
remaining	&lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;
Killed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at the results from &lt;code&gt;dmesg&lt;/code&gt;, we can see what happened:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;                        our thing getting killed!
                                  .------------.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109904&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; alloc.out invoked &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; oom-killer:&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                                  *------------*
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109906&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; alloc.out &lt;span class=&#34;nv&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/ &lt;span class=&#34;nv&#34;&gt;mems_allowed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109911&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; CPU: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; PID: &lt;span class=&#34;m&#34;&gt;22074&lt;/span&gt; Comm: alloc.out Not tainted 4.15.0-36-generic &lt;span class=&#34;c1&#34;&gt;#39-Ubuntu&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109911&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109912&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Call Trace:
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109918&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  dump_stack+0x63/0x8b
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109920&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  dump_header+0x71/0x285
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109923&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  oom_kill_process+0x220/0x440
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109924&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  out_of_memory+0x2d1/0x4f0
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109926&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  mem_cgroup_out_of_memory+0x4b/0x80
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109928&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  mem_cgroup_oom_synchronize+0x2e8/0x320
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109930&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  ? mem_cgroup_css_online+0x40/0x40
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109931&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  pagefault_out_of_memory+0x36/0x7b
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109934&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  mm_fault_error+0x90/0x180
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109935&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  __do_page_fault+0x4a5/0x4d0
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109937&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  do_page_fault+0x2e/0xe0
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109940&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  ? page_fault+0x2f/0x50
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109941&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  page_fault+0x45/0x50

                        Killed!
...               ____________________________
                 /                            &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109950&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Task in /custom-group killed as 
                a result of limit of /custom-group
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109954&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; memory: usage 10240kB, limit 10240kB, failcnt &lt;span class=&#34;m&#34;&gt;56&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109954&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; memory+swap: usage 0kB, limit 9007199254740988kB, failcnt &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109955&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; kmem: usage 940kB, limit 9007199254740988kB, failcnt &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109955&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Memory cgroup stats &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; /custom-group: cache:0KB rss:9300KB rss_huge:0KB shmem:0KB mapped_file:0KB dirty:0KB writeback:0KB inactive_anon:0KB active_anon:9248KB inactive_file:0KB active_file:0KB unevictable:0KB
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.109965&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; pid &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.110005&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;21530&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;21530&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;5837&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;1381&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;90112&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;             &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; bash
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.110011&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;22074&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;22074&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;3440&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;2594&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;69632&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;             &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; alloc.out
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.110012&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Memory cgroup out of memory: Kill process &lt;span class=&#34;m&#34;&gt;22074&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;alloc.out&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; score &lt;span class=&#34;m&#34;&gt;989&lt;/span&gt; or sacrifice child
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.318942&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Killed process &lt;span class=&#34;m&#34;&gt;22074&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;alloc.out&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; total-vm:13760kB, anon-rss:8988kB, file-rss:1388kB, shmem-rss:0kB
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;181346.322003&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; oom_reaper: reaped process &lt;span class=&#34;m&#34;&gt;22074&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;alloc.out&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we can see pretty well that limits &lt;strong&gt;are&lt;/strong&gt; being enforced.&lt;/p&gt;
&lt;p&gt;Again, why is &lt;code&gt;/proc&lt;/code&gt; telling us that we have 2GB of memory?&lt;/p&gt;
&lt;h3 id=&#34;memory-limits-set-by-cgroups-are-not-namespaced&#34;&gt;Memory limits set by cgroups are not namespaced&lt;/h3&gt;
&lt;p&gt;The reason why is that the memory retrieved by &lt;code&gt;/proc/meminfo&lt;/code&gt; is not namespaced.&lt;/p&gt;
&lt;p&gt;Differently from other things like listing pids from &lt;code&gt;/proc&lt;/code&gt;, when the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.17/source/include/linux/fs.h#L1693&#34;&gt;&lt;code&gt;file_operations&lt;/code&gt;&lt;/a&gt; that procfs implements reach the point of gathering memory information, it doesn&amp;rsquo;t acquire a namespaced view of it.&lt;/p&gt;
&lt;p&gt;For instance, let&amp;rsquo;s compare the way that listing the differences in showing contents under &lt;code&gt;/proc/&lt;/code&gt; (listing the directory entries) and &lt;code&gt;/proc/meminfo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the case of &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/proc/base.c#L3202&#34;&gt;listing &lt;code&gt;/proc&lt;/code&gt;&lt;/a&gt; (see &lt;a href=&#34;https://ops.tips/blog/how-is-proc-able-to-list-pids/&#34;&gt;How is /proc able to list process IDs?&lt;/a&gt;), we can see procfs taking the namespace reference and using it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_pid_readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dir_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Takes the namespace as seen by the file
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// provided.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid_namespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_sb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s_fs_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        
        &lt;span class=&#34;c1&#34;&gt;// Iterates through the next available tasks
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// (processes) as seen by the namespace that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// we are within.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next_tgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	     &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	     &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next_tgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Meanwhile, in the case of &lt;a href=&#34;https://elixir.bootlin.com/linux/latest/source/fs/proc/meminfo.c#L33&#34;&gt;reading &lt;code&gt;/proc/meminfo&lt;/code&gt;&lt;/a&gt;, that doesn&amp;rsquo;t happen at all (well, as expected, it&amp;rsquo;s not about namespaces! It&amp;rsquo;s about cgroups):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;meminfo_proc_show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seq_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sysinfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Populate the sysinfo struct with memory-related
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// stuff
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;si_meminfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Add swap information
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;si_swapinfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        
        &lt;span class=&#34;c1&#34;&gt;// ... start displaying
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;show_val_kb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;MemTotal:       &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;totalram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;show_val_kb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;MemFree:        &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;freeram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As expected, no single reference to namespaces (or cgroups).&lt;/p&gt;
&lt;p&gt;Also, &lt;code&gt;si_meminfo&lt;/code&gt;, the method that fills the &lt;code&gt;sysinfo&lt;/code&gt; interface takes some global values and bring it to &lt;code&gt;/proc/meminfo&lt;/code&gt;, has no idea about cgroups either:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * The struct that holds part of the memory information
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * that ends up being displayed in the end.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sysinfo&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_long_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uptime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;		&lt;span class=&#34;cm&#34;&gt;/* Seconds since boot */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loads&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* 1, 5, and 15 minute load averages */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;totalram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Total usable main memory size */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;freeram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Available memory size */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sharedram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Amount of shared memory */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bufferram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Memory used by buffers */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;totalswap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Total swap space size */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;freeswap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* swap space still available */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__u16&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;procs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;		   	&lt;span class=&#34;cm&#34;&gt;/* Number of current processes */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__u16&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pad&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;		   	&lt;span class=&#34;cm&#34;&gt;/* Explicit padding for m68k */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;totalhigh&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Total high memory size */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;freehigh&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Available high memory size */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem_unit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;			&lt;span class=&#34;cm&#34;&gt;/* Memory unit size in bytes */&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__kernel_ulong_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)];&lt;/span&gt;	&lt;span class=&#34;cm&#34;&gt;/* Padding: libc5 uses this.. */&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Fills the `sysinfo` struct passed as a pointer
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * with values collected from the system (globally
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * set).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;si_meminfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sysinfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;totalram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;totalram_pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sharedram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;global_node_page_state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NR_SHMEM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;freeram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;global_zone_page_state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NR_FREE_PAGES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bufferram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nr_blockdev_pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;totalhigh&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;totalhigh_pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;freehigh&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nr_free_highpages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_unit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Interesting fact: &lt;code&gt;totalram_pages&lt;/code&gt; (reported from &lt;code&gt;MemTotal&lt;/code&gt;) &lt;strong&gt;can&lt;/strong&gt; change - see this StackOverflow question: &lt;a href=&#34;https://unix.stackexchange.com/questions/114024/why-does-memtotal-in-proc-meminfo-change&#34;&gt;Why does MemTotal in /proc/meminfo change?&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;whos-controlling-the-allocation-of-memory&#34;&gt;Who&amp;rsquo;s controlling the allocation of memory?&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re now wondering where we end up reaching that limit that we set in the cgroup, we need to look at the path that a memory allocation takes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
   alloc.out	(our process)
      |
      |
      *--&amp;gt; task_struct (process descriptor)
            |
            |
   	    *--&amp;gt; mm_struct (memory descriptor)
   	           |
   	           |
   m_cgroup &amp;lt;------*
   |
   +------&amp;gt; page_counter memory
   |          |
   |          *--&amp;gt; { atomic_long_t count, unsigned long limit }
   |
   |
   *------&amp;gt; page_counter swap

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Within the Kernel, each process created (in our case, &lt;code&gt;alloc.out&lt;/code&gt;) is referenced internally via a process descriptor &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/include/linux/sched.h#L520&#34;&gt;&lt;code&gt;task_struct&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;thread_info&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;thread_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ... 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt; 
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;			&lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mm_struct&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Such process descriptor references a memory descriptor &lt;code&gt;mm&lt;/code&gt; defined as &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/include/linux/mm_types.h#L356&#34;&gt;&lt;code&gt;mm_struct&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mm_struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vm_area_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;		&lt;span class=&#34;cm&#34;&gt;/* list of VMAs */&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mmap_base&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;		&lt;span class=&#34;cm&#34;&gt;/* base of mmap area */&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;		&lt;span class=&#34;cm&#34;&gt;/* size of task vm space */&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MEMCG
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem_cgroup&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_cgroup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Such memory descriptor references a &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/include/linux/memcontrol.h#L162&#34;&gt;&lt;code&gt;mem_cgroup&lt;/code&gt;&lt;/a&gt;, a data structure that keeps track of the cgroup semantics for memory limiting and accounting:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem_cgroup&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cgroup_subsys_state&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;css&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;cm&#34;&gt;/* Private memcg ID. Used to ID objects that outlive the cgroup */&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem_cgroup_id&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;cm&#34;&gt;/* Accounted resources */&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page_counter&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page_counter&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;swap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Such cgroup data structure then references some page counters (&lt;code&gt;memory&lt;/code&gt; and &lt;code&gt;swap&lt;/code&gt;, for instance) defined via the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/include/linux/page_counter.h#L9&#34;&gt;&lt;code&gt;page_counter&lt;/code&gt; struct&lt;/a&gt;, which are responsible for keeping track of usage and providing the limiting functionality when someone tries to acquire a page:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page_counter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;atomic_long_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// The parent CGROUP (remember, cgroups are
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// hierarchical!)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page_counter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Whenever a process needs some pages assigned to it, &lt;code&gt;page_counter_try_charge&lt;/code&gt; goes through the cgroup memory hierarchy, trying to charge a given number of pages, which in case of success (new value would be smaller than the limit), it updates the counts, otherwise, it triggers OOM behavior.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;bcc&lt;/code&gt; to trace &lt;code&gt;page_counter_try_charge&lt;/code&gt;, we can see how the act of &lt;code&gt;page_fault&lt;/code&gt;ing leads to &lt;code&gt;mem_cgroup_try_charge&lt;/code&gt; calling &lt;code&gt;page_counter_try_charge&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;25641   25641   alloc.out       page_counter_try_charge
        page_counter_try_charge+0x1 [kernel]
        mem_cgroup_try_charge+0x93 [kernel]
        handle_pte_fault+0x3e3 [kernel]
        __handle_mm_fault+0x478 [kernel]
        handle_mm_fault+0xb1 [kernel]
        __do_page_fault+0x250 [kernel]
        do_page_fault+0x2e [kernel]
        page_fault+0x45 [kernel]
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;tracing-a-cgroup-running-out-of-memory&#34;&gt;Tracing a cgroup running out of memory&lt;/h3&gt;
&lt;p&gt;If we&amp;rsquo;re even more curious and decide to trace the &lt;code&gt;page_counter_try_charge&lt;/code&gt; arguments, we can see the tries failing in the case when we&amp;rsquo;re within a container and try to grab more memory than we&amp;rsquo;re allowed to.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;bpftrace&lt;/code&gt;, we&amp;rsquo;re able to tailor a small program that inspects the &lt;code&gt;page_counter&lt;/code&gt; used in &lt;code&gt;page_counter_try_charge&lt;/code&gt; and see how the limit changes over time (until the point that we reach the exhaustion - receiving an OOM then).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#include &amp;lt;linux/page_counter.h&amp;gt;&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;BEGIN&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Tracing page_counter_try_charge... Hit Ctrl-C to end.\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%-8s %-6s %-16s %-10s %-10s %-10s\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;TIME&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;PID&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;COMM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;REQUESTED&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CURRENT&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;LIMIT&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;nv&#34;&gt;@epoch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nsecs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;kprobe:page_counter_try_charge&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;$pcounter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page_counter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arg0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;nv&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pcounter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;$current&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pcounter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;$requested&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%-8d %-6d %-16s %-10ld %-10ld %-10ld\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nsecs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;@epoch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1000000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;nv&#34;&gt;$requested&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;nv&#34;&gt;$current&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;nv&#34;&gt;$limit&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running the tracer with a shell session put into the cgroup that limits our memory, we can see it running out of pages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;sudo bpftrace ./try-charge-counter.d
Attaching &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; probes...
Tracing page_counter_try_charge... Hit Ctrl-C to end.
TIME     PID     REQUESTED  CURRENT    LIMIT
...
&lt;span class=&#34;m&#34;&gt;3301&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1288&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3302&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1320&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
...
&lt;span class=&#34;m&#34;&gt;3307&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;2553&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3307&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;2554&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
                        .--------------------.
&lt;span class=&#34;m&#34;&gt;3307&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2554&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2555&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2555&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2556&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2556&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2557&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2557&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2558&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                        *----------.---------*
                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                                still possible
                                to increase the
                                number of pages 
                                   ...

&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;2558&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;2559&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;2559&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt; * LIMIT REACHED
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt; *
&lt;span class=&#34;m&#34;&gt;3308&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;25980&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2560&lt;/span&gt; *
                             &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                             *-----.----*
                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
   Whoopsy, can&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;t allocate  &amp;lt;------*
   anymore!


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Although I&amp;rsquo;ve understood that &lt;code&gt;meminfo&lt;/code&gt; wasn&amp;rsquo;t namespaced, it wasn&amp;rsquo;t clear for my why.&lt;/p&gt;
&lt;p&gt;Going through the exercise of tailoring a quick program to inspect the arguments passed to &lt;code&gt;page_counter_try_charge&lt;/code&gt; was very interesting (and easier than I thought!).&lt;/p&gt;
&lt;p&gt;Shout out to &lt;a href=&#34;https://github.com/iovisor/bpftrace&#34;&gt;bpftrace&lt;/a&gt; once again for allowing us to go deep into the Kernel with ease!&lt;/p&gt;
&lt;p&gt;If you have any further questions, or just want to connect, let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2zE5jOV&#34;&gt;The C Programming Language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
                                <pubDate>Fri, 12 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/why-top-inside-container-wrong-memory/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/why-top-inside-container-wrong-memory/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How is /proc able to list process IDs?</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Continuing with the &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;Month of /proc&lt;/a&gt;, today&amp;rsquo;s blog post is about how reading &lt;code&gt;/proc&lt;/code&gt; works (yep, the directory) .&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/ls-proc.svg&#34;
       alt=&#34;Illustration of what happens after ls is called &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Not only is this article&amp;rsquo;s content about &lt;code&gt;/proc&lt;/code&gt;, but also about reading directories in general (&lt;em&gt;expect syscalls and Kernel inspection&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been curious about how listing directory entries works under the hood, this is for you!&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;This is the second article in a series of 30 articles around &lt;em&gt;procfs&lt;/em&gt;: &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;A Month of /proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to keep up to date with it, make sure you &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#listing-directory-entries-in-linux&#34;&gt;Listing directory entries in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#opening-a-directory&#34;&gt;Opening a directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reading-directory-entries-from-userspace&#34;&gt;Reading directory entries from userspace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#under-the-hood-of-getdents&#34;&gt;Under the hood of getdents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#how-procfs-handles-getdents-calls&#34;&gt;How procfs handles getdents calls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#linux-and-its-pids&#34;&gt;Linux and its pids&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#how-procfs-lists-process-ids&#34;&gt;How procfs lists process IDs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;listing-directory-entries-in-linux&#34;&gt;Listing directory entries in Linux&lt;/h3&gt;
&lt;p&gt;Whenever you issue &lt;code&gt;ls&lt;/code&gt; in a Linux system, three things happen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/bin/ls&lt;/code&gt; (or the equivalent of it) is executed;&lt;/li&gt;
&lt;li&gt;the given directory is opened, and&lt;/li&gt;
&lt;li&gt;a syscall is issued to read the directory entries of such directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can discover all these three things by making use of &lt;a href=&#34;https://linux.die.net/man/1/strace&#34;&gt;&lt;code&gt;strace&lt;/code&gt;&lt;/a&gt;, a utility that allows us to trace the syscalls called by a given process:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a directory somewhere&lt;/span&gt;
mkdir /tmp/ciro

&lt;span class=&#34;c1&#34;&gt;# Run `strace` with the option of &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# tracing child processes as they are&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# created.&lt;/span&gt;
strace -f ls /tmp/ciro
execve&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/bin/ls&amp;#34;&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ls&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/tmp/ciro/&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;, 0x7ffd091bfe30 /* &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; vars */&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
...
        &lt;span class=&#34;c1&#34;&gt;# Open the file, passing some flags to it.&lt;/span&gt;
        openat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AT_FDCWD,     
                &lt;span class=&#34;s2&#34;&gt;&amp;#34;/tmp/ciro/&amp;#34;&lt;/span&gt;,
                O_RDONLY&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_NONBLOCK&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_CLOEXEC&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_DIRECTORY&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;# Read the directory entries.&lt;/span&gt;
        getdents&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3,             
                /* &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; entries */, 32768&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;48&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While &lt;code&gt;execve&lt;/code&gt; is interesting in it self, we&amp;rsquo;re not going to focus on it in this article - we can know just that it&amp;rsquo;s what executes the given program.&lt;/p&gt;
&lt;h3 id=&#34;opening-a-directory&#34;&gt;Opening a directory&lt;/h3&gt;
&lt;p&gt;The next syscall is &lt;code&gt;openat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This one is pretty much the same as &lt;code&gt;open(2)&lt;/code&gt;, which we covered in the last article (see &lt;a href=&#34;https://ops.tips/blog/what-is-slash-proc/#translating-a-file-read-to-an-internal-kernel-method&#34;&gt;What is /proc - section: Translating a file read to an internal kernel method&lt;/a&gt;), except that it has a special flag set: &lt;code&gt;O_DIRECTORY&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&#34;http://man7.org/linux/man-pages/man2/open.2.html&#34;&gt;man open&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;O_DIRECTORY&lt;/strong&gt;: If pathname is not a directory, cause the open to fail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is pretty much an optimization so that we can avoid an extra &lt;a href=&#34;http://man7.org/linux/man-pages/man2/stat.2.html&#34;&gt;&lt;code&gt;stat(2)&lt;/code&gt;&lt;/a&gt; just for checking if the file is a directory before doing any following directory operations.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about how that works, check out the following trace:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;do_last
path_openat
do_sys_open
sys_openat
do_syscall_64
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/namei.c#L3222&#34;&gt;&lt;code&gt;do_last&lt;/code&gt;&lt;/a&gt;, which finishes the file opening, performs the following check:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//                     .--&amp;gt; flag set if 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENOTDIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//   |    `O_DIRECTORY` is passed
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//                     |    to open(2)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//                     |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOOKUP_DIRECTORY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
        &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d_can_lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dentry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

        &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// ends up returning ENOTDIR
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;d like to know more about &lt;code&gt;open(2)&lt;/code&gt;, make sure you also the last article: &lt;a href=&#34;https://ops.tips/blog/what-is-slash-proc/&#34;&gt;what is &lt;code&gt;/proc&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There I cover how &lt;code&gt;open&lt;/code&gt; works under the hood when the Virtual Filesystem interacts with procfs.&lt;/p&gt;
&lt;p&gt;Another great resource is the book &lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;. It goes down to what the kernel does when opening a file too!&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;reading-directory-entries-from-userspace&#34;&gt;Reading directory entries from userspace&lt;/h3&gt;
&lt;p&gt;Now, once the directory has been opened, that is, in the Kernel we have a file description and in userspace we have the file descriptor, we can make use of the &lt;a href=&#34;http://man7.org/linux/man-pages/man2/getdents.2.html&#34;&gt;&lt;code&gt;getdents&lt;/code&gt;&lt;/a&gt; syscall.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The system call getdents() reads several linux_dirent structures from the directory referred to by the open file descriptor fd into the buffer pointed to by &lt;code&gt;dirp&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Something interesting about this one is that it&amp;rsquo;s not wrapped by &lt;code&gt;glibc&lt;/code&gt;, meaning that we need to call it via the &lt;code&gt;syscall(2)&lt;/code&gt; method ourselves.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I don&amp;rsquo;t really know why this syscall in specific is not wrapped! Do you? Please let me know! Reach at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Not being a &lt;code&gt;glibc&lt;/code&gt;-wrapped syscall, we need to call it directly with &lt;a href=&#34;http://man7.org/linux/man-pages/man2/syscall.2.html&#34;&gt;&lt;code&gt;syscall&lt;/code&gt;&lt;/a&gt;, providing the arguments that it expects and memory areas for the Kernel to fill (so we can retrieve the response).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how we can do it (check the comments!):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;linux/types.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/syscall.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// Total size that the buffer that we&amp;#39;ll allocate
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// in the stack can have.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define BUF_SIZE 1024
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// The directory we&amp;#39;ll end up reading.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_directory_path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/proc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Provide the structure that fits our current kernel structure
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * for directory entries (see linux#include/linux/dirent.h).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux_dirent64&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;           &lt;span class=&#34;n&#34;&gt;d_ino&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;cm&#34;&gt;/* 64-bit inode number */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;off_t&lt;/span&gt;          &lt;span class=&#34;n&#34;&gt;d_off&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;cm&#34;&gt;/* 64-bit offset to next structure */&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;d_reclen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Size of this dirent */&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;d_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;   &lt;span class=&#34;cm&#34;&gt;/* File type */&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;           &lt;span class=&#34;n&#34;&gt;d_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Filename (null-terminated) */&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Reads the directory entries from `/proc`.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * It does so using by using the non-wrapped syscall
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * getdents64 until it returns 0 entries.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// `buf` that holds a piece of allocated memory to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// be given to the Kernel to retrieve data.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Given that we&amp;#39;re initializing it with `BUF_SIZE`,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// this is allocating `BUFSIZE * 1` bytes in the stack.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// file descriptor to hold the open file (directory)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// number of directory entries that were read and put
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// in the buffer that we allocated in the stack.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directory_entries_read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// error code to exit.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Open the directory so that we&amp;#39;re able to let the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// kernel deal with the underlying file description.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_directory_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_RDONLY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_DIRECTORY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;open&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;c1&#34;&gt;// Call the `getdents64` syscall passing the buffer
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// to the kernel so that it can fill with directory
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// entries.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;directory_entries_read&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
		  &lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SYS_getdents64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;directory_entries_read&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;SYS_getdents64&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;directory_entries_read&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux_dirent64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Given that the Kernel filled our array of memory with
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// `N` entries (directory_entries_read), iterate over those
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// structs using the right offset.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;off&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;off&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directory_entries_read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux_dirent64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;off&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

			&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;entry: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;off&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d_reclen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Given that we&amp;#39;re done with reading
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// from the file, close it to free the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// underlying structures allocated for
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// it (and make further reads fail).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;IF you&amp;rsquo;re not very familiar with some of the Linux concepts presented above, a great book that covers that is &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve based some of the explanations from it!&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Having that, we&amp;rsquo;re able to read a directory with pure C.&lt;/p&gt;
&lt;p&gt;Given that the interface is the same for any filesystem, we can swap &lt;code&gt;/proc&lt;/code&gt; by &lt;code&gt;/something.txt&lt;/code&gt; and it should work the same way - if &lt;code&gt;/something.txt&lt;/code&gt; is a directory and we have the right permissions, done!&lt;/p&gt;
&lt;h3 id=&#34;under-the-hood-of-getdents&#34;&gt;Under the hood of getdents&lt;/h3&gt;
&lt;p&gt;With the knowledge of what happens at the userspace (&lt;a href=&#34;http://man7.org/linux/man-pages/man2/getdents.2.html&#34;&gt;&lt;code&gt;getdents&lt;/code&gt;&lt;/a&gt;), now it&amp;rsquo;s time to look at what happens under the hood - once &lt;code&gt;getdents&lt;/code&gt; crosses to kernelspace.&lt;/p&gt;
&lt;p&gt;Remembering that the filesystems need to implement the corresponding methods from &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.17/source/include/linux/fs.h#L1693&#34;&gt;&lt;code&gt;file_operations&lt;/code&gt;&lt;/a&gt; interface, we can guess that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;there is a method in such interface for listing directory entries, and&lt;/li&gt;
&lt;li&gt;such method gets called by &lt;code&gt;sys_getdents&lt;/code&gt; at some point.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first point can be confirmed by looking at the interface itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * file_operations describe an interface that
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * filesystems must implement in order to handle
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * calls from syscalls that interact with filesystems.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_operations&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llseek&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ssize_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ssize_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// The method for iterating over the directory
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// entries under a given directory.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dir_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// A method that is similar to `iterate` but allows
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// multiple calls to be performed simultaneously.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate_shared&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dir_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__randomize_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, regarding the second point (checking where in the &lt;code&gt;sys_getdents&lt;/code&gt; path one of those two methods gets called), we can look at the syscall implementation at &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.17/source/fs/readdir.c#L212&#34;&gt;&lt;code&gt;fs/readdir.c&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It first starts by verifying if the task can perform such call at &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/readdir.c#L212&#34;&gt;&lt;code&gt;sys_getdents&lt;/code&gt;&lt;/a&gt;, then it goes to &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/readdir.c#L26&#34;&gt;&lt;code&gt;iterate_dir&lt;/code&gt;&lt;/a&gt;, which is all about offloading the directory entries iteration to the implementor of the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.17/source/include/linux/fs.h#L1693&#34;&gt;&lt;code&gt;file_operations&lt;/code&gt;&lt;/a&gt; interface.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/getdents-under-the-hood.svg&#34;
        &gt;

    
&lt;/figure&gt;

&lt;p&gt;Looking at the at the actual Linux implementation, we can see how &lt;code&gt;iterate_dir&lt;/code&gt; makes use of the underlying filesystem implementation of &lt;code&gt;iterate_shared&lt;/code&gt; (&lt;code&gt;f-&amp;gt;f_op-&amp;gt;iterate_shared&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;iterate_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dir_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shared&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;res&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENOTDIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// making sure that either the iterate_shared or
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// iterate methods of the file_operations interface
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// are implemented
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_op&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate_shared&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;shared&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_op&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// is the directory really there?
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// if so, hand the file to the underlying
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// filesystem implementation and let it 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// iterate over the directory entries.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENOENT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;IS_DEADDIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pos&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_pos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// In either case, let the filesystem
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// implementation do it.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shared&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_op&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate_shared&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_op&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// update the reading offset
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// (&amp;#34;file pointer&amp;#34;)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_pos&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// notify that we accessed the file
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;fsnotify_access&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;file_accessed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;how-procfs-handles-getdents-calls&#34;&gt;How procfs handles getdents calls&lt;/h3&gt;
&lt;p&gt;Now, to know where is the implementation of either &lt;code&gt;iterate_shared&lt;/code&gt; or &lt;code&gt;iterate&lt;/code&gt; from &lt;code&gt;proc&lt;/code&gt;, we can go over to the procfs source code (at &lt;code&gt;fs/proc&lt;/code&gt;) and search for the method signature (&lt;code&gt;iterate&lt;/code&gt; or &lt;code&gt;iterate_shared&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ubuntu@bionic:~/linux/fs/proc$ ag iterate_shared
fd.c
269:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_readfd,
353:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_readfdinfo,

generic.c
306:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_readdir,

root.c
190:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_root_readdir,

proc_net.c
184:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_tgid_net_readdir,

base.c
2215:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_map_files_readdir,
2587:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_attr_dir_readdir,
3009:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_tgid_base_readdir,
3402:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_tid_base_readdir,
3612:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_task_readdir,

namespaces.c
143:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_ns_dir_readdir,

proc_sysctl.c
847:	.iterate_shared	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; proc_sys_readdir,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To filter that list out, we can make use of &lt;a href=&#34;https://github.com/iovisor/bcc/blob/master/tools/funccount.py&#34;&gt;&lt;code&gt;funccount&lt;/code&gt;&lt;/a&gt; from &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;&lt;code&gt;iovisor/bcc&lt;/code&gt;&lt;/a&gt; to check which of those methods get called whenever we issue a call to &lt;code&gt;getdents&lt;/code&gt; on &lt;code&gt;/proc&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;root@bionic:~# funccount &lt;span class=&#34;s1&#34;&gt;&amp;#39;proc_*readdir&amp;#39;&lt;/span&gt;
FUNC                                    COUNT
proc_readdir                                &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
proc_root_readdir                           &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
proc_pid_readdir                            &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having narrowed our scope, now we can learn about those three functions.&lt;/p&gt;
&lt;p&gt;From the naming, we can guess that &lt;code&gt;proc_root_readdir&lt;/code&gt; is responsible for being the first to respond to a request to list all directory entries from &lt;code&gt;/proc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Such affirmation can be confirmed by looking at the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/proc/root.c#L205&#34;&gt;&lt;code&gt;proc_dir_entry&lt;/code&gt;&lt;/a&gt; set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * This is the root &amp;#34;inode&amp;#34; in the /proc tree..
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_dir_entry&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_root&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;low_ino&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PROC_ROOT_INO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;namelen&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S_IFDIR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S_IRUGO&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S_IXUGO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nlink&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ATOMIC_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_iops&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_root_inode_operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 

        &lt;span class=&#34;c1&#34;&gt;// Sets the implementation of the `file_operations`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// interface to use.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_fops&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_root_operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subdir&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RB_ROOT_CACHED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/proc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;


&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * The root /proc directory is special, as it has the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * &amp;lt;pid&amp;gt; directories. Thus we don&amp;#39;t use the generic
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * directory handling functions for that..
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_operations&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_root_operations&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;		 &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;generic_read_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Sets the method for iterating over directory entries.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iterate_shared&lt;/span&gt;	 &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_root_readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llseek&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;generic_file_llseek&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Starts the process of listing the entries from
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `/proc`.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_root_readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dir_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Check if we&amp;#39;re still in the context of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// listing non-PID entries.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pos&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FIRST_PROCESS_ENTRY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unlikely&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pos&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FIRST_PROCESS_ENTRY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Having already read the non-pid directory
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// entries (like `/proc/meminfo`), now go 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// list the PIDs.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_pid_readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first part (listing non-pid directories) doesn&amp;rsquo;t reveal a lot for us - it goes through a list of directories that have registered via their corresponding directory entries structs.&lt;/p&gt;
&lt;p&gt;The second though (listing processes directories), is &lt;strong&gt;the thing&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Before we get there, we need to review the differences between how the Kernel looks at PIDs and threads compared to the userspace.&lt;/p&gt;
&lt;h3 id=&#34;linux-and-its-pids&#34;&gt;Linux and its pids&lt;/h3&gt;
&lt;p&gt;While in the userspace we&amp;rsquo;re accustomed to the term &lt;code&gt;pid&lt;/code&gt; (process identifier), it&amp;rsquo;s not the same thing for &lt;code&gt;tgid&lt;/code&gt; (thread group id).&lt;/p&gt;
&lt;p&gt;Whenever we create a process in userspace, a PID is received.&lt;/p&gt;
&lt;p&gt;Now, considering that this process creates a thread, we can see from userspace that this thread inherits such PID.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;USERSPACE:

         (pid=123)
        my_root_proc      .--&amp;gt; my_root_proc (pid=123)
           |              |
           *----&amp;gt; fork ---+
                          |
                          *-&amp;gt;  my_root_proc (pid=123)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When it comes to the kernel space though, a &lt;code&gt;pid&lt;/code&gt; refers to a single execution, so that those things now differ:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;KERNEL:

         (pid=123)
        my_root_proc      .--&amp;gt; my_root_proc (pid=123)
           |              |
           *----&amp;gt; fork ---+
                          |
                          *-&amp;gt;  my_root_proc (pid=124) 
                                (new pid!)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What unites them is the notion of a &lt;code&gt;tgid&lt;/code&gt; (thread group id). This is a property that gets inherited so that we can keep track of who initiated the whole three:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;KERNEL:

         (pid=123,tgid=123)
        my_root_proc      .--&amp;gt; my_root_proc (pid=123,tgid=123)
           |              |
           *----&amp;gt; fork ---+
                          |
                          *-&amp;gt;  my_root_proc (pid=124,tgid=123)
                                (new pid!)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With that in mind, let&amp;rsquo;s proceed.&lt;/p&gt;
&lt;h3 id=&#34;how-procfs-lists-process-ids&#34;&gt;How procfs lists process IDs&lt;/h3&gt;
&lt;p&gt;The whole implementation of process listing can be found at &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/proc/base.c#L3202&#34;&gt;&lt;code&gt;proc_pid_readdir&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * For the /proc/ directory itself, 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * after non-process stuff has been done.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_pid_readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dir_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Given that calls to `/proc`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// are namespaced (check out `ls /proc`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// from within a docker container),
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// we start by grabbing the PID namespace
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// of the current task executing the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// getdents call.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid_namespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_inode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_sb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s_fs_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ... do some checks ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Iterate over all thread group ids 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// (`tgid`s), capturing the task struct
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// associated with them.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next_tgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	     &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	     &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next_tgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PROC_NUMBUF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
		&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

		&lt;span class=&#34;n&#34;&gt;cond_resched&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;has_pid_permissions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HIDEPID_INVISIBLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// convert the tgid to a string that we can
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// return in the dir entries
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;snprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pos&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TGID_OFFSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_fill_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				     &lt;span class=&#34;n&#34;&gt;proc_pid_instantiate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;put_task_struct&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pos&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PID_MAX_LIMIT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TGID_OFFSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re curious about how the kernel is able to fill that &lt;code&gt;struct task&lt;/code&gt; that &lt;code&gt;next_tgid&lt;/code&gt; gets, then make sure you stick with the &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;Month of proc&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;In the next articles we go further into what information we can grab from such tasks.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Having never wrapped a syscall using &lt;code&gt;C&lt;/code&gt; before, it was a great exercise to learn how that&amp;rsquo;s done.&lt;/p&gt;
&lt;p&gt;I had never really given attention to how a process can list contents from a given directory - it was pretty clear for me that it involved opening a file and then issuing a certain syscall, but really learning what happens under the hood was amazing.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like also to point out how helpful &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;bcc&lt;/a&gt; and &lt;a href=&#34;https://github.com/iovisor/bpftrace&#34;&gt;bpftrace&lt;/a&gt; are for learning about how Linux works internally. Kudos for everyone involved!&lt;/p&gt;
&lt;p&gt;If you have any further questions or would like to drop a comment, let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
                                <pubDate>Thu, 11 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/how-is-proc-able-to-list-pids/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/how-is-proc-able-to-list-pids/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>What is /proc?</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Although many people that are accustomed to Linux are aware of the existence of &lt;code&gt;/proc&lt;/code&gt; and what some files over there can do, many lack the understanding of what goes behind the scenes to power such filesystem (myself included before writing this article).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been wondering about how &lt;code&gt;/proc&lt;/code&gt; works under the hood, stay tuned!&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;This is the first article in a series of 30 articles around &lt;em&gt;procfs&lt;/em&gt;: &lt;a href=&#34;https://ops.tips/blog/a-month-of-proc/&#34;&gt;A Month of /proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to keep up to date with it, make sure you &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#what-is-procfs&#34;&gt;What is procfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#contrasting-procfs-with-a-regular-filesystem&#34;&gt;Contrasting Procfs with a regular filesystem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reading-from-and-writing-to-procfs&#34;&gt;Reading from and writing to procfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#translating-a-file-read-to-an-internal-kernel-method&#34;&gt;Translating a file read to an internal kernel method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#getting-proc-in-your-tree&#34;&gt;Getting &lt;code&gt;/proc&lt;/code&gt; in your tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#procfs-after-vfs&#34;&gt;Procfs after VFS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;what-is-procfs&#34;&gt;What is procfs&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.kernel.org/doc/Documentation/filesystems/proc.txt&#34;&gt;&lt;code&gt;Procfs&lt;/code&gt;&lt;/a&gt; is a special virtual filesystem that can be mounted in your directory tree, allowing processes in userspace to read kernel information conveniently - using regular file I/O operations (like &lt;code&gt;read(2)&lt;/code&gt; and &lt;code&gt;write(2)&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;           process 123: how many files do proc321
                  |          has open?
                  | 
(userspace)       *---&amp;gt; ls /proc/321/fd
                         \----+------/
                              |    ^
------------------------------|----|------------
                              |    |
                      .---&amp;lt;---*    |
                      |            |
                     kernel        *-----------&amp;lt;------. 
(kernelspace)         |                               |
                      *--&amp;gt; list number of open file   |
                           descriptors for proc `321` |
                           in the root namespace      |
                                 |                    |
                                 *------------&amp;gt;-------&#39;
                                     there you go! 
                                        
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &amp;ldquo;virtual&amp;rdquo; comes from the fact that there&amp;rsquo;s not really a block device (like a solid-state drive - SSD) that serves the files that we can access under the place where you mount &lt;code&gt;procfs&lt;/code&gt; (usually &lt;code&gt;/proc&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Instead, there&amp;rsquo;s just some code implementing the filesystem interface that gets called whenever you issue reads and writes against those particular locations.&lt;/p&gt;
&lt;p&gt;For instance, when a user asks for the limits that apply to a given process, the following path gets followed under the hood:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        cat /proc/13323/limits

                
(userspace)     fd = open(&amp;quot;/proc/13323/limits&amp;quot;)
                n = read(fd, buf, bufsize)
                     |
---------------------|--------------
                    vfs (common interface for interacting with
                     |   any filesystem)
                     |
                     *-&amp;gt; who&#39;s responsible for this `/proc`
                         mount?
                         procfs! let it handle the call.
                          |
                          |
(kernelspace)             *-&amp;gt; hey procfs, take this `read` call
                              for `/proc/13323/limits` please!
                                 |
                   sure! &amp;lt;-------*
                   I&#39;ll write the response
                   to the file.
                     |
                     *---&amp;gt; linux/fs/proc/base.c#proc_pid_limits
                           for limit := range limits {
                                fprintf(file, limit)
                           }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using a tracer like &lt;a href=&#34;https://github.com/iovisor/bcc/blob/master/tools/trace.py&#34;&gt;bcc&amp;rsquo;s trace.py&lt;/a&gt;, we can see the kernel stack getting the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/fs/proc/base.c#L573&#34;&gt;&lt;code&gt;proc_pid_limit&lt;/code&gt;&lt;/a&gt; command getting called:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;PID     TID     COMM            FUNC
&lt;span class=&#34;m&#34;&gt;21450&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;21450&lt;/span&gt;   cat             proc_pid_limits
        proc_pid_limits+0x1 
        seq_read+0xe5 
        __vfs_read+0x1b 
        vfs_read+0x8e 
        sys_read+0x55 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;contrasting-procfs-with-a-regular-filesystem&#34;&gt;Contrasting Procfs with a regular filesystem&lt;/h3&gt;
&lt;p&gt;A nice way of viewing the difference between the two is looking at how does the kernel path compare.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say we have a file &lt;code&gt;/myfile.txt&lt;/code&gt; that lives on a disk that makes use of &lt;a href=&#34;https://ext4.wiki.kernel.org/index.php/Main_Page&#34;&gt;EXT4&lt;/a&gt; as a filesystem.&lt;/p&gt;
&lt;p&gt;If we were to read this file (making that that it&amp;rsquo;s not cached), this is how it&amp;rsquo;d look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        cat /myfile.txt

                
(userspace)     fd = open(&amp;quot;/myfile.txt&amp;quot;)
                n = read(fd, buf, bufsize)
                     |
---------------------|--------------
                    vfs (common interface for interacting with
                     |   any filesystem)
                     |
                     *-&amp;gt; who&#39;s responsible for this `/` mount?
                         ext4! let it handle the call.
                          |
                          |
(kernelspace)             *-&amp;gt; hey ext4, take this `read` call
                              for `/myfile.txt` please!
                                 |
                   sure! &amp;lt;-------*
                   Oh, I know that this file exists in the disk!
                   Let me request the underlying block device driver
                   for it.
                     |
                     *---&amp;gt; hey whoever is in charge of /dev/sda1, 
                        please hand me the contents of my file!
                                |
          Oh, this is not ------*
          in my cache; let me ask the disk for what
          is in the blocks where this file exists.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that in the case of the regular file, the &lt;code&gt;read(2)&lt;/code&gt; call ends up getting down to the block device driver that issues the read against a real device.&lt;/p&gt;
&lt;p&gt;Using the same tracer that we used before, we can check that, differently from when &lt;code&gt;read&lt;/code&gt;ing from &lt;code&gt;/proc&lt;/code&gt;, at this time, the path is much longer (goes deep down to the actual &lt;code&gt;blk_*&lt;/code&gt; methods that handle block devices):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Drop the caches so that the call ends up in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a very low-level call to the block device &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# driver.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt; &amp;gt; /proc/sys/vm/drop_caches

&lt;span class=&#34;c1&#34;&gt;# Perform a read&lt;/span&gt;
cat ./myfile.txt

&lt;span class=&#34;c1&#34;&gt;# See the trace results:&lt;/span&gt;
PID     TID     COMM            FUNC
&lt;span class=&#34;m&#34;&gt;28653&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;28653&lt;/span&gt;   cat             blk_start_request
        blk_start_request+0x1 
        scsi_request_fn+0xf5 
        __blk_run_queue+0x43 
        queue_unplugged+0x2a 
        blk_flush_plug_list+0x20a 
        blk_finish_plug+0x2c 
        __do_page_cache_readahead+0x1da 
        ondemand_readahead+0x11a 
        page_cache_sync_readahead+0x2e 
        generic_file_read_iter+0x7fb 
        ext4_file_read_iter+0x56 
        new_sync_read+0xe4 
        __vfs_read+0x29 
        vfs_read+0x8e 
        sys_read+0x55 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although they look very different after &lt;code&gt;vfs_read&lt;/code&gt;, everything feels the same for those consuming the &lt;code&gt;vfs&lt;/code&gt; interface.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;d like to refresh some concepts around Linux in general (including filesystems), I recommend reading &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt; (chapter 12 covers &lt;code&gt;/proc&lt;/code&gt; a bit, and chapter 14 is about filesystems!)&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;reading-from-and-writing-to-procfs&#34;&gt;Reading from and writing to procfs&lt;/h3&gt;
&lt;p&gt;Not only being able to give you some introspection into what is the current state of a given process or the system as a while, &lt;code&gt;/proc&lt;/code&gt; is also able to let you modify some of the behaviors of the system.&lt;/p&gt;
&lt;p&gt;For instance, in the example above, we dropped the caches by performing a &lt;code&gt;write(2)&lt;/code&gt; operation against &lt;code&gt;/proc/sys/vm/drop_caches&lt;/code&gt; from the userspace.&lt;/p&gt;
&lt;p&gt;To summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;when it comes to &lt;code&gt;read(2)&lt;/code&gt; operations, it can be seen as an interface to introspect kernel data structures associated with either the whole system or a particular process; and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;when it comes to &lt;code&gt;write(2)&lt;/code&gt;, it can be used to change some kernel parameters at runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;translating-a-file-read-to-an-internal-kernel-method&#34;&gt;Translating a file read to an internal kernel method&lt;/h3&gt;
&lt;p&gt;Coming back to the interaction between user space and kernel space, you might&amp;rsquo;ve noticed in the previous sections that there was a common thing sitting between the EXT4 filesystem and procfs: the virtual filesystem (&lt;code&gt;vfs&lt;/code&gt;).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/vfs-abstraction.svg&#34;
       alt=&#34;illustration of read being directed to ext4 or procfs via vfs &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;By having this layer that sits between any syscall related to a filesystem, &lt;code&gt;vfs&lt;/code&gt; is able to present a consistent API while letting different implementations to provide their functionality behind the scenes. No need for user programs to know about what&amp;rsquo;s the filesystem under the hood.&lt;/p&gt;
&lt;p&gt;The way that the Kernel does this translation is pretty nifty.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an overview of how a &lt;code&gt;read(2)&lt;/code&gt; from userspace gets down to a filesystem-specific implementation of a read:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; open&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt;, flags&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;fd, buf, bufsize&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
 ----------+-------------------------- &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;userspace boundary&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
  .-------*
  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
  *-&amp;gt; ksys_read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;fd, buf, bufsize&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                        .--&amp;gt; performs a file lookup,
         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    gathering file information
         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    from a given file descriptor &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;per-process&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    to get a file description &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;system-wide&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
         *-&amp;gt; struct fd &lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; fdget_pos&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;fd&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 
             vfs_read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;f.file, buf, bufsize&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; -&amp;gt; performs the actual
                       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                     &lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt; utilizing the info
                       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                   from the file gathered before.
             .---------*
             &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                   
             *-&amp;gt; f.file contains a pointer to a &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;file_operations&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; struct,
                which can be thought as an interface that specifies file
                operations like &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;, &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;write&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;, etc
                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                *--&amp;gt; depending on the mount, a specific implementation of
                     such interface is referenced there.
                     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                     *--&amp;gt; f.file-&amp;gt;f_op-&amp;gt;read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
                                   ^     ^
                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     *-- implementation
                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      
                                interface
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Whenever a file is opened, the userspace program receives a reference to the open file - the &amp;ldquo;file descriptor&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;For instance, in the following program, a file descriptor is retrieved after openning the file , being printed to &lt;code&gt;stdout&lt;/code&gt; and then closed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// Compile with `gcc -Wall ./main.c
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ps.: assumes `/tmp/file.txt` has been created before.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/tmp/file.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;open&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// result: fd=3
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fd=%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file descriptor points to an &lt;em&gt;open file description&lt;/em&gt;, a system-wide entry that is the thing in the kernel that contains the implementation of the &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.18/source/include/linux/fs.h#L1693&#34;&gt;file operations interface&lt;/a&gt; depending on the file system that such file resides (see &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.14/source/include/linux/fs.h#L852&#34;&gt;&lt;code&gt;struct file&lt;/code&gt; in &lt;code&gt;include/linux/fs.h&lt;/code&gt;&lt;/a&gt;), as well as keeping track of other details.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * The file description that gets created when an
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `open(2)` is called from userspace.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// f_count keep track of the number of references
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// being hold for this file.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;atomic_long_t&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;f_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// f_pos records the current file offset
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// (a.k.a. file pointer)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;f_pos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 


        &lt;span class=&#34;c1&#34;&gt;// f_op contains a pointer to an implementation
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// of the `file_operations` interface - a file
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// operation table.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_operations&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f_op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ... many more
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Interface for vfs to interfact with.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * This is meant to be implemented by the filesystems
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * so that VFS can transparentely interact with them.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_operations&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llseek&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ssize_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ssize_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loff_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ssize_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read_iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kiocb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iov_iter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ssize_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write_iter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kiocb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iov_iter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__randomize_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To see that a file description (&lt;code&gt;struct file&lt;/code&gt;) gets created when an &lt;code&gt;open&lt;/code&gt; (or &lt;code&gt;openat&lt;/code&gt;) is issued, we can trace &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.14/source/fs/file_table.c#L104&#34;&gt;&lt;code&gt;get_empty_filp&lt;/code&gt;&lt;/a&gt;, the function that gets called to allocate a new object.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;m&#34;&gt;32648&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;32648&lt;/span&gt;   a.out           get_empty_filp
        get_empty_filp+0x1      &lt;span class=&#34;c1&#34;&gt;# finds an unused file structure &lt;/span&gt;
                                &lt;span class=&#34;c1&#34;&gt;# and returns a pointer to it&lt;/span&gt;
        do_filp_open+0x9b 
        do_sys_open+0x1bb 
        sys_openat+0x14 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After retrieving a file object, it then starts initializing the struct, filling the fields as they need.&lt;/p&gt;
&lt;p&gt;Given that at this moment the kernel has already loaded the &lt;code&gt;inode&lt;/code&gt; related to this file into memory, and knowing that the &lt;code&gt;inode&lt;/code&gt; holds the pointer to the implementation of the &lt;code&gt;file_operations&lt;/code&gt; interface for the underlying filesystem, &lt;code&gt;vfs&lt;/code&gt; is then able to set the file operations accordingly, such that whenever a further file operations come, it just follows the pointers: &lt;code&gt;f.file-&amp;gt;f_op-&amp;gt;read(...)&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/kernel-open-and-read.svg&#34;
       alt=&#34;Representation of what goes behind the scenes when openning and reading a file in Linux &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Now, if that file lived under an &lt;code&gt;xfs&lt;/code&gt; filesystem, pretty much the same would happen, except that the inode would be loaded for &lt;code&gt;xfs&lt;/code&gt;, which would have &lt;code&gt;xfs&lt;/code&gt; file operations, which would then be called when reading through &lt;code&gt;f.file-&amp;gt;f_op-&amp;gt;read&lt;/code&gt; (&lt;code&gt;read&lt;/code&gt; would now be an &lt;code&gt;xfs&lt;/code&gt; read).&lt;/p&gt;
&lt;p&gt;In the case of &lt;code&gt;procfs&lt;/code&gt;, &lt;code&gt;f.file-&amp;gt;f_op-&amp;gt;read&lt;/code&gt; is a &lt;code&gt;procfs&lt;/code&gt; read.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;d like to know more about this area, make sure you get a copy of &lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;. You can get more insights into VFS from the chapter 12 (The Virtual Filesystem).&lt;/p&gt;
&lt;p&gt;Tip: To look around the Linux source code, check the &lt;a href=&#34;https://elixir.bootlin.com/linux/latest/source&#34;&gt;Elixir Cross Referencer&lt;/a&gt;. It allows you to search references and find definitions around the code base across different Linux releases.  Check out how &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.15.16/source/fs/open.c&#34;&gt;&lt;code&gt;linux#fs/open.c&lt;/code&gt;&lt;/a&gt; looks like.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;getting-proc-in-your-tree&#34;&gt;Getting &lt;code&gt;/proc&lt;/code&gt; in your tree&lt;/h3&gt;
&lt;p&gt;Although in most modern Linux distributions &lt;code&gt;procfs&lt;/code&gt; is probably already mounted under &lt;code&gt;/proc&lt;/code&gt;, it&amp;rsquo;s possible that it is not.&lt;/p&gt;
&lt;p&gt;In such case, mounting it requires only the necessary privileges and executing &lt;code&gt;mount&lt;/code&gt; with the right type (&lt;code&gt;proc&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Mount the `proc` device under `/proc`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with the filesystem type specified as&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `proc`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# note.: you could mount procfs pretty much&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        anywhere you want and specify any&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        device name.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         .------------&amp;gt; fs type&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |    &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |     .------&amp;gt; device (dummy identifier&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |    |         in this case - anything)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |    |&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |    |     .-&amp;gt; location&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |    |     |&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#         |    |     |&lt;/span&gt;
mount -t proc proc /proc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the mount point is there, we can now access it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Search for the `meminfo` file in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# procfs mountpoint&lt;/span&gt;
ls /proc &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep meminfo
meminfo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;d like to know more about mounting things in a directory tree, make sure you check out &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a &lt;strong&gt;great&lt;/strong&gt; book to have - I&amp;rsquo;m always consulting it from time to time.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;procfs-after-vfs&#34;&gt;Procfs after VFS&lt;/h3&gt;
&lt;p&gt;Once we got our &lt;code&gt;/proc&lt;/code&gt; mountpoint set up, we can start looking at what happens once we start interacting with it.&lt;/p&gt;
&lt;p&gt;After understanding the functionality of &lt;code&gt;vfs&lt;/code&gt; (and how it can trigger the specific &lt;code&gt;read&lt;/code&gt; of a given filesystem by following the &lt;code&gt;file-&amp;gt;f_op-&amp;gt;read&lt;/code&gt; pointers), it&amp;rsquo;s a matter of looking at how the file operations implementation of &lt;code&gt;procfs&lt;/code&gt; looks like.&lt;/p&gt;
&lt;p&gt;Differently from a regular filesystem (like &lt;code&gt;ext4&lt;/code&gt;), &lt;code&gt;procfs&lt;/code&gt; needs to set different handlers for different files, given that each file ends up in the execution of a different method in the kernel.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/procfs-file-operations.svg&#34;
       alt=&#34;Illustration of different procfs methods being used depending on the path accessed &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Taking the example of reading from &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt; (from the beginning of the article) and a different file, like &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/wchan&lt;/code&gt;, we can see how they differ:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gu&#34;&gt;@@ -1,4 +1,4 @@
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;-        proc_pid_limits+0x1 [kernel]
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+        proc_pid_wchan+0x1 [kernel]
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        seq_read+0xe5 [kernel]
        __vfs_read+0x1b [kernel]
        vfs_read+0x8e [kernel]
        sys_read+0x55 [kernel]
        do_syscall_64+0x73 [kernel]
        entry_SYSCALL_64_after_hwframe+0x3d [kernel]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, what happens inside &lt;code&gt;proc_pid_limits&lt;/code&gt;, or what &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt; is all about &amp;hellip; that&amp;rsquo;s something for another article!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s very interesting how flexible VFS ends up being.&lt;/p&gt;
&lt;p&gt;The way that it presents a consistent interface for applications, letting different filesystem implementions deal with adapting themselves to such interface is pretty interesting.&lt;/p&gt;
&lt;p&gt;Coming from a Golang background, I found pretty neat the way that the concept of an interface is applied in this Kernel code (which is all in C, as you might&amp;rsquo;ve noticed).&lt;/p&gt;
&lt;p&gt;In the following articles I&amp;rsquo;ll go on with exploring some files under &lt;code&gt;/proc&lt;/code&gt;, getting deep down into what are those methods doing, so, stay tuned!&lt;/p&gt;
&lt;p&gt;If you have any questions or would like to drop some feedback for me, feel free to reach me on Twitter! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; over there.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;p&gt;Aside from regular &lt;code&gt;man&lt;/code&gt; pages, two books were referenced in the article (and used during the research):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;: Ch. 12 covering &lt;code&gt;/proc&lt;/code&gt;, and Ch. 14 on Filesystems; and&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QD0kU4&#34;&gt;Understanding the Linux Kernel, 3rd Ed&lt;/a&gt;. Ch 12 on VFS (The Virtual Filesystem).&lt;/li&gt;
&lt;/ul&gt;
</description>
                                <pubDate>Wed, 10 Oct 2018 10:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/what-is-slash-proc/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/what-is-slash-proc/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>A month of /proc</title>
                                <description>&lt;p&gt;Hey!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been wanting to better understand what are some of the capabilities of &lt;a href=&#34;https://www.kernel.org/doc/Documentation/filesystems/proc.txt&#34;&gt;procfs (&lt;code&gt;/proc&lt;/code&gt;)&lt;/a&gt;, so I thought of a little challenge for me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for each day, &lt;strong&gt;for 30 days&lt;/strong&gt;, I&amp;rsquo;ll be posting a new article about a single file under &lt;code&gt;/proc&lt;/code&gt; that should be useful for someone either introspecting a system (or wanting to mutate some kernel param).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given that &lt;em&gt;so many&lt;/em&gt; tools touch the &lt;code&gt;/proc&lt;/code&gt; mountpoint to gather information, and that it&amp;rsquo;s such a great place to learn more about where you can look for the reasons why a given process or the entire system is malfunctioning, I bet this it going to be great for many of the readers.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;d like to go along with me in such journey, &lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;join the mailing list&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Differently from the many other articles around the web covering &lt;code&gt;/proc&lt;/code&gt;, the focus of this series is more on the details and internals of each call.&lt;/p&gt;
&lt;p&gt;For instance, the plan is not only to cover questions like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/fd&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But to include answers to questions like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I call &lt;code&gt;ls /proc/&amp;lt;pid&amp;gt;/fd&lt;/code&gt;, what happens under the hood?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I still don&amp;rsquo;t have a full list of which files I&amp;rsquo;ll be touching (and in what order), so, please, let me know if you&amp;rsquo;d like me to cover a specific one!&lt;/p&gt;
&lt;p&gt;This article will be updated whenever a new post comes out, so feel free to keep track of this one.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;h3 id=&#34;the-articles-so-far&#34;&gt;The articles so far&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://ops.tips/blog/what-is-slash-proc&#34;&gt;&lt;strong&gt;What is /proc?&lt;/strong&gt;&lt;/a&gt; - as the first article in the series, this one focuses on the fundamentals around &lt;a href=&#34;https://www.kernel.org/doc/Documentation/filesystems/proc.txt&#34;&gt;&lt;code&gt;procfs&lt;/code&gt;&lt;/a&gt;, the underlying implementation that responds to calls to &lt;code&gt;/proc&lt;/code&gt;, as well as &lt;a href=&#34;https://www.kernel.org/doc/Documentation/filesystems/vfs.txt&#34;&gt;&lt;code&gt;vfs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://ops.tips/blog/how-is-proc-able-to-list-pids&#34;&gt;&lt;strong&gt;How is /proc able to list process IDs?&lt;/strong&gt;&lt;/a&gt; - given that directories are files, the first file I wanted to look for was the root directory of &lt;code&gt;/proc&lt;/code&gt;. In this article, I go through how listing directories work in Linux and at which point procfs takes care of searching for PIDs and returning them as directory entries for the user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://ops.tips/blog/why-top-inside-container-wrong-memory/&#34;&gt;&lt;strong&gt;Why top and free inside containers don&amp;rsquo;t show the correct container memory?&lt;/strong&gt;&lt;/a&gt; - this one covers some of the underlying aspects of how containers limits resources (tip: &lt;code&gt;cgroups&lt;/code&gt;!) and why is the retrieval of memory information uncontained. If you&amp;rsquo;re into k8s and Docker, check this one out!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://ops.tips/blog/proc-pid-limits-under-the-hood&#34;&gt;&lt;strong&gt;Process limits under the hood&lt;/strong&gt;&lt;/a&gt; - go through the internals of implementing a &lt;code&gt;ulimit&lt;/code&gt; utility in C, inspecting how the Kernel limits the number of open files for a given process and then finally seeing how &lt;code&gt;/proc/pid/limits&lt;/code&gt; works. Expect some tracing and a bunch of Kernel methods exposed!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://ops.tips/blog/using-procfs-to-get-process-stack-trace&#34;&gt;&lt;strong&gt;Using /proc to get a process&#39; current stack trace&lt;/strong&gt;&lt;/a&gt; - go through the process of creating a simple TCP server that blocks, and then using &lt;code&gt;/proc&lt;/code&gt; to identify the stack trace of the method that led the kernel to block at a given syscall. In this post we also look at how that C stack compares to one generated by the Go runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://ops.tips/blog/how-linux-creates-sockets/&#34;&gt;&lt;strong&gt;How Linux creates sockets and counts them&lt;/strong&gt;&lt;/a&gt; - a deep dive into how the Linux kernel creates a Socket under the hood, and how it keeps track of the number of sockets that it has allocated.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;Would you like to keep up with the articles?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://google.us3.list-manage.com/subscribe/post?u=1941019739d6aa1a25eda3787&amp;amp;id=ff9c3cc11e&#34;&gt;&lt;strong&gt;Click here&lt;/strong&gt;&lt;/a&gt; to signup for the newsletter!&lt;/p&gt;

&lt;/div&gt;

</description>
                                <pubDate>Wed, 10 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/a-month-of-proc/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/a-month-of-proc/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>A bpftrace Ansible role</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Today I spotted something &lt;strong&gt;very&lt;/strong&gt; interesting in my Twitter (I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; there, by the way):&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;To learn bpftrace, there is a reference guide and one-liners tutorial: &lt;a href=&#34;https://t.co/EztuxTK9iJ&#34;&gt;https://t.co/EztuxTK9iJ&lt;/a&gt; &lt;a href=&#34;https://t.co/foCH2TUCpv&#34;&gt;https://t.co/foCH2TUCpv&lt;/a&gt;&lt;/p&gt;&amp;mdash; Brendan Gregg (@brendangregg) &lt;a href=&#34;https://twitter.com/brendangregg/status/1049319776743387136?ref_src=twsrc%5Etfw&#34;&gt;October 8, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;p&gt;That&amp;rsquo;s right, &lt;a href=&#34;http://dtrace.org/guide/preface.html&#34;&gt;dtrace&lt;/a&gt; functionality for Linux via eBPF &amp;ldquo;superpowers&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;To be very honest, I know almost nothing about &lt;code&gt;dtrace&lt;/code&gt; itself, but I&amp;rsquo;ve heard about it many times - it brings to the operator a framework that allows he/she to observe what&amp;rsquo;s going on throughout the stack: be it in the user space, or the kernel space.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be taking a deeper look at it soon, but meanwhile, &lt;a href=&#34;https://github.com/iovisor/bpftrace&#34;&gt;&lt;code&gt;bpftrace&lt;/code&gt;&lt;/a&gt; is out there, and you can check it out right now!&lt;/p&gt;
&lt;p&gt;In this quick post, you can check a sample &lt;a href=&#34;https://docs.ansible.com/ansible/latest/index.html&#34;&gt;Ansible&lt;/a&gt; that&amp;rsquo;s able to install the dependencies of &lt;code&gt;bpftrace&lt;/code&gt; as well as build and install it.&lt;/p&gt;
&lt;h3 id=&#34;the-bpftrace-ansible-role&#34;&gt;The bpftrace ansible role&lt;/h3&gt;
&lt;p&gt;The role is pretty much a follow up of the &lt;a href=&#34;https://github.com/iovisor/bpftrace/blob/master/INSTALL.md&#34;&gt;INSTALL guide&lt;/a&gt; from &lt;code&gt;bpftrace&lt;/code&gt;, targetting at an Ubuntu Bionic (18.04) installation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;add llvm apt key&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;https://apt.llvm.org/llvm-snapshot.gpg.key&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;add llvm apt repo&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt_repository&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-6.0 main&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;update_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;install bpftrace dependencies&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;update_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;cache_valid_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3600&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ item }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with_items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;bison&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;clang-6.0&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;clang-6.0-doc&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;clang-tools-6.0&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;cmake&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;flex&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;g++&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;git&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;libclang-6.0-dev&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;libclang-common-6.0-dev&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;libclang1-6.0&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;libelf-dev&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;libfl-dev&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;libllvm6.0&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;llvm-6.0&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;llvm-6.0-dev&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;llvm-6.0-runtime&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;zlib1g-dev&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;clone bpftrace repository&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;https://github.com/iovisor/bpftrace&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/bpftrace&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;force&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;create build directory&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/bpftrace/build&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;directory&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0755&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prepare makefile&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;cmake -DCMAKE_BUILD_TYPE=DEBUG ..&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;chdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/bpftrace/build&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;build&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;make -j3&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;chdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/bpftrace/build&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;install&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;make -j3&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;chdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/bpftrace/build&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run it against your machine (with privileges) and you should be good to go!&lt;/p&gt;
&lt;p&gt;You can find related roles (like one for installing &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;&lt;code&gt;bcc&lt;/code&gt;&lt;/a&gt;) here: &lt;a href=&#34;https://github.com/cirocosta/mylinux&#34;&gt;github.com/cirocosta/mylinux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please let me know if you need any help! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Mon, 08 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/a-bpftrace-ansible-role/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/a-bpftrace-ansible-role/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Article recommendation using Hugo</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;This month I&amp;rsquo;ve been interested in increasing the overall time that a user spends navigating here in the blog.&lt;/p&gt;
&lt;p&gt;Being article recommendation something that the blog was missing, I went for it.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/recommended-articles.svg&#34;
       alt=&#34;Article recommendation in use &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Check out how you can do it for your static site too!&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-idea&#34;&gt;The idea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#implementing-a-recommended-articles-list-in-hugo&#34;&gt;Implementing a Recommended Articles list in Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#displaying-the-recommendation-list&#34;&gt;Displaying the recommendation list&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;the-idea&#34;&gt;The idea&lt;/h3&gt;
&lt;p&gt;Given that my content usually is tagged, I thought that one easy way of adding article recommendation would be to simply take the union between the articles tagged with the same tag as the current one and then randomly list them.&lt;/p&gt;
&lt;p&gt;For instance, consider the case of this article: &lt;a href=&#34;https://ops.tips/blog/udp-client-and-server-in-go/&#34;&gt;A UDP server and client in Go&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Being the article tagged as &lt;a href=&#34;https://ops.tips/tags/linux&#34;&gt;Linux&lt;/a&gt;, &lt;a href=&#34;https://ops.tips/tags/networking&#34;&gt;Networking&lt;/a&gt;, and &lt;a href=&#34;https://ops.tips/tags/go&#34;&gt;Go&lt;/a&gt;, we can infer that there are three pools of content that might be similar to what&amp;rsquo;s been there in this article (having some overlap between them).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/recommendation-overlap.svg&#34;
       alt=&#34;Overlap between bag of articles by selecting articles with tags matching &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Moving forward, we can think that once we addressed the possible articles to recommend, the next step is to give preference to some of them: rank higher those with more overlap in more categories.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s implement that then.&lt;/p&gt;
&lt;h3 id=&#34;implementing-a-recommended-articles-list-in-hugo&#34;&gt;Implementing a Recommended Articles list in Hugo&lt;/h3&gt;
&lt;p&gt;As a first step, we retrive all the pages that are not the currently page that we are seeing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Assign the current scope (the current page) to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// a variable named `$currentArticle` so that within
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// other scopes we are able to still reference the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// current page.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$currentArticle&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// From the list of all pages from the site, only keep
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// those whose name is different from the name of the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// current article and whose kind is `page`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ps.: here we could check something else, like permalink
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// or another unique identifier.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ps.: here you&amp;#39;d probably pick a specific section. To do
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// so, perform another `where`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$articles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;where&lt;/span&gt; 
        &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;where&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Site&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Pages&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;.Kind&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;eq&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;page&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 
        &lt;span class=&#34;s&#34;&gt;&amp;#34;.Title&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;!=&amp;#34;&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$currentArticle&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;note.: the &lt;code&gt;where&lt;/code&gt; above &lt;strong&gt;must&lt;/strong&gt; be inlined. Here I broke it in multiple lines just for achieving better readability.&lt;/p&gt;
&lt;p&gt;Next, we now create two lists:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;one that references all articles with &lt;strong&gt;at least two&lt;/strong&gt; tags that are in the set of tags in the current article; and&lt;/li&gt;
&lt;li&gt;a list that references all articles with &lt;strong&gt;a single&lt;/strong&gt; tag in the set of tags of the current article.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can call these two &lt;code&gt;veryRelevantArticles&lt;/code&gt; and &lt;code&gt;relevantArticles&lt;/code&gt; (accordingly):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Instantiate each of them with an empty slice.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slice&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$relevantArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slice&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the variables set, we can now start iterating over our list of all article pages and checking how many intersections they have with the set of tags from our current page:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Iterate over each of the articles from the list 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// of article pages
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$idx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$article&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$articles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Compute the number of tag intersactions.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$numberOfIntersections&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;intersect&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$article&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$currentArticle&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Tags&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// For those pages with a big number of 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// intersections (&amp;gt;= 2), put in the first
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// slice.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ge&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$numberOfIntersections&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
                &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;=&lt;/span&gt; 
                        &lt;span class=&#34;nc&#34;&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;append&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$article&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// For the rest (single intersaction), put in the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// second slice.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$numberOfIntersections&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
                &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$relevantArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;=&lt;/span&gt; 
                        &lt;span class=&#34;nc&#34;&gt;$relevantArticles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;append&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$article&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// note.: I&amp;#39;m ignoring those with 0 intersections.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we&amp;rsquo;ve gotten all interesting articles, now we can create an ordered list starting from those with the biggest number of recommendations to those with the lowest, i.e., we can create a list that corresponds to the concatenation of the two variables we created above:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Create an empty slice to hold the final list
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$recommendedArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slice&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// For each very recommended article, append to the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// list.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt; 
        &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$recommendedArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$recommendedArticles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;append&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// For each recommended article, append to the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// list.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// This will lead to something like 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// [very, very, rec, rec, rec....]
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$relevantArticles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt; 
        &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$recommendedArticles&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$recommendedArticles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;append&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the list created, now it&amp;rsquo;s time to show it.&lt;/p&gt;
&lt;h3 id=&#34;displaying-the-recommendation-list&#34;&gt;Displaying the recommendation list&lt;/h3&gt;
&lt;p&gt;With a list containing those with the biggest number of intersections first and then the ones that have the less number of intersections, we can move forward with displaying that.&lt;/p&gt;
&lt;p&gt;For this Blog, I took the approach of showing a shuffle of the very first five that are picked from such list.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// For every article in the set of the first 5
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// recommended articles shuffled, show their
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// anchor.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shuffle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;first&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;$recommendedArticles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This guarantees that if I have some articles with big intersections with the content of the current article, they get displayed (even though unordered).&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you have a lot of content, and a lot of tags, you might want to create more categories (not only &lt;code&gt;veryRelevant&lt;/code&gt; and &lt;code&gt;relevant&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In such case, something more elaborate could be done.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s interesting to see how much we can accomplish without &amp;ldquo;an actual language&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Although Hugo gives us some simple primitives, we can build upon that and achieve some pretty satisfactory results.&lt;/p&gt;
&lt;p&gt;What about you? Have you ever achieved something similar doing something different? Please let me know!&lt;/p&gt;
&lt;p&gt;Also, if you have any questions, feel free to drop me a message at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Sat, 06 Oct 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/article-recommendation-using-hugo/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/article-recommendation-using-hugo/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>A UDP server and client in Go</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;While it&amp;rsquo;s prevalent to see implementations of TCP servers in Golang, it&amp;rsquo;s not very common to see the same when it comes to UDP.&lt;/p&gt;
&lt;p&gt;Besides the many differences between UDP and TCP, using Go it feels like these are pretty much alike, except for little details that arise from each protocol specifics.&lt;/p&gt;
&lt;p&gt;If you feel like some Golang UDP knowledge would be valuable, make sure you stick to the end.&lt;/p&gt;
&lt;p&gt;As an extra, this article also covers the underlying differences between TCP and UDP when it comes to the syscalls that Golang uses under the hood, as well as some analysis of what the Kernel does when those syscalls get called.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#overview&#34;&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sending-udp-packets-using-go&#34;&gt;Sending UDP packets using Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#address-resolution&#34;&gt;Address resolution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tcp-dialing-vs-udp-dialing&#34;&gt;TCP Dialing vs UDP Dialing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#writing-to-a-udp-connection&#34;&gt;Writing to a UDP &amp;ldquo;connection&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#receiving-from-a-udp-connection-in-a-client&#34;&gt;Receiving from a UDP &amp;ldquo;connection&amp;rdquo; in a client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#receiving-from-a-udp-connection-in-a-server&#34;&gt;Receiving from a UDP &amp;ldquo;connection&amp;rdquo; in a server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#a-udp-server-in-go&#34;&gt;A UDP Server in Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;overview&#34;&gt;Overview&lt;/h3&gt;
&lt;p&gt;As a goal for the blog post, the final implementation should look like an &amp;ldquo;echo channel&amp;rdquo;, where whatever a client writes to the server, the server echoes back.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        .---&amp;gt; HELLO!! --&amp;gt;-.
        |                 |
client -*                 *--&amp;gt; server --.
   ^                                    |
   |                                    |
   *---&amp;lt;----- HELLO!! ---------&amp;lt;--------*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Being UDP a protocol that doesn&amp;rsquo;t guarantee reliable delivery, it might be the case that the server receives the message, and it might be the case that the client receives the echo back from the server.&lt;/p&gt;
&lt;p&gt;The flow &lt;strong&gt;might&lt;/strong&gt; complete successfully (or not).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        .---&amp;gt; HELLO!! --&amp;gt;-.
        |                 |
client -*                 *--&amp;gt; server --.
                                        |
                                        |
            whoops, lost! -----&amp;lt;--------*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Not being connection-oriented, the client won&amp;rsquo;t really &amp;ldquo;establish a connection&amp;rdquo;, like in TCP; whenever a message arrives at the server, it won&amp;rsquo;t &amp;ldquo;write a response back to the connection&amp;rdquo;, it will only direct a message to the address that wrote to it.&lt;/p&gt;
&lt;p&gt;With that in mind, the flow should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TIME    DESCRIPTION

t0      client and server exist

          client                         server
          10.0.0.1                       10.0.0.2


t1      client sends a message to the server

          client      ------------&amp;gt;      server
          10.0.0.1         msg           10.0.0.2
                       (from:10.0.0.1)
                       (to:  10.0.0.2)


t2      server receives the message, then it takes
        the address of the sender and then prepares
        another message with the same contents and
        then writes it back to the client

          client      &amp;lt;------------      server
          10.0.0.1         msg2          10.0.0.2
                       (from:10.0.0.1)
                       (to:  10.0.0.2)


t3      client receives the message

          client                         server
          10.0.0.1                       10.0.0.2
        
           thxx!! :D :D


ps.: ports omitted for brevity
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That said, let&amp;rsquo;s see how that story rolls out in Go.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;Also,&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like a real deep dive, make sure you consider these books:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2zuuMu1&#34;&gt;Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first takes the approach of going from the very high level part of the networking stack (application layer), and then goes down to the very bottom, explaining the details of the protocols in there as it goes through them - if you need an excellent refresher on networking concepts without digging into the implementation details, check this one out!&lt;/p&gt;
&lt;p&gt;The other two are more about Linux and Unix in general - very worthwhile if you&amp;rsquo;re more focused on the implementation.&lt;/p&gt;
&lt;p&gt;Have a good reading!&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;sending-udp-packets-using-go&#34;&gt;Sending UDP packets using Go&lt;/h3&gt;
&lt;p&gt;Kicking off with the whole implementation at once (full of comments), we can start depicting it, understanding piece by piece, until the point that we can understand each and every interaction that happens behind the scenes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// client wraps the whole functionality of a UDP client that sends
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// a message and waits for a response coming back from the server
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// that it initially targetted.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// Resolve the UDP address so that we can make use of DialUDP
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// with an actual IP and port instead of a name (in case a
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// hostname is specified).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;raddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ResolveUDPAddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Although we&amp;#39;re not in a connection-oriented transport,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the act of `dialing` is analogous to the act of performing
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// a `connect(2)` syscall for a socket of type SOCK_DGRAM:
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// - it forces the underlying socket to only read and write
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//   to and from a specific remote address.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;DialUDP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;raddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Closes the underlying file descriptor associated with the,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// socket so that it no longer refers to any file.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;chan&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;go&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;c1&#34;&gt;// It is possible that this action blocks, although this
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// should only occur in very resource-intensive situations:
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// - when you&amp;#39;ve filled up the socket buffer and the OS
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//   can&amp;#39;t dequeue the queue fast enough.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;packet-written: bytes=%d\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxBufferSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Set a deadline for the ReadOperation so that we don&amp;#39;t
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// wait forever for a server that might not respond on
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// a resonable amount of time.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;deadline&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;timeout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;SetReadDeadline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;deadline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;nRead&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ReadFrom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;packet-received: bytes=%d from=%s\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;nRead&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}()&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;select&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;cancelled&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the client code, we can now depict it, exploring each of its nuances.&lt;/p&gt;
&lt;h3 id=&#34;address-resolution&#34;&gt;Address resolution&lt;/h3&gt;
&lt;p&gt;Before we even start creating a socket and carrying about sending the information to the server, the first thing that happens is a name resolution that translates a given name (like, &lt;code&gt;google.com&lt;/code&gt;) into a set of IP addresses (like, &lt;code&gt;8.8.8.8&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The way we do that in our code is with the call to &lt;a href=&#34;https://golang.org/pkg/net/#ResolveUDPAddr&#34;&gt;net.ResolveUDPAddr&lt;/a&gt;, which in a Unix environment, goes all the way down to performing the DNS resolution via the following stack:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;given&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;goroutine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...)&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004e5dc5&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Resolver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;goLookupIPCNAMEOrder&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dnsclient_unix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;553&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;1&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004fbe69&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Resolver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;lookupIP&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;lookup_unix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;101&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x0000000000514948&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Resolver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;lookupIP-fm&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;207&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;3&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000050faca&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;glob&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;func1&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hook&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;19&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;4&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000051156c&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Resolver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;LookupIPAddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;func1&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;221&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;5&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004d4f7c&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;singleflight&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Group&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;doCall&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;singleflight&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;singleflight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;95&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;6&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000045d9c1&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;goexit&lt;/span&gt;
           &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;asm_amd64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;1333&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;another&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;goroutine&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...)&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x0000000000431a74&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;gopark&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;303&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;1&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004416dd&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;selectgo&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;313&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004fa3f6&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Resolver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;LookupIPAddr&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;227&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;3&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004f6ae9&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;Resolver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;internetAddrList&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ipsock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;279&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;4&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000050807d&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;ResolveUDPAddr&lt;/span&gt;                     &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;udpsock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;82&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;5&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000051e63b&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;main&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;./&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;resolve&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;14&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;6&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x0000000000431695&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;main&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;201&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;7&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000045d9c1&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;goexit&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;asm_amd64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;1333&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I&amp;rsquo;m not mistaken, the overall process looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;it checks if we&amp;rsquo;re giving an already IP address or a hostname; if a hostname, then&lt;/li&gt;
&lt;li&gt;looks up the host using the local resolver according to the lookup order specified by the system; then,&lt;/li&gt;
&lt;li&gt;eventually performs an actual DNS request asking for records for such domain; then,&lt;/li&gt;
&lt;li&gt;if all of that succeeds, a list of IP addresses is retrieved and then sorted out according to an &lt;a href=&#34;https://tools.ietf.org/html/rfc6724&#34;&gt;RFC&lt;/a&gt;; which gives us the highest priority IP from the list.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Follow the stack trace above and you should be able to see by yourself the source code where the &amp;ldquo;magic&amp;rdquo; happens (it&amp;rsquo;s an interesting thing to do!).&lt;/p&gt;
&lt;p&gt;With an IP address chosen, we can proceed.&lt;/p&gt;
&lt;p&gt;note.: this process is &lt;strong&gt;not&lt;/strong&gt; different for TCP.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;The book &lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt; has a great section about DNS.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d &lt;strong&gt;really&lt;/strong&gt; recommend you going through it to know more about.&lt;/p&gt;
&lt;p&gt;I also wrote a blog post about writing something that is able to resolve &lt;code&gt;A&lt;/code&gt; records from scratch using Go: &lt;a href=&#34;https://ops.tips/blog/raw-dns-resolver-in-go/&#34;&gt;Writing DNS messages from scratch using Go&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;tcp-dialing-vs-udp-dialing&#34;&gt;TCP Dialing vs UDP Dialing&lt;/h3&gt;
&lt;p&gt;Instead of using a regular &lt;a href=&#34;https://golang.org/pkg/net/#Dial&#34;&gt;&lt;code&gt;Dial&lt;/code&gt;&lt;/a&gt; commonly used with TCP, for our UDP client, a different method was used: &lt;a href=&#34;https://golang.org/pkg/net/#DialUDP&#34;&gt;&lt;code&gt;DialUDP&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The reason for that is that we can enforce the type of address passed, as well as receive a specialized connection: the &amp;ldquo;concrete type&amp;rdquo; &lt;a href=&#34;https://golang.org/pkg/net/#UDPConn&#34;&gt;&lt;code&gt;UDPConn&lt;/code&gt;&lt;/a&gt; instead of the generic &lt;a href=&#34;https://golang.org/pkg/net/#Conn&#34;&gt;&lt;code&gt;Conn&lt;/code&gt;&lt;/a&gt; interface.&lt;/p&gt;
&lt;p&gt;Although both &lt;code&gt;Dial&lt;/code&gt; and &lt;code&gt;DialUDP&lt;/code&gt; might sound like the same (even when it comes to the syscalls used while talking to the kernel), they end up being pretty different concerning the network stack implementation.&lt;/p&gt;
&lt;p&gt;For instance, we can check that both methods use &lt;a href=&#34;http://man7.org/linux/man-pages/man2/connect.2.html&#34;&gt;&lt;code&gt;connect(2)&lt;/code&gt;&lt;/a&gt; under the hood:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TCP&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// TCP - performs an actual `connect` under the hood,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// trying to establish an actual connection with the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// other side.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Dial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;1.1.1.1:53&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// strace -f -e trace=network ./main
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//  [pid  4891] socket(
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
 &lt;span class=&#34;o&#34;&gt;-----&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SOCK_STREAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SOCK_CLOEXEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SOCK_NONBLOCK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;nx&#34;&gt;IPPROTO_IP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;//  [pid  4891] connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr(&amp;#34;1.1.1.1&amp;#34;)}, 16) = -1 EINPROGRESS (Operation now in progress)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;UDP&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// UDP - calls `connect` just like TCP, but given that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the arguments are different (it&amp;#39;s not SOCK_STREAM),
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the semantics differ - it constrains the socket 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// regarding to whom it might communicate with.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Dial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;1.1.1.1:53&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// strace -f -e trace=network ./main
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// [pid  5517] socket(
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
 &lt;span class=&#34;o&#34;&gt;-----&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SOCK_CLOEXEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SOCK_NONBLOCK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;nx&#34;&gt;IPPROTO_IP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;// [pid  5517] connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr(&amp;#34;1.1.1.1&amp;#34;)}, 16) = 0
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While they&amp;rsquo;re pretty much the same, from the documentation we can see how they are semantically different depending on the way we configure the &lt;code&gt;socket&lt;/code&gt; created via the &lt;code&gt;socket(2)&lt;/code&gt; call that happens before &lt;code&gt;connect(2)&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the socket sockfd is of type &lt;strong&gt;SOCK_DGRAM&lt;/strong&gt;, then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If the socket is of type &lt;strong&gt;SOCK_STREAM&lt;/strong&gt; or SOCK_SEQ‐PACKET,  this  call  attempts  to  make a connection to the socket that is bound to the address specified by addr.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Should we be able to verify that with the TCP transport the &lt;code&gt;Dial&lt;/code&gt; method would perform the act of really connecting to the other side? Sure!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;./tools/funccount -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pidof main&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;tcp_*&amp;#39;&lt;/span&gt;
Tracing &lt;span class=&#34;m&#34;&gt;316&lt;/span&gt; functions &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;tcp_*&amp;#34;&lt;/span&gt;... Hit Ctrl-C to end.
^C
FUNC                                    COUNT
tcp_small_queue_check.isra.28               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_current_mss                             &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_schedule_loss_probe                     &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_mss_to_mtu                              &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_write_queue_purge                       &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_write_xmit                              &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_select_initial_window                   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_fastopen_defer_connect                  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_mtup_init                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_v4_connect                              &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_v4_init_sock                            &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_rearm_rto.part.61                       &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_close                                   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_connect                                 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_send_fin                                &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_rearm_rto                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_tso_segs                                &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_event_new_data_sent                     &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_check_oom                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_clear_retrans                           &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_init_xmit_timers                        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_init_sock                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_initialize_rcv_mss                      &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_assign_congestion_control               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_sync_mss                                &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_init_tso_segs                           &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_stream_memory_free                      &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_setsockopt                              &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
tcp_chrono_stop                             &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_rbtree_insert                           &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_set_state                               &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_established_options                     &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_transmit_skb                            &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_v4_send_check                           &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_rate_skb_sent                           &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_options_write                           &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_poll                                    &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
tcp_release_cb                              &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
tcp_v4_md5_lookup                           &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
tcp_md5_do_lookup                           &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the case of UDP though, in theory, it merely takes care of marking the socket for reads and writes to the specified address.&lt;/p&gt;
&lt;p&gt;Going through the same process that we did for TCP (going further from looking at the syscall interface), we can trace the underlying kernel methods used by both &lt;code&gt;DialUDP&lt;/code&gt; and &lt;code&gt;Dial&lt;/code&gt; to see how they differ:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;./tools/funccount -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pidof main&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;udp_*&amp;#39;&lt;/span&gt;
Tracing &lt;span class=&#34;m&#34;&gt;57&lt;/span&gt; functions &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;udp_*&amp;#34;&lt;/span&gt;... Hit Ctrl-C to end.
^C
FUNC                                    COUNT
udp_v4_rehash                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_poll                                    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_v4_get_port                             &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_lib_close                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_lib_lport_inuse                         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_init_sock                               &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_lib_unhash                              &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_lib_rehash                              &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_lib_get_port                            &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
udp_destroy_sock                            &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Much&amp;hellip; Much less.&lt;/p&gt;
&lt;p&gt;If we go even further, try to explore what happens at each of these calls, we can notice how &lt;code&gt;connect(2)&lt;/code&gt; in the case of TCP ends up really transmitting data (to establish perform the handshake, for instance):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;PID     TID     COMM            FUNC
&lt;span class=&#34;m&#34;&gt;6747&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;6749&lt;/span&gt;    main            tcp_transmit_skb
        tcp_transmit_skb+0x1
        tcp_v4_connect+0x3f5
        __inet_stream_connect+0x238
        inet_stream_connect+0x3b
        SYSC_connect+0x9e
        sys_connect+0xe
        do_syscall_64+0x73
        entry_SYSCALL_64_after_hwframe+0x3d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While in the case of UDP, nothing is transmitted, just some set up is performed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;PID     TID     COMM            FUNC
&lt;span class=&#34;m&#34;&gt;6815&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;6817&lt;/span&gt;    main            ip4_datagram_connect
        ip4_datagram_connect+0x1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;kernel&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        SYSC_connect+0x9e &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;kernel&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        sys_connect+0xe &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;kernel&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        do_syscall_64+0x73 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;kernel&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        entry_SYSCALL_64_after_hwframe+0x3d &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;kernel&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re not convinced yet that these two are &lt;strong&gt;really&lt;/strong&gt; different (in the sense that the TCP one sends packets to establish the connection, while UDP doesn&amp;rsquo;t), we can set up some triggers in the network stack to tell us whenever packets flow:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# By creating a rule that will only match&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# packets destined at `1.1.1.1` and that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# match a specific protocol, we&amp;#39;re able&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to see what happens at the time that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `connect(2)` happens with a given protocol&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# or another.&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --table filter &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --insert OUTPUT &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --jump LOG &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --protocol udp &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --destination 1.1.1.1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --log-prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;[UDP] &amp;#34;&lt;/span&gt;

iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --table filter &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --insert OUTPUT &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --jump LOG &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --protocol tcp &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --destination 1.1.1.1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --log-prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;[TCP] &amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, run &lt;code&gt;Dial&lt;/code&gt; against a TCP target and &lt;code&gt;DialUDP&lt;/code&gt; target and compare the differences.&lt;/p&gt;
&lt;p&gt;You should only see &lt;code&gt;[TCP]&lt;/code&gt; logs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;46260.105662&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;TCP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enp0s3&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;SYN&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;URGP&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;46260.120454&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;TCP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enp0s3&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;ACK&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;URGP&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;46260.120718&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;TCP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enp0s3&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;ACK&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;FIN&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;URGP&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;46260.150452&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;TCP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enp0s3&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.1&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;ACK&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;URGP&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;re not familiar with the inner workings of &lt;code&gt;dmesg&lt;/code&gt;, check out my other blog post - &lt;a href=&#34;https://ops.tips/blog/dmesg-under-the-hood&#34;&gt;dmesg under the hood&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By the way, &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt; is a great book to know more about sockets and other related topics!&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;writing-to-a-udp-connection&#34;&gt;Writing to a UDP &amp;ldquo;connection&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;With our UDP socket properly created and configured for a specific address, we&amp;rsquo;re now on time to go through the &amp;ldquo;write&amp;rdquo; path - when we actually take some data and write to the &lt;code&gt;UDPConn&lt;/code&gt; object received from &lt;code&gt;net.DialUDP&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A sample program that just sends a little bit of data to a given UDP server would be as follow:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Perform the address resolution and also
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// specialize the socket to only be able
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// to read and write to and from such
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// resolved address.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Dial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;panic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Call the `Write()` method of the implementor
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// of the `io.Writer` interface.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;something&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that &lt;code&gt;conn&lt;/code&gt; returned by &lt;code&gt;Dial&lt;/code&gt; implements the &lt;code&gt;io.Writer&lt;/code&gt; interface, we can make use of something like &lt;code&gt;fmt.Fprintf&lt;/code&gt; (that takes an &lt;code&gt;io.Writer&lt;/code&gt; as its first argument) as let it call &lt;code&gt;Write()&lt;/code&gt; with the message we pass to it.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If interfaces and other Golang concepts are not clear for you yet, make sure you check Kernighan&amp;rsquo;s book: &lt;a href=&#34;https://amzn.to/2R7XdVe&#34;&gt;The Go Programming Language&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;yeah, from the guy who wrote &lt;a href=&#34;https://amzn.to/2zE5jOV&#34;&gt;The C Programming Language&lt;/a&gt; with Dennis Ritchie&lt;/em&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Under the hood, &lt;a href=&#34;https://golang.org/pkg/net/#UDPConn&#34;&gt;&lt;code&gt;UDPConn&lt;/code&gt;&lt;/a&gt; implements the &lt;code&gt;Write()&lt;/code&gt; method from the &lt;a href=&#34;https://golang.org/pkg/io/#Writer&#34;&gt;&lt;code&gt;io.Writer&lt;/code&gt;&lt;/a&gt; interface by being a composition of &lt;a href=&#34;https://github.com/golang/go/blob/a0e7f12771c2e84e626dcf5e30da5d62a3b1adf6/src/net/net.go#L164-L166&#34;&gt;&lt;code&gt;conn&lt;/code&gt;&lt;/a&gt;, a struct that implements the most basic methods regarding writing to and reading from a given file descriptor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;netFD&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Write implements the Conn Write method.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;EINVAL&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;OpError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;write&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Source&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;laddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;raddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;// UDPConn is the implementation of the Conn 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// and PacketConn interfaces for UDP network 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// connections.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;UDPConn&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, knowing that in the end &lt;code&gt;fmt.Fprintf(conn, &amp;quot;something&amp;quot;)&lt;/code&gt; ends up in a &lt;code&gt;write(2)&lt;/code&gt; to a file descriptor (the UDP socket), we can investigate even further and see how does the kernel path look for such &lt;code&gt;write(2)&lt;/code&gt; call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;PID     TID     COMM            FUNC
&lt;span class=&#34;m&#34;&gt;14502&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;14502&lt;/span&gt;   write.out       ip_send_skb
        ip_send_skb+0x1 
        udp_sendmsg+0x3b5 
        inet_sendmsg+0x2e 
        sock_sendmsg+0x3e 
        sock_write_iter+0x8c 
        new_sync_write+0xe7 
        __vfs_write+0x29 
        vfs_write+0xb1 
        sys_write+0x55 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At that point, the packet should be on its way to the other side of the communication channel.&lt;/p&gt;
&lt;h3 id=&#34;receiving-from-a-udp-connection-in-a-client&#34;&gt;Receiving from a UDP &amp;ldquo;connection&amp;rdquo; in a client&lt;/h3&gt;
&lt;p&gt;The act of receiving from &lt;code&gt;UDPConn&lt;/code&gt; can be seen as pretty much the same as the &amp;ldquo;write path&amp;rdquo;, except that at this time, a buffer is supplied (so that it can get filled with the contents that arrive), and we don&amp;rsquo;t really know how long we have to wait for the content to arrive.&lt;/p&gt;
&lt;p&gt;For instance, we could have the following code path for reading from a known address:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bufSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This would turn into a &lt;code&gt;read(2)&lt;/code&gt; syscall under the hood, which would then go through &lt;code&gt;vfs&lt;/code&gt; and turn into a &lt;code&gt;read&lt;/code&gt; from a socket:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;m&#34;&gt;22313&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;22313&lt;/span&gt;   &lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt;            __skb_recv_udp
        __skb_recv_udp+0x1 
        inet_recvmsg+0x51 
        sock_recvmsg+0x43 
        sock_read_iter+0x90 
        new_sync_read+0xe4 
        __vfs_read+0x29 
        vfs_read+0x8e 
        sys_read+0x55 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Something important to remember is that when it comes to reading from the socket, that&amp;rsquo;s going to be a blocking operation.&lt;/p&gt;
&lt;p&gt;Given that a message might never return from such socket, we can get stuck waiting forever.&lt;/p&gt;
&lt;p&gt;To avoid such situation, we can set a reading deadline that would kill the whole thing in case we wait for too long:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bufSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Sets the read deadline for now + 15seconds.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// If you plan to read from the same connection again,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// make sure you expand the deadline before reading
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// it.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;SetReadDeadline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Second&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, In case the other end takes too long to answer:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;read udp 10.0.2.15:41745-&amp;gt;1.1.1.1:53: i/o timeout
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;receiving-from-a-udp-connection-in-a-server&#34;&gt;Receiving from a UDP &amp;ldquo;connection&amp;rdquo; in a server&lt;/h3&gt;
&lt;p&gt;While that&amp;rsquo;s great for the &lt;code&gt;client&lt;/code&gt; (we know whom we&amp;rsquo;re reading from), it&amp;rsquo;s not for a server.&lt;/p&gt;
&lt;p&gt;The reason why is that at the server side, we don&amp;rsquo;t know who we&amp;rsquo;re reading from (the address is unknown).&lt;/p&gt;
&lt;p&gt;Differently from the case of a TCP server where we have &lt;code&gt;accept(2)&lt;/code&gt; which returns to the server implementor the connection that the server can write to, in the case of UDP, there&amp;rsquo;s no such thing as a &amp;ldquo;connection to write to&amp;rdquo;. There&amp;rsquo;s only a &amp;ldquo;whom to write to&amp;rdquo;, that can be retrieved by inspecting the packet that arrived.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WITH READ

  &amp;quot;Hmmm, let me write something to
   my buddy at 1.1.1.1:53&amp;quot;

   client --.
            |
            | client: n, err := udpConn.Write(buf)
            | server: n, err := udpConn.Read(buf)
            |
            *---&amp;gt; server
                  &amp;quot;Oh, somebody wrote me something!
                   I&#39;d like to write back to him/her,
                   but, what&#39;s his/her address?
                   
                   I don&#39;t have a connection... I need
                   an address to write to! I can&#39;t to
                   a thing now!&amp;quot;



WITH READFROM

   client --.
            |
            | client: n, err := udpConn.Write(buf)
            | server: n, address, err := udpConn.Read(buf)
            |
            *---&amp;gt; server
                  &amp;quot;Oh, looking at the packet, I can
                   see that my friend Jane wrote to me,
                   I can see that from `address`!
                   
                   Let me answer her back!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For that reason, on the server, we need the specialized connection: &lt;a href=&#34;https://golang.org/pkg/net/#UDPConn&#34;&gt;&lt;code&gt;UDPConn&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Such specialized connection is able of giving us &lt;code&gt;ReadFrom&lt;/code&gt;, a method that instead of just reading from a file descriptor and adding the contents to a buffer, it also inspects the headers of the packet and gives us information about who sent the package.&lt;/p&gt;
&lt;p&gt;Its usage looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Given a buffer that is meant to hold the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// contents from the messages arriving at the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// socket that `udpConn` wraps, it blocks until
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// messages arrive. 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For each message arriving, `ReadFrom` unwraps
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the message, getting information about the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// sender from the protocol headers and then
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// fills the buffer with the data.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;udpConn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ReadFrom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;panic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An interesting way of trying to understand how things work under the hood is looking at the &lt;a href=&#34;https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs&#34;&gt;plan9&lt;/a&gt; implementation (&lt;a href=&#34;https://github.com/golang/go/blob/a0e7f12771c2e84e626dcf5e30da5d62a3b1adf6/src/net/udpsock_plan9.go#L14-L28&#34;&gt;&lt;code&gt;net/udpsock_plan9.go&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how it looks (with comments of my own):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;UDPConn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;readFrom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;UDPAddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// creates a buffer a little bit bigger than
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the one we provided (to account for the header of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the UDP headers)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;udpHeaderSize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// reads from the underlying file descriptor (this might
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// block).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;udpHeaderSize&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;New&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;short read reading UDP header&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// strips out the parts that were not readen
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// interprets the UDP header
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;unmarshalUDPHeader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        
        &lt;span class=&#34;c1&#34;&gt;// copies the data back to our supplied buffer
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// so that we only receive the data, not the header.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;UDPAddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;IP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;raddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rport&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)},&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Naturally, under Linux, that&amp;rsquo;s not the path that &lt;code&gt;readFrom&lt;/code&gt; takes. It uses &lt;code&gt;recvfrom&lt;/code&gt; which does the whole &amp;ldquo;UDP header interpretation&amp;rdquo; under the hood, but the idea is the same (except that with &lt;code&gt;plan9&lt;/code&gt; it&amp;rsquo;s all done in userspace).&lt;/p&gt;
&lt;p&gt;To verify the fact that under Linux we&amp;rsquo;re using &lt;code&gt;recvfrom&lt;/code&gt;, we trace &lt;code&gt;UDPConn.ReadFrom&lt;/code&gt; down (you can use &lt;a href=&#34;https://github.com/derekparker/delve&#34;&gt;&lt;code&gt;delve&lt;/code&gt;&lt;/a&gt; for that):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span class=&#34;nt&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004805b8&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;recvfrom&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;zsyscall_linux_amd64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;1641&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;1&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000047e84f&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Recvfrom&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;syscall_unix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;262&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x0000000000494281&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;poll&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;FD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;ReadFrom&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;poll&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;fd_unix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;215&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;3&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000004f5f4e&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;netFD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;readFrom&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;fd_unix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;208&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;4&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x0000000000516ab1&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;UDPConn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;readFrom&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;udpsock_posix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;47&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;5&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x00000000005150a4&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.(*&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;UDPConn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;ReadFrom&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;udpsock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;121&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;6&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x0000000000526bbf&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;func1&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;./&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;65&lt;/span&gt;
&lt;span class=&#34;nt&#34;&gt;7&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;0x000000000045e1d1&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;goexit&lt;/span&gt;
   &lt;span class=&#34;nt&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;asm_amd64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;1333&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At the kernel level, we can also check what are the methods involved:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;m&#34;&gt;24167&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;24167&lt;/span&gt;   go-sample-udp   __skb_recv_udp
        __skb_recv_udp+0x1 
        inet_recvmsg+0x51 
        sock_recvmsg+0x43 
        SYSC_recvfrom+0xe4 
        sys_recvfrom+0xe 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;a-udp-server-in-go&#34;&gt;A UDP Server in Go&lt;/h3&gt;
&lt;p&gt;Now, going to the server-side implementation, here&amp;rsquo;s how the code would look like (heavily commented):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// maxBufferSize specifies the size of the buffers that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// are used to temporarily hold data from the UDP packets
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// that we receive.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxBufferSize&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// server wraps all the UDP echo server functionality.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ps.: the server is capable of answering to a single
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// client at a time.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ListenPacket provides us a wrapper around ListenUDP so that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// we don&amp;#39;t need to call `net.ResolveUDPAddr` and then subsequentially
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// perform a `ListenUDP` with the UDP address.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// The returned value (PacketConn) is pretty much the same as the one
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// from ListenUDP (UDPConn) - the only difference is that `Packet*`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// methods and interfaces are more broad, also covering `ip`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;pc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ListenPacket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// `Close`ing the packet &amp;#34;connection&amp;#34; means cleaning the data structures
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// allocated for holding information about the listening socket.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;pc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;chan&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxBufferSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Given that waiting for packets to arrive is blocking by nature and we want
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// to be able of canceling such action if desired, we do that in a separate
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// go routine.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;go&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;c1&#34;&gt;// By reading from the connection into the buffer, we block until there&amp;#39;s
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// new content in the socket that we&amp;#39;re listening for new packets.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// Whenever new packets arrive, `buffer` gets filled and we can continue
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// the execution.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// note.: `buffer` is not being reset between runs.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;//	  It&amp;#39;s expected that only `n` reads are read from it whenever
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;//	  inspecting its contents.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;pc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ReadFrom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
				&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

			&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;packet-received: bytes=%d from=%s\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

			&lt;span class=&#34;c1&#34;&gt;// Setting a deadline for the `write` operation allows us to not block
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// for longer than a specific timeout.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// In the case of a write operation, that&amp;#39;d mean waiting for the send
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;// queue to be freed enough so that we are able to proceed.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;nx&#34;&gt;deadline&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;timeout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;pc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;SetWriteDeadline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;deadline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
				&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

			&lt;span class=&#34;c1&#34;&gt;// Write the packet&amp;#39;s contents back to the client.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;pc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;WriteTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;
				&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

			&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;packet-written: bytes=%d to=%s\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}()&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;select&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;cancelled&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;doneChan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you might have noticed, it&amp;rsquo;s not all that different from the client! The reason why is that not having an actual connection involved (like in TCP), both client and servers end up going through the same path: preparing a socket to read and write from and to, then checking the content from the packets and doing the same thing over and over again.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It was great to go through this exploration, checking what&amp;rsquo;s going on behind the scenes in the Go source code (very well written, by the way), as well as in the Kernel.&lt;/p&gt;
&lt;p&gt;I think I finally got a great workflow when it comes to debugging with &lt;a href=&#34;https://github.com/derekparker/delve&#34;&gt;Delve&lt;/a&gt; and verifying the Kernel functions with &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;bcc&lt;/a&gt;, maybe I&amp;rsquo;ll write about that soon - let me know if that&amp;rsquo;d be interesting!&lt;/p&gt;
&lt;p&gt;If you have any questions, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter, and I&amp;rsquo;d love to receive your feedback.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Sun, 30 Sep 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/udp-client-and-server-in-go/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/udp-client-and-server-in-go/</guid>

                                
                                        <category>linux</category>
                                
                                        <category>networking</category>
                                
                                        <category>go</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Retrieving the full path of a process on MacOS (and exploring procfs)</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Another day I was trying to make sure that a given process that I was running was using a specific binary that I had built, but I couldn&amp;rsquo;t figure out: &lt;code&gt;ps&lt;/code&gt; would only show me the non-absolute path.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# How could I know what is the absolute path of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `hugo` binary, assuming that I could have multiple&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `hugo` binaries in `$PATH`?&lt;/span&gt;
ps
  PID TTY           TIME CMD
 &lt;span class=&#34;m&#34;&gt;4153&lt;/span&gt; ttys000    5:14.98 hugo serve     &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
 &lt;span class=&#34;m&#34;&gt;9035&lt;/span&gt; ttys001    0:00.04 /Applications/iTerm.app/Content...
 &lt;span class=&#34;m&#34;&gt;9037&lt;/span&gt; ttys001    0:00.10 -bash
 &lt;span class=&#34;m&#34;&gt;9086&lt;/span&gt; ttys001    0:02.27 /usr/local/Cellar/macvim/8.1-15...
 &lt;span class=&#34;m&#34;&gt;9236&lt;/span&gt; ttys002    0:00.04 /Applications/iTerm.app/Content...
 &lt;span class=&#34;m&#34;&gt;9238&lt;/span&gt; ttys002    0:00.10 -bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I were using Linux though, I thought, that&amp;rsquo;d be easy: head to &lt;code&gt;/proc&lt;/code&gt;, search for the &lt;code&gt;pid&lt;/code&gt; of the process and then check what &lt;code&gt;exe&lt;/code&gt; links to; done.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# (on a Linux machine ...)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# See `hugo` will still not show up with the absolute path&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# like on MacOS.&lt;/span&gt;
ps aux &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep hugo
ubuntu    &lt;span class=&#34;m&#34;&gt;2275&lt;/span&gt;  0.0  0.0 &lt;span class=&#34;m&#34;&gt;101852&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;748&lt;/span&gt; pts/0    Sl+  00:26   0:00 hugo serve

&lt;span class=&#34;c1&#34;&gt;# Given that the proc filesystem can provide us with some&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# more information about the process, check out the `exe`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# link (which should provide a link to the actual executable).&lt;/span&gt;
stat /proc/2275/exe
  File: /proc/2275/exe -&amp;gt; /usr/local/bin/hugo
  Size: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         	Blocks: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          IO Block: &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;   symbolic link
Device: 4h/4d	Inode: &lt;span class=&#34;m&#34;&gt;140106&lt;/span&gt;      Links: &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
Access: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0777/lrwxrwxrwx&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  Uid: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt; 1001/  ubuntu&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;   Gid: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt; 1001/  ubuntu&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
Access: 2018-09-24 00:26:37.167004005 +0000
Modify: 2018-09-24 00:26:27.391004005 +0000
Change: 2018-09-24 00:26:27.391004005 +0000
 Birth: -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this post, I go through how we can gather such information on a MacOS, and what the &lt;code&gt;procfs&lt;/code&gt; in Linux is all about.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;tl;dr: &lt;code&gt;/proc&lt;/code&gt; on Linux is dope; on MacoS: compile a little code that uses &lt;a href=&#34;https://opensource.apple.com/source/xnu/xnu-2422.1.72/libsyscall/wrappers/libproc/libproc.h.auto.html&#34;&gt;&lt;code&gt;proc_pidpath&lt;/code&gt;&lt;/a&gt; from &lt;code&gt;libproc&lt;/code&gt;, or install &lt;a href=&#34;https://github.com/cirocosta/pidpath&#34;&gt;&lt;code&gt;pidpath&lt;/code&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-proc-filesystem-in-linux&#34;&gt;The /proc filesystem in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#procfs-under-the-hood&#34;&gt;procfs under the hood&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-libproc-library-in-macos&#34;&gt;The libproc library in MacOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#a-golang-binary-that-suits-linux-and-macos&#34;&gt;A Golang binary that suits Linux and MacOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;the-proc-filesystem-in-linux&#34;&gt;The /proc filesystem in Linux&lt;/h3&gt;
&lt;p&gt;In &amp;ldquo;Linux land&amp;rdquo;, there&amp;rsquo;s this thing called &amp;ldquo;procfs&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a virtual filesystem - in the sense that there are no real regular files in your disk that map to the filesystem representation - that allows a user (in userspace) to perform some introspection about its current running process and others as well.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&#34;https://www.kernel.org/doc/Documentation/filesystems/proc.txt&#34;&gt;the kernel docs&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The proc file system acts as an interface to internal data structures in the kernel.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It  can  be  used to obtain information about the system and to change certain kernel parameters at runtime (&lt;a href=&#34;https://linux.die.net/man/8/sysctl&#34;&gt;sysctl&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The way the interaction with it is set up is pretty nifty:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;each process receives a given path under &lt;code&gt;/proc&lt;/code&gt; (like, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;&lt;/code&gt;), and then&lt;/li&gt;
&lt;li&gt;as subdirectories of this path, various other files and subdirectories are present to allow deeper introspection about the specific pid.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Display the files and directories present at the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# very root of `/proc`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here we can find the list of PIDs that we can access,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as well as some more system-wide information and &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# settings that we can tweak.&lt;/span&gt;
ls -lah /proc
total 4.0K
dr-xr-xr-x &lt;span class=&#34;m&#34;&gt;124&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:56 .
drwxr-xr-x  &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; root     root    4.0K Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:57 ..
dr-xr-xr-x   &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:56 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
dr-xr-xr-x   &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 00:54 &lt;span class=&#34;m&#34;&gt;2016&lt;/span&gt;
dr-xr-xr-x   &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:57 &lt;span class=&#34;m&#34;&gt;417&lt;/span&gt;
...
-r--r--r--   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:25 sched_debug
-r--r--r--   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:25 schedstat
dr-xr-xr-x   &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:25 scsi
lrwxrwxrwx   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root     root       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:56 self -&amp;gt; &lt;span class=&#34;m&#34;&gt;2574&lt;/span&gt;
...


&lt;span class=&#34;c1&#34;&gt;# Getting into a specific pid path, we&amp;#39;re able to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# gather more information about the specifics of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a given process.&lt;/span&gt;
ls -lah /proc/472
total &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
dr-xr-xr-x   &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:57 .
dr-xr-xr-x &lt;span class=&#34;m&#34;&gt;123&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:56 ..
...
lrwxrwxrwx   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:30 cwd -&amp;gt; /
-r--------   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:30 environ
lrwxrwxrwx   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:57 exe -&amp;gt; /lib/systemd/systemd-udevd
dr-x------   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 23:57 fd
lrwxrwxrwx   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:30 root -&amp;gt; /
-rw-r--r--   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; 01:30 sched
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not only that, &lt;code&gt;procfs&lt;/code&gt; is very helpful when you&amp;rsquo;re not sure if a process is blocked on something you didn&amp;rsquo;t expect (like a &lt;code&gt;write(2)&lt;/code&gt; to an &lt;code&gt;nfs&lt;/code&gt; mount point that is malformed due to a bad set of servers not responding), or something simple as your process sleeping when you didn&amp;rsquo;t want to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Sleep for 33 days on the background&lt;/span&gt;
sleep 33d &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2786&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Check what&amp;#39;s the state of the process&lt;/span&gt;
cat /proc/2786/stat
&lt;span class=&#34;m&#34;&gt;2786&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;sleep&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; S ...
 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;-&amp;gt; state &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;interruptible sleep&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;     &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;-&amp;gt; &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; being run &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;sleep &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
 &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;-&amp;gt; process id &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;the pid we used before&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Check what&amp;#39;s the stack trace (from the kernel&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# perspective) that led the process to this &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# sleep state&lt;/span&gt;
cat /proc/2786/stack
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; hrtimer_nanosleep+0xd8/0x1d0
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SyS_nanosleep+0x72/0xa0
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; do_syscall_64+0x73/0x130
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; entry_SYSCALL_64_after_hwframe+0x3d/0xa2
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 0xffffffffffffffff
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;procfs-under-the-hood&#34;&gt;procfs under the hood&lt;/h3&gt;
&lt;p&gt;What&amp;rsquo;s interesting about being virtual is that the implementation of &lt;code&gt;procfs&lt;/code&gt; is able to generate the representation of the filesystem on the fly - whenever you issue an I/O call like &lt;code&gt;read(2)&lt;/code&gt;, Linux answers back with what you asked for, be it the list of file descriptors opened by a given process, or the list of environment variables that were set at process startup time.&lt;/p&gt;
&lt;p&gt;For instance, if tracing the execution of &lt;code&gt;cat /proc/&amp;lt;pid&amp;gt;/meminfo&lt;/code&gt; down, we can find the path that the &lt;code&gt;read(2)&lt;/code&gt; syscall takes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# stack trace of `cat /proc/&amp;lt;pid&amp;gt;/meminfo`&lt;/span&gt;
        meminfo_proc_show
        proc_reg_read
        __vfs_read
        vfs_read
        sys_read
        do_syscall_64
        entry_SYSCALL_64_after_hwframe


&lt;span class=&#34;c1&#34;&gt;# stack trace of `cat /file.txt` &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# on an ext4 mount point&lt;/span&gt;
        ext4_file_read_iter
        __vfs_read
        vfs_read
        sys_read
        do_syscall_64
        entry_SYSCALL_64_after_hwframe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Very different from a regular &lt;code&gt;read&lt;/code&gt; (as shown in the second stack trace), there&amp;rsquo;s no real file on disk being accessed - just &lt;code&gt;meminfo_proc_show&lt;/code&gt; returning the contents related to what the user asked for: virtual memory stuff.&lt;/p&gt;
&lt;p&gt;By the way, if you&amp;rsquo;re interested in knowing more about related subjects, a &lt;strong&gt;great&lt;/strong&gt; reference for this type of knowledge is &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface: A Linux and UNIX System Programming Handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now to MacOS.&lt;/p&gt;
&lt;h3 id=&#34;the-libproc-library-in-macos&#34;&gt;The libproc library in MacOS&lt;/h3&gt;
&lt;p&gt;Differently from Linux, it feels like we can&amp;rsquo;t know all that much about how things work on MacOS.&lt;/p&gt;
&lt;p&gt;After searching a bit on how to accomplish how to gather information about a process, &lt;code&gt;libproc&lt;/code&gt; showed up.&lt;/p&gt;
&lt;p&gt;As mentioned in &lt;a href=&#34;https://opensource.apple.com/source/xnu/xnu-2422.1.72/libsyscall/wrappers/libproc/libproc.h.auto.html&#34;&gt;&lt;code&gt;libproc.h&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * This header file contains private interfaces 
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * to obtain process information.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * These interfaces are subject to change in future releases.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the interfaces are &lt;strong&gt;private&lt;/strong&gt; - no guaranteed compatibility with future releases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This has been elucidated by an Apple staff member on &lt;a href=&#34;https://forums.developer.apple.com/thread/46963&#34;&gt;post&lt;/a&gt; at the Apple&amp;rsquo;s developer forum regarding gathering process information:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[&amp;hellip;] Apple has not put a lot of effort into providing APIs for getting this sort of information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;What APIs that do exist were either inherited from OS X’s predecessor OSs or were added &lt;strong&gt;primarily to meet our internal requirements rather than the needs for third-party developers&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Thus, you will find a lot of places where these APIs are: incomplete; incorrect; poorly documented and aren’t as binary compatible as they should be.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anyway, we can still make use of it - more specifically, we can make use of &lt;code&gt;proc_pidpath&lt;/code&gt;, a method that takes a &lt;code&gt;pid&lt;/code&gt; (the &lt;code&gt;pid&lt;/code&gt; of the process that we want to know more about), a buffer where the path should be written to, and the buffer size.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_pidpath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;// pid of the process to know more about
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// buffer to fill with the abs path
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;buffersize&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// size of the buffer
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That said, we can go ahead and create our Go binary that can handle both Linux and MacOS by specifying two different compilation targets.&lt;/p&gt;
&lt;h3 id=&#34;a-golang-binary-that-suits-linux-and-macos&#34;&gt;A Golang binary that suits Linux and MacOS&lt;/h3&gt;
&lt;p&gt;Given that &lt;code&gt;libproc&lt;/code&gt; will not be a thing under Linux, we can start by creating a &lt;code&gt;pidpath_linux.go&lt;/code&gt; file that is meant to be compiled only on Linux, and another file, &lt;code&gt;pidpath_darwin.go&lt;/code&gt;, aimed at MacOS machines.&lt;/p&gt;
&lt;p&gt;The Linux one is rather simple: it follows the &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/exe&lt;/code&gt; symlink, and that&amp;rsquo;s it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// +build linux
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GetExePathFromPid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pid&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Readlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/proc/&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strconv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Itoa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/exe&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The MacOS version though, needs a little bit more.&lt;/p&gt;
&lt;p&gt;Given that we&amp;rsquo;d access &lt;code&gt;libproc&lt;/code&gt; via C, we can leverage &lt;a href=&#34;https://golang.org/cmd/cgo/&#34;&gt;CGO&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// +build darwin
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// #include &amp;lt;libproc.h&amp;gt;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// #include &amp;lt;stdlib.h&amp;gt;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// #include &amp;lt;errno.h&amp;gt;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;unsafe&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// bufSize references the constant that the implementation
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// of proc_pidpath uses under the hood to make sure that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// no overflows happen.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// See https://opensource.apple.com/source/xnu/xnu-2782.40.9/libsyscall/wrappers/libproc/libproc.c
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bufSize&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PROC_PIDPATHINFO_MAXSIZE&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GetExePathFromPid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pid&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// Allocate in the C heap a string (char* terminated
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// with `/0`) of size `bufSize` and then make sure
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// that we free that memory that gets allocated
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// in C (see the `defer` below).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bufSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Call the C function `proc_pidpath` from the included
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// header file (libproc.h).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;proc_pidpath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bufSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Errorf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to retrieve pid path: %v&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Convert the C string back to a Go string.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;GoString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That done, we can now consume &lt;code&gt;GetExePathFromPid&lt;/code&gt; in our application.&lt;/p&gt;
&lt;p&gt;To see that in place, check out &lt;a href=&#34;https://github.com/cirocosta/pidpath&#34;&gt;cirocosta/pidpath&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It was interesting to me to check out how different things are in MacOS land.&lt;/p&gt;
&lt;p&gt;Although I use a Macbook Pro as a personal computer (and a Mac at work), I&amp;rsquo;ve not really paid attention to these little details.&lt;/p&gt;
&lt;p&gt;Also, &lt;code&gt;/proc&lt;/code&gt; is just &lt;strong&gt;so&lt;/strong&gt; valuable! Definitely worth knowing more about other functionality over there. Make sure you check out &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface: A Linux and UNIX System Programming Handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have any questions, or suggestions to improve this blog post, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt;, and I&amp;rsquo;d love to chat.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Tue, 25 Sep 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/macos-pid-absolute-path-and-procfs-exploration/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/macos-pid-absolute-path-and-procfs-exploration/</guid>

                                
                                        <category>programming</category>
                                
                                        <category>go</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Dmesg under the hood</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;This week I wanted to discover a bit more about how &lt;code&gt;dmesg&lt;/code&gt; works under the hood. In the past, I wanted to have alerting based on error messages popping at &lt;code&gt;dmesg&lt;/code&gt;, so, maybe by trying to create something that uses the same thing that &lt;code&gt;dmesg&lt;/code&gt; uses under the hood, I could better understand it.&lt;/p&gt;
&lt;p&gt;Also, I knew that in some systems, it was possible to gather the same information from &lt;code&gt;kern.log&lt;/code&gt; and that &lt;code&gt;dmesg&lt;/code&gt; was all about reading &amp;ldquo;the kernel ring buffer&amp;rdquo;, but, what did that mean?&lt;/p&gt;
&lt;p&gt;More specifically, where was &lt;code&gt;dmesg&lt;/code&gt; reading from?&lt;/p&gt;
&lt;p&gt;In this blog post, I go through some exploration to better understand the whole picture.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#producing-logs-from-kernel-space&#34;&gt;Producing logs from kernel space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#producing-logs-from-iptables&#34;&gt;Producing logs from iptables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#producing-logs-from-a-linux-loadable-kernel-module&#34;&gt;Producing logs from a Linux loadable kernel module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#producing-logs-from-kmsg&#34;&gt;Producing logs from kmsg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#seeing-kernel-logs-from-user-space&#34;&gt;Seeing kernel logs from user space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#interpreting-the-kmsg-messages&#34;&gt;Interpreting the kmsg messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;You can jump to the tl;dr &lt;a href=&#34;#seeing-kernel-logs-from-user-space&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;producing-logs-from-kernel-space&#34;&gt;Producing logs from kernel space&lt;/h3&gt;
&lt;p&gt;Whenever something in the Linux kernel (which could be a &lt;a href=&#34;https://en.wikipedia.org/wiki/Loadable_kernel_module&#34;&gt;module&lt;/a&gt;) wants to do the equivalent of a &lt;a href=&#34;https://linux.die.net/man/3/printf&#34;&gt;&lt;code&gt;printf&lt;/code&gt;&lt;/a&gt;, a similar utility (&lt;code&gt;printk&lt;/code&gt;) can be used.&lt;/p&gt;
&lt;p&gt;That allows the program to give information back to the developer (or any other user) in userspace to know more about what&amp;rsquo;s going on with the module - be a warning message, stack traces or some pure debugging information.&lt;/p&gt;
&lt;p&gt;To test out producing logs from the Kernel, I came up with some ideas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://linux.die.net/man/8/iptables&#34;&gt;&lt;code&gt;iptables&lt;/code&gt;&lt;/a&gt; has a &lt;a href=&#34;http://ipset.netfilter.org/iptables-extensions.man.html#lbDD&#34;&gt;&lt;code&gt;LOG&lt;/code&gt; target&lt;/a&gt; that essentially produces some logs from &lt;code&gt;iptables&lt;/code&gt; itself whenever the target is, well, targetted. Being &lt;code&gt;iptables&lt;/code&gt; something that runs in kernel space (not the &lt;code&gt;cli&lt;/code&gt;, I mean - the actual thing), we could see logs coming out of the kernel;&lt;/li&gt;
&lt;li&gt;writing a minimal kernel module should not be something very hard - many people did that before. I could write a &lt;code&gt;printk(&amp;quot;hello-world&amp;quot;)&lt;/code&gt; and that&amp;rsquo;s it!&lt;/li&gt;
&lt;li&gt;check if there&amp;rsquo;s something simpler that we could use to produce the logs (maybe the Kernel exposes a standard interface for doing that?)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Being this an exploration, why not try all of them?&lt;/p&gt;
&lt;h3 id=&#34;producing-logs-from-iptables&#34;&gt;Producing logs from iptables&lt;/h3&gt;
&lt;p&gt;Although this blog post is not particularly about iptables, we can use it as an example where interacting with something that is going on under the hood deep in the kernel is interesting for a user that sits on userspace.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&#34;https://linux.die.net/man/8/iptables&#34;&gt;&lt;code&gt;iptables&lt;/code&gt; man page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Iptables is used to set up, maintain, and inspect the tables of IP packet filter rules in the Linux kernel. Several different tables may be defined.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These mentioned rules can be either very simple things (drop a packet if it comes from a given source), or some very complicated chain of rules that depend on a bunch of conditionals.&lt;/p&gt;
&lt;p&gt;Acknowledging that it&amp;rsquo;s very useful to be able to visualize the packets that are hitting a specific chain of rules, the &lt;code&gt;LOG&lt;/code&gt; target came to existence.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;LOG: Turn on kernel logging of matching packets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;When this option is set for a rule, the Linux kernel will print some information on all matching packets (like most IP/IPv6 header fields) via the kernel log.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s an example set up that allows us to see that working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# List the current state of the `filter` table.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As we can see below, nothing is set up:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - any packet arriving w/ our machine as the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   destination is accepted;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - any packet arriving that should be forwarded&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   is dropped;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - any packet that is sent from our machine is&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   accepted (can go through).&lt;/span&gt;
iptables --table filter --list
Chain INPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination

Chain FORWARD &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy DROP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination

Chain OUTPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination


&lt;span class=&#34;c1&#34;&gt;# Add a rule to the OUTPUT chain to log every packet&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that is destined towards 8.8.8.8 (google&amp;#39;s public&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# dns) &lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --table filter &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --insert OUTPUT &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --jump LOG &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --destination 8.8.8.8 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --log-prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;[google-dns-out]&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check that the rule has been placed in the OUTPUT &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# chain of the `filter` table&lt;/span&gt;
iptables --table filter --list OUTPUT --numeric
Chain OUTPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target   prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;       destination
LOG      all  --  0.0.0.0/0    8.8.8.8        LOG flags &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; level &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; prefix &lt;span class=&#34;s2&#34;&gt;&amp;#34;[google-dns-out]&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Perform a DNS query targetting 8.8.8.8&lt;/span&gt;
dig example.com @8.8.8.8
... example.com.		18272	IN	A	93.184.216.34

&lt;span class=&#34;c1&#34;&gt;# Verify the request packet in our logs (dmesg)&lt;/span&gt;
dmesg &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep google-dns-out
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;66458.608136&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;google-dns-out&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;enp0s3 &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.2.15 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;8.8.8.8 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TOS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x00 &lt;span class=&#34;nv&#34;&gt;PREC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x00 &lt;span class=&#34;nv&#34;&gt;TTL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;30602&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PROTO&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;UDP &lt;span class=&#34;nv&#34;&gt;SPT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;39573&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DPT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;53&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;producing-logs-from-a-linux-loadable-kernel-module&#34;&gt;Producing logs from a Linux loadable kernel module&lt;/h3&gt;
&lt;p&gt;Not being a driver developer myself (honestly, having never written a kernel module before), it was interesting to look for resources that would teach me how to accomplish this task.&lt;/p&gt;
&lt;p&gt;Based on &lt;a href=&#34;https://linux-kernel-labs.github.io/master/labs/kernel_modules.html&#34;&gt;a guide from The Linux Kernel Labs&lt;/a&gt;, I came up with the following code for a very simple kernel module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `module.h` contains the most basic functionality needed for
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * us to create a loadable kernel module, including the `MODULE_*`
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * macros, `module_*` functions and including a bunch of other
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * relevant headers that provide useful functionality for us
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * (for instance, `printk`, which comes from `linux/printk.h`,
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * a header included by `linux/module.h`).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;linux/module.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Following, we make use of several macros to properly provide
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * information about the kernel module that we&amp;#39;re creating.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * The information supplied here are visible through tools like
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `modinfo`.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Note.: the license you choose here **DOES AFFECT** other things -
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * by using a proprietary license your kernel will be &amp;#34;tainted&amp;#34;.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;MODULE_LICENSE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;GPL&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;MODULE_AUTHOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Ciro S. Costa&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;MODULE_DESCRIPTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;A hello-world printer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;MODULE_VERSION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/** hello_init - initializes the module
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * The `hello_init` method defines the procedures that performs the set up
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * of our module.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;hello_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;c1&#34;&gt;// By making use of `printk` here (in the initialization),
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// we can look at `dmesg` and verify that what we log here
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// appears there at the moment that we load the module with
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// `insmod`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;printk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KERN_INFO&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;HELLO-WORLD: Hello world!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;hello_exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// similar to `init`, but for the removal time.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;printk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KERN_INFO&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;HELLO-WORLD: Bye bye world!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// registers the `hello_init` method as the method to run at module
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// insertion time.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hello_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// similar, but for `removal`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hello_exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;ps.: the source code is available at &lt;a href=&#34;https://github.com/cirocosta/hello-world-lkm&#34;&gt;github.com/cirocosta/hello-world-lkm&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Load the module, and there you go:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;dmesg &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep HELLO-WORLD
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;62076.224353&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; HELLO-WORLD: Hello world!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;producing-logs-from-kmsg&#34;&gt;Producing logs from kmsg&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg&#34;&gt;https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A standard interface that we can use to insert messages into the &lt;code&gt;printk&lt;/code&gt; buffer is exactly the same that we can use to read the messages from it: &lt;code&gt;/dev/kmsg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg&#34;&gt;kernel documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Injecting messages: Every write() to the opened device node places a log entry in
the kernel&amp;rsquo;s printk buffer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is, whatever we &lt;code&gt;echo &amp;quot;haha&amp;quot;&lt;/code&gt; as a single &lt;code&gt;write&lt;/code&gt; to &lt;code&gt;/dev/kmsg&lt;/code&gt; goes into the buffer.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try it then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Generate the message from my current unprivileged&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# user and then pipe to the privileged `tee` which is&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# able to write into `/dev/kmsg` (yep, /dev/kmsg can be&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# see and read, but to write you need more privileges)&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;haha&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee &lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/kmsg&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Check that we can see our message is indeed there:&lt;/span&gt;
dmesg &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep haha
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;67030.010334&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; haha
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;seeing-kernel-logs-from-user-space&#34;&gt;Seeing kernel logs from user space&lt;/h3&gt;
&lt;p&gt;Having already spoiled the blog post by mentioning &lt;code&gt;kmsg&lt;/code&gt; in the section before, there&amp;rsquo;s not a bunch to talk now.&lt;/p&gt;
&lt;p&gt;The kernel provides to us &lt;code&gt;/dev/kmsg&lt;/code&gt; in userspace, a special device that allows us to read from the ring buffer (with multitenancy in mind), and that&amp;rsquo;s what dmesg uses.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Trace the syscalls `openat` and `read` to verify&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that it reads from `/dev/kmsg`&lt;/span&gt;
strace -e openat,read -f dmesg &amp;gt; /dev/null
openat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AT_FDCWD, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/kmsg&amp;#34;&lt;/span&gt;, O_RDONLY&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_NONBLOCK&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, &lt;span class=&#34;s2&#34;&gt;&amp;#34;5,0,0,-;Linux version 4.15.0-34-&amp;#34;&lt;/span&gt;..., 8191&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;192&lt;/span&gt;
read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, &lt;span class=&#34;s2&#34;&gt;&amp;#34;6,1,0,-;Command line: BOOT_IMAGE&amp;#34;&lt;/span&gt;..., 8191&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;142&lt;/span&gt;
read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, &lt;span class=&#34;s2&#34;&gt;&amp;#34;6,2,0,-;KERNEL supported cpus:\n&amp;#34;&lt;/span&gt;, 8191&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;31&lt;/span&gt;
read&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, &lt;span class=&#34;s2&#34;&gt;&amp;#34;6,3,0,-;  Intel GenuineIntel\n&amp;#34;&lt;/span&gt;, 8191&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Going even deeper, whenever a &lt;code&gt;read(2)&lt;/code&gt; syscall is emitted targetting such file, the kernel triggers &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.18.8/source/kernel/printk/printk.c#L823&#34;&gt;&lt;code&gt;kernel/printk/devkmsg_read&lt;/code&gt;&lt;/a&gt; internally, taking a message from the circular queue, formatting it and then sending back to the user.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# We can use `iovisor/bcc#examples/trace/stacknoop.py` to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# gather the stack trace from the execution of `devkmsg_read`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to verify that the `read` gets right there when `vfs_read`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is called.&lt;/span&gt;
./stacksnoop.py -v devkmsg_read
TIME&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;            COMM         PID    CPU FUNCTION
1.875072956        tail         &lt;span class=&#34;m&#34;&gt;1565&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   devkmsg_read
	devkmsg_read
	vfs_read
	sys_read
	do_syscall_64
	entry_SYSCALL_64_after_hwframe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A similar path is followed when writing to the circular queue as well: whenever a &lt;code&gt;write(2)&lt;/code&gt; is issued, at some point &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.18.8/source/kernel/printk/printk.c#L760&#34;&gt;&lt;code&gt;devkmsg_write&lt;/code&gt;&lt;/a&gt; is called.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;devkmsg&lt;/code&gt; translates such call to the equivalent of a &lt;code&gt;printk&lt;/code&gt;, which then takes the path of reaching &lt;code&gt;log_store&lt;/code&gt;, the method that ends up finally taking a free space from the queue and adding the log message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# In one terminal&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;haha&amp;#34;&lt;/span&gt; &amp;gt; /dev/kmsg

&lt;span class=&#34;c1&#34;&gt;# In another terminal&lt;/span&gt;
./stacksnoop.py -v log_store
TIME&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;            COMM         PID    CPU FUNCTION
1.786375046        bash         &lt;span class=&#34;m&#34;&gt;1450&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;   log_store
	log_store
	printk_emit
	devkmsg_write
	new_sync_write
	__vfs_write
	vfs_write
	sys_write
	do_syscall_64
	entry_SYSCALL_64_after_hwframe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By knowing that the kernel provides this interface, we can implement a simple program that constantly performs &lt;code&gt;read(2)&lt;/code&gt;s against such device and then parses the contents (messages) that arrive.&lt;/p&gt;
&lt;h3 id=&#34;interpreting-the-kmsg-messages&#34;&gt;Interpreting the kmsg messages&lt;/h3&gt;
&lt;p&gt;Knowing that every &lt;code&gt;read(2)&lt;/code&gt; syscall performed against &lt;code&gt;/dev/kmsg&lt;/code&gt; returns us a single message, we&amp;rsquo;re left to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;implementing a reader that continuously looks at &lt;code&gt;/dev/kmsg&lt;/code&gt; and then extracts the raw messages from there; as well as&lt;/li&gt;
&lt;li&gt;implementing the parsing of those messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The later is the most interesting, imo.&lt;/p&gt;
&lt;p&gt;Each message comes packed in the following format: a list of comma-separated info fields and a message (these, separated by a semicolon).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//                  INFO		              MSG
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//     .------------------------------------------. .------.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |                                            |        |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |	int	int      int      char, &amp;lt;ignore&amp;gt;   | string |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    prefix,   seq, timestamp_us,flag[,..........];&amp;lt;message&amp;gt;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are four standard fields in the info section, leaving room for other fields in the future.&lt;/p&gt;
&lt;p&gt;From the &lt;code&gt;priority&lt;/code&gt; field, we can extract two pieces of information: priority and facility.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// DecodePrefix extracts both priority and facility from a given
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// syslog(2) encoded prefix.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//	   facility    priority
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      .-----------.  .-----.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      |           |  |     |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//	7  6  5  4  3  2  1  0    bits
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the rest of the fields, we&amp;rsquo;re able to know when the message was produced and what ID does such message carry in the sequence of messages that have been put in the buffer.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in seeing this parsing in the form of actual code, I wrote a Golang implementation that you can check here: &lt;a href=&#34;https://github.com/cirocosta/dmesg_exporter/blob/fc7962f46d304c158f21cc71cf2049af7d183c0a/kmsg/kmsg.go#L178&#34;&gt;github.com/cirocosta/dmesg_exporter/kmsg/kmsg.go&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It was great to have the opportunity of going deep into the stack and verifying how components from the kernel can communicate with userspace applications.&lt;/p&gt;
&lt;p&gt;That led me to create &lt;a href=&#34;https://github.com/cirocosta/dmesg_exporter&#34;&gt;&lt;code&gt;dmesg_exporter&lt;/code&gt;&lt;/a&gt;, a tool for exporting &amp;ldquo;dmesg&amp;rdquo; logs metrics so that people can eventually alert messages marked as &amp;ldquo;critical&amp;rdquo; arriving from a specific facility.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;During the writing of this blog post, I made use of the following book: &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;. Please make sure you check it out! It&amp;rsquo;s definitely one of the best books on Linux out there.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;If you&amp;rsquo;ve had any questions, or have ideas for improvements, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, and I&amp;rsquo;d love to hear from you!&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Sat, 22 Sep 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/dmesg-under-the-hood/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/dmesg-under-the-hood/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Analyzing Tcpdump capture in real-time with Wireshark</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been doing some work in a Linux VM recently, and having to use &lt;a href=&#34;https://linux.die.net/man/1/scp&#34;&gt;secure copy (&lt;code&gt;scp&lt;/code&gt;)&lt;/a&gt; every time just to copy a &lt;a href=&#34;https://www.tcpdump.org/&#34;&gt;tcpdump&lt;/a&gt; capture to my MacOS machine to inspect it with &lt;a href=&#34;https://www.wireshark.org/&#34;&gt;Wireshark&lt;/a&gt; is not very fun.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
        VM                              MACOS

tcpdump --&amp;gt; capture
                                scp linux --&amp;gt; /tmp/capture
                                wireshark /tmp/capture

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Given that Wireshark can inspect packets flowing in real time, what if Wireshark perform the equivalent of a &lt;code&gt;tail -f&lt;/code&gt; operation on a given packet file?&lt;/p&gt;
&lt;p&gt;It turns out that this is possible and pretty simple.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;tl;dr: &lt;code&gt;wireshark -k -i &amp;lt;(tail -f -c +0 $PCAP_FILE)&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#whats-behind-tail&#34;&gt;What&amp;rsquo;s behind &lt;code&gt;tail&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#opening-a-capture-file-with-wireshark&#34;&gt;Opening a capture file with Wireshark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reading-tcpdump-packet-capture-in-realtime-with-wireshark&#34;&gt;Reading tcpdump packet capture in realtime with Wireshark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;whats-behind-tail&#34;&gt;What&amp;rsquo;s behind &lt;code&gt;tail&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;While &lt;code&gt;tail&lt;/code&gt; is pretty much just what it claims to be (a program that outputs the last part of a given fail), it has a pretty neat functionality of being able to &amp;ldquo;follow&amp;rdquo; a file (keep track of its status), and, whenever new things come (content gets appended to it), print to &lt;code&gt;stdout&lt;/code&gt; these additions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;nx&#34;&gt;file_fd&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;txt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;notification_fd&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;inotify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;nf&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;notification_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;tail&lt;/code&gt; initializes &lt;code&gt;inotify&lt;/code&gt; to keep track of changes happening to a file (let&amp;rsquo;s say, &lt;code&gt;file.txt&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;then it waits for a change on the underlying file;&lt;/li&gt;
&lt;li&gt;when the change occurs, &lt;code&gt;tail&lt;/code&gt; then reads all that has not been read so far and then keeps track of the position where it was; then&lt;/li&gt;
&lt;li&gt;when a new change occurs, does the same thing: reads everything from the old position until the end (&lt;code&gt;read(2)&lt;/code&gt; keeps track of the offset under the hood - seeking is only needed at the first time, assuming that arguments like &lt;code&gt;-c&lt;/code&gt; and &lt;code&gt;-n&lt;/code&gt; are specified).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you&amp;rsquo;re curious to see this in practice, you can either check the &lt;a href=&#34;https://github.com/coreutils/coreutils/blob/master/src/tail.c#L1430&#34;&gt;source code&lt;/a&gt; or set up a simple test scenario where you can &lt;code&gt;strace&lt;/code&gt; the execution of &lt;code&gt;tail -f&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;opening-a-capture-file-with-wireshark&#34;&gt;Opening a capture file with Wireshark&lt;/h3&gt;
&lt;p&gt;Having installed &lt;code&gt;Wireshark&lt;/code&gt; on my MacOS using the regular procedure (downloading the package and then performing the regular installation), &lt;code&gt;wireshark&lt;/code&gt; binary should already be in your &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Looking at the help (&lt;code&gt;wireshark --help&lt;/code&gt;), we can see an interesting option to use (&lt;code&gt;-r&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;wireshark --help
Wireshark 2.6.2 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;v2.6.2-0-g1b3cedbc&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
Interactively dump and analyze network traffic.
...

Input file:
  -r &amp;lt;infile&amp;gt;   &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; the filename to &lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt; 
                from &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;no pipes or stdin!&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;reading-tcpdump-packet-capture-in-realtime-with-wireshark&#34;&gt;Reading tcpdump packet capture in realtime with Wireshark&lt;/h3&gt;
&lt;p&gt;While being able to read a packet capture in Wireshark is already interesting by itself, it doesn&amp;rsquo;t solve the problem stated at the beginning of the blog post.&lt;/p&gt;
&lt;p&gt;Ideally, it&amp;rsquo;d be interesting if Wireshark was able to handle the result of a &lt;code&gt;tail -f&lt;/code&gt; that could come to it either via &lt;code&gt;stdin&lt;/code&gt; (we could pipe &lt;code&gt;tail -f&lt;/code&gt; to &lt;code&gt;wireshark&lt;/code&gt;), or via a &lt;a href=&#34;https://www.linuxjournal.com/article/2156&#34;&gt;pipe&lt;/a&gt; (we could provide the pipe to a flag).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while new_packets:
        tcpdump ---&amp;gt;
                /tmp/capture.pcap
                        ------&amp;gt; 
                                wireshark
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Having no success with the first option (supplying stuff via &lt;code&gt;stdin&lt;/code&gt;), I went with the second (supplying a pipe to &lt;code&gt;-r&lt;/code&gt;, the option that makes Wireshark read from a file):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Execute the `wireshark` binary with the result &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of the bash process substitution as the argument &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of `-r`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The process substitution creates a temporary&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# pipe that takes the output of the `tail -f`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process and makes it readable by `wireshark`.&lt;/span&gt;
wireshark &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -r &amp;lt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;tail -f -c +0 /tmp/capture.pcap&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/wireshark-cant-read-pipes.png&#34;
       alt=&#34;Wireshark complaining about file being a pipe &#34; &gt;

    &lt;figcaption class=&#34;img-description&#34;&gt;
        Wireshark not happy with file being a pipe
      &lt;/figcaption&gt;
    
&lt;/figure&gt;

&lt;p&gt;No success, &lt;em&gt;but&lt;/em&gt;, a pretty clear direction: use &lt;code&gt;-i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Replace &lt;code&gt;-r&lt;/code&gt; with &lt;code&gt;-i&lt;/code&gt; and see it &amp;ldquo;not failing&amp;rdquo; (nothing starts):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;wireshark &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -i &amp;lt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;tail -f -c +0 /tmp/capture.pcap&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s because we&amp;rsquo;re missing an extra flag (&lt;code&gt;-k&lt;/code&gt;): the one that tells Wireshark to start capturing the packets right away:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;wireshark &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -k &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -i &amp;lt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;tail -f -c +0 /tmp/capture.pcap&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s great how we can combine something like bash process substitution with a program like Wireshark and achieve a much better result compared to what I had before.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;ve decided to go with a MacbookPro for personal use while I still do a bunch of Linux development, having these tricks under the belt helps a lot.&lt;/p&gt;
&lt;p&gt;Do you have some that you use all the time as well?&lt;/p&gt;
&lt;p&gt;Please let me know!&lt;/p&gt;
&lt;p&gt;By the way, if you want to get in touch, I&amp;rsquo;m very open - reach me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter!&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</description>
                                <pubDate>Sun, 09 Sep 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/tcpdump-to-wireshark-in-realtime/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/tcpdump-to-wireshark-in-realtime/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Passing the results of a command as a file to another script</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Being accustomed to tying together multiple bash programs with the pipe operator, sometimes I&amp;rsquo;ve seen myself not being able to easily do so when a command expected the input to come from a file instead of &lt;code&gt;stdin&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/pipe-to-dirname-fails.svg&#34;
       alt=&#34;Illustration of a pipe to dirname failing &#34; &gt;

    &lt;figcaption class=&#34;img-description&#34;&gt;
        Given that `dirname` doesn&amp;#39;t expect input from `stdin`, piping to it doesn&amp;#39;t work as expected
      &lt;/figcaption&gt;
    
&lt;/figure&gt;

&lt;p&gt;Using process substitution we can make sure that pretty much every command can perform the equivalent of taking contents from standard input.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;tl;dr: &lt;code&gt;dirname &amp;lt;(echo &amp;quot;/var/lib/my/file.txt&amp;quot;)&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#rationale&#34;&gt;Rationale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#example-consuming-from-stdin-using-go&#34;&gt;Example: consuming from &lt;code&gt;stdin&lt;/code&gt; using Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#example-consuming-from-a-file-using-go&#34;&gt;Example: consuming from a file using Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#example-consuming-from-both-a-file-and-stdin-using-go&#34;&gt;Example: consuming from both a file and stdin using Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-process-substitution-to-pass-a-temporary-file-consuming-the-output-of-a-command&#34;&gt;Using process substitution to pass a temporary file consuming the output of a command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;rationale&#34;&gt;Rationale&lt;/h3&gt;
&lt;p&gt;Although it&amp;rsquo;s prevalent for some programs like &lt;a href=&#34;https://stedolan.github.io/jq/&#34;&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt; (the command-line JSON processor) to receive things from its standard input, process them, and then give the response back on the standard output, not every program is made like that.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/jq-common-stdin-stdout.svg&#34;
       alt=&#34;Visualization of JQ taking a JSON input from the standard intput and producing a filter JSON as output &#34; &gt;

    &lt;figcaption class=&#34;img-description&#34;&gt;
        JQ receiving JSON from stdin and procuding a filtered output at stdout
      &lt;/figcaption&gt;
    
&lt;/figure&gt;

&lt;p&gt;Some programs, like &lt;a href=&#34;https://linux.die.net/man/1/dirname&#34;&gt;&lt;code&gt;dirname&lt;/code&gt;&lt;/a&gt;, expect that the input comes as a form of positional argument (others usually expect a flag).&lt;/p&gt;
&lt;p&gt;While that might not look like a big deal, for some use cases where you want to streamline operations between multiple processes, it might feel like you can&amp;rsquo;t easily do that when a file is expected.&lt;/p&gt;
&lt;p&gt;The programmer that created the command line interface for the program needs to be aware that someone might want to use its software in such manner and then code it for that.&lt;/p&gt;
&lt;h3 id=&#34;example-consuming-from-stdin-using-go&#34;&gt;Example: consuming from &lt;code&gt;stdin&lt;/code&gt; using Go&lt;/h3&gt;
&lt;p&gt;For instance, if we&amp;rsquo;re doing a byte counter in &lt;a href=&#34;https://golang.org&#34;&gt;Go&lt;/a&gt;, that&amp;rsquo;s how we&amp;rsquo;d do it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;bufio&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;io&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// maxBufferSize defines the maximum size of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the buffer that we&amp;#39;re creating for temporarily
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// holding the contents of what&amp;#39;s coming from
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// stdin.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxBufferSize&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4096&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;totalRead&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxBufferSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bufio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewReader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stdin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Keep reading in a buffered fashion
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// from `stdin` until an EOF is returned
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// in the form of an error.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// When that happens, output to `stdout`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the total count and exit.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;EOF&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

			&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;nx&#34;&gt;totalRead&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Write the `stdout` the total amount of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// bytes that were read.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;totalRead&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compile the code with a standard &lt;code&gt;go build&lt;/code&gt; and check that it indeed works as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a 1MB file named `./1M`&lt;/span&gt;
dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./1M &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Confirm that we sent 1024*1024 bytes to the file&lt;/span&gt;
ls -lah &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep 1M
-rw-r--r--  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; cirocosta  wheel   1.0M  &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; Sep 21:13 1M


&lt;span class=&#34;c1&#34;&gt;# Check how many bytes are there in this file by&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# running our go code by sending the whole contents&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of the file to the standard input of our command&lt;/span&gt;
cat ./1M &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ./byte-counter
&lt;span class=&#34;m&#34;&gt;1048576&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;example-consuming-from-a-file-using-go&#34;&gt;Example: consuming from a file using Go&lt;/h3&gt;
&lt;p&gt;If we were about to change this code to not take from &lt;code&gt;stdin&lt;/code&gt;, but instead, read from a file, the changes wouldn&amp;rsquo;t be significant: take the filename either from a flag or a positional argument and then read it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/tmp/before b/tmp/after
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index fe7f39c..e4102af 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/tmp/before
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/tmp/after
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -16,8 +16,24 @@ const maxBufferSize = 4096
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt; func main() {
        var totalRead uint64

&lt;span class=&#34;gi&#34;&gt;+       if len(os.Args) &amp;lt; 2 {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               fmt.Fprintln(os.Stderr, &amp;#34;error: not enough arguments&amp;#34;)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               fmt.Fprintln(os.Stderr, &amp;#34;Usage: byte-counter &amp;lt;filename&amp;gt;&amp;#34;)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               os.Exit(1)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       fileName := os.Args[1]
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       // Open the file that the user provided us
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       // with a path. 
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       // Given that `os.Open` returns os.File which 
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       // implements the `io.Reader` interface, we don&amp;#39;t 
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       // need to change the rest of the code.
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       reader, err := os.Open(fileName)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       if err != nil {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               fmt.Fprintln(os.Stderr, err)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               os.Exit(1)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       defer file.Close()
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        buffer := make([]byte, maxBufferSize)
&lt;span class=&#34;gu&#34;&gt;@@ -41,8 +57,5 @@ func main() {
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even better, because it doesn&amp;rsquo;t matter to us what the reader is (the interface only cares about the methods that the implementor implements), we can modify the code very little.&lt;/p&gt;
&lt;h3 id=&#34;example-consuming-from-both-a-file-and-stdin-using-go&#34;&gt;Example: consuming from both a file and stdin using Go&lt;/h3&gt;
&lt;p&gt;We can go even deeper and simplify our reading logic and make it handle both cases - when it should read from a file and when it should read from the standard input:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;io&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;io/ioutil&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// maxBufferSize defines the maximum size of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the buffer that we&amp;#39;re creating for temporarily
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// holding the contents of what&amp;#39;s coming from
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// stdin.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxBufferSize&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4096&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Reader&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;writer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ioutil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Discard&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Make sure that the user always supplies
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// a positional argument to be explcit that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// it either wants to consume the input of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// stdin or a file.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;error: not enough arguments&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Usage: byte-counter (filename|-)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stdin&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Use the `io.Copy` method to read the contents
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// of the file into a temporary buffer and then
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// write those to the discard facility (/dev/null).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Naturally, there&amp;#39;s no need for the `write` part,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// but this simplifies our code.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;writer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fprintln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Write the `stdout` the total amount of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// bytes that were read.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that for &lt;a href=&#34;https://golang.org/pkg/io/#Copy&#34;&gt;&lt;code&gt;io.Copy&lt;/code&gt;&lt;/a&gt; all that matters is something that implements the &lt;code&gt;io.Reader&lt;/code&gt; interface (and well, both &lt;code&gt;stdin&lt;/code&gt; and a file can be referred by a file descriptor in Linux anyway - pretty close semantics), we can use both &lt;code&gt;os.Stdin&lt;/code&gt; and the &lt;code&gt;os.File&lt;/code&gt; interchangeably with &lt;code&gt;io.Copy&lt;/code&gt;. Neat!&lt;/p&gt;
&lt;h3 id=&#34;using-process-substitution-to-pass-a-temporary-file-consuming-the-output-of-a-command&#34;&gt;Using process substitution to pass a temporary file consuming the output of a command&lt;/h3&gt;
&lt;p&gt;While it&amp;rsquo;s pretty well known that bash can interpolate the results of the execution of a given command (like, &lt;code&gt;echo $(date)&lt;/code&gt; becomes &lt;code&gt;echo Sun 9 Sep 2018 20:53:41 EDT&lt;/code&gt;), it is also capable of interpolating the execution of a command with a named pipe (see the article &lt;a href=&#34;https://www.linuxjournal.com/article/2156&#34;&gt;Introduction to Named Pipes&lt;/a&gt; for some great info about what pipes are).&lt;/p&gt;
&lt;p&gt;Here is where &lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html&#34;&gt;process substitution&lt;/a&gt; comes in place.&lt;/p&gt;
&lt;p&gt;Whenever bash spots the &lt;code&gt;&amp;lt;(cmd)&lt;/code&gt; operator, it runs the given &lt;code&gt;cmd&lt;/code&gt; and then makes its standard output be connected to a temporary named pipe that it creates.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dirname &amp;lt;(echo &amp;quot;/var/lib/my/file.txt&amp;quot;)
                |
                *-----&amp;gt; 1. creates a named pipe under /dev/fd/&amp;lt;number&amp;gt;
                *-----&amp;gt; 2. substitutes the execution by the file path

                        dirname /dev/fd/&amp;lt;number&amp;gt;

                        *---&amp;gt; executes the `dirname` command
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The interpolation then substitutes such syntax by the path to this temporary file and now whatever program you&amp;rsquo;re running is capable of reading from this temporary file!&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;ps&lt;/em&gt;: the resulting temporary file is &lt;strong&gt;not&lt;/strong&gt; a regular file.&lt;/p&gt;
&lt;p&gt;If the command you&amp;rsquo;re supplying this named pipe to checks if the file is a regular file, the entire operation might fail (as the file types are different).&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Having a little bit of extra knowledge about some capabilities of bash is definitely handy.&lt;/p&gt;
&lt;p&gt;I really hope I enjoyed this quick bash tip tied with a bit of Go as well.&lt;/p&gt;
&lt;p&gt;Please let me know if you have any questions or additions! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter and would love your feedback!&lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;Ciro&lt;/p&gt;
</description>
                                <pubDate>Sun, 09 Sep 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/bash-process-substitution/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/bash-process-substitution/</guid>

                                
                                        <category>programming</category>
                                
                                        <category>shell</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Measuring HTTP response times with cURL</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Oftentimes I see myself needing to check response times while making a bunch of requests quickly. Most of the tools out there either do not continuously make new requests (via an entirely new TCP connection) or don&amp;rsquo;t expose connection times.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/httpstat.png&#34;
       alt=&#34;Snapshot of the HTTPSTAT tool showing the request times &#34; &gt;

    &lt;figcaption class=&#34;img-description&#34;&gt;
        Snapshot of the `httpstat` tool
      &lt;/figcaption&gt;
    
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/davecheney/httpstat&#34;&gt;&lt;code&gt;httpstat&lt;/code&gt;&lt;/a&gt; is a great tool that does the job really well. It&amp;rsquo;s a single binary that you can put under your &lt;code&gt;$PATH&lt;/code&gt; and have nice stats, but it&amp;rsquo;s yet another tool, and you might just be inside a container (or maybe a sealed environment?) and want to check response times quickly.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; comes very handy when needing to have an easy way of displaying response times. Tied with a little of shell scripting, you can even create a comma-separated values output that allows you to see how it changes over time.&lt;/p&gt;
&lt;h3 id=&#34;discovering-the-right-curl-flags&#34;&gt;Discovering the right curl flags&lt;/h3&gt;
&lt;p&gt;Looking at &lt;code&gt;man curl&lt;/code&gt; (&lt;code&gt;curl&lt;/code&gt;&amp;rsquo;s &lt;code&gt;man&lt;/code&gt; page), we can see that there&amp;rsquo;s an interesting flag named &lt;code&gt;--write-out&lt;/code&gt; that we can leverage to gather further insights about the connection:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-w, --write-out &amp;lt;format&amp;gt;
        Make curl display information on stdout 
        after a completed transfer. 
        
        The format is a string that may contain plain 
        text mixed with any  number  of  variables.

        The variables present in the output format will 
        be substituted by the value or text that curl 
        thinks fit, as described below. 
        
        All variables are specified  as %{variable_name}.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What are these variables? Let&amp;rsquo;s see some of them:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_code           The  numerical  response  code that was found 
                    in the last retrieved HTTP(S) or FTP(s) transfer.

time_appconnect     The time, in seconds, it took from the start until 
                    the SSL/SSH/etc connect/handshake to the remote host 
                    was completed.

time_connect        The time, in seconds, it took from the start until 
                    the TCP connect to the remote host (or proxy) was 
                    completed.

time_namelookup     The time, in seconds, it took from the start until the name 
                    resolving was completed.

time_pretransfer    The time, in seconds, it took from the start until the 
                    file transfer was just about to begin.

time_starttransfer  The time, in seconds, it took from the start until the first 
                    byte was just about to be transferred.

time_total          The total time, in seconds, that the full operation lasted.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Knowing those variables, it becomes a matter of creating a format (a template) to pass to the &lt;code&gt;--write-out&lt;/code&gt; flag specifying which variables we want to see.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check out how much time it&amp;#39;s going to take for the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# name resolution to happen.&lt;/span&gt;
curl --write-out &lt;span class=&#34;s1&#34;&gt;&amp;#39;%{time_namelookup}&amp;#39;&lt;/span&gt; https://google.com
&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;content-type&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;text/html;charset=utf-8&amp;#34;&lt;/span&gt;&amp;gt;
&amp;lt;TITLE&amp;gt;301 Moved&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;
&amp;lt;H1&amp;gt;301 Moved&amp;lt;/H1&amp;gt;
The document has moved
&amp;lt;A &lt;span class=&#34;nv&#34;&gt;HREF&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.google.com/&amp;#34;&lt;/span&gt;&amp;gt;here&amp;lt;/A&amp;gt;.
&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;
0.068856
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that it took &lt;code&gt;0.06&lt;/code&gt; seconds, but it also contains some information there that doesn&amp;rsquo;t really matter for me - if all we want is the timing information, why get all that information from the body?&lt;/p&gt;
&lt;p&gt;We can get rid of that by telling &lt;code&gt;curl&lt;/code&gt; to send the body to the &lt;a href=&#34;https://en.wikipedia.org/wiki/Null_device&#34;&gt;&lt;code&gt;null&lt;/code&gt; device&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#  -o, --output &amp;lt;file&amp;gt; Write output to &amp;lt;file&amp;gt; instead of stdout&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --output /dev/null &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --write-out &lt;span class=&#34;s1&#34;&gt;&amp;#39;%{time_namelookup}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        https://google.com
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
&lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;220&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;220&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;462&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; --:--:-- --:--:-- --:--:--   &lt;span class=&#34;m&#34;&gt;462&lt;/span&gt;
0.069249
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, we still have some stuff left - there are these extra header lines that tells us &lt;code&gt;curl&lt;/code&gt;&amp;rsquo;s progress.&lt;/p&gt;
&lt;p&gt;Fortunately, we can get rid of that too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# -s, --silent&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Silent  or  quiet  mode.  &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Don&amp;#39;t  show progress meter or error messages.  &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Makes Curl mute. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# It will still output the data you ask for.&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --output /dev/null &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --write-out &lt;span class=&#34;s1&#34;&gt;&amp;#39;%{time_namelookup}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        https://google.com
0.004344
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cool, now that we have the information we want, let&amp;rsquo;s tailor a script retrieves all the information needed.&lt;/p&gt;
&lt;h3 id=&#34;a-snippet-for-printing-a-csv-of-response-times-using-curl&#34;&gt;A snippet for printing a CSV of response times using CURL&lt;/h3&gt;
&lt;p&gt;Knowing how the command looks like, now it&amp;rsquo;s a matter of creating a better defined templated and let it run for &lt;code&gt;n&lt;/code&gt; times:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Set the `errexit` option to make sure that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# if one command fails, all the script execution&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# will also fail (see `man bash` for more &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# information on the options that you can set).&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;c1&#34;&gt;# This is the main routine of our bash program.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# It makes sure that we&amp;#39;ve supplied the necessary&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# arguments, then it prints a CSV header and then&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# keeps making requests and printing their responses.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Note.: because we&amp;#39;re calling `curl` each time in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        the loop, a new `curl` process is created for &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        each request. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        This means that a new connection will be made &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        each time.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        Such property might be useful when you&amp;#39;re testing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        if a given load-balancer in the middle might be&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#        messing up with some requests.&lt;/span&gt;
main &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -z &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$url&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ERROR:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  An URL must be provided.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Usage: check-res &amp;lt;url&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Aborting.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    &amp;#34;&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

  print_header
  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 10000&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    make_request &lt;span class=&#34;nv&#34;&gt;$url&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# This method does nothing more that just print a CSV&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# header to STDOUT so we can consume that later when&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# looking at the results.&lt;/span&gt;
print_header &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;code,time_total,time_connect,time_appconnect,time_starttransfer&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Make request performs the actual request using `curl`. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# It specifies those parameters that we&amp;#39;ve defined before,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# taking a given `url` as its parameter.&lt;/span&gt;
make_request &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --write-out &lt;span class=&#34;s2&#34;&gt;&amp;#34;%{http_code},%{time_total},%{time_connect},%{time_appconnect},%{time_starttransfer}\n&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --output /dev/null &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$url&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Trying it out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;./check-res https://google.com
code,time_total,time_connect,time_appconnect,time_starttransfer
301,0.469397,0.125566,0.292027,0.469221
301,0.380109,0.049464,0.204842,0.379735
301,0.389428,0.048424,0.208052,0.389043
301,0.731204,0.047314,0.547336,0.730819
301,0.379709,0.048266,0.205082,0.379577
301,0.384067,0.048614,0.211338,0.383765
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;While there are tools out there that are able to do this, it&amp;rsquo;s very useful to have some options to quickly test out when you&amp;rsquo;re in the middle of an on-call.&lt;/p&gt;
&lt;p&gt;I hope this article was useful for you! If you have any questions or just want to chat a bit, I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m planning to post some other articles regarding useful shell scripts that I use, so make sure you also subscribe to the mailing list to get updates on that topic.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ciro&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 17 Jul 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/measuring-http-response-times-curl/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/measuring-http-response-times-curl/</guid>

                                
                                        <category>shell</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How to minify and bundle assets using Hugo</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Hugo v0.43 just got released today (see &lt;a href=&#34;https://github.com/gohugoio/hugo/releases/tag/v0.43&#34;&gt;the GitHub Releases page&lt;/a&gt; for Download links and notes about all that&amp;rsquo;s included in v0.43) with great news!&lt;/p&gt;
&lt;p&gt;From my point of view, the most significant feature in this release (as noted in the &lt;code&gt;gohugo.io&lt;/code&gt; website) is the introduction of the asset pipeline (&lt;code&gt;Hugo Pipes&lt;/code&gt;), a way of allowing the user to specify transformations to be applied to assets (&lt;code&gt;css&lt;/code&gt;, &lt;code&gt;javascript&lt;/code&gt;, &lt;code&gt;svg&lt;/code&gt; and more) right from the template.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/hugo-asset-pipeline.svg&#34;
       alt=&#34;Illustration of Hugo&amp;#39;s asset pipeline &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The &lt;em&gt;tl;dr&lt;/em&gt; is illustrated in the &lt;a href=&#34;https://gohugo.io/news/0.43-relnotes/&#34;&gt;release docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$styles&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Get&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;scss/main.scss&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;toCSS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;postCSS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minify&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fingerprint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;link&lt;/span&gt;   &lt;span class=&#34;na&#34;&gt;rel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; 
        &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$styles&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Permalink&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt; 
        &lt;span class=&#34;na&#34;&gt;integrity&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$styles&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Data.Integrity&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt; 
        &lt;span class=&#34;na&#34;&gt;media&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;screen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As I was in the middle of refactoring this blog&amp;rsquo;s template to better support &lt;a href=&#34;https://www.ampproject.org&#34;&gt;Accelerated Mobile Pages Project (AMP)&lt;/a&gt;, this release came just in time.&lt;/p&gt;
&lt;p&gt;You can check why this is useful for AMP below, but first, some intro.&lt;/p&gt;
&lt;h3 id=&#34;whats-minification-all-about&#34;&gt;What&amp;rsquo;s minification all about?&lt;/h3&gt;
&lt;p&gt;Although we usually code for humans (hopefully), placing a great deal of space between elements, adding comments and making either function names or variables verbose, the browser doesn&amp;rsquo;t really care about all of that.&lt;/p&gt;
&lt;p&gt;For instance, consider the following Javascript file (491 bytes):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// maybeRemoveTrailingSlash - removes the trailing slash (`/`) 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// of a given string if it has one. Otherwise, nothing is done.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maybeRemoveTrailingSlash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
   &lt;span class=&#34;c1&#34;&gt;// Perform an early termination if it doesn&amp;#39;t match
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// the type of string that we&amp;#39;re looking for.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;   &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;endsWith&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;// Remove the last character.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substring&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;maybeRemoveTrailingSlash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;maybeRemoveTrailingSlash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we consider the fact that every byte that you add in a given file needs to shipped via an unreliable network (that might be very expensive for the user in the case of Mobile phones), that&amp;rsquo;s us requiring our customers to not only wait longer, but pay more to get our content.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/hugo-minifying.svg&#34;
       alt=&#34;Illustration of the minification process &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;By minifying our assets we can remove all that&amp;rsquo;s needed for a human to understand the code (thus, effectively reducing its size), while still maintaining its semantics.&lt;/p&gt;
&lt;p&gt;The code above could then become something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Minified - 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)=&amp;gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;endsWith&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substring&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a reduction from 491 bytes to 85 bytes!&lt;/p&gt;
&lt;h3 id=&#34;what-about-bundling&#34;&gt;What about bundling?&lt;/h3&gt;
&lt;p&gt;Bundling allows us to take a series of files (for instance, &lt;code&gt;base.css&lt;/code&gt; which specifies the base styling of our website, and &lt;code&gt;syntax.css&lt;/code&gt;, which specifies coloring for
of &lt;code&gt;pre&lt;/code&gt; blocks) and concatenate them all such that the end result is a single file.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/hugo-bundling.svg&#34;
       alt=&#34;Illustration of the bundling (concatenation) process &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Although nowadays that&amp;rsquo;s a practice that is not very useful anymore in many cases (see &lt;a href=&#34;https://css-tricks.com/musings-on-http2-and-bundling/&#34;&gt;Musings on HTTP/2 and Bundling&lt;/a&gt;), there&amp;rsquo;s still AMP forcing us to adhere to such practices - all custom styles &lt;strong&gt;must&lt;/strong&gt; be defined in the &lt;code&gt;head&lt;/code&gt; section of the page within an &lt;code&gt;&amp;lt;style amp-custom&amp;gt;&lt;/code&gt; element (see &lt;a href=&#34;https://www.ampproject.org/docs/design/responsive/style_pages#disallowed-styles&#34;&gt;AMP - Supported CSS&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Hugo Pipes comes &lt;em&gt;very&lt;/em&gt; handy for this.&lt;/p&gt;
&lt;h3 id=&#34;the-asset-bundling-and-minification-pipeline&#34;&gt;The asset bundling and minification pipeline&lt;/h3&gt;
&lt;p&gt;Knowing that we have those two primitives to build our asset pipeline upon, we can go ahead and actually put it into code.&lt;/p&gt;
&lt;p&gt;Having my &lt;code&gt;_default/single.html&lt;/code&gt; (the template that defines the page of a single article) defined like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;prefix&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;og: http://ogp.me/ns# article: http://ogp.me/ns/article#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;content/single/base_head.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;content/single/ld.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;article&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;content/single/main.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;footer.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;style.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;  &lt;span class=&#34;c&#34;&gt;&amp;lt;!-- THIS IS WHERE I&amp;#39;LL USE HUGO PIPES --&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;tracking.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can then move on and define that partial (&lt;code&gt;partials/style.html&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$cssOpts&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dict&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;targetPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;styles/syntax.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Get&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;css/index.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$syntax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Get&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;css/syntax.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$style&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;slice&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$syntax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Concat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bundle.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minify&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fingerprint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;link&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;rel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;
      &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$style&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Permalink&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;
      &lt;span class=&#34;na&#34;&gt;integrity&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$style&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Data.Integrity&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: the snippet above is horizontally scrollable.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once an article gets rendered, that &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element becomes what you might expect:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;link&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;rel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;
      &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;https://ops.tips/bundle.min.e838f1fc0247d7eff52385847b5a86ec8747ed58aeeb35d32f8c22926256d7ec.css&amp;#34;&lt;/span&gt;
      &lt;span class=&#34;na&#34;&gt;integrity&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sha256-6Djx/AJH1&amp;amp;#43;/1I4WEe1qG7IdH7Viu6zXTL4wikmJW1&amp;amp;#43;w=&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: you can check this out by prepending &lt;code&gt;view-source:&lt;/code&gt; to this article page and go to the end of the page if you&amp;rsquo;re using Chrome.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;making-the-minified-bundle-amp-ready&#34;&gt;Making the minified bundle AMP ready&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re into AMP though, you know that what we did above doesn&amp;rsquo;t provide a valid AMP page.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because you can&amp;rsquo;t make use of &lt;code&gt;link&lt;/code&gt; elements unless it&amp;rsquo;s for specifying a custom font resource. We &lt;strong&gt;have&lt;/strong&gt; to put the CSS code in the &lt;code&gt;html&lt;/code&gt; file in the &lt;code&gt;head&lt;/code&gt; section inside a &lt;code&gt;style&lt;/code&gt; element. Period.&lt;/p&gt;
&lt;p&gt;To do that, I make use of Hugo&amp;rsquo;s &lt;a href=&#34;https://gohugo.io/templates/output-formats/&#34;&gt;Custom Output Formats&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just like I have a &lt;code&gt;_default/single.html&lt;/code&gt; template, I create an extra &lt;code&gt;_default/single.amp.html&lt;/code&gt;, in which I can then specify a different partial: &lt;code&gt;style.amp.html&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;amp&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;prefix&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;og: http://ogp.me/ns# article: http://ogp.me/ns/article#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;content/single/base_head.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;content/single/ld.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;amp-boilerplate.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;style.amp.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;  &lt;span class=&#34;c&#34;&gt;&amp;lt;!-- HERE&amp;#39;S THE STYLE PARTIAL --&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;article&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;content/single/main.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;footer.amp.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
    &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;tracking.amp.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Properly placed in the &lt;code&gt;head&lt;/code&gt; as AMP mandates, we then implement the partial:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$cssOpts&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dict&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;targetPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;styles/syntax.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Get&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;css/index.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$syntax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Get&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;css/syntax.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$style&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;slice&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$syntax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resources&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Concat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bundle.css&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minify&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;style&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;amp-custom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;$style&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Content&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;safeCSS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;style&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Said and done, now we have inlined bundled and minified CSS for our AMP pages:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/hugo-minify-amp.png&#34;
       alt=&#34;Evidence of Hugo minifying the CSS contents in the AMP page &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Being a Hugo user for not a long time (since I started this blog in November 2017), Hugo has always been a piece of cake to deal with, allowing me to have my blog up and running without knowing a lot about it while still providing me a great deal of value as I learn more and more.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m delighted that this new release as it removes complexity - while you needed to do those optimizations and further templating yourself before, now it&amp;rsquo;s even easier (my &lt;code&gt;Makefile&lt;/code&gt; just sent a &lt;em&gt;Thanks&lt;/em&gt;&amp;quot;).&lt;/p&gt;
&lt;p&gt;If you have any questions or found something weird here, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;In case you want to receive updates about content like this, make sure you subscribe to the mailing list.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ciro&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 09 Jul 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/minifying-and-bundling-assets-using-hugo/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/minifying-and-bundling-assets-using-hugo/</guid>

                                
                                        <category>go</category>
                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Blog Archive</title>
                                <description></description>
                                <pubDate>Fri, 06 Jul 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Gists</title>
                                <description>&lt;p&gt;Differently from the &lt;a href=&#34;https://ops.tips/blog&#34;&gt;blog posts&lt;/a&gt;, these are smaller posts which are usually more direct; not a lot of plain-text explanation - more code.&lt;/p&gt;
</description>
                                <pubDate>Fri, 06 Jul 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Shell: replacing a variable with the contents of a file</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been trying to improve the &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; template that I created for this blog, and one of the things I wanted to do was inject the contents of an &lt;code&gt;index.css&lt;/code&gt; file into a &lt;code&gt;index.amp.html&lt;/code&gt; layout file - &lt;a href=&#34;https://www.ampproject.org/&#34;&gt;Accelerated Mobile Pages (AMP)&lt;/a&gt; requires us to have our custom styles inlined in the HTML (see &lt;a href=&#34;https://www.ampproject.org/docs/design/responsive/style_pages&#34;&gt;Custom Amp Styles&lt;/a&gt;).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/awk-templater-idea.svg&#34;
       alt=&#34;Illustration of the AWK templating &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Here I go through a way of achieving that - using &lt;code&gt;awk&lt;/code&gt; - and a way of &lt;strong&gt;not&lt;/strong&gt; achieving that - using &lt;code&gt;sed&lt;/code&gt; (naively).&lt;/p&gt;
&lt;p&gt;If you ever need to template a file with contents of another, this gist is for you.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: yes, with Hugo you could use &lt;a href=&#34;https://gohugo.io/templates/partials/&#34;&gt;partials&lt;/a&gt;, but let&amp;rsquo;s say you want to just have some sort of poor man&amp;rsquo;s templating engine.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you want to skip the introduction, &lt;a href=&#34;#moving-on-using-awk-to-template-the-file&#34;&gt;jump to the awk section&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;getting-started-with-the-naive-way---sed-without-escapeing&#34;&gt;Getting started with the naive way - sed without escapeing&lt;/h3&gt;
&lt;p&gt;Knowing that &lt;code&gt;sed&lt;/code&gt; is all about performing substitions, it was the first tool I tried.&lt;/p&gt;
&lt;p&gt;Unfortunatelly, it didn&amp;rsquo;t work as I expected.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the file that contains the contents that we want&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to insert into another file at a specific location.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;xxxxxxx
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;yyyyyyy
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;zzzzzzz&amp;#39;&lt;/span&gt; &amp;gt; ./content.txt

&lt;span class=&#34;c1&#34;&gt;# Create the template that we want to have the variable&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# substitution.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;11111111
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;22222222
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;__REPLACE_ME__
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;33333333&amp;#39;&lt;/span&gt; &amp;gt; ./template.txt


&lt;span class=&#34;c1&#34;&gt;# Perform the substituion of `__REPLACE_ME__` by a single&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# string just to test the `sed` syntax.&lt;/span&gt;
sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s/__REPLACE_ME__/SOMETHING_NEW/g&amp;#39;&lt;/span&gt; ./template.txt
&lt;span class=&#34;m&#34;&gt;11111111&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;22222222&lt;/span&gt;
SOMETHING_NEW
&lt;span class=&#34;m&#34;&gt;33333333&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Well, if it worked for that simple case, why not just &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# replace `SOMETHING_NEW&amp;#39; by all the contents of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# file? We can get that via `cat` anyway:&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;CONTENT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;cat ./content.txt&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
sed &lt;span class=&#34;s2&#34;&gt;&amp;#34;s/__REPLACE_ME__/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$CONTENT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/g&amp;#34;&lt;/span&gt; ./template.txt

sed: 1: &lt;span class=&#34;s2&#34;&gt;&amp;#34;s/__REPLACE_ME__/xxxxxxx
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; ...&amp;#34;&lt;/span&gt;: unescaped newline inside substitute pattern
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see, that doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;The main reason is that the command was not properly formatted - there are newlines not being escaped when we perform the substitution.&lt;/p&gt;
&lt;p&gt;That happens because &lt;code&gt;bash&lt;/code&gt; is performing a simple text substitution when we specify &lt;code&gt;$CONTENT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To see that working, make use of the &lt;code&gt;xtrace&lt;/code&gt; option invoking &lt;code&gt;bash&lt;/code&gt; directly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# By invoking bash with the `-x` flag, we enable the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `xtrace` option (which is usually added to scripts&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# when debugging by specifying `set -o xtrace` or&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `set -x`).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The options has the effect of expanding every command&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and variables that are supplied to it.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This way, we&amp;#39;re able to see what bash used as the full&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# command after substituting the $CONTENT variable.&lt;/span&gt;
/bin/bash -x -c &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;sed \&amp;#34;s/__REPLACE_ME__/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$CONTENT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/g\&amp;#34; ./template.txt&amp;#34;&lt;/span&gt;

+ sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s/__REPLACE_ME__/xxxxxxx
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;yyyyyyy
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;zzzzzzz/g&amp;#39;&lt;/span&gt; ./template.txt
sed: 1: &lt;span class=&#34;s2&#34;&gt;&amp;#34;s/__REPLACE_ME__/xxxxxx ...&amp;#34;&lt;/span&gt;: 
unescaped newline inside substitute pattern
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Knowing that, we can either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;escape the newlines before supplying &lt;code&gt;$CONTENT&lt;/code&gt; to &lt;code&gt;sed&lt;/code&gt;; or&lt;/li&gt;
&lt;li&gt;make use of something that has greater flexibility (like &lt;code&gt;awk&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With &lt;code&gt;1&lt;/code&gt;, it means that we&amp;rsquo;d need to get into regular expressions and some fancy &lt;code&gt;sed&lt;/code&gt; syntax (see &lt;a href=&#34;https://stackoverflow.com/a/1252191/2178180&#34;&gt;this stackoverflow answer&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;2&lt;/code&gt;, we can create a little program that we can be very verbose about what&amp;rsquo;s doing and make the whole process pretty explicity. I&amp;rsquo;ll go with this one.&lt;/p&gt;
&lt;h3 id=&#34;moving-on---using-awk-to-template-the-file&#34;&gt;Moving on - using AWK to template the file&lt;/h3&gt;
&lt;p&gt;AWK (just like &lt;code&gt;sed&lt;/code&gt;) is a pretty ubiquotous tool in Unix systems, meaning that you can find it everywhere.&lt;/p&gt;
&lt;p&gt;It allows you to create data-driven programs where given a set of rules, actions are performed whenever a match happens.&lt;/p&gt;
&lt;p&gt;By taking data from files (either &lt;code&gt;stdin&lt;/code&gt; or regular files supplied via arguments), &lt;code&gt;awk&lt;/code&gt; contiguously checks whether your matchers match and then it so, proceeds with the action specified.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/awk-processing-pipeline.svg&#34;
       alt=&#34;Illustration of the AWK processing pipeline &#34; &gt;

    
&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;The &lt;code&gt;awk&lt;/code&gt; utility interprets a special-purpose programming language that makes it easy to handle simple data-reformatting jobs.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;The basic function of awk is to search files for lines (or other units of text) that contain certain patterns.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/gawk/manual/gawk.html&#34;&gt;— The GNU Awk User’s Guide&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given that, we can start modelling a solution for our problem in terms of matches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;we definitely want to match &lt;code&gt;__REPLACE_ME__&lt;/code&gt; at a given point; and&lt;/li&gt;
&lt;li&gt;we certainly want to match lines those lines that are not meant to be replaced and just printed to &lt;code&gt;stdout&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can also model it in terms of actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;we want to replace the &lt;code&gt;__REPLACE_ME__&lt;/code&gt; tag; and&lt;/li&gt;
&lt;li&gt;we want to just print to the standard output what doesn&amp;rsquo;t match the &lt;code&gt;__REPLACE_ME__&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, it&amp;rsquo;s a matter of adhering to the &lt;code&gt;awk&lt;/code&gt; specifics and implementing it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;note.: because &lt;code&gt;awk&lt;/code&gt; gives us a fully featured programming language, here I include parameter validation and the ability for the user to specify the pattern that (s)he wants to replace by using an environment variable (&lt;code&gt;PATTERN&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-awk&#34; data-lang=&#34;awk&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/usr/bin/awk -f&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# templater - takes a file and replaces a variable&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in a given template with the contents of another file.&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# err() - Prints a supplied `text` to standard error.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# @text: Text to be printed to stderr.&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;kr&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/stderr&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# The BEGIN matcher is a special type of matcher that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# gets executed whenever the AWK program is starting&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and no records have been matched yet.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;BEGIN&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;ARGC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Error: not enough arguments.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Usage: ./templater &amp;lt;content_file&amp;gt; &amp;lt;template_file&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Aborting.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;ENVIRON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PATTERN&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Error: no pattern specified.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Specify a pattern via the `PATTERN` environment variable.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;For example: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;  PATTERN=__CONTENT__ templater contents.txt template.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Aborting.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# By using the `NR=FNR` pattern we&amp;#39;re able to specify&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# an action that we want to perform only on the first&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# file that we supply via the command line.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# FNR is a counter that keeps track of the current line&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the current file that is being processed.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# NR is a counter that keeps track of the total number&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of lines that have been processed so far.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By trying to match `NR==FNR` we can perform an action&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the very first file. To visualize that, we can set&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# up an experiment:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $ cat file1&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       b&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       c&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $ cat file2&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       d&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       e&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $ awk &amp;#39;{print FILENAME, NR, FNR, $0}&amp;#39; file1 file2&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       file1 1 1 a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       file1 2 2 b&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       file1 3 3 c&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       file2 4 1 d -&amp;gt; not equal -&amp;gt; starts the second one&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       file2 5 2 e -&amp;gt; not equal&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# In the action we can then store all the lines from&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the first file in memory so that we can use it later&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# when we find the string to replace.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By specifying the `next` statement, no further matching&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is performed for this record (line).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: we could also check `FILENAME`, like:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       FILENAME==ARGV[1]&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;NR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;FNR&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;content_lines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=$&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Once we find the string to replace, we iterate over&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# all the lines that we stored (from the first file)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and then once we&amp;#39;re done, we force AWK to immediately&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# stop processing the current record so that it doesn&amp;#39;t&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# print `__CONTENT__` and don&amp;#39;t proceed with performing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# further matches for this record (line).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: if you didn&amp;#39;t want to take a variable here, for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instance, have a fixed pattern to replace, you could&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# simply use `/PATTERN/ { ... }`.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;~&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;ENVIRON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PATTERN&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;kr&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content_lines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;next&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Given that 1 always evaluates to `true`, this is a match&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that will always occur.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As we can either omit an action or a match (not both!),&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can use a catch-all match (1) and let awk use the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# default action (print current line).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This has the effect of printing all lines that didn&amp;#39;t&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# match the other matches that we specified above.&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we&amp;rsquo;re already specifying the interpreter directive (&lt;code&gt;#!/usr/bin/awk -f&lt;/code&gt;), we can execute the program by making it executable and then feeding some data to it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Make it executable&lt;/span&gt;
chmod +x ./templater.awk

&lt;span class=&#34;c1&#34;&gt;# Execute it passing the necessary arguments&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;PATTERN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;__REPLACE_ME__ &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./templater.awk &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        content.txt &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        template.txt
&lt;span class=&#34;m&#34;&gt;11111111&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;22222222&lt;/span&gt;
xxxxxxx
yyyyyyy
zzzzzzz
&lt;span class=&#34;m&#34;&gt;33333333&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Using `-` as the `template.txt` argument&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and feeding its `stdin` also works:&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PATTERN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;__REPLACE_ME__
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;this is
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;very cool
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;__REPLACE_ME__
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;right?&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ./templater.awk &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        content.txt &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -
this is
very cool
xxxxxxx
yyyyyyy
zzzzzzz
right?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Although I&amp;rsquo;ve copied and pasted AWK snippets now and then, I&amp;rsquo;ve never really understood the intrisics of them.&lt;/p&gt;
&lt;p&gt;Now, going through its documentation, it feels like I have so much more power when it comes to processing text in the terminal.&lt;/p&gt;
&lt;p&gt;I hope you feel that way too! If you&amp;rsquo;re willing to know more, make sure you check out the &lt;a href=&#34;https://www.gnu.org/software/gawk/manual/html_node&#34;&gt;&lt;code&gt;gawk&lt;/code&gt; manual&lt;/a&gt;. There you have multiple examples and it&amp;rsquo;s also very detailed.&lt;/p&gt;
&lt;p&gt;If you have any questions or just want to make contact, feel free to reach me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Thu, 05 Jul 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/shell-replacing-variable-by-file-content/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/shell-replacing-variable-by-file-content/</guid>

                                
                                        <category>shell</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Developing eBPF code with autocompletion support</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Some days ago I wrote about &lt;a href=&#34;https://ops.tips/gists/navigating-the-linux-kernel-source-with-youcompleteme/&#34;&gt;how you can configure YouCompleteMe to navigate the Linux source code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One great benefit of going through such setup is that it showed me how I could use the very same concepts to develop &lt;a href=&#34;https://www.iovisor.org/technology/ebpf&#34;&gt;eBPF&lt;/a&gt; code better by leveraging autocompletion and jumps to definitions and declarations.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/map-lookup-autocomplete.png&#34;
       alt=&#34;Example of YouCompleteMe searching available structure fields &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;While it&amp;rsquo;s common for people to just embed their eBPF code directly into Python scripts, I find such approach very hard to debug (not being very accustomed to Kernel stuff).&lt;/p&gt;
&lt;p&gt;Given that not all eBPF code targets the same subsystems in the Kernel, some peculiarities arise when trying to provide proper autocompletion.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: I&amp;rsquo;m still learning these things!&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;autocompleting-ebpf-compiled-via-clang-without-bcc&#34;&gt;Autocompleting eBPF compiled via Clang without BCC&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re performing the builds yourself (calling &lt;code&gt;clang&lt;/code&gt; with the &lt;code&gt;bpf&lt;/code&gt; backend specified via &lt;code&gt;-target bpf&lt;/code&gt;), nothing more than a basic &lt;code&gt;.ycm_extra_conf.py&lt;/code&gt; like showed in the &lt;a href=&#34;https://ops.tips/gists/navigating-the-linux-kernel-source-with-youcompleteme/&#34;&gt;article mentioned before&lt;/a&gt; is needed.&lt;/p&gt;
&lt;p&gt;Usually, all you need is referencing &lt;code&gt;/usr/include&lt;/code&gt; and you&amp;rsquo;re done.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;FlagsForFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kwargs&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;flags&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
            &lt;span class=&#34;s1&#34;&gt;&amp;#39;-I/usr/include&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;s1&#34;&gt;&amp;#39;-I/usr/local/include&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;s1&#34;&gt;&amp;#39;-std=gnu99&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# this allows us to leverage `asm`&lt;/span&gt;
            &lt;span class=&#34;s1&#34;&gt;&amp;#39;-xc&amp;#39;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: if you need to reference internal kernel structures, make sure you include the proper paths from your local kernel source. For instance, if I have the kernel cloned at &lt;code&gt;/home/ubuntu/linux&lt;/code&gt;, then I&amp;rsquo;d probably add something like &lt;code&gt;-I/home/ubuntu/linux/include&lt;/code&gt; or whatever else you need from it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a more specific example, in case you&amp;rsquo;re targetting ebpf programs for &lt;code&gt;tc&lt;/code&gt;, it might be useful that you leverage the helpers from &lt;code&gt;iproute2&lt;/code&gt;. It ships with a set of helpers that might be useful for you when using eBPF with &lt;code&gt;tc&lt;/code&gt;, so it might be worth cloning &lt;code&gt;iproute2&lt;/code&gt; and manually installing their bpf helpers file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Clone the IPROUTE2 repository and get into the directory&lt;/span&gt;
git clone git://git.kernel.org/pub/scm/network/iproute2/iproute2.git 
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./iproute2

&lt;span class=&#34;c1&#34;&gt;# Copy the `bpf_api.h` helpers file that lives under `./include`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to your `/usr/include` directory.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: this could be anywhere - including your current source tree.&lt;/span&gt;
install &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -m &lt;span class=&#34;m&#34;&gt;0644&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./include/bpf_api.h &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /usr/include/iproute2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, create a bpf hello world that gets loaded into the ingress path and you&amp;rsquo;ll see that the definitions properly show up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;iproute2/bpf_api.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;linux/bpf.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ingress&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cls_ingress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__sk_buff&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;skb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;skb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;printt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Hello World&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TC_ACT_UNSPEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the autocompletion working, we can quickly visualize what are the fields that the &lt;code&gt;__sk_buff&lt;/code&gt; structure gives us:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/skb-autocomplete.png&#34;
       alt=&#34;Example of YouCompleteMe searching available structure fields &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;More importantly, we can get our Vim cursor on top of it and jump to its declaration (&lt;code&gt;YcmCompleter GoToDeclaration&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Given that there are helpers defined in &lt;code&gt;iproute2/bpf_api.h&lt;/code&gt;, and that we include it (and YouCompleteMe knows where to find this file given that we specified the include list at &lt;code&gt;.ycm_extr_conf.py&lt;/code&gt;), we can do the same for the bpf helper functions (as shown in the image at the beginning of the article).&lt;/p&gt;
&lt;h3 id=&#34;autocompleting-ebpf-compiled-using-bcc&#34;&gt;Autocompleting eBPF compiled using BCC&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re using &lt;a href=&#34;https://github.com/iovisor/bcc&#34;&gt;bcc&lt;/a&gt; to get your eBPF in, then the story changes a little bit - there&amp;rsquo;s a subset of code that gets injected behind the scenes (not very good for us, trying to provide the whole source code to the autocompletion engine).&lt;/p&gt;
&lt;p&gt;Such subset is what gives you some handy definitions like &lt;a href=&#34;https://github.com/iovisor/bcc/blob/44c28bf979f068cd7ace66a28e97becf1862ef5d/src/cc/export/helpers.h#L129-L132&#34;&gt;&lt;code&gt;BPF_HASH&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Not only BCC provides helpers, but it actually acts as part of the &lt;a href=&#34;https://clang.llvm.org/&#34;&gt;Clang&lt;/a&gt; compilation process, transforming the eBPF source code that we provide.&lt;/p&gt;
&lt;p&gt;For instance, we can see how &lt;code&gt;bcc&lt;/code&gt; adds some helpers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Helpers are inlined in the following file (C). 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Load the definitions and pass the partially compiled 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// module to the B frontend to continue with.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;helpers_h&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ExportedFiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/virtual/include/bcc/helpers.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;helpers_h&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ExportedFiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Internal error: missing bcc/helpers.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_includes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;helpers_h&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;second&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;BLoader&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;b_loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Source code from &lt;a href=&#34;https://github.com/iovisor/bcc/blob/44c28bf979f068cd7ace66a28e97becf1862ef5d/src/cc/bpf_module.cc#L970-L980&#34;&gt;bpf_module.cc#L970-l980&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;m still not completely sure about how it interacts with the LLVM toolchain, but it seems like it&amp;rsquo;s something like this:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/bcc-compile-path.svg&#34;
       alt=&#34;Illustration of the BCC LLVM compilation path &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;ps.: There&amp;rsquo;s a great presentation by &lt;a href=&#34;https://twitter.com/@alexei_ast&#34;&gt;Alexei Starovoitov&lt;/a&gt; illustrating  the process: &lt;a href=&#34;https://blog.linuxplumbersconf.org/2015/ocw/system/presentations/3249/original/bpf_llvm_2015aug19.pdf&#34;&gt;Slides - BPF in LLVM and kernel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If we want to leverage those definitions (from the injected &lt;code&gt;helpers.h&lt;/code&gt;) in our autocompletion though, we need to reference that file manually. The catch here is that if you look at it, there&amp;rsquo;s an extra line at both the beginning and end that would invalidate our use - it makes the whole code a comment.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;n&#34;&gt;R&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;********(&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Copyright (c) 2015 PLUMgrid, Inc.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Licensed under the Apache License, Version 2.0 (the &amp;#34;License&amp;#34;);
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * you may not use this file except in compliance with the License.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; [...]
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;        } while (0);
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;#endif
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;)********&amp;#34;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Naturally, that&amp;rsquo;s not acceptable for us as including it would fail.&lt;/p&gt;
&lt;p&gt;To remove the first and last line, we can then make use of &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the location at which we plan to store the `helpers.h`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# file.&lt;/span&gt;
mkdir -p /usr/local/include/bcc


&lt;span class=&#34;c1&#34;&gt;# Clone the bcc project&lt;/span&gt;
git clone https://github.com/iovisor/bcc


&lt;span class=&#34;c1&#34;&gt;# `tail -n +2` removes the first line by making&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it send to `stdout` only the last `n` lines starting&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at the second line.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `head -n -1` does the opposite: it the first `n-1`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# lines (that is, all of the lines except the last one)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and sends them to stdout.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that we&amp;#39;re doing those two operations in a pipeline&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# manner, in the end, we have removed the first and the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# last lines.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Piping the result to `/usr/local/include/bcc/helpers.h` makes &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the modified content available at such location.&lt;/span&gt;
cat ./bcc/src/cc/export/helpers.h &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        tail -n +2  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        head -n -1 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        sudo tee -a &amp;gt; /usr/local/include/bcc/helpers.h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s create an example to be used with &lt;code&gt;bcc&lt;/code&gt; to see the autocompletion working.&lt;/p&gt;
&lt;p&gt;First, create a Python wrapper that is going to take our source and then make use of the BCC toolchain.&lt;/p&gt;
&lt;p&gt;The BCC toolchain uses its frontend to translate our code to a Clang-compatible code which gets turned into BPF bytecode via the LLVM BPF backend.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;bcc&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BPF&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# BPF creates a new BPF module with the given&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# source code that we can specify either via&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `src_file` or `text`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `trace_print` reads the kernel debug trace pipe&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and then prints what&amp;#39;s there to stdout.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This way, we&amp;#39;re able to easily visualize our&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# debug statements issued via `bpf_trace_printk`.&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;BPF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./trace_vfs_open.c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trace_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the wrapper set, we can the code our &lt;code&gt;trace_vfs_open.c&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * If `BPF_HASH` is already defined, it means that we&amp;#39;re
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * in the BCC compilation path, so we don&amp;#39;t need to import
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `bcc/helpers.h` as its been already added to this file
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * already.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#ifndef BPF_HASH
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;bcc/helpers.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * kprobe__vfs_open() - instrument the vfs_open call with a custom handler
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * @ctx: registers and the bpf context (unused).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Instruments the internall call `vfs_open` (`fs/open.c`) which is responsible
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * for allocating a file structure, initializing it and then submitting a
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * subsequent `open` call to the filesystem.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * By using the special prefix `kprobe__`, `bcc` will automatically
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * attach the kprobe for us to the kernel method `sys_statfs`.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;kprobe__vfs_open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__attribute__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unused&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * `bpf_trace_printk` is a method that gets defined by the bcc
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * toolchain - see [1].
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * It defines a `printk`-like facility for debugging (that should
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * really just be used for quick debugging).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * [1]:
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 * https://github.com/iovisor/bcc/blob/d17d5a8fd4f3b8a9638c8326a77b56ba56dc5eec/src/cc/frontends/clang/b_frontend_action.cc#L840-L852
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;	 */&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;bpf_trace_printk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;vfs_open called&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although the example is pretty contrived, we can already see where the autocompletion support shines - we can discover which operations we can perform with the &lt;code&gt;ctx&lt;/code&gt; argument:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #fcf4dc; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/ebpf-autocomplete-example.svg&#34;
       alt=&#34;Animated example of EBPF autocomplete &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;If we switch this trace from &lt;code&gt;vps_open&lt;/code&gt; to something more elaborate, like &lt;code&gt;tcp_v4_connect&lt;/code&gt;, then we can see how such functionality shines. Consider the &lt;a href=&#34;https://github.com/iovisor/bcc/blob/ee9f0e0a35ec389049c99c22a2238d122355737d/examples/tracing/tcpv4connect.py&#34;&gt;&lt;code&gt;tcpv4connect.py&lt;/code&gt;&lt;/a&gt; example from the BCC repository:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kprobe__tcp_v4_connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pt_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bpf_get_current_pid_tgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// stash the sock ptr for lookup on return
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;currsock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we wanted to know more about &lt;code&gt;sock&lt;/code&gt;, using the autocomplete feature we can quickly do it:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/sk-autocomplete.png&#34;
       alt=&#34;Screenshot of the terminal with VIM showing the autocomplete of a socket linux structure &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Not being a Kernel developer myself, I found that by leveraging some additional tooling made me much more productive when learning about eBPF.&lt;/p&gt;
&lt;p&gt;It seems to me that if more people who are not very educated about Linux start getting into eBPF, then the more approachable this area tends to get.&lt;/p&gt;
&lt;p&gt;So, I hope that this helped you! Please let me know if you find something weird (or completely wrong). I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 30 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/developing-ebpf-with-autocompletion-support/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/developing-ebpf-with-autocompletion-support/</guid>

                                
                                        <category>programming</category>
                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Blocking ingress traffic to Docker swarm worker machines</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;When Docker Swarm mode got announced, one of the big features included was the &lt;a href=&#34;https://docs.docker.com/engine/swarm/ingress/&#34;&gt;routing mesh&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/ingress-routing-mesh.png&#34;
       alt=&#34;Illustration of how the routing mesh works &#34; &gt;

    
&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;Image from &lt;a href=&#34;https://docs.docker.com/engine/swarm/ingress/#publish-a-port-for-a-service&#34;&gt;docs.docker.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Although the feature indeed works as expected, there&amp;rsquo;s the possibility that you might not want to have all of your nodes accepting connections and performing the job of a load-balancer.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/ingress-routing-mesh-with-blocking.svg&#34;
       alt=&#34;Illustration of what we want to achieve with the blocking &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In this blog post, I go through what are the fundamental blocks that the routing mesh uses under the hood so we can block such kind of traffic on specific machines.&lt;/p&gt;
&lt;h3 id=&#34;the-ingress-load-balancing-setup-lifecycle&#34;&gt;The ingress load-balancing setup lifecycle&lt;/h3&gt;
&lt;p&gt;Given a cluster of machines, whenever a service publishes a port, any machine can be targetted at such port, and an internal load-balancer (&lt;a href=&#34;http://www.linuxvirtualserver.org/software/ipvs.html&#34;&gt;IPVS&lt;/a&gt;) will send the traffic to a host containing an instance of such service.&lt;/p&gt;
&lt;p&gt;For instance, assume that we have the following service definition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;3.2&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;nginx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;nginx:alpine&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;8000:80&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;deploy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;replicas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that we have three machines: &lt;code&gt;worker-1&lt;/code&gt;, &lt;code&gt;worker-2&lt;/code&gt; and &lt;code&gt;manager&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once the service is pushed to a Docker Swarm manager, it gets the service instantiated in the form of tasks - only one in this case (&lt;code&gt;replicas == 1&lt;/code&gt;)-, which turns into a container in a machine chosen by the manager.&lt;/p&gt;
&lt;p&gt;Having a port published (&lt;code&gt;target=80,published=8000&lt;/code&gt;), Swarm proceeds with the configuration of the routing mesh, which happens at two moments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;at the time that the service gets created, all participating nodes in the cluster set up their IPVS configuration to have a virtual server listening on port &lt;code&gt;8000&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;at the moment the task lands in a node and a container is created, then all machines update their IPVS configuration again, but now to include a real server that corresponds to the machine in which the container landed, forming the mesh.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/swarm-ingress-mesh.svg&#34;
       alt=&#34;Illustration of the network routing &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Each machine now has the published port (&lt;code&gt;8000&lt;/code&gt;) set to listen for incoming connections so that you can target any of them and have the connection adequately established to a container.&lt;/p&gt;
&lt;p&gt;If it happens that the &lt;code&gt;nginx&lt;/code&gt; container dies and the scheduler (Docker Swarm) creates a task for placing the container somewhere else, or it happens that we have a scale out situation (increasing the number of replicas to two, for instance), all machines become aware of that and update their IPVS configurations.&lt;/p&gt;
&lt;p&gt;If the service is removed (or a published port gets unpublished), then again, all participants get to know the change in the overall state and then reflect such changes in their local IPVS configuration.&lt;/p&gt;
&lt;h3 id=&#34;under-the-hood---how-ingress-gets-traffic-directed-to-containers&#34;&gt;Under the hood - how Ingress gets traffic directed to containers&lt;/h3&gt;
&lt;p&gt;If at this point you&amp;rsquo;ve tried to see how IPVS gets set up, you might&amp;rsquo;ve noticed that nothing shows up by running &lt;code&gt;ipvsadm --list&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because such configuration is isolated in a namespace (&lt;code&gt;ingress_sbox&lt;/code&gt;), and to have a full understanding of how the packet flow looks like, we need to take a look at the iptables rules set in the default namespace to make those packets get into the ingress namespace which is then responsible for doing the whole load-balancing.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/how-to-direct-to-sbox.svg&#34;
       alt=&#34;Image showing the traffic flowing from the public interface to the ingress sandbox &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;To do so, let&amp;rsquo;s assume a more straightforward scenario:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;there are two machines (&lt;code&gt;machine1&lt;/code&gt; and &lt;code&gt;machine2&lt;/code&gt;), both members of the swarm cluster (it doesn&amp;rsquo;t matter which one is the manager);&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s a &lt;code&gt;nginx&lt;/code&gt; service deployed (publishing port 8000 for the target port 80), having the one (and only one) replica landed in &lt;code&gt;machine1&lt;/code&gt;; and&lt;/li&gt;
&lt;li&gt;we&amp;rsquo;re reaching the nginx service from &lt;code&gt;machine2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the packet gets received by the machine, its device issues an interrupt. A driver that has registered itself as a handler for that takes the packet data from the device (via direct memory access - DMA) and then fills the proper kernel representation of it in its driver (&lt;code&gt;skb&lt;/code&gt;). After this, the packet starts flowing through a series of steps in the kernel before it&amp;rsquo;s sent to a local application or forwarded to a different interface.&lt;/p&gt;
&lt;p&gt;One of these steps is passing the packet through the kernel firewall, which can be configured from userspace using &lt;code&gt;iptables&lt;/code&gt; (and many others), allowing you to set rules that can do all sorts of packet mangling, filtering, forwarding and more.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/packet-path.svg&#34;
       alt=&#34;Illustration of the path that a packet takes within the host &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;These rules that we specify are placed in either preconfigured chains - hooks in the packet flow that are activated at certain points - or custom ones that we can reference from those that are preconfigured.&lt;/p&gt;
&lt;p&gt;These chains live under tables, which aggregate a set of chains by their purpose.&lt;/p&gt;
&lt;p&gt;For now, let&amp;rsquo;s focus on the &lt;code&gt;nat&lt;/code&gt; table - the table where rules are set to implement network address translation. From the &lt;code&gt;man&lt;/code&gt; page:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nat: This table is consulted when a packet 
     that creates a new connection is encountered.

It  consists  of  four  built-ins: 
- PREROUTING (for altering packets as soon as they come in), 
- INPUT (for altering packets destined  for  local  sockets),  
- OUTPUT  (for altering  locally-generated  packets before routing), and
- POSTROUTING (for altering packets as they are about to go out).  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Being even more specific, let&amp;rsquo;s focus on the &lt;code&gt;PREROUTING&lt;/code&gt; chain and those chains that are referenced there:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;tip: As a way of quickly grasping over all the additions to &lt;code&gt;iptables&lt;/code&gt; that Docker made, I like to run &lt;code&gt;iptables-save&lt;/code&gt; so we can see all that&amp;rsquo;s set across all tables.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# List all the chains from the NAT table (by default,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# iptables lists the chains from the FILTER table).&lt;/span&gt;
iptables --list --table nat

&lt;span class=&#34;c1&#34;&gt;# As the packet has not been generated in our machine,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# packets get to this chain first before a routing &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# decision is taken (i.e., before it&amp;#39;s either set that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the packet is indeed for this machine - INPUT - or that &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it&amp;#39;s meant to be sent to another machine - FORWARD).&lt;/span&gt;
Chain PREROUTING &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target          prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;     destination         
&lt;span class=&#34;c1&#34;&gt;# Using the `addrtype` iptables extension, it looks at&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the packets and then performs matching based on its&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# destination address type.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# When this rule was set, it was configured to match the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# address type of the destination address to LOCAL - a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# local address.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: LOCAL does not mean only 127.0.0.0/8 CIDR used for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# loopback addresses, but any address that represents the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# local machine (as per the routing table).&lt;/span&gt;
DOCKER-INGRESS  all  --  anywhere   anywhere       ADDRTYPE match dst-type LOCAL
DOCKER          all  --  anywhere   anywhere       ADDRTYPE match dst-type LOCAL

Chain DOCKER-INGRESS &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; references&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target          prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;     destination   
&lt;span class=&#34;c1&#34;&gt;# Matches packets that make use of the TCP protocol and &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that are targetted towards port 8000, applying `DNAT`ing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to them, effectively substituting the destination address&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to 172.18.0.2.&lt;/span&gt;
DNAT            tcp  --  anywhere   anywhere       tcp dpt:8000 to:172.18.0.2:8000
RETURN          all  --  anywhere   anywhere  


Chain DOCKER &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; references&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target          prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;     destination   
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/redirect-to-sbox.svg&#34;
       alt=&#34;Illustration of the process of redirecting a packet to the ingress sandbox &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Now, taking a quick look at &lt;code&gt;ip addr&lt;/code&gt; (lists all the devices in the current network namespace together with their addresses), we can notice that such ip (&lt;code&gt;172.18.0.2&lt;/code&gt;) must belong to the device connected to the &lt;code&gt;docker_gwbridge&lt;/code&gt; bridge:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Verify that the `docker_gwbridge` interface that belongs&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the bridge device is indeed the gateway for the 172.18.0.1/16&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# network.&lt;/span&gt;
ip addr show docker_gwbridge
13: docker_gwbridge: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; qdisc noqueue state UP group default 
    link/ether 02:42:af:92:92:f6 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global docker_gwbridge
       valid_lft forever preferred_lft forever
    inet6 fe80::42:afff:fe92:92f6/64 scope link 
       valid_lft forever preferred_lft forever

&lt;span class=&#34;c1&#34;&gt;# Check which interfaces have been connected to this bridge.&lt;/span&gt;
bridge link show docker_gwbridge
25: veth79f1181 state UP @if24: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; master docker_gwbridge state forwarding priority &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt; cost &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; 
29: veth8aec496 state UP @if28: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; master docker_gwbridge state forwarding priority &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt; cost &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; 

&lt;span class=&#34;c1&#34;&gt;# We can see that there are two veth pairs connected to it.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Naturally, being veth pairs, from this network namespace we can see&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# one side of the pairs, while the other side have their interfaces in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# different network namespaces.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We can corroborate the hypothesis that there exists at least two different&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# namespaces by checking that under the hood the `docker_gwbridge` docker network&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# has two hidden containers:&lt;/span&gt;
docker network inspect &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --format &lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ json .Containers }}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        docker_gwbridge &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;ddf1af4f39efaeb556964351800f282aca75d509537d166ff78d5d12b8911cef&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;gateway_ddf1af4f39ef&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;EndpointID&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;5903ff858bc2d5...&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;MacAddress&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;02:42:ac:12:00:03&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;IPv4Address&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;172.18.0.3/16&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;IPv6Address&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;ingress-sbox&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;gateway_ingress-sbox&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;EndpointID&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;650cc71d444f...&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;MacAddress&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;02:42:ac:12:00:02&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;IPv4Address&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;172.18.0.2/16&amp;#34;&lt;/span&gt;,     &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt; the ip we saw!&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;IPv6Address&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Get inside this container and see what&amp;#39;s going on there when&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it comes to IPVS.&lt;/span&gt;
nsenter &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --net&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/var/run/docker/netns/ingress_sbox &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ipvsadm --list --numeric
IP Virtual Server version 1.2.1 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4096&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
Prot LocalAddress:Port Scheduler Flags
  -&amp;gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  &lt;span class=&#34;m&#34;&gt;257&lt;/span&gt; rr
  -&amp;gt; 10.255.0.6:0                 Masq    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       

&lt;span class=&#34;c1&#34;&gt;# Translating that output to pure English, it means:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - for those connections marked with the firewall mark 257, load-balance&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   them using NAT (masquerading) between the list of servers below (given&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   that we have a single replica, there&amp;#39;s only one address there).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# To understand where that IP address comes from, get into the nginx&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# container and check its interfaces:&lt;/span&gt;
 docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$NGINX_CONTAINER_ID&lt;/span&gt; ip addr show eth0
26: eth0@if27: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1450&lt;/span&gt; qdisc noqueue state UP 
    link/ether 02:42:0a:ff:00:04 brd ff:ff:ff:ff:ff:ff
    inet 10.255.0.4/16 brd 10.255.255.255 scope global eth0
       valid_lft forever preferred_lft forever

&lt;span class=&#34;c1&#34;&gt;# Now if you&amp;#39;re wondering where this network comes from, checkout &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `docker network ls` and inspect the `ingress` network:&lt;/span&gt;
docker network inspect ingress --format &lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ json .IPAM }}&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Driver&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Options&amp;#34;&lt;/span&gt;: null,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Config&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;s2&#34;&gt;&amp;#34;Subnet&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.255.0.0/16&amp;#34;&lt;/span&gt;,
      &lt;span class=&#34;s2&#34;&gt;&amp;#34;Gateway&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.255.0.1&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last thing that&amp;rsquo;s missing understanding from the ingress sandbox is: how does &lt;code&gt;fwmark&lt;/code&gt; (firewall mark) that IPVS uses gets set? The answer is, one more time, &lt;code&gt;iptables&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, the difference now is that this gets set in the &lt;code&gt;mangle&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get inside the `ingress_sbox` namespace and then issue&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the iptables command to list the chains and rules that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# are set in the `mangle` table.&lt;/span&gt;
nsenter &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --net&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/var/run/docker/netns/ingress_sbox &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        iptables --list --table mangle
Chain PREROUTING &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot src  dst 
&lt;span class=&#34;c1&#34;&gt;# For every packet that is destined to port 8000 (the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# nginx&amp;#39; published port), set the firewall mark to 0x101).&lt;/span&gt;
MARK       tcp  any  any  dpt:8000 MARK &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; 0x101

Chain OUTPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# For every packet that is destined to a virtual IP that swarm&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# assigns to a specific service (10.255.0.3), also mark the packet&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with the corresponding virtual service mark.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that this destination (10.255.0.3) lives in the ingress&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# network, this is only accessible from within a container.&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination         
MARK       all  --  anywhere             10.255.0.3           MARK &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; 0x101

&lt;span class=&#34;c1&#34;&gt;# Given that in iptables that value is set in its hexadecimal&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# form, we can look at what 0x101 means in the decimal form&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (shown in the `ipvsadm` listing).&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;%d\n&amp;#34;&lt;/span&gt; 0x101
&lt;span class=&#34;m&#34;&gt;257&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By looking at the man page of &lt;code&gt;iptables-extensions&lt;/code&gt; we can see what that target does:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;MARK - This  target  is used to set the Netfilter mark value associated with the packet.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;From &lt;a href=&#34;https://linux.die.net/man/8/iptables&#34;&gt;https://linux.die.net/man/8/iptables&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then, looking at &lt;code&gt;ipvsadm&lt;/code&gt; man page we can also check how it can make use of such mark:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Using firewall-mark virtual services provides a convenient method of &lt;strong&gt;grouping together
different IP addresses, ports, and protocols into a single virtual service&lt;/strong&gt;. This is use‐
ful  for  both  simplifying  configuration  if  a  large number of virtual services are
required and grouping persistence across what would otherwise be multiple virtual  ser‐
vices.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;From &lt;a href=&#34;https://linux.die.net/man/8/ipvsadm&#34;&gt;https://linux.die.net/man/8/ipvsadm&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/sbox-internals.svg&#34;
       alt=&#34;Illustration of the decisions that happen within the ingress sandbox &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In summary, what goes on is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A packet is destined for our machine (&lt;code&gt;192.168.10.4&lt;/code&gt;); then&lt;/li&gt;
&lt;li&gt;if it&amp;rsquo;s destination port matches a published port, we take the original destination address (our machine address) and replace it by a different address (&lt;code&gt;172.18.0.2&lt;/code&gt;). As this is performed before a routing decision has been made, it has the effect of making the packet be routed to the &lt;code&gt;gateway_ingress-sbox&lt;/code&gt; container that contains the IPVS load-balancer rules.&lt;/li&gt;
&lt;li&gt;once the packet lands in &lt;code&gt;ingress_sbox&lt;/code&gt;, it passes through its own iptables rules. This time, it goes through the &lt;code&gt;mangle&lt;/code&gt; table, which (in the case of being targetted at port 8000), has the effect of adding a marker to the packet (&lt;code&gt;fwmark&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;landing in its destination (ipvs), the packet&amp;rsquo;s fwmark indicates the service that the packet needs to be load-balancer to. IPVS then picks one of the target real servers (using a given scheduling algorithm - roundrobin in this case) and then forwards it to the destination.&lt;/li&gt;
&lt;li&gt;As the destination servers are in the &lt;code&gt;ingress&lt;/code&gt; networks, the overlay setup takes care of making the packets reach the destination address accordingly.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;changing-iptables-to-block-ingress-traffic&#34;&gt;Changing IPTables to block Ingress traffic&lt;/h3&gt;
&lt;p&gt;Having some idea of what goes on under the scenes, we can now jump into the process of putting barriers in the middle of these steps such that traffic can&amp;rsquo;t go through.&lt;/p&gt;
&lt;p&gt;Looking at the last two images, we can imagine that we can either put a barrier between &lt;code&gt;eth0&lt;/code&gt; and &lt;code&gt;ingress_sbox&lt;/code&gt;, or we can but a barrier between &lt;code&gt;ingress_sbox&lt;/code&gt; and &lt;code&gt;ipvs&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/where-to-block-ingress.svg&#34;
       alt=&#34;Image questioning where we should place the block &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;If we perform the first block (cut traffic between &lt;code&gt;eth0&lt;/code&gt; and &lt;code&gt;ingress_sbox&lt;/code&gt;), then we&amp;rsquo;re going to be blocking connections that are made from one machine to the physical interface of another, but we&amp;rsquo;d still allow traffic originating in the host itself.&lt;/p&gt;
&lt;p&gt;Taking the second approach looks like a more protective block.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create some services and some networks and apply the block to see that in action.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a network named `mynet` that uses the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# overlay network driver.&lt;/span&gt;
docker network create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --driver overlay &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  mynet


&lt;span class=&#34;c1&#34;&gt;# Create two services in the same network:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# 1. nginx1 that specifies a public port mapping&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#    8123 --&amp;gt; 80&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# 2. nginx2 that specifies a public port mapping&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#    8124 --&amp;gt; 80&lt;/span&gt;
docker service create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --no-resolve-image &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --network mynet &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --publish 8123:80 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --name nginx1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  nginx:alpine

docker service create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --no-resolve-image &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --network mynet &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --publish 8124:80 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --name nginx2 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  nginx:alpine


&lt;span class=&#34;c1&#34;&gt;# Create the `CURL_ARGS` variable that is going to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# hold the non-positional arguments that we&amp;#39;ll be&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# using throughout the example. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --connect-timeout: specifies the maximum amount of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                    time that `connect(2)` should&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                    take. This is needed because we&amp;#39;re&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                    simply dropping packets.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --silent: removes the verbose curl information&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --output: allows us to specify a file that should&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#           be used as the stdout for the body. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#           Using /dev/null we simply discard it.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --write-out: allows us to specify a template of text&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#              containing information regarding the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#              connection / request. By specifying&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#              %{http_code} we can display the HTTP status&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#              code of the request (000) on connection&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#              failures.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;CURL_ARGS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;--connect-timeout 0.5 \
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;--silent \
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;--write-out &amp;#39;%{http_code}&amp;#39; \
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;--output /dev/null&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Verify that both of the services can be &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# reached from machine1 by targetting its&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# own loopback interface.&lt;/span&gt;
curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8123
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;
curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8124
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Get into machine2 and verify&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that it can indeed connect to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# services by targetting the machine&amp;#39;s&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# interface (eth0).&lt;/span&gt;
ssh ubuntu@machine2
machine2 $ curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  machine1:8123
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;
machine2 $ curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  machine2:8124
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Still in machine2, verify that the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# service is accessible in its own IPVS &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# load-balancer by trying to reach the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# service making a request to its own loopback&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# interface.&lt;/span&gt;
machine2 $ curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8123
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;
machine2 $ curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8124
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Get back to machine1.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Get into the `ingress_sbox` network namespace.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# To do this we can either make use of `nsenter`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# like we did before or make use of `ip netns` which &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# assumes that the network namespace files live under&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# /var/run/netns.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As docker creates its network namespace files under&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# /var/run/docker/netns, we can get over such default&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by creating a soft link.&lt;/span&gt;
ln -s /var/run/docker/netns /var/run/netns


&lt;span class=&#34;c1&#34;&gt;# Given that Docker doesn&amp;#39;t make use of the `filter`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# table and doesn&amp;#39;t change it at all during service&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# changes, we can include specific rules in specific chains&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# there to drop desired connections.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By including a rule in the INPUT table, we&amp;#39;re able to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# filter packets that are destined to a local address that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# represents the current machine.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; ingress_sbox &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  iptables -A INPUT -p tcp -m tcp --dport &lt;span class=&#34;m&#34;&gt;8123&lt;/span&gt; -j DROP


&lt;span class=&#34;c1&#34;&gt;# Verify that the `nginx` (8123) can&amp;#39;t be &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# accessed by touching `machine1` ports&lt;/span&gt;
curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8123
&lt;span class=&#34;m&#34;&gt;000&lt;/span&gt;

curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  machine1:8123
&lt;span class=&#34;m&#34;&gt;000&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Verify that when targetting machine2, the service is &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# available:&lt;/span&gt;
curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  machine2:8123
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Get into machine2 and verify that it can&amp;#39;t access&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the service by targetting machine1&lt;/span&gt;
ssh ubuntu@machine2
machine2 $ curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  machine1:8123
&lt;span class=&#34;m&#34;&gt;000&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# But that it can access it via itself&lt;/span&gt;
machine2 $ curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8123
&lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Go back to machine1 (manager) and create a new &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# service and verify that docker didn&amp;#39;t mess with &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the `ingress_sbox` rules:&lt;/span&gt;
docker service create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --no-resolve-image &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --network mynet &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --publish 8125:80 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --name nginx3 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  nginx:alpine


&lt;span class=&#34;c1&#34;&gt;# Verify that it still fails (which is what we expect)&lt;/span&gt;
curl &lt;span class=&#34;nv&#34;&gt;$CURL_ARGS&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  localhost:8123
&lt;span class=&#34;m&#34;&gt;000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It was very interesting to go through all of this as a way of learning how to set up a simple block for a given set of ports that wouldn&amp;rsquo;t mess with the default ingress load-balancing and other Docker-specific chains.&lt;/p&gt;
&lt;p&gt;Please let me know if I got something wrong - I&amp;rsquo;m new to networking and going through this definitely helped me improve and I&amp;rsquo;d appreciate a lot to be corrected if I presented a misleading or completely wrong information here.&lt;/p&gt;
&lt;p&gt;You can reach me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter!&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Wed, 27 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/blocking-ingress-traffic-to-docker-swarm-worker-machines/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/blocking-ingress-traffic-to-docker-swarm-worker-machines/</guid>

                                
                                        <category>docker</category>
                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                

                        
                

                        
                        <item>
                                <title>How to set up a Private Docker Registry using AWS S3</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Some time ago I needed to check whether AWS EC2 instance profiles would work fine with Docker Registry, and guess what? It does!&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/s3-registry-interaction.svg&#34;
       alt=&#34;Illustration of the EC2 instance with a registry interacting with the S3 bucket &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;What interests me the most in such setup is how it facilitates a scenario where you can have a highly available internal registry, having a load-balancer in front of a set of registries and granting privileges to only those who really need it.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/s3-registry-with-lb.svg&#34;
       alt=&#34;Illustration of a scenario where a load-balancer balances the load across multiple registries &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Given that the pushes to the registry (and pulls from it) usually involve large amounts of data being transferred, with a well-done load-balancing we can scale the throughput with ease.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a setup that makes use of &lt;a href=&#34;https://terraform.io&#34;&gt;&lt;code&gt;terraform&lt;/code&gt;&lt;/a&gt; and the official Docker Registry image to achieve the first scenario.&lt;/p&gt;
&lt;h3 id=&#34;the-terraform-setup&#34;&gt;The terraform setup&lt;/h3&gt;
&lt;p&gt;By taking a top-down approach, the infrastructure resources that Terraform is meant to create is composed of only two top-level resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the instance that will hold the docker registry; and&lt;/li&gt;
&lt;li&gt;the S3 bucket that is meant to store the registry data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The bucket can be created using the policy specified in the &lt;a href=&#34;https://docs.docker.com/registry/storage-drivers/s3/#s3-permission-scopes&#34;&gt;official registry documentation&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;# Create a AWS S3 bucket that is encrypted by default
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# at the server side using the name provided by the
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# `bucket` variable.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Given that we&amp;#39;re not specifying an ACL, by default
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the `private` canned ACL is used, which means that
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# only the owner gets FULL_CONTROL access (and no
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# one else).
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_s3_bucket&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;encrypted&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;bucket&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${var.bucket}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;force_destroy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;server_side_encryption_configuration&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;rule&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;apply_server_side_encryption_by_default&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;sse_algorithm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;AES256&amp;#34;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Set up the bucket policy to allow only a 
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# specific set of operations on both the root
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# of the bucket as well as its subdirectories.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Here we also explicitly set who&amp;#39;s able to have
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# such capabilities - those that make use of the
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# role that we defined in `permissions.tf`. 
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_s3_bucket_policy&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;bucket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${var.bucket}&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POLICY&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;&amp;#34;Statement&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Action&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:PutObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:GetObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:DeleteObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:ListMultipartUploadParts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:AbortMultipartUpload&amp;#34;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Effect&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Principal&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;AWS&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_iam_role.main.arn}&amp;#34;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Resource&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Sid&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;AddCannedAcl&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Action&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:ListBucket&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:GetBucketLocation&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:ListBucketMultipartUploads&amp;#34;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Effect&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Principal&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;AWS&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_iam_role.main.arn}&amp;#34;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
            &lt;span class=&#34;s&#34;&gt;&amp;#34;Resource&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;POLICY&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Naturally, there&amp;rsquo;s one piece there in the policies that we didn&amp;rsquo;t create yet at this point - the role to which we grant access to.&lt;/p&gt;
&lt;p&gt;This role is the one that we&amp;rsquo;re going to ship in the form of an instance profile to the EC2 instances such that they can have access to the S3 buckets.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;# The bucket-root policy defines the API actions that are
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# allowed to take place on the bucket root directory.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Given that by default nothing is allowed, here we list
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the actions that are meant to be allowed.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# This list of actions that are required by the Docker Registry
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# can be found in the official Docker Registry documentation.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_policy_document&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bucket-root&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;statement&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;effect&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;actions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:ListBucket&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:GetBucketLocation&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:ListBucketMultipartUploads&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;resources&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# The bucket-subdirs policy defines the API actions that
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# are allowed to take place on the bucket subdirectories.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# 
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Given that by default nothing is allowed, here we list
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the actions that are meant to be allowed.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;# Just like the policy for the root directory of the bucket,
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# this list of necessary actions to be allowed can be found in 
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the official Docker Registry documentation.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_policy_document&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bucket-subdirs&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;statement&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;effect&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;actions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:PutObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:GetObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:DeleteObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:ListMultipartUploadParts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;s3:AbortMultipartUpload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;resources&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Define a base policy document that dictates which principals
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the roles that we attach to this policy are meant to affect.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Given that we want to grant the permissions to an EC2 instance,
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the pricipal is not an account, but a service: `ec2`.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Here we allow the instance to use the AWS Security Token Service
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# (STS) AssumeRole action as that&amp;#39;s the action that&amp;#39;s going to
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# give the instance the temporary security credentials needed
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# to sign the API requests made by that instance.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_policy_document&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;statement&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;effect&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;actions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;#34;sts:AssumeRole&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;principals&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Service&amp;#34;&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;identifiers&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s&#34;&gt;&amp;#34;ec2.amazonaws.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Creates an IAM role with the trust policy that enables the process
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# of fetching temporary credentials from STS.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# By tying this trust policy with access policies, the resulting 
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# temporary credentials generated by STS have only the permissions 
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# allowed by the access policies.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_role&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;               &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;assume_role_policy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.aws_iam_policy_document.default.json}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Attaches an access policy to that role.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_role_policy&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bucket-root&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bucket-root-s3&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;role&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_iam_role.main.name}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.aws_iam_policy_document.bucket-root.json}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Attaches an access policy to that role.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_role_policy&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bucket-subdirs&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bucket-subdirs-s3&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;role&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_iam_role.main.name}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.aws_iam_policy_document.bucket-subdirs.json}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Creates the instance profile that acts as a container for that
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# role that we created that has the trust policy that is able
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# to gather temporary credentials using STS and specifies the
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# access policies to the bucket.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# This instance profile can then be provided to the aws_instance
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# resource to have it at launch time.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_iam_instance_profile&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;instance-profile&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;role&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_iam_role.main.name}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the permissions created, as well as the bucket, what&amp;rsquo;s left now is creating the instance with its corresponding networking and AMI:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;n&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;region&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${var.region}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;profile&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${var.profile}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# We could create an extra VPC, properly set a subnet and
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# have the whole thing configured (internet gateway, an updated
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# routing table etc).
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# However, given that this is only a sample, we can make use of
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# the default VPC (assuming you didn&amp;#39;t delete your default VPC
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# in your region, you can too).
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_vpc&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Provide the public key that we want in our instance so we can
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# SSH into it using the other side (private) of it.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_key_pair&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;key_name_prefix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;sample-key&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;public_key&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${file(&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rsa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pub&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;)}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Create a security group that allows anyone to access our
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# instance&amp;#39;s port 5000 (where the main registry functionality
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# lives).
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Naturally, you&amp;#39;d not do this if you&amp;#39;re deploying a private
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# registry - something you could do is allow the internal cidr
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# and not 0.0.0.0/0.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_security_group&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;allow-registry-ingress&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;allow-registry-ingress&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allows ingress SSH traffic and egress to any address.&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;vpc_id&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.aws_vpc.main.id}&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;ingress&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;from_port&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5000&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;to_port&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5000&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;cidr_blocks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0.0.0.0/0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;allow_registry-ingress&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Allow SSHing into the instance
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_security_group&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;allow-ssh-and-egress&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;allow-ssh-and-egress&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Allows ingress SSH traffic and egress to any address.&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;vpc_id&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.aws_vpc.main.id}&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;ingress&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;from_port&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;to_port&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;cidr_blocks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0.0.0.0/0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;egress&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;from_port&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;to_port&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;protocol&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;-1&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;cidr_blocks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0.0.0.0/0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;allow_ssh-and-egress&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Template the registry configuration with the desired
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# bucket and region information.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# Note.: no credentials are needed given that the golang
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# aws sdk is going to retrieve them from the instance
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# role that we set to the machine.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;template_file&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;registry-config&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${file(&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;registry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yml&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tpl&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;)}&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;vars&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;bucket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${var.bucket}&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;region&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${var.region}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Template the instance initialization script with information
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# regarding the region and bucket that the user configured.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;template_cloudinit_config&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gzip&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;base64_encode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;part&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;content_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;text/cloud-config&amp;#34;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EOF&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#cloud-config
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;write_files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base64encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;${data.template_file.registry-config.rendered}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}&lt;/span&gt;
    &lt;span class=&#34;nl&#34;&gt;encoding&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b64&lt;/span&gt;
    &lt;span class=&#34;nl&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;
    &lt;span class=&#34;nl&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;etc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;registry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yml&lt;/span&gt;
    &lt;span class=&#34;nl&#34;&gt;permissions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mo&#34;&gt;0755&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;EOF&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;part&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;content_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;text/x-shellscript&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${file(&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;)}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cp&#34;&gt;# Create an instance in the default VPC with a specified
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# SSH key so we can properly SSH into it to verify whether
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;# everything is worked as intended.
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;aws_instance&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;instance_type&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;t2.micro&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;ami&lt;/span&gt;                  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.aws_ami.ubuntu.id}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;key_name&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_key_pair.main.id}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;iam_instance_profile&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_iam_instance_profile.main.name}&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;user_data&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${data.template_cloudinit_config.init.rendered}&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;vpc_security_group_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_security_group.allow-ssh-and-egress.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_security_group.allow-registry-ingress.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;public-ip&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Public IP of the instance created&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;${aws_instance.main.public_ip}&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, aside from the Terraform setup that has already been done at this point, the next step is configuring the registry itself.&lt;/p&gt;
&lt;p&gt;As we&amp;rsquo;re using cloud-init&amp;rsquo;s &lt;code&gt;write_files&lt;/code&gt; to send our templated registry configuration, this is how such configuration looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# -*- mode: yaml -*-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# vi: set ft=yaml :&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Template of a registry configuration.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# It expects the folling variables:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - region: AWS region where the S3 bucket is deployed to; and&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - bucket: the name of the bucket to push registry data to.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Without modifying the default command line arguments of the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# registry image, put this configuration under &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `/etc/docker/registry/config.yml`.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0.1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;formatter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;registry&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;storage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;blobdescriptor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;inmemory&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;s3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${region}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;bucket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${bucket}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;:5000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;secret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a-secret&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;:5001&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# In the `master` branch there&amp;#39;s already native support for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Prometheus metrics.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If you want to make use of this feature: &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 1. clone `github.com/docker/distribution`;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 2. build the image (`docker build -t registry .`);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 3. reference the recently built image in the initialization.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;prometheus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/metrics&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;X-Content-Type-Options&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;nosniff&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;health&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;storagedriver&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;10s&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;threshold&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Update: Note that there I specified a Prometheus endpoint - that&amp;rsquo;s because in a future release the Docker registry will be able to export metrics to prometheus; if you&amp;rsquo;re curious about it, checkout &lt;a href=&#34;https://ops.tips/gists/retrieving-docker-registry-metrics-using-prometheus/&#34;&gt;how to retrieve metrics using prometheus&lt;/a&gt; in which I tie these metrics with the newest Grafana Prometheus heatmap support that just landed in &lt;code&gt;Grafana v5.1&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s it! Create an instance initialization script and there you go! You have a registry backed by S3.&lt;/p&gt;
&lt;p&gt;Such script doesn&amp;rsquo;t need to be complicated - something like the following would do it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run docker registry with the configuration provided&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at `/etc/registry.yml` as a readonly volume mount&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the registry container.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I make use of the host networking mode (no extra&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# network namespace is created), but you&amp;#39;re free to make &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# use of port forwarding as you wish.&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --volume /etc/registry.yml:/etc/docker/registry/config.yml:ro&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --network host &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        registry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that all the setup is independent of a particular container scheduler.&lt;/p&gt;
&lt;p&gt;In the case of a scheduler like Kubernetes or Swarm you could provide the proper labels to the instance and make sure that the registry container gets scheduled to such instance type.&lt;/p&gt;
&lt;p&gt;The whole code that&amp;rsquo;s been described here can be found in the &lt;a href=&#34;https://github.com/cirocosta/sample-docker-registry-aws&#34;&gt;cirocosta/sample-docker-registry-aws&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;If you have any questions or found something odd, feel free to get in touch! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 23 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/aws-s3-private-docker-registry/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/aws-s3-private-docker-registry/</guid>

                                
                                        <category>aws</category>
                                
                                        <category>docker</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Retrieving Docker Registry metrics using Prometheus</title>
                                <description>&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #181a1c; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/blob-upload-latency.png&#34;
       alt=&#34;Docker Registry Blob upload latency Heatmap &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Today I was looking at the internal struct that ends up being filled as the result of parsing the Docker Registry configuration, and doing that I found that in the &lt;code&gt;master&lt;/code&gt; branch of the repository there&amp;rsquo;s already support for metrics scraping by Prometheus (see &lt;a href=&#34;https://github.com/docker/distribution/blob/749f6afb4572201e3c37325d0ffedb6f32be8950/configuration/configuration.go#L137&#34;&gt;configuration.go&lt;/a&gt;), something that used to be only available in OpenShift (see &lt;a href=&#34;https://github.com/openshift/origin/issues/3916&#34;&gt;openshift/origin issue&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;It surprised me that this addition came not super recently:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-git&#34; data-lang=&#34;git&#34;&gt;commit e3c37a46e2529305ad6f5648abd6ab68c777820a
Author: tifayuki &amp;lt;tifayuki@gmail.com&amp;gt;
Date:   Thu Nov 16 16:43:38 2017 -0800

    Add Prometheus Metrics
    
    at the first iteration, only the following metrics are collected:
    
      - HTTP metrics of each API endpoint
      - cache counter for request/hit/miss
      - histogram of storage actions, including:
        GetContent, PutContent, Stat, List, Move, and Delete
    
    Signed-off-by: tifayuki &amp;lt;tifayuki@gmail.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What about giving it a try?&lt;/p&gt;
&lt;p&gt;So, first, start by building an image right from the &lt;code&gt;master&lt;/code&gt; branch:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Clone the Docker registry repository&lt;/span&gt;
git clone https://github.com/docker/distribution

&lt;span class=&#34;c1&#34;&gt;# Build the registry image using the provided Dockerfile&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that lives right in the root of the project.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I tag it as `local` just to make sure that we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# don&amp;#39;t confuse it with `registry:latest`. &lt;/span&gt;
docker build --tag registry:local .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the image built using the latest code, tailor a configuration that enables the exporter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0.1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;formatter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;registry&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;storage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;blobdescriptor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;inmemory&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;filesystem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rootdirectory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/lib/registry&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;:5000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;:5001&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;prometheus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/metrics&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;X-Content-Type-Options&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;nosniff&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the registry with this configuration and note how &lt;code&gt;:5001/metrics&lt;/code&gt; will provide you with the metrics you expect.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Make a request to the metrics endpoint and filter the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# output so we can see what the metrics descriptions are.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: each of those metrics end up expanding to multiple&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# dimensions via labels.&lt;/span&gt;
curl localhost:5001/metrics --silent &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ag registry_ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ag HELP

HELP registry_http_in_flight_requests The in-flight HTTP requests
HELP registry_http_request_duration_seconds The HTTP request latencies in seconds.
HELP registry_http_request_size_bytes The HTTP request sizes in bytes.
HELP registry_http_requests_total Total number of HTTP requests made.
HELP registry_http_response_size_bytes The HTTP response sizes in bytes.
HELP registry_storage_action_seconds The number of seconds that the storage action takes
HELP registry_storage_cache_total The number of cache request received
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wanting to see how useful these metrics can be, I set up an environment in AWS where there&amp;rsquo;s an EC2 instance with a registry instance that&amp;rsquo;s backed by an S3 bucket as the storage tier (you can check more about how to achieve it here: &lt;a href=&#34;https://ops.tips/gists/aws-s3-private-docker-registry&#34;&gt;How to set up a private docker registry using AWS S3&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;With the registry up, it was now a matter of having Prometheus and Grafana running locally so I could start making some queries:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;3.3&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Create a &amp;#34;pod-like&amp;#34; container that will serve as both the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# network entrypoint for both of the containers as well as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# provide a common ground for them to communicate over localhost&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# (given that they&amp;#39;ll share the same network namespace).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;pod&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;9090:9090&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;3000:3000&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;alpine&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;grafana&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;grafana&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;depends_on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;pod&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;network_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;service:pod&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;grafana/grafana:5.2.0-beta3&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;always&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;prometheus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prometheus&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;depends_on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;pod&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;network_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;service:pod&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prom/prometheus&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;always&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; 
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;./prometheus.yml:/etc/prometheus/prometheus.yml&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that &lt;code&gt;prometheus&lt;/code&gt; is making use of a local configuration under &lt;code&gt;./prometheus.yml&lt;/code&gt;, this one looked like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;15s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;evaluation_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;15s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_timeout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;10s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;job_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prometheus&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;static_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;targets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;localhost:9090&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;job_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;registry&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here I just specified the public IP address of the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# EC2 instance that I had holding the registry at that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# time. &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Naturally, you wouldn&amp;#39;t keep it open like this.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;static_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;targets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;52.67.104.105:5001&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, to reproduce the panel showed in the beginning, head over to our grafana dashboard and create a heatmap panel with the following query:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rate(registry_http_request_duration_seconds_bucket{handler=&amp;quot;blob_upload&amp;quot;}[10m])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;If you have any questions or found something odd, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 23 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/retrieving-docker-registry-metrics-using-prometheus/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/retrieving-docker-registry-metrics-using-prometheus/</guid>

                                
                                        <category>docker</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Navigating the Linux Kernel source tree with YouCompleteMe</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;These days I&amp;rsquo;ve been doing some research that involves looking at the Linux kernel to figure things out.&lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;ve been using &lt;a href=&#34;https://github.com/Valloric/YouCompleteMe&#34;&gt;YouCompleteMe&lt;/a&gt; for a reasonable amount of time, and that I love how simple it is to configure it, why not give a try to using it for inspecting the Linux kernel?&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/function-search.png&#34;
       alt=&#34;Example of YouCompleteMe searching available functions &#34; &gt;

    
&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;Example of YouCompleteMe searching available functions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ps.: for a browser experience, &lt;a href=&#34;https://elixir.bootlin.com/linux/latest/source&#34;&gt;bootlin&lt;/a&gt; is AMAZING. It lets you navigate through the code providing links to definitions and making you go back in time to previous versions of the source - it&amp;rsquo;s great! Here I focus on navigating the Kernel source using VIM and a terminal though.&lt;/p&gt;
&lt;p&gt;Check out how to tailor a YouCompleteMe configuration that suits the Linux kernel source code.&lt;/p&gt;
&lt;h3 id=&#34;getting-youcompleteme-ready&#34;&gt;Getting YouCompleteMe ready&lt;/h3&gt;
&lt;p&gt;The first thing to do is getting YCM ready.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;m constantly doing some experiments in AWS and from time to time running a VM here and there, I automated the process using Ansible and Packer (with &lt;code&gt;Ansible&lt;/code&gt; I describe how to get to the desired state, with &lt;code&gt;Packer&lt;/code&gt; I build a base image) - check out &lt;a href=&#34;https://github.com/cirocosta/mylinux&#34;&gt;cirocosta/mylinux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Below is how the YouCompleteMe part of it looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;install ycm&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./install.py --go-completer --clang-completer&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; 
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{ ansible_env.PATH }}:/usr/local/go/bin&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;chdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ user_home }}/.vim/bundle/YouCompleteMe&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ps.: You might notice that I also specify &lt;code&gt;--go-completer&lt;/code&gt; there. That&amp;rsquo;s not needed for &lt;code&gt;C&lt;/code&gt; code (like Linux), so you can get rid of that.&lt;/p&gt;
&lt;p&gt;pps.: Check out my &lt;a href=&#34;https://github.com/cirocosta/mylinux/blob/ac976ef24b2ea4743dbd15da225f4f1ce469d6ac/ansible/roles/vim/tasks/main.yml&#34;&gt;Vim Ansible role&lt;/a&gt; to see the full installation of my Vim setup.&lt;/p&gt;
&lt;p&gt;As I use &lt;a href=&#34;https://github.com/tpope/vim-pathogen&#34;&gt;pathogen&lt;/a&gt; to provide Vim plugins to my environment, there&amp;rsquo;s just the need to clone the repository to &lt;code&gt;.vim/bundle&lt;/code&gt; (with submodules) and then running the installation script.&lt;/p&gt;
&lt;h3 id=&#34;setting-up-the-youcompleteme-configuration&#34;&gt;Setting up the YouCompleteMe configuration&lt;/h3&gt;
&lt;p&gt;Given that the Kernel does not make use of CMake or Ninja, we can&amp;rsquo;t make use of the compilation database that CMake would create (a database that tells which commands were used to compile a given file).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update (30 Jun, 2018): it turns out that you can get a full fidelity compilation database even without &lt;code&gt;cmake&lt;/code&gt; - the &lt;a href=&#34;https://github.com/rizsotto/Bear&#34;&gt;&lt;code&gt;bear&lt;/code&gt;&lt;/a&gt; utility takes the approach of intercepting the build calls, gather the relevant info and generate a complete compilation database. Having such database ready, you can either make full use of it and ignore an extra &lt;code&gt;.ycm_extra_conf.py&lt;/code&gt; or gather flags you find useful from there and tailor your special config. Thanks &lt;a href=&#34;https://www.reddit.com/r/programming/comments/8v2eg4/navigating_the_linux_kernel_source_tree_with/e1kd9t0/&#34;&gt;lanzaio&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, we can still have such mapping by providing a &lt;code&gt;.ycm_extra_conf.py&lt;/code&gt; file that does the job of delivering the compilation flags for any given file. The whole point of this python file is to make the project owner implement the YCM interface for detecting flags for files:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a source file, give me its compilation flags.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As it&amp;rsquo;s common in C project to have a &amp;ldquo;catch all&amp;rdquo; target in a Makefile (like &lt;code&gt;%.o: %.c&lt;/code&gt;) that provides the same flags to every file, we can have a pretty simplified &lt;code&gt;.ycm_extra_conf.py&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;FlagsForFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kwargs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;flags&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;-I/usr/include&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;-std=gnu89&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;-xc&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Linux, that&amp;rsquo;s not very different - gather the flags used, supply them to &lt;code&gt;FlagsForFile&lt;/code&gt; and we&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;The necessary flags can be gathered by exposing two variables that get set in the Makefile: &lt;code&gt;LINUXINCLUDE&lt;/code&gt; and &lt;code&gt;USERINCLUDE&lt;/code&gt;. That&amp;rsquo;s because, for just autocompletion and source code navigation, includes and definitions are sufficient.&lt;/p&gt;
&lt;p&gt;To dump those variables, create an extra target in &lt;code&gt;./Makefile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/Makefile b/Makefile
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 019a5a02..88e1ad10 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/Makefile
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/Makefile
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -1792,6 +1792,10 @@ endif    # skip-makefile
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt; PHONY += FORCE
 FORCE:
 
&lt;span class=&#34;gi&#34;&gt;+show-includes:
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       @$(foreach include, $(LINUXINCLUDE), echo $(include);)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       @$(foreach include, $(USERINCLUDE), echo $(include);)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt; # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a v
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then prepare the &lt;code&gt;.config&lt;/code&gt; file that would be necessary for the tiniest possible kernel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make tinyconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the configuration set, now, executing &lt;code&gt;make&lt;/code&gt; specifying the &lt;code&gt;show-includes&lt;/code&gt; target dumps the variables we need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Piping it to `sort -u` to remove the duplicates&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and keep the list sorted.&lt;/span&gt;
make show-includes &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort -u
-I./arch/x86/include
-I./arch/x86/include/generated
-I./arch/x86/include/generated/uapi
-I./arch/x86/include/uapi
-I./include
-I./include/generated/uapi
-I./include/uapi
-include
./include/linux/kconfig.h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As the next step is to supply those variables to YouCompleteMe, we need first to realize that the daemon (&lt;code&gt;ycmd&lt;/code&gt;) will not deal well with these relative paths.&lt;/p&gt;
&lt;p&gt;In our Python script we can deal with that though:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;CURRENT_DIR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abspath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__file__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;include_dirs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./arch/x86/include&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./arch/x86/include/generated&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./arch/x86/include/generated/uapi&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./arch/x86/include/uapi&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./include&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./include/generated/uapi&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./include/uapi&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;include_files&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;./include/linux/kconfig.h&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;-D__KERNEL__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;-std=gnu89&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;-xc&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;-nostdinc&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;FlagsForFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kwargs&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Given a source file, retrieves the flags necessary for compiling it.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;dir&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;include_dirs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;-I&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CURRENT_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;include_files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;-include&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CURRENT_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;flags&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, open a file (like, &lt;code&gt;./net/socket.c&lt;/code&gt;) and check the autocompletion working! You can also check how &amp;ldquo;jump to&amp;rdquo; declarations and definitions also work.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/struct-autocompletion.png&#34;
       alt=&#34;Example of YouCompleteMe autocompleting a kernel struct &#34; &gt;

    
&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;Example of YouCompleteMe autocompleting a kernel struct.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have any questions or found any error, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Thu, 21 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/navigating-the-linux-kernel-source-with-youcompleteme/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/navigating-the-linux-kernel-source-with-youcompleteme/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>A minimal TCP Client in C</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;This week I needed to check whether in a given situation a given error would occur when connecting to a TCP server, so why not go back to the &lt;code&gt;man&lt;/code&gt; pages and review the steps?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I come up with! I hope it&amp;rsquo;s going to be useful for you who&amp;rsquo;s reading.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Start by specifying our dependencies.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * As we&amp;#39;re using only standard dependencies you&amp;#39;d find in a
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Linux machine, these can be found under `/usr/include`.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - `stdio.h` gives us the standard io (input and output) methods
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   like `fprintf` that allows us to format a given string and
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   write it to a specific file descriptor (usually stderr or
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   stdout).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - `unistd.h` defines constants, types and methods that provides
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   access to the POSIX API. Here we make use of the `close(2)`
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   syscall definition that can be found there.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - `arpa/inet` provides definitions for internet operations, most
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   notably, it gives us ways of converting addresses from string
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   formats (presentation) to numeric ones (and vice-versa).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   Given that `arpa/inet` includes `netinet/in.h`, it also provides
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   us with the definitions of `sockaddr_in`, the structure used
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   to define internet addresses.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * - `sys/socket.h` provides us the `socket(2)` syscall and its
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   necessary definitions.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * ADDRESS defines the IP of the server that we should
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * connect to.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * In this exampe, it must be a standard IPV4 address with
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * four octects representing the IP in a string format -
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * no names are allowed given that we don&amp;#39;t perform name
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * resolution.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Using GCC, this value can be specified by using the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * -D arguments with the address itself having escaped
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *  quotes (for instance: -DADDRESS=\&amp;#34;127.0.0.1\&amp;#34;). Without
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *  the escaping, `127.0.0.1` would be supplied instead of
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *  `&amp;#34;127.0.0.1&amp;#34;`, causing errors.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#ifndef ADDRESS
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define ADDRESS &amp;#34;127.0.0.1&amp;#34;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * PORT represents the server port we want to connect to.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Naturally, it must live in the range of [1,65k).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#ifndef PORT
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define PORT 8000
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;                &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;                &lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Specifiy the communication domain in which the address lives:
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// AF_INET      - IPV4;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// AF_INET6     - IPV6;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// AF_UNIX      - Local communication (used w/ unix sockets).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sin_family&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Assign the port that we supplied in host byte order in the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// form of network byte order (`htons` performs the conversion).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// On amd64 (x86-64), the byte ordering of the host is little endian
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// (o.e., the least significant byte comes first).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// However, when it comes to networking, the byte ordering is big
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// endian - the most significant byte comes first.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// This means that a value (like 8000) defined in our machine needs
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// to be properly translated to the network byte order before being
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// sent.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sin_port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;htons&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Fill the destination address with a 4-byte (32bit) unsigned integer
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// in network byte order after converting the address from the string
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// representation (e.g., &amp;#34;127.0.0.1&amp;#34;).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Given that we might see a failure in the conversion (e.g., if we
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// supply an invalid server_addr pointer or an invalid string), check
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// for these errors.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Note that differently from the majority of syscalls and glibc
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// methods, success is defined with `1`, and not `0`. The information of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// what represents success can often be found in man pages - e.g., `man
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// inet_pton`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inet_pton&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ADDRESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sin_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;inet_pton&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		        &lt;span class=&#34;s&#34;&gt;&amp;#34;failed to convert address %s &amp;#34;&lt;/span&gt;
		        &lt;span class=&#34;s&#34;&gt;&amp;#34;to binary net address&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		        &lt;span class=&#34;n&#34;&gt;ADDRESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stdout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CONNECTING: address=%s port=%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ADDRESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Create an endpoint for communication in our machine (our side) that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// is meant to communicate over the AF_INET (IPv4) domain, using
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// SOCK_STREAM semantics (sequenced, reliable, two-way, connection-base
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// byte streams - TCP, for instance).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Note that at this point, no communication has been made to an
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// external server yet - this operation is entirely local.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOCK_STREAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;socket&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Connect our local endpoint (represented by the socket file
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// descriptor) to the address specified by `server_addr`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// On a TCP connection, `connect` passes to the kernel the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// responsability of perming the TCP handshake, blocking the call while
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the kernel goes forward (when nonblocking flag - SOCK_NONBLOCK - is
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// not set in the socket).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Once the handshake has been succesful, on the server side the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// connection is then put into a queue so that the server can
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// `accept(2)` on a passive socket to make use of such established
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// connection.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
	  &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;connect&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// After the connection has been properly established, we could go
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// forward with `read(2)` and `write(2)` calls.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// As in this example we don&amp;#39;t want to read or write from it, we can
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// proceed with a `shutdown(2)`, which takes care of terminating our
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// side of the channel.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// By specifying `SHUT_RDWR`, not only furtes receptions are
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// dissallowed, but transmissions to.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shutdown&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SHUT_RDWR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;shutdown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Once the connection got properly terminated, now we can proceed with
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// actually closing the file descriptor
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you spot anything weird, just let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Wed, 20 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/a-minimal-tcp-client-in-c/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/a-minimal-tcp-client-in-c/</guid>

                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Using network namespaces and a virtual switch to isolate servers</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working on an &lt;code&gt;tc + ebpf&lt;/code&gt;-based load-balancer that I&amp;rsquo;ll soon talk about here in this blog, and one of the things I wanted to do was test such load-balancing feature.&lt;/p&gt;
&lt;p&gt;In my line of thought, I wondered: if I&amp;rsquo;m going to redirect the traffic by changing the destination address of the packets, that means that I&amp;rsquo;ll need somehow to have a different internet set up in the machine where I could put processes listening on those addresses.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/lb-overview.svg&#34;
       alt=&#34;Representation of the load-balancing architecture &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Having worked with Docker and implemented a tiny container runtime myself, it seemed clear that going with network namespaces, virtual interfaces and bridging would get the job done.&lt;/p&gt;
&lt;p&gt;How these two relate to each other become clearer after looking at what jobs they do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;network namespaces, according to &lt;code&gt;man 7 network_namespaces&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Network  namespaces  provide  isolation  of the system resources associated with networking: network devices, IPv4 and IPv6 protocol stacks, IP routing tables, firewall rules, the /proc/net directory, the /sys/class/net directory, various files under /proc/sys/net, port numbers (sockets), and so on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;virtual interfaces provide us with virtualized representations of physical network interfaces; and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the bridge gives us the virtual equivalent of a switch.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That said, we can combine these three virtual components and create a virtual network inside the host without the need of VMs. Very lightweight (and with a single dependency - &lt;code&gt;iproute2&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;setting-up&#34;&gt;Setting up&lt;/h3&gt;
&lt;p&gt;Assuming we want to simulate load-balancing across two different servers, that would mean that we&amp;rsquo;d set up the machine to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;two network namespace (in this case, we can think of each network namespace as a different computer);&lt;/li&gt;
&lt;li&gt;two veth pairs (we can think of each pair as two ethernet cards with a cable between them); and&lt;/li&gt;
&lt;li&gt;a bridge device that provides the routing to these two namespaces (we can think of this device as a switch).&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/namespaces-setup.svg&#34;
       alt=&#34;Representation of linux namespaces playing together with a virtual switch &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;First, let&amp;rsquo;s start with the namespaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Making use of the `ip` command from the `iproute2` &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# package we&amp;#39;re able to create the namespaces.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By convention, network namespace handles created by&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# iproute2 live under `/var/run/netns` (although they&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# could live somewhere, like `docker` does with its&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# namespaces - /var/run/docker/netns`).&lt;/span&gt;
ip netns add namespace1
ip netns add namespace2

&lt;span class=&#34;c1&#34;&gt;# Check that iproute2 indeed creates the files&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# under `/var/run/netns`.&lt;/span&gt;
tree /var/run/netns/
/var/run/netns/
├── namespace1
└── namespace2

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the namespaces have been set up, we can confirm the isolation by taking advantage of &lt;code&gt;ip netns exec&lt;/code&gt; and executing some commands there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# List all the interfaces with their corresponding&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# configurations.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We can verify that inside the namespace, only the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# loopback interface has been set.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip address show
1: lo: &amp;lt;LOOPBACK&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;65536&lt;/span&gt; qdisc noop state DOWN group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, we can start creating the veth pairs and associating one of their sides to their respective namespaces.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the two pairs.&lt;/span&gt;
ip link add veth1 &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; veth peer name br-veth1
ip link add veth2 &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; veth peer name br-veth2

&lt;span class=&#34;c1&#34;&gt;# Associate the non `br-` side&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with the corresponding namespace&lt;/span&gt;
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; veth1 netns namespace1
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; veth2 netns namespace2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These pairs act as tunnels between the namespaces (for instance, &lt;code&gt;namespace1&lt;/code&gt; and the default namespace).&lt;/p&gt;
&lt;p&gt;Now that the namespaces have an additional interface, check out that they&amp;rsquo;re actually there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Differently from before, now we see the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# extra interface (veth1) that we just added.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip address show
1: lo: &amp;lt;LOOPBACK&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;65536&lt;/span&gt; qdisc noop state DOWN group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
30: veth1@if29: &amp;lt;BROADCAST,MULTICAST&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; qdisc noop state DOWN group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
    link/ether d2:92:25:3c:79:c5 brd ff:ff:ff:ff:ff:ff link-netnsid &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see, the &lt;code&gt;veth&lt;/code&gt; interface has no IPV4 address associated with it.&lt;/p&gt;
&lt;p&gt;We can do so by making use of &lt;code&gt;ip addr add&lt;/code&gt; from within the corresponding network namespaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Assign the address 192.168.1.11 with netmask 255.255.255.0&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (see the `/24` mask there) to `veth1`.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip addr add 192.168.1.11/24 dev veth1


&lt;span class=&#34;c1&#34;&gt;# Verify that the ip address has been set.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip address show
1: lo: &amp;lt;LOOPBACK&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;65536&lt;/span&gt; qdisc noop state DOWN group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
30: veth1@if29: &amp;lt;BROADCAST,MULTICAST&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; qdisc noop state DOWN group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
    link/ether d2:92:25:3c:79:c5 brd ff:ff:ff:ff:ff:ff link-netnsid &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
    inet 192.168.1.2/24 scope global veth1
       valid_lft forever preferred_lft forever


&lt;span class=&#34;c1&#34;&gt;# Repeat the process, assigning the address 192.168.1.12 with &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# netmask 255.255.255.0 to `veth2`.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace2 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip addr add 192.168.1.12/24 dev veth2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although we have both IPs and interfaces set, we can&amp;rsquo;t establish communication with them.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because there&amp;rsquo;s no interface in the default namespace that can send the traffic to those namespaces - we didn&amp;rsquo;t either configure addresses to the other side of the veth pairs or configured a bridge device.&lt;/p&gt;
&lt;p&gt;With the creation of the bridge device, we&amp;rsquo;re then able to provide the necessary routing, properly forming the network:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the bridge device naming it `br1`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and set it up:&lt;/span&gt;
ip link add name br1 &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; bridge
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; br1 up

&lt;span class=&#34;c1&#34;&gt;# Check that the device has been created.&lt;/span&gt;
ip link &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep br1
33: br1: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; qdisc noqueue state UNKNOWN mode DEFAULT group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the bridge created, now it&amp;rsquo;s time to connect the bridge-side of the veth pair to the bridge device:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Set the bridge veths from the default&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# namespace up.&lt;/span&gt;
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; br-veth1 up
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; br-veth2 up

&lt;span class=&#34;c1&#34;&gt;# Set the veths from the namespaces up too.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; veth1 up
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace2 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; veth2 up

&lt;span class=&#34;c1&#34;&gt;# Add the br-veth* interfaces to the bridge&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by setting the bridge device as their master.&lt;/span&gt;
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; br-veth1 master br1
ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; br-veth2 master br1

&lt;span class=&#34;c1&#34;&gt;# Check that the bridge is the master of the two&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# interfaces that we set (i.e., that the two interfaces&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# have been added to it).&lt;/span&gt;
bridge link show br1
29: br-veth1@if30: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; master br1 state disabled priority &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt; cost &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
31: br-veth2@if32: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; master br1 state disabled priority &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt; cost &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, it&amp;rsquo;s a matter of giving this bridge device an address so that we can target such IP in our machine&amp;rsquo;s routing table making it a target for connections to those interfaces that we added to it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Set the address of the `br1` interface (bridge device)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to 192.168.1.10/24 and also set the broadcast address&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to 192.168.1.255 (the `+` symbol sets  the host bits to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# 255).&lt;/span&gt;
ip addr add 192.168.1.10/24 brd + dev br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Checking our routing table (from the default namespace), we can see that any requests with a destination to our namespaces (&lt;code&gt;192.168.1.0/24&lt;/code&gt;) go through our bridge device:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
10.0.2.2 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;
192.168.1.0/24 dev br1 proto kernel scope link src 192.168.1.10 &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can verify that we indeed have connectivity:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check the connectivity from the default namespace (host)&lt;/span&gt;
ping 192.168.1.12
PING 192.168.1.12 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;192.168.1.12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 56&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;84&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; bytes of data.
&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; bytes from 192.168.1.12: &lt;span class=&#34;nv&#34;&gt;icmp_seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ttl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0.050 ms
&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; bytes from 192.168.1.12: &lt;span class=&#34;nv&#34;&gt;icmp_seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ttl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0.061 ms

&lt;span class=&#34;c1&#34;&gt;# We can also reach the interface of the other namespace&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# given that we have a route to it.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip route
192.168.1.0/24 dev veth1 proto kernel scope link src 192.168.1.11

&lt;span class=&#34;c1&#34;&gt;# Let&amp;#39;s reach the other then iface then.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ping 192.168.1.12
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that the routing table from &lt;code&gt;namespace1&lt;/code&gt; doesn&amp;rsquo;t have a default gateway, it can&amp;rsquo;t reach any other machine from outside the &lt;code&gt;192.168.1.0/24&lt;/code&gt; range.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Try to reach Google&amp;#39;s DNS servers (8.8.8.8).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that there&amp;#39;s no route for something that doesn&amp;#39;t &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# match the `192.168.1.0/24` range, 8.8.8.8 should be unreachable.&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ping 8.8.8.8
connect: Network is unreachable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To fix that, the first step is giving the namespaces a default gateway route:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Execute the command to add the default gateway in all&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the network namespaces under `/var/run/netns`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The command is going to add a default gateway which should&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# be used for all connections that doesn&amp;#39;t match the other&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# specific routes. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# 192.168.1.10 corresponds to the address assigned to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# bridge device - reachable from both namespaces, as well as&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the host machine.&lt;/span&gt;
ip -all netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip route add default via 192.168.1.10

&lt;span class=&#34;c1&#34;&gt;# Check how the routing table looks inside the namespace&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ip route
default via 192.168.1.10 dev veth1
192.168.1.0/24 dev veth1 proto kernel scope link src 192.168.1.11
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Show we be able to reach the internet now? Not yet.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Try to reach Google&amp;#39;s DNS servers (8.8.8.8).&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ping 8.8.8.8
        PING 8.8.8.8 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8.8.8.8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 56&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;84&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; bytes of data.
^C
--- 8.8.8.8 ping statistics ---
&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; packets transmitted, &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; received, 100% packet loss, &lt;span class=&#34;nb&#34;&gt;time&lt;/span&gt; 2043ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although the network is now reachable, there&amp;rsquo;s no way that we can have responses back - packets from external networks can&amp;rsquo;t be sent directly to our &lt;code&gt;192.168.1.0/24&lt;/code&gt; network.&lt;/p&gt;
&lt;p&gt;To get around that, we can make use of NAT (network address translation) by placing an &lt;code&gt;iptables&lt;/code&gt; rule in the &lt;code&gt;POSTROUTING&lt;/code&gt; chain of the &lt;code&gt;nat&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# -t specifies the table to which the commands&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# should be directed to. By default it&amp;#39;s `filter`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -A specifies that we&amp;#39;re appending a rule to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# chain the we tell the name after it;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -s specifies a source address (with a mask in &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# this case).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -j specifies the target to jump to (what action to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# take).&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -t nat &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -A POSTROUTING &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -s 192.168.1.0/24 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -j MASQUERADE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although &lt;code&gt;NAT&lt;/code&gt; is set to work for the packets originating from &lt;code&gt;192.168.1.0/24&lt;/code&gt;, there&amp;rsquo;s still (yet another) one more configuration to do: enable packet forwarding (maybe this is already active in your case):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Enable ipv4 ip forwarding&lt;/span&gt;
sysctl -w net.ipv4.ip_forward&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Send some packets to 8.8.8.8&lt;/span&gt;
ip netns &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; namespace1 ping 8.8.8.8
PING 8.8.8.8 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8.8.8.8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 56&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;84&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; bytes of data.
&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; bytes from 8.8.8.8: &lt;span class=&#34;nv&#34;&gt;icmp_seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ttl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;61&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;43&lt;/span&gt; ms
&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; bytes from 8.8.8.8: &lt;span class=&#34;nv&#34;&gt;icmp_seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ttl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;61&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;35&lt;/span&gt; ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now (finally), we&amp;rsquo;re good! We have connectivity all the way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the host can direct traffic to an application inside a namespace;&lt;/li&gt;
&lt;li&gt;an application inside a namespace can direct traffic to an application in the host;&lt;/li&gt;
&lt;li&gt;an application inside a namespace can direct traffic to another application in another namespace; and&lt;/li&gt;
&lt;li&gt;an application inside a namespace can access the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Did we need bridge at all? That depends.&lt;/p&gt;
&lt;p&gt;If the intention was to have the communication going through the host to a namespace (or vice-versa) directly, just setting the pairs would be enough.&lt;/p&gt;
&lt;p&gt;Just in case you spot any mistake, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 12 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/using-network-namespaces-and-bridge-to-isolate-servers/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/using-network-namespaces-and-bridge-to-isolate-servers/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Adding privileged containers to Docker Swarm mode</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s been some time since an issue has been open under SwarmKit to address the lack of support to having privileged containers (see &lt;a href=&#34;https://github.com/docker/swarmkit/issues/1030)&#34;&gt;https://github.com/docker/swarmkit/issues/1030)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Although pull requests have been made (see &lt;a href=&#34;https://github.com/docker/swarmkit/pull/1129,&#34;&gt;https://github.com/docker/swarmkit/pull/1129,&lt;/a&gt; for instance), it seems like there&amp;rsquo;s no intention by the Docker team to have the feature added before entitlements get into moby (see &lt;a href=&#34;https://github.com/moby/moby/issues/32801)&#34;&gt;https://github.com/moby/moby/issues/32801)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Knowing those facts, and given that I&amp;rsquo;ve forked docker before (I blogged before on &lt;a href=&#34;https://ops.tips/blog/compiling-your-own-forked-docker-release/&#34;&gt;how to compile and run your own docker fork&lt;/a&gt;), why not give a try forking it and add support to privileged containers?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the journey looked like.&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#1-the-idea&#34;&gt;The idea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#2-modifying-the-cli&#34;&gt;Modifying the CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#3-modifying-swarmkit&#34;&gt;Modifying SwarmKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#4-modifying-the-docker-daemon&#34;&gt;Modifying the Docker Daemon&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;p&gt;Let&amp;rsquo;s get started then!&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/fork-docker-privileged-journey.svg&#34;
       alt=&#34;Illustration of the journey to get the fork working &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;1-the-idea&#34;&gt;1. The idea&lt;/h3&gt;
&lt;p&gt;The whole point of the modifications is as outlined in the swarmkit pull request:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;When create some container, we need &lt;code&gt;privileged=True&lt;/code&gt;. But swarmkit does not support this.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/docker/swarmkit/issues/1030#issue-161106957&#34;&gt;https://github.com/docker/swarmkit/issues/1030#issue-161106957&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is, the &lt;code&gt;--privileged&lt;/code&gt; flag that exists in a regular &lt;code&gt;docker run&lt;/code&gt; does not exist in &lt;code&gt;docker service create&lt;/code&gt; (and the subsequent API calls used by the CLI).&lt;/p&gt;
&lt;p&gt;Having that enables us to have any interesting functionality that requires more privileges than the default ones chosen by the Docker contributors. For instance, with &lt;code&gt;--privileged&lt;/code&gt; you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run docker in docker (&lt;code&gt;dind&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;run an NFS server;&lt;/li&gt;
&lt;li&gt;create special devices; and&lt;/li&gt;
&lt;li&gt;more.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-privileged-instantiation.svg&#34;
       alt=&#34;Representation of the process of instantiating a privileged service &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;As shown in the picture above, there are many places where our &lt;code&gt;privileged&lt;/code&gt; annotation has to go on.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s put them in place.&lt;/p&gt;
&lt;h3 id=&#34;2-modifying-the-cli&#34;&gt;2. Modifying the CLI&lt;/h3&gt;
&lt;p&gt;Not wanting to interact with the new feature using the remote api directly (using &lt;code&gt;curl&lt;/code&gt;, for instance), I decided to start messing with the &lt;a href=&#34;https://github.com/docker/cli&#34;&gt;docker/cli&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;Here is where we&amp;rsquo;re able to expose the &lt;code&gt;--privileged&lt;/code&gt; flag to users of the &lt;code&gt;docker&lt;/code&gt; client. For this part, check out the &lt;code&gt;privileged&lt;/code&gt; branch from my fork: &lt;a href=&#34;https://github.com/cirocosta/docker-cli/tree/privileged&#34;&gt;https://github.com/cirocosta/docker-cli/tree/privileged&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For any Go developer who has already developed an application with flag parsing and all that stuff, the first thing to search for is the place where the definition of the flags to be parsed live.&lt;/p&gt;
&lt;p&gt;Given that the &lt;code&gt;docker&lt;/code&gt; client has multiple subcommands, the organization in the repository follows the same pattern:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;tree ./cli/command -L &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
./cli/command
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- bundlefile
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- checkpoint
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- image
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- inspect
...
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- network
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- node
...
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- service     &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-- stack
...
&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;-- volume
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Getting there under &lt;code&gt;service&lt;/code&gt;, there&amp;rsquo;s an &lt;code&gt;opts.go&lt;/code&gt; file with all the options that the subcommands of &lt;code&gt;service&lt;/code&gt; needs. There you go:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 6d427451..b61b6c0f 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/cli/command/service/opts.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/cli/command/service/opts.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -483,6 +483,7 @@ type serviceOptions struct {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;        stopSignal      string
&lt;span class=&#34;gi&#34;&gt;+       privileged      bool
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        mounts          opts.MountOpt
        dns             opts.ListOpts
        dnsSearch       opts.ListOpts
&lt;span class=&#34;gu&#34;&gt;@@ -622,6 +623,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                                Groups:     options.groups.GetAll(),
                                StopSignal: options.stopSignal,
                                TTY:        options.tty,
&lt;span class=&#34;gi&#34;&gt;+                               Privileged: options.privileged,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;                                ReadOnly:   options.readOnly,
                                Mounts:     options.mounts.Value(),
                                DNSConfig: &amp;amp;swarm.DNSConfig{
&lt;span class=&#34;gu&#34;&gt;@@ -795,6 +797,8 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValu
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       flags.BoolVar(&amp;amp;opts.privileged, flagPrivileged, false, &amp;#34;Give extended privileges to the service&amp;#34;)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       flags.SetAnnotation(flagPrivileged, &amp;#34;version&amp;#34;, []string{&amp;#34;1.35&amp;#34;})
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        flags.BoolVarP(&amp;amp;opts.tty, flagTTY, &amp;#34;t&amp;#34;, false, &amp;#34;Allocate a pseudo-TTY&amp;#34;)

&lt;span class=&#34;gu&#34;&gt;@@ -878,6 +882,7 @@ const (
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       flagPrivileged              = &amp;#34;privileged&amp;#34;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        flagUpdateDelay             = &amp;#34;update-delay&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we were able to compile &lt;code&gt;cli&lt;/code&gt;, then &lt;em&gt;voilà&lt;/em&gt;, we&amp;rsquo;d have &lt;code&gt;--privileged&lt;/code&gt; setting a &lt;code&gt;Privileged&lt;/code&gt; boolean to &lt;code&gt;true&lt;/code&gt; in the service spec.&lt;/p&gt;
&lt;p&gt;Why wouldn&amp;rsquo;t it compile yet? Because the service spec doesn&amp;rsquo;t have such field! Time to modify SwarmKit.&lt;/p&gt;
&lt;h3 id=&#34;3-modifying-swarmkit&#34;&gt;3. Modifying SwarmKit&lt;/h3&gt;
&lt;p&gt;Looking at &lt;code&gt;api/specs.proto&lt;/code&gt;, we can see the definition of the messages that go through the SwarmKit API.&lt;/p&gt;
&lt;p&gt;There we can find one type of message that carries the type of information that fits our purpose: &lt;code&gt;ContainerSpec&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Container specifies runtime parameters for a container.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;see &lt;a href=&#34;https://github.com/cirocosta/swarmkit/blob/5598a39a89bd7482864c6279ae5544d9e8aa5299/api/specs.proto#L164&#34;&gt;swarmkit#api/specs.proto line 164&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That could only mean one thing - we had to proceed to add a &amp;ldquo;privileged&amp;rdquo; to this &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Being a property of a &lt;code&gt;protobuf&lt;/code&gt; message, that also meant that I&amp;rsquo;d need to regenerate the Golang definitions that are made up from the &lt;code&gt;protobuf&lt;/code&gt; specification.  That is, before proceeding, I&amp;rsquo;d need to grab the &lt;code&gt;protobuf&lt;/code&gt; compiler tooling ready.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/swarmkit-flow.svg&#34;
       alt=&#34;Representation of the modification of the swarmkit api protobuf message &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The installation goes like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;grab a &lt;code&gt;protoc&lt;/code&gt; (&lt;code&gt;protobuf&lt;/code&gt; compiler) release; and&lt;/li&gt;
&lt;li&gt;install the binary and the includes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, go to the &lt;a href=&#34;https://github.com/google/protobuf/releases&#34;&gt;protobuf releases page&lt;/a&gt; and grab the &lt;code&gt;x86-64&lt;/code&gt; (&lt;code&gt;amd64&lt;/code&gt;) version.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a zip that comes with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Archive:  ./protoc-3.5.1-linux-x86_64.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2017-12-22 19:21   include/
        0  2017-12-22 19:21   include/google/
        0  2017-12-22 19:21   include/google/protobuf/
     3781  2017-12-22 19:21   include/google/protobuf/struct.proto
     6283  2017-12-22 19:21   include/google/protobuf/type.proto
    36277  2017-12-22 19:21   include/google/protobuf/descriptor.proto
     7734  2017-12-22 19:21   include/google/protobuf/api.proto
     2422  2017-12-22 19:21   include/google/protobuf/empty.proto
        0  2017-12-22 19:21   include/google/protobuf/compiler/
     8200  2017-12-22 19:21   include/google/protobuf/compiler/plugin.proto
     5483  2017-12-22 19:21   include/google/protobuf/any.proto
     8196  2017-12-22 19:21   include/google/protobuf/field_mask.proto
     3745  2017-12-22 19:21   include/google/protobuf/wrappers.proto
     5975  2017-12-22 19:21   include/google/protobuf/timestamp.proto
     4890  2017-12-22 19:21   include/google/protobuf/duration.proto
     2352  2017-12-22 19:21   include/google/protobuf/source_context.proto
        0  2017-12-22 19:21   bin/
  4433736  2017-12-21 19:11   bin/protoc
      715  2017-12-22 19:21   readme.txt
---------                     -------
  4529789                     19 files
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;/bin/protoc&lt;/code&gt; is the binary that we need to have in our &lt;code&gt;$PATH&lt;/code&gt;, while those &lt;code&gt;protobuf&lt;/code&gt; definitions under &lt;code&gt;include&lt;/code&gt; must be placed in our default include path (&lt;code&gt;/usr/local/include&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In summary, here&amp;rsquo;s what you can do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Grab the release zip&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -SL &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -o protoc.zip &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-linux-x86_64.zip

&lt;span class=&#34;c1&#34;&gt;# Unzip it&lt;/span&gt;
unzip ./protoc.zip

&lt;span class=&#34;c1&#34;&gt;# Move the correpsonding files&lt;/span&gt;
sudo mv ./bin/protoc /usr/local/bin
sudo mv ./include/google /usr/local/include/google
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that, we have protobuf set for generating &lt;code&gt;swarmkit&lt;/code&gt; protobuf files.&lt;/p&gt;
&lt;p&gt;note.: we don&amp;rsquo;t need to install &lt;code&gt;github.com/golang/protobuf/protoc-gen-go&lt;/code&gt; given that &lt;code&gt;swarmkit&lt;/code&gt; uses &lt;code&gt;protoc-gen-gogoswarm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that done, we&amp;rsquo;re not able to apply the changes to our local clone of &lt;code&gt;swarmkit&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gd&#34;&gt;--- a/agent/exec/dockerapi/container.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/agent/exec/dockerapi/container.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -209,6 +209,7 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                PortBindings: c.portBindings(),
                Init:         c.init(),
                Isolation:    c.isolation(),
&lt;span class=&#34;gi&#34;&gt;+               Privileged:   c.spec().Privileged,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        }
 
        // The format of extra hosts on swarmkit is specified in:


&lt;span class=&#34;gh&#34;&gt;diff --git a/cmd/swarmctl/service/flagparser/container.go b/cmd/swarmctl/service/flagparser/container.go
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 1507a168..37f11dd1 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/cmd/swarmctl/service/flagparser/container.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/cmd/swarmctl/service/flagparser/container.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -15,6 +15,15 @@ func parseContainer(flags *pflag.FlagSet, spec *api.ServiceSpec) error {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                spec.Task.GetContainer().Image = image
        }
 
&lt;span class=&#34;gi&#34;&gt;+       if flags.Changed(&amp;#34;privileged&amp;#34;) {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               privileged, err := flags.GetBool(&amp;#34;privileged&amp;#34;)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               if err != nil {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                       return err
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               spec.Task.GetContainer().Privileged = privileged
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        if flags.Changed(&amp;#34;hostname&amp;#34;) {
                hostname, err := flags.GetString(&amp;#34;hostname&amp;#34;)
                if err != nil {

&lt;span class=&#34;gh&#34;&gt;diff --git a/api/specs.proto b/api/specs.proto
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 14448d04..a5945ec3 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/api/specs.proto
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/api/specs.proto
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -318,6 +318,9 @@ message ContainerSpec {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;        // PidsLimit prevents from OS resource damage by applications inside the container 
        // using fork bomb attack.
        int64 pidsLimit = 25;
&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       // Privileged gives extended privileges to the container
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       bool privileged = 26;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;protobuf&lt;/code&gt; definition updated, now generate the golang &lt;code&gt;protobuf&lt;/code&gt; files using &lt;code&gt;swarmkit&lt;/code&gt;&amp;rsquo;s makefile target:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Install extra dependencies that might be needed.&lt;/span&gt;
make setup

&lt;span class=&#34;c1&#34;&gt;# Generate the protobuf golang files.&lt;/span&gt;
make generate

&lt;span class=&#34;c1&#34;&gt;# Build the swarkit binaries&lt;/span&gt;
make binaries
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With everything getting properly compiled, that means that we should now proceed to the next step - incorporating the setting of &lt;code&gt;privileged&lt;/code&gt; flag to the &lt;code&gt;ContainerSpec&lt;/code&gt; message whenever &lt;code&gt;dockerd&lt;/code&gt; receives a &lt;code&gt;Privileged&lt;/code&gt; flag in its service spec.&lt;/p&gt;
&lt;h3 id=&#34;4-modifying-the-docker-daemon&#34;&gt;4. Modifying the Docker Daemon&lt;/h3&gt;
&lt;p&gt;Having a local fork, incorporating the modified &lt;code&gt;swarmkit&lt;/code&gt; into the fork doesn&amp;rsquo;t take much more than setting up the vendoring tool and changing a file here and there.&lt;/p&gt;
&lt;p&gt;As &lt;code&gt;docker&lt;/code&gt; makes use of &lt;a href=&#34;https://github.com/LK4D4/vndr&#34;&gt;vndr&lt;/a&gt; to vendor its dependencies, we can modify the &lt;code&gt;vndr&lt;/code&gt; configuration pointing &lt;code&gt;swarmkit&lt;/code&gt; at our forked repository instead of the regular &lt;code&gt;docker/swarmkit&lt;/code&gt; one and have it update the &lt;code&gt;vendor&lt;/code&gt; directory with it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get the current commit &lt;/span&gt;
swarmkit $ &lt;span class=&#34;nv&#34;&gt;FORKED_SWARMKIT_COMMIT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
5598a39a89bd7482864c6279ae5544d9e8aa5299

&lt;span class=&#34;c1&#34;&gt;# Go to our forked moby/moby repository&lt;/span&gt;
swarmkit $ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ../docker

&lt;span class=&#34;c1&#34;&gt;# Set a variable that defines the repository for `vndr`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to use to gather our forked source code.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;FORKED_SWARMKIT_REPO&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;https://github.com/cirocosta/swarmkit

&lt;span class=&#34;c1&#34;&gt;# Prepare the variables to be used in the SED replacement&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;SED_FROM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;\(github.com/docker/swarmkit\) \([a-zA-Z0-9]*\)&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;SED_TO&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;\1 &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$FORKED_SWARMKIT_COMMIT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$FORKED_SWARMKIT_REPO&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Perform the replacement in `vendor.conf`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: you could just grab an editor of your choice&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (like vim) and do the changes there.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I&amp;#39;m using `sed` just to make the changes&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# reproducible by copying and pasting.&lt;/span&gt;
docker $ sed &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  --in-place &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;s#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$SED_FROM&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$SED_TO&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;#g&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  ./vendor.conf

&lt;span class=&#34;c1&#34;&gt;# Update the dependencies&lt;/span&gt;
vndr
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the dependencies updated (i.e., with our &lt;code&gt;swarmkit&lt;/code&gt; code in!), build the binaries (they will now include our swarmkit code):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the `binary` target specified in ./Makefile&lt;/span&gt;
make binary
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will make use of a local instance of Docker that you must have running and then generate the daemon binaries at &lt;code&gt;./bundle&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./bundles/
├── binary-daemon
│   ├── docker-containerd
│   ├── docker-containerd-ctr
│   ├── docker-containerd-ctr.md5
│   ├── docker-containerd-ctr.sha256
│   ├── docker-containerd.md5
│   ├── docker-containerd.sha256
│   ├── docker-containerd-shim
│   ├── docker-containerd-shim.md5
│   ├── docker-containerd-shim.sha256
│   ├── dockerd -&amp;gt; dockerd-dev
│   ├── dockerd-dev
│   ├── dockerd-dev.md5
│   ├── dockerd-dev.sha256
│   ├── docker-init
│   ├── docker-init.md5
│   ├── docker-init.sha256
│   ├── docker-proxy
│   ├── docker-proxy.md5
│   ├── docker-proxy.sha256
│   ├── docker-runc
│   ├── docker-runc.md5
│   └── docker-runc.sha256
└── latest -&amp;gt; .
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Naturally, without any changes to &lt;code&gt;docker/docker&lt;/code&gt; itself, no flags would be passed to the recently modified SwarmKit &lt;code&gt;ContainerSpec&lt;/code&gt; struct.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/api/types/swarm/container.go b/api/types/swarm/container.go
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 0041653c9..c16c55fd8 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/api/types/swarm/container.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/api/types/swarm/container.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -57,6 +57,7 @@ type ContainerSpec struct {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;        Privileges      *Privileges             `json:&amp;#34;,omitempty&amp;#34;`
        StopSignal      string                  `json:&amp;#34;,omitempty&amp;#34;`
        TTY             bool                    `json:&amp;#34;,omitempty&amp;#34;`
&lt;span class=&#34;gi&#34;&gt;+       Privileged      bool                    `json:&amp;#34;,omitempty&amp;#34;`
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        OpenStdin       bool                    `json:&amp;#34;,omitempty&amp;#34;`
        ReadOnly        bool                    `json:&amp;#34;,omitempty&amp;#34;`
        Mounts          []mount.Mount           `json:&amp;#34;,omitempty&amp;#34;`
&lt;span class=&#34;gh&#34;&gt;diff --git a/daemon/cluster/convert/container.go b/daemon/cluster/convert/container.go
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 0a34fc73e..9eb1feb4e 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/daemon/cluster/convert/container.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/daemon/cluster/convert/container.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -17,6 +17,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;        if c == nil {
                return nil
        }
&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        containerSpec := &amp;amp;types.ContainerSpec{
                Image:      c.Image,
                Labels:     c.Labels,
&lt;span class=&#34;gu&#34;&gt;@@ -32,6 +33,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                OpenStdin:  c.OpenStdin,
                ReadOnly:   c.ReadOnly,
                Hosts:      c.Hosts,
&lt;span class=&#34;gi&#34;&gt;+    Privileged: c.Privileged,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;                Secrets:    secretReferencesFromGRPC(c.Secrets),
                Configs:    configReferencesFromGRPC(c.Configs),
                Isolation:  IsolationFromGRPC(c.Isolation),
&lt;span class=&#34;gu&#34;&gt;@@ -228,6 +230,7 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                Groups:     c.Groups,
                StopSignal: c.StopSignal,
                TTY:        c.TTY,
&lt;span class=&#34;gi&#34;&gt;+    Privileged: c.Privileged,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;                OpenStdin:  c.OpenStdin,
                ReadOnly:   c.ReadOnly,
                Hosts:      c.Hosts,
&lt;span class=&#34;gh&#34;&gt;diff --git a/daemon/cluster/executor/container/container.go b/daemon/cluster/executor/container/container.go
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 69d673bd3..829c5dcc3 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/daemon/cluster/executor/container/container.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/daemon/cluster/executor/container/container.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -351,6 +351,7 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;        hc := &amp;amp;enginecontainer.HostConfig{
                Resources:      c.resources(),
                GroupAdd:       c.spec().Groups,
&lt;span class=&#34;gi&#34;&gt;+               Privileged:     c.spec().Privileged,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;                PortBindings:   c.portBindings(),
                Mounts:         c.mounts(),
                ReadonlyRootfs: c.spec().ReadOnly,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compile it again, and now everything should be fine!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;To finish the whole thing, update the vendoring of the &lt;code&gt;docker/cli&lt;/code&gt; fork to incorporate those changes (yes, &lt;code&gt;docker/cli&lt;/code&gt; depends on &lt;code&gt;docker/docker&lt;/code&gt;, which depends on &lt;code&gt;docker/swarmkit&lt;/code&gt;) and now everything should compile.&lt;/p&gt;
&lt;p&gt;Modify your &lt;code&gt;docker.service&lt;/code&gt; to use the built binaries, call &lt;code&gt;docker service create&lt;/code&gt; using the recently built &lt;code&gt;docker&lt;/code&gt; binary and you&amp;rsquo;re good to go!&lt;/p&gt;
&lt;p&gt;If you found any mistakes or felt a little lost, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 05 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/adding-privileged-to-docker-swarm-mode/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/adding-privileged-to-docker-swarm-mode/</guid>

                                
                                        <category>docker</category>
                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Compiling and running your own forked Docker release</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Some days ago I needed to tweak Docker a little bit to check if changing some parameters of SwarmKit would make it work more reliably.&lt;/p&gt;
&lt;p&gt;Given that the value I needed changing was hardcoded, no &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; configuration would do the job. That meant that a fork would be needed.&lt;/p&gt;
&lt;p&gt;It turns out that building and running a forked version of Docker is not complicated once you get to know what are the pieces involved.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-ce-overview.svg&#34;
       alt=&#34;A sample illustration of the packages involved in a docker release &#34; &gt;

    
&lt;/figure&gt;

&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#what-does-the-docker-ce-package-installs-on-my-system&#34;&gt;What does the docker-ce package installs on my system?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#running-the-docker-daemon-behind-the-scenes&#34;&gt;Running the docker daemon behind the scenes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#building-right-from-the-docker-ce-repository&#34;&gt;Building right from the docker-ce repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#modifying-docker-the-daemon-from-the-main-repository&#34;&gt;Modifying docker (the daemon) from the main repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;what-does-the-docker-ce-package-installs-on-my-system&#34;&gt;What does the docker-ce package installs on my system?&lt;/h3&gt;
&lt;p&gt;As I&amp;rsquo;ve always been installing docker using &lt;code&gt;apt&lt;/code&gt;, the first step was to get it running right from the binaries.&lt;/p&gt;
&lt;p&gt;Not knowing what to expect from the building process, I started looking at what are the binaries that the &lt;code&gt;docker-ce&lt;/code&gt; package installs on the system.&lt;/p&gt;
&lt;p&gt;You can check which binaries are these by looking at &lt;code&gt;dpkg --listfiles &amp;lt;pkg_name&amp;gt;&lt;/code&gt; (it lists the files installed to your system from &lt;code&gt;pkg_name&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# List the files that the docker-ce package brought&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# us and then filter out those that are not in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the `/usr/bin` directory.&lt;/span&gt;
sudo dpkg --listfiles docker-ce &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  grep /usr/bin

/usr/bin
/usr/bin/docker
/usr/bin/docker-containerd
/usr/bin/docker-containerd-ctr
/usr/bin/docker-containerd-shim
/usr/bin/docker-init
/usr/bin/docker-proxy
/usr/bin/docker-runc
/usr/bin/dockerd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aside from &lt;code&gt;/usr/bin/docker&lt;/code&gt;, which is the Docker CLI, the others are components that are run behind the scenes by the Docker daemon (&lt;code&gt;dockerd&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dockerd&lt;/code&gt; is the daemon that keeps running as a server, taking commands from your &lt;code&gt;docker&lt;/code&gt; client (usually from a unix socket) and then acting upon them, creating containers leveraging the other &lt;code&gt;docker-*&lt;/code&gt; binaries.&lt;/p&gt;
&lt;h3 id=&#34;running-the-docker-daemon-behind-the-scenes&#34;&gt;Running the docker daemon behind the scenes&lt;/h3&gt;
&lt;p&gt;To have &lt;code&gt;dockerd&lt;/code&gt; running at all times, &lt;code&gt;docker-ce&lt;/code&gt; (the package) sets two &lt;a href=&#34;https://www.freedesktop.org/wiki/Software/systemd/&#34;&gt;&lt;code&gt;systemd&lt;/code&gt;&lt;/a&gt; configuration files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# List the files installed by `docker-ce` and the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# filter out those without a systemd in the path.&lt;/span&gt;
sudo dpkg --listfiles docker-ce &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  grep systemd

/lib/systemd
/lib/systemd/system
/lib/systemd/system/docker.service      &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt; &lt;/span&gt;
/lib/systemd/system/docker.socket       &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These are &lt;code&gt;systemd&lt;/code&gt; units, files that describe resources that should be taken care by &lt;code&gt;systemd&lt;/code&gt; - the default &lt;a href=&#34;https://en.wikipedia.org/wiki/Init&#34;&gt;init process&lt;/a&gt; used by most distributions (e.g., Ubuntu and Debian).&lt;/p&gt;
&lt;p&gt;The later (&lt;code&gt;docker.socket&lt;/code&gt;) controls the socket that &lt;code&gt;dockerd&lt;/code&gt; uses to listen for requests made by a client.&lt;/p&gt;
&lt;p&gt;Given that generally every &lt;code&gt;.socket&lt;/code&gt; file must have a corresponding &lt;code&gt;.service&lt;/code&gt; unit, the &lt;code&gt;docker.socket&lt;/code&gt; is tied to the &lt;code&gt;docker.service&lt;/code&gt; unit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;k&#34;&gt;[Unit]&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By telling the unit that it&amp;#39;s part of `docker.service`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we&amp;#39;re tying a relationship between them, making a restart&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# on `docker.service` propagate to this unit (the same for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a stop but not for a start).&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;PartOf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;docker.service&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Information about the socket that systemd should supervise.&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;[Socket]&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The address to listen on for a stream (`SOCK_STREAM`).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that it starts with a `slash`, a filesystem socket (`AF_UNIX`) &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is created.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;ListenStream&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/var/run/docker.sock&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# File permissions that should be used in the socket file.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;SocketMode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;0660&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;SocketUser&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;root&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;SocketGroup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;docker&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# This section carries information regarding installation of the unit.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Its sole purpose is to provide `systemd` information regarding `enable`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and `disable` commands issued by `systemctl` during installation or&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# uninstallation of units.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: without this section, `systemctl enable` doesn&amp;#39;t work.&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;[Install]&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Creates a symbolic link in the `.wants` directory of the `sockets` target,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# having the effect of making it a dependency of another unit.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This is telling systemd to pull in the unit when starting sockets.target.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;WantedBy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;sockets.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ps.: a cool effect of having the &lt;code&gt;.socket&lt;/code&gt; unit is that you can keep the socket unit active (thus, having &lt;code&gt;/var/run/docker.sock&lt;/code&gt; created) and the docker unit inactive (dockerd not running) at machine startup time such that only when a connection is made to the socket, docker starts.&lt;/p&gt;
&lt;p&gt;The former (&lt;code&gt;docker.service&lt;/code&gt;) is a service unit that not only executes the &lt;code&gt;dockerd&lt;/code&gt; daemon, but it also keeps track of its liveness and makes sure that this is only initialized after some dependencies are met.&lt;/p&gt;
&lt;p&gt;It looks like this (with comments added by me):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;k&#34;&gt;[Unit]&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here we specify some of the dependencies that `dockerd` has.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Although `After` only configures service startup order,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We place a strict dependency on `docker.socket`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - `network-online` is a target that waits until the network is&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   considered up. After this target is met, it&amp;#39;s supposed that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   connections to network resources can be established.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - `firewalld.service` lets us wait for any firewalld configs to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   go on before docker starts. Under a regular ubuntu installation&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#   this target generally doesn&amp;#39;t exist.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - `docker.socket` makes us start after the socket activation.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;After&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;network-online.target docker.socket firewalld.service&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# `Wants=` establishes a weak dependency on something.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This means that in contrast with `Requires=`, if something goes &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# wrong with it, it can still proceed.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Wants&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;network-online.target&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Enforces a hard dependency on `docker.socket` unit - if it fails,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# then this service will also fail.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Requires&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;docker.socket&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;[Service]&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Makes use of what&amp;#39;s specified in ExecStart as the main process&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of the service and then only proceeds to activate other dependencies&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (i.e., other units that specify a dependency on this service) after&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the process (dockerd) sends a notification to systemd via `sd_notify`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# See moby/cmd/dockerd/daemon_linux.go to check the `notifySystem` call.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;notify&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;ExecStart&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/usr/bin/dockerd -H fd://&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;ExecReload&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/bin/kill -s HUP $MAINPID&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;LimitNOFILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;1048576&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;LimitNPROC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;infinity&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;LimitCORE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;infinity&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;TasksMax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;infinity&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;TimeoutStartSec&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;0&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# As systemd can act as a Linux containers daemon, this clearly conflicts&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with the interests of the docker daemon over the containers controlled&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by docker.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Specifying `delegate=yes` we make systemd grant all the resource control&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the main process started by `ExecStart`.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Delegate&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;yes&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;KillMode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;process&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Restart&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;on-failure&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;StartLimitBurst&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;StartLimitInterval&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;60s&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;[Install]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;WantedBy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having those two files and the binaries, we can get Docker running from a set of binaries.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s now generate them then.&lt;/p&gt;
&lt;h3 id=&#34;building-right-from-the-docker-ce-repository&#34;&gt;Building right from the docker-ce repository&lt;/h3&gt;
&lt;p&gt;Although I&amp;rsquo;m not from Docker Inc, it seems like all the docker packaging for the community edition happens with what&amp;rsquo;s there in the &lt;a href=&#34;https://github.com/docker/docker-ce&#34;&gt;docker/docker-ce&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s make use of such repository then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Clone the docker-ce repository to somewhere&lt;/span&gt;
git clone https://github.com/docker/docker-ce
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./docker-ce

&lt;span class=&#34;c1&#34;&gt;# Checkout to the tag you want.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: you can gather the list of tags by &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# running git tag.&lt;/span&gt;
git checkout v18.03.1-ce

&lt;span class=&#34;c1&#34;&gt;# Having `make` installed, perform the build of &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the static binaries.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This will invoke a series of build steps that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# make use of the source code that lives under&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the `components` directory.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: you&amp;#39;re required to have a running `docker`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# daemon to proceed (`dockerd` is built using docker).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# If you&amp;#39;re curious, on a `t2.medium` machine without&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# any previous runs of this command (i.e, zero cache),&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# this takes the following `time`:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       real	9m44.885s&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       user	0m9.320s&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       sys	0m0.634s&lt;/span&gt;
make static &lt;span class=&#34;nv&#34;&gt;DOCKER_BUILD_PKGS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;static-linux


&lt;span class=&#34;c1&#34;&gt;# Check that results from the build&lt;/span&gt;
tree ./components/packaging/static/build/linux

./components/packaging/static/build/linux
├── docker
│   ├── docker
│   ├── docker-containerd
│   ├── docker-containerd-ctr
│   ├── docker-containerd-shim
│   ├── dockerd
│   ├── docker-init
│   ├── docker-proxy
│   └── docker-runc
└── docker-18.03.1-ce.tgz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it! Send that &lt;code&gt;.tgz&lt;/code&gt; to the machines you want, unpack it to the desired destination (&lt;code&gt;/usr/bin&lt;/code&gt; if you don&amp;rsquo;t want to change the systemd scripts) and you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;If all you wanted was a way to build docker from the ground and have the binaries, you can stop here.&lt;/p&gt;
&lt;h3 id=&#34;modifying-docker-the-daemon-from-the-main-repository&#34;&gt;Modifying docker (the daemon) from the main repository&lt;/h3&gt;
&lt;p&gt;Because &lt;code&gt;docker-ce&lt;/code&gt; is just a repository that gathers three others (&lt;code&gt;docker/docker-ce-packaging&lt;/code&gt;, &lt;code&gt;moby/moby&lt;/code&gt; and &lt;code&gt;docker/cli&lt;/code&gt;), it&amp;rsquo;s better to keep our modifications under a fork of the real thing (&lt;code&gt;moby/moby&lt;/code&gt;) and then (optionally) use a fork of &lt;code&gt;docker-ce&lt;/code&gt; to centralize our modifications.&lt;/p&gt;
&lt;p&gt;When cloning &lt;code&gt;moby/moby&lt;/code&gt; you&amp;rsquo;ll notice that the process of producing binaries is fairly straightforward: having &lt;code&gt;docker&lt;/code&gt; already running, issue &lt;code&gt;make binary&lt;/code&gt; and you&amp;rsquo;ll have a &lt;code&gt;bundles&lt;/code&gt; directory filled with the daemon binaries.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# `docker/docker` has been renamed to `moby/moby`, &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# but given that I want to keep the golang import&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# paths working, cloning from `docker/docker` makes&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# things easier.&lt;/span&gt;
git clone https://github.com/docker/docker

&lt;span class=&#34;c1&#34;&gt;# Set up the git remotes to have my fork&amp;#39;s source&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# code in.&lt;/span&gt;
git remote set-url origin https://github.com/cirocosta/docker
git remote add upstream https://github.com/docker/docker

&lt;span class=&#34;c1&#34;&gt;# Grab the code&lt;/span&gt;
git fetch --all

&lt;span class=&#34;c1&#34;&gt;# Check out to a branch with the modifications&lt;/span&gt;
git checkout privileged

&lt;span class=&#34;c1&#34;&gt;# Build the binaries&lt;/span&gt;
make binary
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being &lt;code&gt;dockerd&lt;/code&gt; made up of several components (like &lt;code&gt;swarmkit&lt;/code&gt; and &lt;code&gt;libnetwork&lt;/code&gt;), make sure that when you update those, you also update &lt;code&gt;moby/moby&lt;/code&gt;&amp;rsquo;s references (there&amp;rsquo;s a &lt;code&gt;vendor.conf&lt;/code&gt; file there that &lt;a href=&#34;https://github.com/LK4D4/vndr&#34;&gt;vndr&lt;/a&gt; - the vendoring tool - uses to fetch the dependencies). Thankfully, it&amp;rsquo;s very easy to make use of a fork in &lt;code&gt;vendor.conf&lt;/code&gt; - you specify the import path, the git reference of your modified content and then the fork.&lt;/p&gt;
&lt;p&gt;For instance, having modified &lt;code&gt;docker/swarmkit&lt;/code&gt;, I updated &lt;code&gt;vendor.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IMPORT PATH                GIT REF       MY FORK
github.com/docker/swarmkit 268f203dda... https://github.com/cirocosta/swarmkit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ps.: the same is true for other repositories, like &lt;code&gt;docker/cli&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If all you need is a modified daemon (and not a client), then now you&amp;rsquo;re done - distribute the binaries and you&amp;rsquo;re good.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It looks like the Docker contributors have spent a big time making sure that building Docker is not hard. What bothered me a bit is that it&amp;rsquo;s quite huge when it comes to dependencies - updating a dependency (using &lt;code&gt;vndr&lt;/code&gt;) will end up in fetching a bunch of repositories.&lt;/p&gt;
&lt;p&gt;Aside from the dependency complexity (which is understandable), I felt that the process was pretty straightforward - now I get why there are so many contributors.&lt;/p&gt;
&lt;p&gt;If you had any question or spotted a mistake, please let me know - I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter!&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 03 Jun 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/compiling-your-own-forked-docker-release/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/compiling-your-own-forked-docker-release/</guid>

                                
                                        <category>docker</category>
                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Shell: how to add a prefix to the output of multiple commands</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;This week I wanted to make the logs of a Docker build easier to read, and remembering how some tools prefix their outputs with a name, I thought that doing so would be a good way to go.&lt;/p&gt;
&lt;p&gt;In such scenario, I had the following structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── Dockerfile          # The Dockerfile that instruct the 
│                       # image building process
│
└── scripts             # directory full of scripts to be run
    ├── first.sh        # Ideally, each script would have its name
    ├── second.sh       # used as the prefix in the logs when they
    └── third.sh        # get executed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For this example, let&amp;rsquo;s assume that each of these scripts output a dummy text.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;cat ./scripts/&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;first,second,third&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;.sh
&lt;span class=&#34;c1&#34;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hello, first here&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hello, second here&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hello, third here&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Knowing how to run these three scripts would give a hint to how to proceed.&lt;/p&gt;
&lt;p&gt;Here I had some options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;find&lt;/code&gt; and `xargs together;&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;find&lt;/code&gt; with its &lt;code&gt;-exec&lt;/code&gt; argument;&lt;/li&gt;
&lt;li&gt;using a &lt;code&gt;for&lt;/code&gt; together with variable expansion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although all of them are capable of achieving the goal, I&amp;rsquo;d always first give a try to &lt;code&gt;find&lt;/code&gt; piping to &lt;code&gt;xargs&lt;/code&gt; - there are some caveats to running &lt;code&gt;for&lt;/code&gt; loops over files that might break your script in ways you don&amp;rsquo;t expect (given that there&amp;rsquo;s a variable expansion going on, files named after command-line arguments could break your execution later).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Search for all the files under the `./scripts`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# directory that end with `.sh`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Pipe the result of the search to `xargs`, which&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# then executes the command supplied in the positional&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# arguments replacing the replacement string supplied&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to `-I` (that is, when it finds `lol.sh`, it executes&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `bash lol.sh`.&lt;/span&gt;
find ./scripts -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.sh&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xargs -I &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt; bash &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt;
hello, first here
hello, third here
hello, second here
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, given that we&amp;rsquo;ll need to make use of piping to have our outputs prefixed, that&amp;rsquo;d mean making &lt;code&gt;xargs&lt;/code&gt; call an extra shell for that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# If we want to pipe the result of `bash` to another&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# command, then we need to use an extra shell to process&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the piping operator and set up the piping itself.&lt;/span&gt;
find ./scripts -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.sh&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xargs -I &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt; /bin/sh -c &lt;span class=&#34;s1&#34;&gt;&amp;#39;bash {} | wc -c&amp;#39;&lt;/span&gt;
      &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;
      &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;
      &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, in this case, using a &lt;code&gt;for&lt;/code&gt; loop seems to be the way to go (knowing that none of our files there are going to break us):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; script in *.sh&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
        bash &lt;span class=&#34;nv&#34;&gt;$script&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; wc -c
&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
      &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;
      &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;
      &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, to solve the problem we introduced before (prefixing the output of the executions), we can leverage the fact that we can take the output produced by those executions and then mutate them accordingly such that the final result has a prefix.&lt;/p&gt;
&lt;p&gt;Naturally, &lt;code&gt;sed&lt;/code&gt; is a great candidate for mutating streams of strings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a stream of multiline text&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;haha\nhaha\nhaha\n&amp;#39;&lt;/span&gt;
haha
haha
haha

&lt;span class=&#34;c1&#34;&gt;# Create a stream of multiline text and pipe&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it to `sed`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Using the `s/regular expression/replacement/`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can provide a regular expression that matches&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the very initial part of the string and then &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# replace that by a prefix.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;haha\nhaha\nhaha\n&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s/^/prefix: /&amp;#39;&lt;/span&gt;
prefix: haha
prefix: haha
prefix: haha
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Putting all together, we can make use of script name in the place of &lt;code&gt;prefix&lt;/code&gt; in the &lt;code&gt;sed&lt;/code&gt; rule and achieve our goal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Iterate over all the script files under ./scripts.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that the expansion will result in names that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# include the `./scripts` prefix and the `.sh` suffix,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can make use of bash&amp;#39;s prefix and suffix replacement&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# syntax to get rid of that and end up with the pure name.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Once clean names are got, then it&amp;#39;s time to use in `sed`.&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; script in ./scripts/*.sh&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#./scripts/&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.sh&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;

  bash &lt;span class=&#34;nv&#34;&gt;$script&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sed &lt;span class=&#34;s2&#34;&gt;&amp;#34;s/^/[&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;] /&amp;#34;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;first&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; hello, first here
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;second&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; hello, second here
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;third&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; hello, third here
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As an extra tip, if you happen to have your output being forwarded to a log collector and you see many lines (that should be separate) comming together, it might be the case that &lt;code&gt;sed&lt;/code&gt; is performing some buffering. You can get rid of such behavior by executing &lt;code&gt;sed&lt;/code&gt; with &lt;code&gt;stdbuf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;Please let me know if you have any questions or if you spot anything wrong. I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 13 May 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/shell-prefix-output-of-commands/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/shell-prefix-output-of-commands/</guid>

                                
                                        <category>shell</category>
                                
                        </item>
                        
                

                        
                

                        
                        <item>
                                <title>Using HAProxy maps with Access control lists (acl)</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve ever wondered whether you can tie Access Control Lists (ACLs) with maps in HAProxy, the answer is: yes.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s tailor a scenario here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;based on a map, decide whether a request to a given domain should be answered by the current frontend or not - in the negative case, forward the request to a different frontend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One application that can be thought from this is the case where some domains are meant to be served by both a plain HTTP frontend and a HTTPS frontend too, but some other domains must be redirected to HTTPS when a request is made to HTTP.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://test.example.com&lt;/code&gt; and &lt;code&gt;https://test.example.com&lt;/code&gt; OK;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://prod.example.com&lt;/code&gt; is OK but no &lt;code&gt;http://prod.example.com&lt;/code&gt; such that when a request is made to &lt;code&gt;http://prod.example.com&lt;/code&gt;, this should be redirected to the HTTPS frontend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That said, this is how our configuration would look like:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/gists/-/images/haproxy-acl-map-config.svg&#34;
       alt=&#34;Illustration of the frontend configuration of the haproxy configuration &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Let&amp;rsquo;s write it then.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Load the `./script.lua` script that defines some services&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that are meant to respond with `SERVICE_N OK` when a request&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is made to them.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Having these services defined allows us to not need a real&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# server behind the scenes.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;global&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;lua-load	./script.lua&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;mode		http&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;timeout		client 10000&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;timeout		server 10000&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;timeout		connect 1000&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# The frontend `fe1` is the one that clients are meant to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# make requests to in order to access the backends as mapped&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by the `./domain-map` file.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The contents of the `domain-map` file are:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       foo.com backend_1&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       bar.com backend_2&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This way, requests that are not for `foo.com` or `bar.com`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# are sent to the other frontend (fe2) based on an ACL, otherwise,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the respective backend is used.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend		fe1&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;bind		127.0.0.1:8000&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;acl		has_domain hdr(Host),map_str(./domain-map) -m found&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;redirect	prefix http://127.0.0.1:8001 if ! has_domain&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;use_backend	%[req.hdr(host),lower,map_str(./domain-map)]&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# A sample frontend that always responds with a specific&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# service (demonstration purposes).&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend		fe2&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;bind		127.0.0.1:8001&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;http-request	use-service lua.service3&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;backend			backend_1&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;http-request	use-service lua.service1&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;backend			backend_2&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;http-request	use-service lua.service2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being &lt;code&gt;service1&lt;/code&gt;, &lt;code&gt;service2&lt;/code&gt; and &lt;code&gt;service3&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span class=&#34;n&#34;&gt;core.register_service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;service1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;SERVICE 1 OK&amp;#34;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;core.register_service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;service2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;SERVICE 2 OK&amp;#34;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;core.register_service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;service3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;SERVICE 3 OK&amp;#34;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can see it in practice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Make a request with `foo.com` as the destination host.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that `foo.com` is a mapped backend, the request&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# will get directed to a backend controlled by the frontend&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# itself (backend_1)&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --location &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Host: foo.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --verbose &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        localhost:8000/
* Connected to localhost &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;127.0.0.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; port &lt;span class=&#34;m&#34;&gt;8000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;#0)&lt;/span&gt;
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: foo.com
&amp;gt; User-Agent: curl/7.59.0
&amp;gt; Accept: */*
&amp;gt; 
&amp;lt; HTTP/1.1 &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt; OK
&amp;lt; Transfer-encoding: chunked
&amp;lt; 
SERVICE &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; OK

&lt;span class=&#34;c1&#34;&gt;# Just like in the case above, `bar.com` is also a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# domain controlled by this frontend.&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --location &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Host: bar.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --verbose &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        localhost:8000/
* Connected to localhost &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;127.0.0.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; port &lt;span class=&#34;m&#34;&gt;8000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;#0)&lt;/span&gt;
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: bar.com
&amp;gt; User-Agent: curl/7.59.0
&amp;gt; Accept: */*
&amp;gt; 
&amp;lt; HTTP/1.1 &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt; OK
&amp;lt; Transfer-encoding: chunked
&amp;lt; 
* Connection &lt;span class=&#34;c1&#34;&gt;#0 to host localhost left intact&lt;/span&gt;
SERVICE &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; OK


&lt;span class=&#34;c1&#34;&gt;# Differently from the two cases above, `test.com`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is not included in the frontend1 map.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This means that the ACL we placed there will evaluate&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `has_domain` to false and then will redirect us to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the second frontend  (which always responds with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# SERVICE 3). &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Check out how we get redirected to the other frontend.&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --location &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Host: test.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --verbose &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        localhost:8000/
* Connected to localhost &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;127.0.0.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; port &lt;span class=&#34;m&#34;&gt;8000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;#0)&lt;/span&gt;
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: test.com
&amp;gt; User-Agent: curl/7.59.0
&amp;gt; Accept: */*
&amp;gt; 
&amp;lt; HTTP/1.1 &lt;span class=&#34;m&#34;&gt;302&lt;/span&gt; Found
&amp;lt; Cache-Control: no-cache
&amp;lt; Content-length: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&amp;lt; Location: http://127.0.0.1:8001/      &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt; REDIRECTION&lt;/span&gt;
&amp;lt;                                       &lt;span class=&#34;c1&#34;&gt;# sends us to another frontend&lt;/span&gt;

* Connection &lt;span class=&#34;c1&#34;&gt;#0 to host localhost left intact&lt;/span&gt;
* Issue another request to this URL: &lt;span class=&#34;s1&#34;&gt;&amp;#39;http://127.0.0.1:8001/&amp;#39;&lt;/span&gt;
*   Trying 127.0.0.1...
* TCP_NODELAY &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;
* Connected to 127.0.0.1 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;127.0.0.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; port &lt;span class=&#34;m&#34;&gt;8001&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;#1)&lt;/span&gt;
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: 127.0.0.1:8001
&amp;gt; User-Agent: curl/7.59.0
&amp;gt; Accept: */*
&amp;gt; 
&amp;lt; HTTP/1.1 &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt; OK
&amp;lt; Transfer-encoding: chunked
&amp;lt; 
* Connection &lt;span class=&#34;c1&#34;&gt;#1 to host 127.0.0.1 left intact&lt;/span&gt;
SERVICE &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;If you have any questions or spotted something off, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Thu, 10 May 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/how-to-haproxy-acl-map/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/how-to-haproxy-acl-map/</guid>

                                
                                        <category>haproxy</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Making HAProxy respond 200 OK to health checks</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;This is a quick post for those who might need to perform HTTP health checks against a running HAProxy instance.&lt;/p&gt;
&lt;p&gt;From my perspective, three ways of doing it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using the &lt;code&gt;monitor-uri&lt;/code&gt; directive (you should use this one);&lt;/li&gt;
&lt;li&gt;using a custom HTTP file with &lt;code&gt;errorfile&lt;/code&gt; directive;&lt;/li&gt;
&lt;li&gt;using a lua script.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While the first and seconds should work in any HAProxy installation, the third requires &lt;code&gt;lua&lt;/code&gt;, which your HAProxy binary might have support or not.&lt;/p&gt;
&lt;p&gt;ps.: In the past, I wrote about &lt;a href=&#34;https://ops.tips/blog/installing-haproxy-lua-macos/&#34;&gt;how to install haproxy with Lua on MacOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The gist of it can be summarized in a single &lt;code&gt;haproxy.conf&lt;/code&gt; file that contains three frontends - each representing a way of doing it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#	This configuration demonstrates how several frontends&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	can be created in different ways to indicate&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	via HTTP that the HAProxy instance is running.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	The usefulness of these arise in scenarios like&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	AWS NLB where no TCP health check can be specified&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	and you can&amp;#39;t modify the health check headers.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;global&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;lua-load	./script.lua&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;mode		http&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;timeout		client 10000&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;timeout		server 10000&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;timeout		connect 1000&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;#	The first way of doing it is via lua scripting:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	a script (which registers a service) is loaded&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	and then when a request is made to a frontend&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	with the directive `use-service`, the script&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	does the job of responding with 200OK.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend		status-lua&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;bind		127.0.0.1:8000&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;http-request	use-service lua.status_service&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;#	The second way is using `monitor-uri` (the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	proper way of doing since you can make the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	monitor fail in other parts of the configuration&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	and there&amp;#39;s no lua involved).&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend		status-monitor&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;bind		127.0.0.1:8001&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;monitor-uri	/&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	The third way is using a &amp;#34;hack&amp;#34;: setting errorfile&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	to respond with a 200OK when a 503 happens, we&amp;#39;re&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#	able to indicate that HAProxy is active.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend		status-errorfile&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;bind		127.0.0.1:8002&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;http-request	set-log-level silent&lt;/span&gt;
	&lt;span class=&#34;na&#34;&gt;errorfile	503 ./200.http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that, we now need to tailor a &lt;code&gt;script.lua&lt;/code&gt; file that defines the &lt;code&gt;status_service&lt;/code&gt; that is used by the first frontend:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span class=&#34;c1&#34;&gt;-- `core` is a static class provided by haproxy containing all&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- the haproxy methods we can use.&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;-- `register_init` registers a function to be executed after&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- configuration parsing.&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;core.register_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;core.log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core.info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;script loaded: case-200-ok&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;-- `register_service` registers a lua function to be executed&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- as a service. Once it&amp;#39;s been properly registered, the service&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- can be referenced in the haproxy configuration as `lua.&amp;lt;svc_name&amp;gt;`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;--&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- Depending on the mode (tcp or http), the applet is either an&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- AppletHTTP or AppletTCP class instance.&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;core.register_service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;status_service&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;applet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then, for the last frontend, tailor a &lt;code&gt;200.http&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-http&#34; data-lang=&#34;http&#34;&gt;&lt;span class=&#34;kr&#34;&gt;HTTP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1.0&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;OK&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Cache-Control&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;no-cache&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;close&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Content-Type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;text/plain&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;User-Agent&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;*&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Allow&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;/&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ps.: given that we&amp;rsquo;re defining the whole HTTP message, it must end with carriege return and line feed (&lt;code&gt;\r\n&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;Load &lt;code&gt;haproxy.conf&lt;/code&gt; and you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;p&gt;If you have any doubts or spotted any mistakes, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 05 May 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/making-haproxy-respond-200ok-to-health-checks/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/making-haproxy-respond-200ok-to-health-checks/</guid>

                                
                                        <category>haproxy</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Blocking EC2 Metadata service from Docker containers in AWS</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Those who already have deployed Docker to an EC2 instance might have noticed (or not) that, within the containers, you&amp;rsquo;re able to perform requests to the EC2 metadata service, discovering information about the host from within these containers.&lt;/p&gt;
&lt;p&gt;While in some cases that&amp;rsquo;s a desired thing (i.e., not needing to explicitly pass credentials to containers and make use of instance profiles to authenticate against AWS services), sometimes it ends up leaking information that the containers (which maybe you don&amp;rsquo;t control) shouldn&amp;rsquo;t have access to.&lt;/p&gt;
&lt;p&gt;As a way of showing both the usefulness of the metadata service and a setup where containers can&amp;rsquo;t access the service, one could tailor an instance like this:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/ec2-metadata-block-overview.svg&#34;
       alt=&#34;Sample EC2 instance with containers being blocked of accessing the EC2 metadata service while a regular process can &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;A regular EC2 instance containing two components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cirocosta/awsmon&#34;&gt;cirocosta/awsmon&lt;/a&gt; service: a daemon that gathers host metrics that AWS doesn&amp;rsquo;t automatically retrieve for you (like memory and load) and forwards it to AWS CloudWatch - without any hardcoded credentials, it makes use of the aws metadata service to retrieve the credentials necessary for putting metrics in cloudwatch;&lt;/li&gt;
&lt;li&gt;docker running containers that I want not to be able to access the EC2 metadata service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It turns out that there&amp;rsquo;s not much documentation out there on how to accomplish such kind of setup.&lt;/p&gt;
&lt;p&gt;In this blog post, I go through the steps of making regular processes be able to connect to a destination while at the same time blocking containers from doing so (while still not removing all their external connectivity).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#what-s-ec2-metadata-service-about&#34;&gt;What&amp;rsquo;s EC2 metadata service about&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#blocking-any-connectivity-to-the-ec2-metadata-service&#34;&gt;Blocking any connectivity to the EC2 metadata service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-internal-networks-to-block-external-requests&#34;&gt;Using internal networks to block external requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-classid-marking&#34;&gt;Using classid marking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#a-solution-using-the-docker-user-chain&#34;&gt;A solution: using the DOCKER-USER chain&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;whats-ec2-metadata-service-about&#34;&gt;What&amp;rsquo;s EC2 metadata service about&lt;/h3&gt;
&lt;p&gt;The instance metadata service is a service that you can access by making requests to a well-defined address from within an EC2 instance: &lt;code&gt;http://169.254.169.254&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check what are the types of metadata values that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can gather.&lt;/span&gt;
curl 169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
hostname
iam/                    &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt; this is interesting&lt;/span&gt;
instance-action
instance-id
...


&lt;span class=&#34;c1&#34;&gt;# Retrieve the public IPV4 address of the current&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instance.&lt;/span&gt;
curl 169.254.169.254/latest/meta-data/public-ipv4
18.231.176.21


&lt;span class=&#34;c1&#34;&gt;# Retrieve the instance profile associated with the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instance that we&amp;#39;re running.&lt;/span&gt;
curl http://169.254.169.254/latest/meta-data/iam/info
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Code&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;Success&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;LastUpdated&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;2018-04-29T13:29:01Z&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;InstanceProfileArn&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;arn:aws:iam::111111111:instance-profile/put-metrics-profile&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;InstanceProfileId&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;AAAABBBBBBBCCCCCDDD&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Retrieve the credentials generated for the role (default) &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# assigned to the instance profile associated with the instance.&lt;/span&gt;
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/default
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Code&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;Success&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;LastUpdated&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;2018-04-29T13:28:16Z&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Type&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;AWS-HMAC&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;AccessKeyId&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;AAAEEEEEIIIIOOO&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;SecretAccessKey&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;aaaaaaaa2222222233333330000aaa&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Token&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;a-very-long-token-that-looks-to-be-base64-encoded=&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Expiration&amp;#34;&lt;/span&gt; : &lt;span class=&#34;s2&#34;&gt;&amp;#34;2018-04-29T19:50:14Z&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not only information regarding the machine can be retrieved as you can see - security credentials are also first-class citizens in the metadata service.&lt;/p&gt;
&lt;p&gt;When you create an instance with an instance profile attached, this instance can retrieve the role credentials by making requests to this service.&lt;/p&gt;
&lt;p&gt;Given that the service (like almost any other in AWS) is &lt;a href=&#34;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-throttling&#34;&gt;throttled&lt;/a&gt;, making too many requests to the service will make it unavailable for the machine.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re using the instance metadata service to retrieve AWS security credentials, avoid querying for credentials during every transaction or concurrently from a high number of threads or processes, as this may lead to throttling. Instead, we recommend that you cache the credentials until they start approaching their expiry time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A user container could create a denial of service just by making too many requests to it, making the service unavailable to services in the machine that need to use it.&lt;/p&gt;
&lt;h3 id=&#34;blocking-any-connectivity-to-the-ec2-metadata-service&#34;&gt;Blocking any connectivity to the EC2 metadata service&lt;/h3&gt;
&lt;p&gt;The most straightforward way to block any requests to the EC2 metadata service is by modifying the routing table of the instance.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Show the kernel&amp;#39;s IP routing table&lt;/span&gt;
route 
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.31.0.1      0.0.0.0         UG    &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; docker0
172.18.0.0      0.0.0.0         255.255.0.0     U     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; docker_gwbridge
172.31.0.0      0.0.0.0         255.255.240.0   U     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; eth0
172.31.0.1      0.0.0.0         255.255.255.255 UH    &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; eth0


&lt;span class=&#34;c1&#34;&gt;# Place a rejection for the fixed IP of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# metadata service&lt;/span&gt;
route add -host 169.254.169.254 reject

&lt;span class=&#34;c1&#34;&gt;# Check the updated IP table&lt;/span&gt;
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.31.0.1      0.0.0.0         UG    &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; eth0
169.254.169.254 -               255.255.255.255 !H    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      -        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -
172.17.0.0      0.0.0.0         255.255.0.0     U     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; docker0
172.18.0.0      0.0.0.0         255.255.0.0     U     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; docker_gwbridge
172.31.0.0      0.0.0.0         255.255.240.0   U     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; eth0
172.31.0.1      0.0.0.0         255.255.255.255 UH    &lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; eth0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given that we&amp;rsquo;re rejecting traffic at the routing decision moment, no traffic (either from a container of from the host) is able to get to that address.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Try to make a request to the EC2 metadata service&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# right from the host.&lt;/span&gt;
curl http://169.254.169.254/ -v
*   Trying 169.254.169.254...
* TCP_NODELAY &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;
* Immediate connect fail &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; 169.254.169.254: No route to host
* Closing connection &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
curl: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; Couldnt connect to server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a container, we can&amp;rsquo;t connect either:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run a container and then try the same&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# command.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that at some point the process inside&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the container will end up issuing a `connect`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that goes through the routing table, it&amp;#39;ll&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# fail.&lt;/span&gt;
docker run -it alpine /bin/sh
apk add --update curl
curl http://169.254.169.254/ -v
*   Trying 169.254.169.254...
* TCP_NODELAY &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;
* connect to 169.254.169.254 port &lt;span class=&#34;m&#34;&gt;80&lt;/span&gt; failed: Host is unreachable
* Failed to connect to 169.254.169.254 port 80: Host is unreachable
* Closing connection &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
curl: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; Failed to connect to 169.254.169.254 port 80: Host is unreachable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If all you need is make sure that happens after you extracted initial metadata that is static (e.g., the instance&amp;rsquo;s region, the instance&amp;rsquo;s id etc), this is enough and no concerns regarding Docker changing iptables would be raised.&lt;/p&gt;
&lt;p&gt;In the case of needing to preserve host connectivity to the service and disallowing docker containers to access it, then a different approach is needed.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: you can remove the &amp;ldquo;reject route&amp;rdquo; by issuing &lt;code&gt;route del 169.254.169.254 reject&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;using-internal-networks-to-block-external-requests&#34;&gt;Using internal networks to block external requests&lt;/h3&gt;
&lt;p&gt;When making use of overlay networks, one easy way of prohibiting requests to external services is creating internal-only networks.&lt;/p&gt;
&lt;p&gt;These are networks without connectivity to the &lt;code&gt;docker_gwbridge&lt;/code&gt; that allows containers to make external requests.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create two networks: one that is internal-only and another&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that is a regular network with external connectivity.&lt;/span&gt;
docker network create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --driver overlay &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --attachable &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --internal mynet-internal
docker network create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --driver overlay &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --attachable mynet

&lt;span class=&#34;c1&#34;&gt;# Run a container in the network with external connectivity&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --network mynet &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --tty &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name with-conn &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        alpine /bin/sh

docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; with-conn ping 8.8.8.8
PING 8.8.8.8 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8.8.8.8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;56&lt;/span&gt; data bytes
&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; bytes from 8.8.8.8: &lt;span class=&#34;nv&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ttl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;51&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;2.603 ms
&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt; bytes from 8.8.8.8: &lt;span class=&#34;nv&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ttl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;51&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;2.629 ms
^C


&lt;span class=&#34;c1&#34;&gt;# Run a container in the network without external connectivity&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --network mynet-internal &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --tty &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name without-conn &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        alpine /bin/sh

docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; without-conn ping 8.8.8.8
PING 8.8.8.8 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8.8.8.8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;56&lt;/span&gt; data bytes
ping: sendto: Network unreachable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Naturally, this covers a very particular use case - total isolation from outside the network -, not very suitable for most people.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious regarding the difference between these two networks, check out how the interfaces and routing are set up inside the namespaces of these containers we just created.&lt;/p&gt;
&lt;p&gt;In the one with a network that enables external connectivity, there&amp;rsquo;s an extra interface that ends up connected to the &lt;code&gt;docker_gwbridge&lt;/code&gt; interface in the host via an extra interface set up within the container&amp;rsquo;s network namespace:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-container-with-connectivity.svg&#34;
       alt=&#34;Sample container network configuration together with its routing table &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Any requests that are not directed towards the internal network are then routed to &lt;code&gt;docker_gwbridge&lt;/code&gt; in the host.&lt;/p&gt;
&lt;p&gt;Given that, in the host, docker configures the necessary iptables rules to NAT outgoing packets that originate from the &lt;code&gt;docker_gwbridge&lt;/code&gt; interface, packets can flow to the outside world without problems.&lt;/p&gt;
&lt;p&gt;In the other container though, there&amp;rsquo;s only the overlay network interface and no extra route to a default gateway like in the first.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-container-without-connectivity.svg&#34;
       alt=&#34;Sample container connected to an internal network without external connectivity &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Putting everything together and assuming that there&amp;rsquo;s an extra container without connectivity, the overview is like the following:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-external-connectivity.svg&#34;
       alt=&#34;Overview of the network configuration of containers in a network with and without external connectivity &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;using-classid-marking&#34;&gt;Using classid marking&lt;/h3&gt;
&lt;p&gt;Given that every container runs in a &lt;code&gt;cgroup&lt;/code&gt;, and that it&amp;rsquo;s possible to make Docker use a parent cgroup that encapsulates all the containers, we could eventually use &lt;code&gt;net_cls.classid&lt;/code&gt; to put a little mark in every packet and then make use of that mark in &lt;code&gt;iptables&lt;/code&gt; to block certain traffic.&lt;/p&gt;
&lt;p&gt;Although it&amp;rsquo;s indeed possible to have &lt;code&gt;net_cls.classid&lt;/code&gt; setup, we can&amp;rsquo;t make use of such mark from outside the network namespace of the container (as the &lt;code&gt;classid&lt;/code&gt; is restricted by the namespace).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-container-classid.svg&#34;
       alt=&#34;Sample container with net_cls.classid configured and making SCMP requests &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Such limitation means that to go with such strategy we&amp;rsquo;d need to put specific iptables rules in every container namespace created.&lt;/p&gt;
&lt;p&gt;Not good.&lt;/p&gt;
&lt;h3 id=&#34;a-solution-using-the-docker-user-chain&#34;&gt;A solution: using the DOCKER-USER chain&lt;/h3&gt;
&lt;p&gt;Recent Docker daemons include an extra chain that is never changed by the daemon - the &lt;code&gt;DOCKER-USER&lt;/code&gt; chain -, meaning that we can modify it without having to worry about it being flushed or messed up by Docker.&lt;/p&gt;
&lt;p&gt;As the table sits right in the forward path that packets from containers to external networks, we can place our filtering rules right there and then block any container access to the EC2 metadata server.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;iptables --list
Chain INPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination         

Chain FORWARD &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy DROP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target            prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;        destination         
DOCKER-USER       all  --  anywhere      anywhere     &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
DOCKER-ISOLATION  all  --  anywhere      anywhere            
ACCEPT            all  --  anywhere      anywhere     ctstate RELATED,ESTABLISHED
DOCKER            all  --  anywhere      anywhere            
ACCEPT            all  --  anywhere      anywhere            
ACCEPT            all  --  anywhere      anywhere            

Chain OUTPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination         

Chain DOCKER &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; references&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination         

Chain DOCKER-ISOLATION &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; references&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination         
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-USER &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; references&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                      &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;               destination         
RETURN     all  --  anywhere             anywhere     
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One easy way to making sure that this is the right chain to place rules is by adding a rule that will simply lead to the &lt;code&gt;LOG&lt;/code&gt; target, giving us palpable results regarding matching when running some scenarios.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Insert a rule to the DOCKER-USER chain to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# jump to the LOG target such that we can&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# visualize the logs in the kernel logs&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# whenever a container reaches 1.1.1.1.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Because `DOCKER-USER` comes referenced&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in FORWARD, it&amp;#39;ll only be matched in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# case of the host forwarding the connections&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# from the containers, and not those being&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# initiated directly from the host (not &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# namespaced).&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --insert DOCKER-USER &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --jump LOG &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --destination 1.1.1.1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --log-prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;[container]&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Insert rule to the OUTPUT chain to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# jump to the LOG target such that we can&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# visualize the packets sent to 1.1.1.1 &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# from the host.&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --insert OUTPUT &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --jump LOG &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --destination 1.1.1.1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --log-prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;[host]&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check how our two rules have been placed in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the two chains that matter.&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --list &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --numeric
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
Chain OUTPUT &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;         destination
LOG        all  --  0.0.0.0/0      1.1.1.1       LOG flags &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; level &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; prefix &lt;span class=&#34;s2&#34;&gt;&amp;#34;[host]&amp;#34;&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
Chain DOCKER-USER &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; references&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;         destination
LOG        all  --  0.0.0.0/0      1.1.1.1       LOG flags &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; level &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; prefix &lt;span class=&#34;s2&#34;&gt;&amp;#34;[container]&amp;#34;&lt;/span&gt;
RETURN     all  --  0.0.0.0/0      0.0.0.0/0


&lt;span class=&#34;c1&#34;&gt;# Clear the kernel ring buffer so we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# don&amp;#39;t check old logs&lt;/span&gt;
dmesg --clear

&lt;span class=&#34;c1&#34;&gt;# Send some packets from the host&lt;/span&gt;
ping 1.1.1.1 -c &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check dmesg for kernel logs.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: you could initiate a second terminal and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# follow the logs with the `--follow` opt.&lt;/span&gt;
dmesg
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3632.384997&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;host&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.31.5.64 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3633.386725&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;host&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.31.5.64 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3634.388343&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;host&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.31.5.64 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3635.389922&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;host&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.31.5.64 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3636.391557&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;host&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.31.5.64 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; 

&lt;span class=&#34;c1&#34;&gt;# Send some packets from a container &lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --rm &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        alpine &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ping 1.1.1.1 -c &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# From the host, check `dmesg` and see that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# there are no other new `[host]` entries, but&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# only new `[container]` entries as we wanted.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Note that there&amp;#39;s an included `IN` interface and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and an `OUT` as we expected given that we&amp;#39;re in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the middle of a forwarding path.&lt;/span&gt;
dmesg
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3724.759112&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;container&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;docker0 &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.17.0.3 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3725.759295&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;container&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;docker0 &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.17.0.3 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3726.759484&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;container&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;docker0 &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.17.0.3 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3727.759673&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;container&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;docker0 &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.17.0.3 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; 
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 3728.759849&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;container&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;IN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;docker0 &lt;span class=&#34;nv&#34;&gt;OUT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eth0 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;172.17.0.3 &lt;span class=&#34;nv&#34;&gt;DST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.1.1.1 &lt;span class=&#34;nv&#34;&gt;LEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt; ... &lt;span class=&#34;nv&#34;&gt;SEQ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Knowing which chain to use to place a filter rule, now it&amp;rsquo;s matter of dropping the connections to the EC2 metadata service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Delete (optionally) the log rule.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: The `1` argument is the number of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# rule in the chain.&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --delete DOCKER-USER &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Add the rule to reject traffic to the ec2 metadata&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# service.&lt;/span&gt;
iptables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --insert DOCKER-USER &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --destination 169.254.169.254 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --jump REJECT

&lt;span class=&#34;c1&#34;&gt;# Try to access the metadata service from the host.&lt;/span&gt;
curl 169.254.169.254/latest/meta-data/instance-id
i-0648792307a6e6610

&lt;span class=&#34;c1&#34;&gt;# Try to access the metadata service from the container.&lt;/span&gt;
docker run -it alpine /bin/sh
apk add --update curl 
curl -v 169.254.169.254/
*   Trying 169.254.169.254...
* TCP_NODELAY &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;
* connect to 169.254.169.254 port &lt;span class=&#34;m&#34;&gt;80&lt;/span&gt; failed: Connection refused
* Failed to connect to 169.254.169.254 port 80: Connection refused
* Closing connection &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
curl: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; Failed to connect to 169.254.169.254 port 80: Connection refused
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;Make sure that you have the iptables configuration properly set up at boot (given that the changes are not permanent) and you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;If you have any questions or saw anything wrong in the blog post, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;Ciro&lt;/p&gt;
</description>
                                <pubDate>Sun, 29 Apr 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/blocking-docker-containers-from-ec2-metadata/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/blocking-docker-containers-from-ec2-metadata/</guid>

                                
                                        <category>aws</category>
                                
                                        <category>docker</category>
                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Running Docker with a forked RunC</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;While Docker takes some time to expose more options to service creation (for instance, limiting the maximum number of PIDs of a service), it&amp;rsquo;s important that they are still enforced (at least with a default number).&lt;/p&gt;
&lt;p&gt;Many docker options that are not exposed to docker swarm mode yet - see &lt;a href=&#34;https://github.com/moby/moby/issues/25303&#34;&gt;add more options to &lt;code&gt;service create&lt;/code&gt; / `service update&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turns out though that there&amp;rsquo;s a way of adding such functionality without forking SwarmKit &lt;em&gt;and&lt;/em&gt; Docker just to add that if you&amp;rsquo;re fine with setting a single default - adding a modified runtime to containerd (which is transparently managed by docker for you) and then making it the default runtime.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-containerd-runc-interaction.svg&#34;
       alt=&#34;Example of interaction between docker-cli, the docker daemon, and runc &#34; &gt;

    
&lt;/figure&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#can-you-run-docker-with-a-forked-runc&#34;&gt;Can you run Docker with a forked runc?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-communication-between-docker-and-containerd&#34;&gt;The communication between Docker and ContainerD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-instantiation-of-containers-by-containerd&#34;&gt;The instantiation of containers by ContainerD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#forking-runc&#34;&gt;Forking runc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#adding-a-new-runtime-to-the-docker-daemon-configuration&#34;&gt;Adding a new runtime to the Docker daemon configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#modifying-runc-to-place-a-default-pid-limit&#34;&gt;Modifying runc to place a default PID limit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;can-you-run-docker-with-a-forked-runc&#34;&gt;Can you run Docker with a forked runc?&lt;/h3&gt;
&lt;p&gt;That&amp;rsquo;s possible because the Docker daemon is not the process that gets executed (in the sense of performing an &lt;code&gt;execve&lt;/code&gt;) when a container is meant to be ran - it delegates the action to containerd which then controls a list of runtimes (runc by default) which is then responsible for creating a new process (calling the defined runtime as specified in the configuration parameters) with some isolation and only then &lt;code&gt;execve&lt;/code&gt;ing the entrypoint of that container.&lt;/p&gt;
&lt;p&gt;Regarding interactions between docker, containerd, and runc, we can understand that without even looking at the source code - plain &lt;code&gt;strace&lt;/code&gt; and &lt;code&gt;pstree&lt;/code&gt; can do the job.&lt;/p&gt;
&lt;p&gt;Without any container running, perform a &lt;code&gt;ps aux | grep docker&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ps aux &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep docker
root      &lt;span class=&#34;m&#34;&gt;1002&lt;/span&gt;  /usr/bin/dockerd -H fd://
root      &lt;span class=&#34;m&#34;&gt;1038&lt;/span&gt;  docker-containerd --config /var/run/docker/containerd/containerd.toml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This shows us that we have two daemons running - the docker daemon and the docker-containerd daemon.&lt;/p&gt;
&lt;p&gt;Given that &lt;code&gt;dockerd&lt;/code&gt; interacts heavily with &lt;code&gt;containerd&lt;/code&gt; all the time and the last is never exposed to the internet, it makes sense to bet that its interface is unix-socket based.&lt;/p&gt;
&lt;h3 id=&#34;the-communication-between-docker-and-containerd&#34;&gt;The communication between Docker and ContainerD&lt;/h3&gt;
&lt;p&gt;We can check that by looking at the docker-conatainerd configuration (&lt;code&gt;/var/run/docker/containerd/containerd.toml&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span class=&#34;nx&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/lib/docker/containerd/daemon&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/containerd/daemon&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c&#34;&gt;# ...&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;grpc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/containerd/docker-containerd.sock&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;uid&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;gid&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another options is to just grab &lt;code&gt;docker-containerd&lt;/code&gt; pid and inspect its file descriptors:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Retrieve the PID of `containerd`&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;CONTAINERD_PID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;ps -C docker-containerd -o &lt;span class=&#34;nv&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tr -d &lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check what are the file descriptors associated with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that process by looking at proc fs&lt;/span&gt;
sudo ls -lah /proc/&lt;span class=&#34;nv&#34;&gt;$CONTAINERD_PID&lt;/span&gt;/fd
...
 &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; -&amp;gt; socket:&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;17674&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
 &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; -&amp;gt; socket:&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;17675&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
 &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt; -&amp;gt; socket:&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;17676&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
 &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; -&amp;gt; socket:&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;18597&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# That doesn&amp;#39;t help much, aside from seeing that there are&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# some sockets created. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We can gather more information looking at the inspection&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# performed by `lsof` though.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that the inode of the sockets are known, we can filter&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the result to focus only on a single socket if we want&lt;/span&gt;
sudo lsof -p &lt;span class=&#34;nv&#34;&gt;$CONTAINERD_PID&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;m&#34;&gt;17674&lt;/span&gt;
CMD        FD   TYPE  NODE  NAME
docker-co  6u   unix  &lt;span class=&#34;m&#34;&gt;17674&lt;/span&gt; /var/run/docker/containerd/docker-containerd.sock &lt;span class=&#34;nv&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;STREAM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can see how docker delegates all the work of setting up the container to containerd by looking at the &lt;code&gt;write(2)&lt;/code&gt;s performed by docker to the containerd&amp;rsquo;s unix socket right before creating the container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Retrieve the PID of `dockerd`&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;DOCKERD_PID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;ps -C dockerd -o &lt;span class=&#34;nv&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tr -d &lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;BUFSIZE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Start strace following all forks and allowing it to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# print big lines (as big as 1024 bytes).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By grepping `mycontainer` we can follow our trace of &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `HOSTNAME=mycontainer` which should land at some point&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at containerd and in the end go through runc.&lt;/span&gt;
sudo strace -f &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -e write &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -s &lt;span class=&#34;nv&#34;&gt;$BUFSIZE&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -p &lt;span class=&#34;nv&#34;&gt;$DOCKERD_PID&lt;/span&gt; 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        grep containerd

&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;pid  1062&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; write&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;11, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;...io.containerd.runtime.v1.linux\22P\n!containerd.linux.runc.RuncOptions\22+&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;\n\vdocker-runc\22\34/var/run/docker/runtime-runc*\340\235\1\n6types.containerd&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.io/opencontainers/runtime-spec/1/Spec\22\244\235\1{\&amp;#34;ociVersion\&amp;#34;:\&amp;#34;1.0.1\&amp;#34;,\&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;  \&amp;#34;HOSTNAME=mycontainer\&amp;#34;,\&amp;#34;NGINX_VERSION=1.13.9\&amp;#34;],\&amp;#34;cwd\&amp;#34;:\&amp;#34;/\&amp;#34;,\&amp;#34;capabilities\&amp;#34;&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;:{\&amp;#34;bounding\&amp;#34;:[\&amp;#34;CAP_CHOWN\&amp;#34;,\&amp;#34;CAP_DAC_OVERRIDE\&amp;#34;,\&amp;#34;CA, 16393 &amp;lt;unfinished ...&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we can see that &lt;code&gt;docker&lt;/code&gt; is writing all that config to the file descriptor &lt;code&gt;11&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Looking at &lt;code&gt;/proc/$DOCKERD_PID/fd&lt;/code&gt; doesn&amp;rsquo;t reveal much though - it doesn&amp;rsquo;t tell us what&amp;rsquo;s the end of that socket (just like with a plain TCP client-server communication, when you chat over unix sockets, clients also create a socket on their end):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;sudo ls -lah /proc/&lt;span class=&#34;nv&#34;&gt;$DOCKERD_PID&lt;/span&gt;/fd &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s1&#34;&gt;&amp;#39;11 -&amp;gt;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;11&lt;/span&gt; -&amp;gt; socket:&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;17757&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To determine what&amp;rsquo;s the end of that socket (the server-side unix socket that is in &lt;code&gt;PASSIVE&lt;/code&gt; state), we can use &lt;code&gt;ss&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check out what is the INODEs involved in the established&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# connecition between a file descriptor 11 in the system&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (we could have more processes with a connection of fd=11 as&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that&amp;#39;s per-process, but that&amp;#39;s ok) and another peer.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# With both INODEs in hand we can use `lsof` again to inspect&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# what are them&lt;/span&gt;
sudo ss -a --unix -p &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;nv&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;11&lt;/span&gt;
Netid  State      Recv-Q Send-Q  Local Address:Port   Peer Address:Port                
u_str  ESTAB      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       * &lt;span class=&#34;m&#34;&gt;17757&lt;/span&gt;              * &lt;span class=&#34;m&#34;&gt;17758&lt;/span&gt;           users:&lt;span class=&#34;o&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;dockerd&amp;#34;&lt;/span&gt;,pid&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1002,fd&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;11&lt;span class=&#34;o&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check what those sockets are all about&lt;/span&gt;
sudo lsof -U &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s1&#34;&gt;&amp;#39;17757\|17758&amp;#39;&lt;/span&gt;
CMD                PID   FD   TYPE ADDR                INODE  NAME
dockerd            &lt;span class=&#34;m&#34;&gt;1002&lt;/span&gt;  11u  unix 0xffff90edf6db6800  &lt;span class=&#34;m&#34;&gt;17757&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;STREAM
docker-containerd  &lt;span class=&#34;m&#34;&gt;1038&lt;/span&gt;  10u  unix 0xffff90edf6db6000  &lt;span class=&#34;m&#34;&gt;17758&lt;/span&gt; /var/run/docker/containerd/docker-containerd.sock &lt;span class=&#34;nv&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;STREAM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-containerd-create-container.svg&#34;
       alt=&#34;Docker daemon issuing a container creation command to containerd &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;the-instantiation-of-containers-by-containerd&#34;&gt;The instantiation of containers by ContainerD&lt;/h3&gt;
&lt;p&gt;In that &lt;code&gt;{CONTAINER_CONFIG}&lt;/code&gt; there&amp;rsquo;s one line that stadands out for what we&amp;rsquo;re looking for here (changing the default runtime):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;containerd.linux.runc.RuncOptions
        \22+\n\vdocker-runc
                \22\34/var/run/docker/runtime-runc*\340\235\1\n6
                types.containerd.io/opencontainers/runtime-spec/1/Spec\22\244\235\1
        {\&amp;quot;ociVersion\&amp;quot;:\&amp;quot;1.0.1\&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can&amp;rsquo;t see very well from the result of strace, but we can inspect that looking at the configuration used by containerd by using &lt;code&gt;ctr&lt;/code&gt;, the command line utility that helps us interact with the &lt;code&gt;containerd&lt;/code&gt; daemon:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check out what the containerd directory structure looks like&lt;/span&gt;
tree /var/lib/docker/containerd/daemon
.
├── io.containerd.content.v1.content
│   └── ingest
├── io.containerd.metadata.v1.bolt
│   └── meta.db
├── io.containerd.runtime.v1.linux
│   └── moby                            &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt; THE NAMESPACE&lt;/span&gt;
│       └── ac550b5a0083269e9866...     &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt; THE CONTAINER&lt;/span&gt;
├── io.containerd.snapshotter.v1.btrfs
└── io.containerd.snapshotter.v1.overlayfs
    └── snapshots


&lt;span class=&#34;c1&#34;&gt;# Gather the containers that have been spawn in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# moby namespace.&lt;/span&gt;
sudo docker-containerd-ctr &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --namespace moby &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --address /var/run/docker/containerd/docker-containerd.sock &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        containers ls
CONTAINER        ..   IMAGE    RUNTIME                           
ac550b5a0083269e9..   -        io.containerd.runtime.v1.linux 

&lt;span class=&#34;c1&#34;&gt;# Gather the information related to the runtime of the container.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This should reveal which binary it&amp;#39;s used to create the actual&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# containers.&lt;/span&gt;
sudo docker-containerd-ctr &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --namespace moby  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --address /var/run/docker/containerd/docker-containerd.sock &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        containers info &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ac550b5a0083269e9866e0d868e34e2fd35e1c5c6de31df00f481734d94a3ff7 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.Runtime&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;io.containerd.runtime.v1.linux&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Options&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;type_url&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;containerd.linux.runc.RuncOptions&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;Cgtkb2NrZXItcnVuYxIcL3Zhci9ydW4vZG9ja2VyL3J1bnRpbWUtcnVuYw==&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Decode the base64 value such that we can understand&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# what&amp;#39;s in there&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Cgtkb2NrZXItcnVuYxIcL3Zhci9ydW4vZG9ja2VyL3J1bnRpbWUtcnVuYw==&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; base64 -d
docker-runc/var/run/docker/runtime-runc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can now verify that &lt;code&gt;containerd&lt;/code&gt; indeed makes use of &lt;code&gt;runtime-runc&lt;/code&gt; when it initializes a container by, again, using &lt;code&gt;strace&lt;/code&gt;, but this time, on &lt;code&gt;containerd&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Trace the execution of the running docker-containerd but&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# filter the syscall tracing to only catch the `execve` calls&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# such that we can see which process images are being used for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the new processes.&lt;/span&gt;
sudo strace -f &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -e execve &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -p &lt;span class=&#34;nv&#34;&gt;$CONTAINERD_PID&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# A containerd-shim is created to execute `docker-runc` and keep&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# track of its execution, allowing it to run the container entrypoint &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process and not have to stay around after its execution.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# It&amp;#39;s also responsible for keeping the IO and performing some extra&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# cleanup roles if necessary.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Note.: although this is spawn by containerd, it can be reparented&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by the machine pid1.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;pid  3749&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; execve&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/bin/docker-containerd-shim&amp;#34;&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker-containerd-shim&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-namespace&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;moby&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-workdir&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/lib/docker/containerd/daemo&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-address&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/containerd/docke&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-containerd-binary&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/bin/docker-containerd&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-runtime-root&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/runtime-runc&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;/* &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; vars */&lt;span class=&#34;o&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# docker-runc starts the process of creating the OCI container bundle&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;pid  3755&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; execve&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/bin/docker-runc&amp;#34;&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker-runc&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--root&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/runtime-runc/mob&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--log&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/run/docker/containerd/daemon/io&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--log-format&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;create&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--bundle&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/containerd/daemo&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--pid-file&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/run/docker/containerd/daemon/io&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;a919d61879fac203b1f2f78ddee3903c&amp;#34;&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;/* &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; vars */&lt;span class=&#34;o&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# docker-runc then starts the actual container&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;pid  3807&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; execve&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/bin/docker-runc&amp;#34;&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker-runc&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--root&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/docker/runtime-runc/mob&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--log&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;/run/docker/containerd/daemon/io&amp;#34;&lt;/span&gt;..., 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--log-format&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;start&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;a919d61879fac203b1f2f78ddee3903c&amp;#34;&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;/* &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; vars */&lt;span class=&#34;o&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# the container entrypoint gets executed&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;pid  3771&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; execve&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/sbin/nginx&amp;#34;&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt;, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-g&amp;#34;&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;daemon off;&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;, &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;/* &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; vars */&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &amp;lt;unfinished ...&amp;gt;



&lt;span class=&#34;c1&#34;&gt;# We can now inspect the process tree of the container&amp;#39;s entrypoint&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to see which processes are left (and check what is the first process&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# when the namespaces got changed).&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;NGINX_PID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3771&lt;/span&gt;
sudo pstree &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --show-pids &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --ascii &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --long &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --ns-changes &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --show-parents &lt;span class=&#34;nv&#34;&gt;$NGINX_PID&lt;/span&gt;

systemd&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
        ---dockerd&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1002&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
                ---docker-containerd&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1038&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
                        ---docker-containerd-shim&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3749&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
                                ---nginx&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3771,ipc,mnt,net,pid,uts&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/docker-runc-execution.svg&#34;
       alt=&#34;containerd executing a container &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Regardless of what we use in that &lt;code&gt;runc&lt;/code&gt; component, if it&amp;rsquo;s an OCI compliant runtime, then a container can be run.&lt;/p&gt;
&lt;h3 id=&#34;forking-runc&#34;&gt;Forking runc&lt;/h3&gt;
&lt;p&gt;Being a regular Golang project, make sure you have what&amp;rsquo;s needed to build a Go project (set your &lt;code&gt;$GOPATH&lt;/code&gt; and stuff accordingly).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Retrieve the `opencontainers/runc` and have it&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# under `GOPATH/src`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This way we can very quickly perform the modifications&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the source code, compile and see if they indeed &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# work.&lt;/span&gt;
go get -v github.com/opencontainers/runc

&lt;span class=&#34;c1&#34;&gt;# Get into the source code destination&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$GOPATH&lt;/span&gt;/src/github.com/opencontainers/runc

&lt;span class=&#34;c1&#34;&gt;# Here you should see `runc` already built.&lt;/span&gt;
./runc --help
NAME:
   runc - Open Container Initiative runtime

runc is a &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; line client &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; running applications 
packaged according to the Open Container Initiative &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;OCI&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 
format and is a compliant implementation of the Open Container 
Initiative specification.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although with that we have &lt;code&gt;runc&lt;/code&gt; already built, this version doesn&amp;rsquo;t have seccomp support (which is activated with an extra build tag).&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t have it yet, gather the dependency (on Ubuntu it&amp;rsquo;s &lt;code&gt;libseccomp-dev&lt;/code&gt;) and then build it with &lt;code&gt;seccomp&lt;/code&gt; as a build tag:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Verify that there&amp;#39;s no libseccomp being open when&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we execute ./runc (that is, it&amp;#39;s not compiled with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# support to seccomp) - nothing shows as it&amp;#39;s not &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# there.&lt;/span&gt;
sudo strace -e openat ./runc --help 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep seccomp

&lt;span class=&#34;c1&#34;&gt;# Remove the binary without seccomp&lt;/span&gt;
rm ./runc

&lt;span class=&#34;c1&#34;&gt;# Update the package information from all the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# configured sources&lt;/span&gt;
sudo apt update -y

&lt;span class=&#34;c1&#34;&gt;# Install the development package of libseccomp&lt;/span&gt;
sudo apt install -y &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libseccomp-dev

&lt;span class=&#34;c1&#34;&gt;# Build `runc` again, but now specifying that we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# want seccomp as well as apparmor.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Note.: the default `BUILDTAGS` in the Makefile&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# uses only `seccomp`. Docker requires both though.&lt;/span&gt;
make &lt;span class=&#34;nv&#34;&gt;BUILDTAGS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;seccomp apparmor&amp;#39;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Verify that libseccomp is being loaded:&lt;/span&gt;
sudo strace -e openat ./runc --help 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep seccomp
openat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AT_FDCWD, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;/lib/x86_64-linux-gnu/libseccomp.so.2&amp;#34;&lt;/span&gt;, 
        O_RDONLY&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_CLOEXEC&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have a fresh build of &lt;code&gt;runc&lt;/code&gt;, we can tell Docker to use our own version instead of &lt;code&gt;docker-runc&lt;/code&gt; (the default runtime).&lt;/p&gt;
&lt;h3 id=&#34;adding-a-new-runtime-to-the-docker-daemon-configuration&#34;&gt;Adding a new runtime to the Docker daemon configuration&lt;/h3&gt;
&lt;p&gt;Head over to the daemon configuration file (&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;) and add a new field:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;runtimes&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;our-runtime&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/local/bin/our-runc&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Link the &lt;code&gt;runc&lt;/code&gt; generated in &lt;code&gt;$GOPATH/src/github.com/opencontainers/runc&lt;/code&gt; to &lt;code&gt;/usr/local/bin/our-runc&lt;/code&gt; and then tell &lt;code&gt;dockerd&lt;/code&gt; to reload (send a &lt;code&gt;SIGHUP&lt;/code&gt; to the &lt;code&gt;dockerd&lt;/code&gt; process):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Link the custom runc to `/usr/local/bin/our-runc`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# such that we can update the binary with a simple&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `make` and not have to copy to `/usr/local/bin`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# all the time.&lt;/span&gt;
sudo ln -sf &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;realpath ./runc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; /usr/local/bin/our-runc

&lt;span class=&#34;c1&#34;&gt;# Tell dockerd to reload&lt;/span&gt;
sudo &lt;span class=&#34;nb&#34;&gt;kill&lt;/span&gt; -s SIGHUP &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pgrep dockerd&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check that the daemon actually got the signal to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# reload and it&amp;#39;s really doing it.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By default, dockerd will output the full configuration&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that it loaded and will be in use now.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: not every configuration will be reloaded with a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#      soft-reload via SIGHUP. Check the docs.&lt;/span&gt;
sudo journalctl -u docker.service -f

dockerd&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1002&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;: &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2018-0...&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;info &lt;span class=&#34;nv&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Got signal to reload configuration, reloading from: /etc/docker/daemon.json&amp;#34;&lt;/span&gt;
dockerd&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1002&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;: &lt;span class=&#34;nv&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2018-0...&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;info &lt;span class=&#34;nv&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Reloaded configuration: {\&amp;#34;mtu\&amp;#34;:1500, ...
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        \&amp;#34;runtimes\&amp;#34;:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;                {\&amp;#34;our-runtime\&amp;#34;:{\&amp;#34;path\&amp;#34;:\&amp;#34;/usr/local/bin/our-runc\&amp;#34;},
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;                \&amp;#34;runc\&amp;#34;:{\&amp;#34;path\&amp;#34;:\&amp;#34;docker-runc\&amp;#34;}},
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        \&amp;#34;default-runtime\&amp;#34;:\&amp;#34;runc\&amp;#34; ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Parsing that configuration that dockerd showed us (in JSON), we can highlight some things:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If we don&amp;#39;t specify a runtime, the runtime named `runc` &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from the runtimes object is used.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Naturally, this can be configured&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;default-runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;runc&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runtimes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;our-runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# our runtime got loaded&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/local/bin/our-runc&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                 &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# default `runc` runtime that docker has&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker-runc&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# $PATH resolution can be performed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check in `docker info` if the configuration got&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# properly loaded&lt;/span&gt;
docker info &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        grep -i runtime

Runtimes: our-runtime runc
Default Runtime: runc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cool, with that set, let&amp;rsquo;s modify &lt;code&gt;our-runc&lt;/code&gt; and run a container.&lt;/p&gt;
&lt;h3 id=&#34;modifying-runc-to-place-a-default-pid-limit&#34;&gt;Modifying runc to place a default PID limit&lt;/h3&gt;
&lt;p&gt;Given that Docker swarm mode doensn&amp;rsquo;t allow us to place a limit on the number of PIDs that a container can hold, we can go directly to &lt;code&gt;runc&lt;/code&gt; and modify that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/libcontainer/cgroups/fs/pids.go b/libcontainer/cgroups/fs/pids.go
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index f1e37205..418a5152 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/libcontainer/cgroups/fs/pids.go
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/libcontainer/cgroups/fs/pids.go
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -23,6 +23,11 @@ func (s *PidsGroup) Apply(d *cgroupData) error {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;        if err != nil &amp;amp;&amp;amp; !cgroups.IsNotFound(err) {
                return err
        }
&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       if d.config.PidsLimit == 0 {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+               d.config.PidsLimit = 500
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+       }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;        return nil
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, compile it with &lt;code&gt;make BUILDTAGS=&#39;seccomp apparmor&#39;&lt;/code&gt; and run a container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the container specifying that we want `our-runtime` (`our-runc`)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to be used as the container runtime.&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --rm &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name c1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --runtime our-runtime 
        nginx:alpine

&lt;span class=&#34;c1&#34;&gt;# Gather the full ID of the container such that we can&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# look at the cgroup filesystem and check if the pids&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# limit has really been set.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;CONTAINER_ID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;docker inspect c1 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.[] | .Id&amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Look at the `pids.max` key to verify if the 500&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is really set - the default value when we don&amp;#39;t&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# specify (per the changes we did).&lt;/span&gt;
cat /sys/fs/cgroup/pids/docker/&lt;span class=&#34;nv&#34;&gt;$CONTAINER_ID&lt;/span&gt;/pids.max
&lt;span class=&#34;m&#34;&gt;500&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it! We&amp;rsquo;re running a Docker container with a modified runc.&lt;/p&gt;
&lt;p&gt;Now, if you&amp;rsquo;re willing to always run containers with that &lt;code&gt;runc&lt;/code&gt;, set the &lt;code&gt;default-runtime&lt;/code&gt; property in &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; and you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s great that Docker is modular enough to allow us to perform some quick modifications like this.&lt;/p&gt;
&lt;p&gt;Being this building block for PaaSes, I guess this is more of a requirement than a feature.&lt;/p&gt;
&lt;p&gt;Please let me know if you have any questions or want to point out a mistake I made.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter,&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Wed, 28 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/run-docker-with-forked-runc/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/run-docker-with-forked-runc/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Implementing a TCP server in C</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve wanted to cover some Linux networking basics, and I felt that going through the exercise of setting up a straightforward TCP server would do good, and writing a guide during that process would certainly force me to go over details that I&amp;rsquo;d usually skip.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious (or just wanted a tutorial) on how to set up a TCP server using Linux and C, this is for you.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-overview&#34;&gt;The overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-socket&#34;&gt;The socket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-a-socket&#34;&gt;Creating a Socket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#extra-writing-to-a-socket-in-closed-state&#34;&gt;(extra) Writing to a socket in CLOSED state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#binding-the-socket-to-an-address&#34;&gt;Binding the socket to an address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#making-the-socket-listen-for-connections&#34;&gt;Making the socket listen for connections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#extra-messing-up-with-the-backlog&#34;&gt;(extra) Messing up with the backlog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#accepting-connections&#34;&gt;Accepting connections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-overview&#34;&gt;The overview&lt;/h3&gt;
&lt;p&gt;At the very high level, there are two actors: a client and a server.&lt;/p&gt;
&lt;p&gt;The server has a know IP address that represents a machine to connect to at some point (this address could be retrieved via DNS) and a known port (that represents the service that we want to talk to in that machine).&lt;/p&gt;
&lt;p&gt;At this moment, nothing can happen - TCP has its communication based on connections and without some handshaking and connection establishment, no data can be sent.&lt;/p&gt;
&lt;p&gt;So, that&amp;rsquo;s what happens at the first moment.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/tcp-connection-overview.svg&#34;
       alt=&#34;Overview of the flow of an application that uses TCP under the hood &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Once the connection gets established, it&amp;rsquo;s then up to the application to decide whether there&amp;rsquo;s indeed a server component and a client component. They could be peers and synchronize data back and forth, for instance.&lt;/p&gt;
&lt;p&gt;For an application protocol like HTTP/1.1 though, there&amp;rsquo;s a well-defined client-server model, where a client issues requests with specific methods, and a server that processes these requests and gives back results.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/tcp-interaction-http.svg&#34;
       alt=&#34;Interaction between a server and a client using TCP as the transport and HTTP as the application protocol &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Being at the application-level, HTTP simply assumes that there&amp;rsquo;s a way for the server to send data back to the client and &lt;em&gt;vice-versa&lt;/em&gt;. If there&amp;rsquo;s a channel in which messages can be sent, all good for HTTP.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;In case you&amp;rsquo;re not familiar with these terms or the way the networking layers fit together, make sure you get a copy of &lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It goes &amp;ldquo;layer-by-layer&amp;rdquo;, allowing the reader to build the understanding of networking concepts from a high-level to as low level as it gets.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;the-socket&#34;&gt;The socket&lt;/h3&gt;
&lt;p&gt;The interface that allows the interaction between the application layer (e.g., HTTP/1.1) and the transport layer (e.g., TCP) is the &lt;code&gt;socket&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An analogy that I remember from college is the one of a series of houses and its doors:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Considering that houses are applications in machines, then sockets are their doors: to get a message from one to another, it needs to cross a door of the first house and a door of the second.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/tcp-sockets.svg&#34;
       alt=&#34;Two processes communication with sockets over the internet &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In &lt;code&gt;C&lt;/code&gt;, we can access such socket interface via a file descriptor that is returned by the &lt;code&gt;socket(2)&lt;/code&gt; syscall.&lt;/p&gt;
&lt;p&gt;As this interface is required for any communication to happen (it&amp;rsquo;s the abstraction presented to us by our TCP/IP implementation under the hood), in my example I started by creating a &lt;code&gt;struct&lt;/code&gt; that keeps track of it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Encapsulates the properties of the server.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// file descriptor of the socket in passive
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// mode to wait for connections.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way we can pass the &lt;code&gt;server_t&lt;/code&gt; struct around the functions that depend on that socket.&lt;/p&gt;
&lt;p&gt;Our &lt;code&gt;main&lt;/code&gt; routine can then be declared:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Creates a socket for the server and makes it passive such that
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * we can wait for connections on it later.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;server_listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;


&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Accepts new connections and then prints `Hello World` to
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * them.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;server_accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;


&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Main server routine.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *      -       instantiates a new server structure that holds the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *              properties of our server;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *      -       creates a socket and makes it passive with
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *              `server_listen`;
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *      -       accepts new connections on the server socket.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;server_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Failed to listen on address 0.0.0.0:%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
                        &lt;span class=&#34;n&#34;&gt;PORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Failed accepting connection&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s implement each of those methods.&lt;/p&gt;
&lt;h3 id=&#34;creating-a-socket&#34;&gt;Creating a Socket&lt;/h3&gt;
&lt;p&gt;To have the socket created, the first thing we do is call the &lt;code&gt;socket(2)&lt;/code&gt; syscall specifying the type of communication protocol to be used (TCP, in this case) and the domain in which we&amp;rsquo;re using it (IPv4).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;note.: the domain is relevant because we could be using, e.g., unix sockets to communicate - not internet / network specific.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Looking at &lt;a href=&#34;https://linux.die.net/man/2/socket&#34;&gt;socket(2) man page&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SOCKET(2)      Linux Programmer&#39;s Manual          SOCKET(2)

NAME
       socket - create an endpoint for communication

SYNOPSIS
       int socket(int domain, int type, int protocol);

DESCRIPTION
       socket()  creates  an  endpoint for communication and 
       returns a file descriptor that refers to that endpoint.

       The file descriptor returned by a successful call will be 
       the lowest-numbered file descriptor  not  currently open 
       for the process.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that if we succeed, we end up with a file descriptor that we can reference later. This file descriptor that we receive is what we can store under &lt;code&gt;server-&amp;gt;listen_fd&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// The `socket(2)` syscall creates an endpoint for communication
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// and returns a file descriptor that refers to that endpoint.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// It takes three arguments (the last being just to provide greater
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// specificity):
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// -    domain (communication domain)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//      AF_INET              IPv4 Internet protocols
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// -    type (communication semantics)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//      SOCK_STREAM          Provides sequenced, reliable,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//                           two-way, connection-based byte
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//                           streams.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOCK_STREAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;socket&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Failed to create socket endpoint&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To verify that we really end up with a file descriptor right after the &lt;code&gt;socket(2)&lt;/code&gt; call, check out &lt;code&gt;lsof&lt;/code&gt; (which lists open files):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Capture the PID of the server process that only&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# calls `socket(2)` and the `pause(2)` to wait for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a signal indefinitely.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;SERVER_PROC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pgrep server.out&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# List the open files of this process but filter&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# out those that do not contain `sock` in the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# line.&lt;/span&gt;
lsof &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ag &lt;span class=&#34;nv&#34;&gt;$SERVER_PROC&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ag sock
COMMAND    PID    TYPE    NODE  NAME
server.out &lt;span class=&#34;m&#34;&gt;8824&lt;/span&gt;   sock   &lt;span class=&#34;m&#34;&gt;34368&lt;/span&gt;  protocol: TCP


&lt;span class=&#34;c1&#34;&gt;# Check out what file descriptors are assigned&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to our process by inspecting the `proc` virtual&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# filesystem.&lt;/span&gt;
ls -lah /proc/&lt;span class=&#34;nv&#34;&gt;$SERVER_PROC&lt;/span&gt;/fd
 .
 ..
 &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/0
 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /dev/pts/0
 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /dev/pts/0
 &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; -&amp;gt; socket:&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;34368&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;While at university I read &lt;a href=&#34;https://amzn.to/2zuuMu1&#34;&gt;this great book&lt;/a&gt; by W. Richard Stevens. As it&amp;rsquo;s in its title - it&amp;rsquo;s all about the sockets networking API in Unix systems.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;At this point we have a socket that is both not connected and can&amp;rsquo;t accept connections, but what if we try to write to this socket?&lt;/p&gt;
&lt;h3 id=&#34;extra-writing-to-a-socket-in-closed-state&#34;&gt;(extra) Writing to a socket in CLOSED state&lt;/h3&gt;
&lt;p&gt;Naturally, things break:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;        &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOCK_STREAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;hey&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;write&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to write&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compile it and run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ ./server.out
$ 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing shows! That&amp;rsquo;s because the default behavior of a write to a closed socket is to fail with &lt;code&gt;SIGPIPE&lt;/code&gt;, which has the default action of killing thr process (although you can catch the signal and do whatever you want):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;strace ./server.out
socket&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AF_INET, SOCK_STREAM, IPPROTO_IP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
write&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, &lt;span class=&#34;s2&#34;&gt;&amp;#34;hey&amp;#34;&lt;/span&gt;, 3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; -1 EPIPE &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Broken pipe&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
--- SIGPIPE &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;si_signo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SIGPIPE, &lt;span class=&#34;nv&#34;&gt;si_code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SI_USER, &lt;span class=&#34;nv&#34;&gt;si_pid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;11008, &lt;span class=&#34;nv&#34;&gt;si_uid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1001&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; ---
+++ killed by SIGPIPE +++
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at the man pages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;man &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; signal
       SIGPIPE  &lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;   Broken pipe: write to pipe with no
                                  readers.


man &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; write
       EPIPE    fd  is  connected  to  a  pipe  or  socket whose 
                reading end is closed.  When this happens the 
                writing process will also receive a SIGPIPE signal.  

                &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Thus, the write &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; value is seen only &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; 
                the program catches, blocks or ignores this signal.&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Very neat.&lt;/p&gt;
&lt;h3 id=&#34;binding-the-socket-to-an-address&#34;&gt;Binding the socket to an address&lt;/h3&gt;
&lt;p&gt;Although we have a socket, this socket isn&amp;rsquo;t bound to an address yet. This is where another syscall comes: &lt;a href=&#34;https://linux.die.net/man/2/bind&#34;&gt;&lt;code&gt;bind(2)&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind(2)&lt;/code&gt; takes a socket and a well defined structure that lets you tell it about the address you want to bind the socket to.&lt;/p&gt;
&lt;p&gt;For an IPv4 application like we&amp;rsquo;re creating here, we make use of &lt;code&gt;sockaddr_in&lt;/code&gt; which allows you to specify a 32-bit address (the IPv4 address) and a 16-bit number (the port).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// `sockaddr_in` provides ways of representing a full address
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// composed of an IP address and a port.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// SIN_FAMILY   address family   AF_INET refers to the address
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//                               family related to internet
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//                               addresses
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// S_ADDR       address (ip) in network byte order (big endian)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// SIN_PORT     port in network byte order (big endian)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sin_family&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// INADDR_ANY is a special constant that signalizes &amp;#34;ANY IFACE&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// i.e., 0.0.0.0.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sin_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;htonl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;INADDR_ANY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sin_port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;htons&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the &lt;code&gt;sockaddr_in&lt;/code&gt; structure set, it&amp;rsquo;s time to call &lt;code&gt;bind&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;
	&lt;span class=&#34;c1&#34;&gt;// bind() assigns the address specified to the socket referred 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// to by the file descriptor (`listen_fd`).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Here we cast `sockaddr_in` to `sockaddr` and specify the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// length such that `bind` can pick the values from the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// right offsets when interpreting the structure pointed to.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	           &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	           &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bind&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Failed to bind socket to address&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once &lt;code&gt;bind&lt;/code&gt; is called, now our socket is attached to a specific address, but we still can&amp;rsquo;t see it on &lt;code&gt;ss&lt;/code&gt; or any other program like that, and that&amp;rsquo;s because our socket is still in the &lt;code&gt;CLOSED&lt;/code&gt; state (no connection state at all).&lt;/p&gt;
&lt;h3 id=&#34;making-the-socket-listen-for-connections&#34;&gt;Making the socket listen for connections&lt;/h3&gt;
&lt;p&gt;As, by default, the socket is created for active connections (acting as a client), we must make it passive using &lt;a href=&#34;https://linux.die.net/man/2/listen&#34;&gt;&lt;code&gt;listen(2)&lt;/code&gt;&lt;/a&gt; if we want to accept connections:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LISTEN(2)      Linux Programmer&#39;s Manual    LISTEN(2)

NAME
       listen - listen for connections on a socket

SYNOPSIS
       int listen(int sockfd, int backlog);

DESCRIPTION
       listen()  marks  the socket referred to by sockfd as 
       a passive socket, that is, as a socket that will be 
       used to accept incoming connection requests using 
       accept(2).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With &lt;code&gt;listen(2)&lt;/code&gt; we then mark the socket with &lt;code&gt;SO_ACCEPTCON&lt;/code&gt; to listen for connections and specify a backlog size - the maximum amount of pending connections that can be enqueued for that socket.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// listen() marks the socket referred to by sockfd as a passive socket,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// that is, as a socket that will be used to accept incoming connection
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// requests using accept(2).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BACKLOG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;listen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Failed to put socket in passive mode&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Calling this syscall also has the effect of moving our socket to a different state.&lt;/p&gt;
&lt;p&gt;Instead of &lt;code&gt;CLOSED&lt;/code&gt;, now the socket is put into &lt;code&gt;LISTEN&lt;/code&gt; state (represents waiting for a connection request from any remote TCP and port - &lt;a href=&#34;https://tools.ietf.org/rfc/rfc793.txt&#34;&gt;RFC 793 - TCP&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check that `lsof` identifies our socket listening on&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# port 8080&lt;/span&gt;
lsof -i:8080
COMMAND    TYPE DEVICE NAME
server.out IPv4 &lt;span class=&#34;m&#34;&gt;38593&lt;/span&gt;  TCP *:http-alt &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;LISTEN&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check that `ss` properly recognizes our socket as `listen`&lt;/span&gt;
ss &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --listening &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --numeric &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --tcp  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ag &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;
LISTEN     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;128&lt;/span&gt;          *:8080                     *:*  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can also look at &lt;code&gt;/proc/net/tcp&lt;/code&gt; to see exactly the same as what the commands above are seeing (i.e., going under the hood):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get the inode of our socket.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that `socket(2)` creates a file descriptor&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that is the next fd in the sequence (0, 1, and 2&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# are already taken), we know that `3` references&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# our socket.&lt;/span&gt;
 &lt;span class=&#34;nv&#34;&gt;SERVER_SOCKET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;stat &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --dereference &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --printf %i &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /proc/&lt;span class=&#34;nv&#34;&gt;$SERVER_PROC&lt;/span&gt;/fd/3

&lt;span class=&#34;c1&#34;&gt;# Check the state of our socket inode in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# /proc/net/tcp table:&lt;/span&gt;
cat /proc/net/tcp &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ag &lt;span class=&#34;nv&#34;&gt;$SERVER_SOCKET&lt;/span&gt;
  sl  local_address rem_address   st  
   1: 00000000:1F90 00000000:0000 0A   ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;st&lt;/code&gt; defines the state of the socket, so we can know what &lt;code&gt;0A&lt;/code&gt; (10 in decimal) means by looking at &lt;code&gt;/usr/src/linux-headers-&amp;lt;LINUX_VER&amp;gt;/include/net/tcp_states.h&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TCP_ESTABLISHED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TCP_SYN_SENT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;// 02
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;TCP_SYN_RECV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;// 03
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;TCP_FIN_WAIT1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;TCP_FIN_WAIT2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                  
	&lt;span class=&#34;n&#34;&gt;TCP_TIME_WAIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TCP_CLOSE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TCP_CLOSE_WAIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                 &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;TCP_LAST_ACK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;// 09
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;TCP_LISTEN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 0A  &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;TCP_CLOSING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TCP_NEW_SYN_RECV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;TCP_MAX_STATES&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we wanted, it&amp;rsquo;s in the &lt;code&gt;TCP_LISTEN&lt;/code&gt; state.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;To know more about &lt;code&gt;/proc&lt;/code&gt; and other Linux interfaces, make sure you check the book &lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;extra-messing-up-with-the-backlog&#34;&gt;(extra) Messing up with the backlog&lt;/h3&gt;
&lt;p&gt;As at this point we&amp;rsquo;re able to listen for income connections, but we don&amp;rsquo;t accept them, what would happen if people started trying to connect to our server?&lt;/p&gt;
&lt;p&gt;One easy way of simulating the backlog exhaustion is by putting our server up and then start creating connections to it.&lt;/p&gt;
&lt;p&gt;With a call to &lt;code&gt;pause(2)&lt;/code&gt; right after &lt;code&gt;listen(2)&lt;/code&gt; we&amp;rsquo;ll start enqueuing connections without closing them, so if we create a bunch of &lt;code&gt;telnet&lt;/code&gt; clients that connect to our server, we should see them failing after &lt;code&gt;N&lt;/code&gt; connections (where &lt;code&gt;N&lt;/code&gt; equals the size of the backlog).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# In one terminal, start the server.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: I modified the code to have the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# backlog set to 4.&lt;/span&gt;
./server.out

&lt;span class=&#34;c1&#34;&gt;# In another terminal, start a handful of &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# connections using telnet.&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 10&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; sleep 1&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        telnet localhost &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11696&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; worked&lt;/span&gt;
Trying 127.0.0.1...
Connected to localhost.
Escape character is &lt;span class=&#34;s1&#34;&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.

telnet localhost &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;2&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11698&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; worked&lt;/span&gt;
Trying 127.0.0.1...
Connected to localhost.
Escape character is &lt;span class=&#34;s1&#34;&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.

telnet localhost &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;3&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11700&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; worked&lt;/span&gt;
Trying 127.0.0.1...
Connected to localhost.
Escape character is &lt;span class=&#34;s1&#34;&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.

telnet localhost &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;4&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11702&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; worked&lt;/span&gt;
Trying 127.0.0.1...
Connected to localhost.
Escape character is &lt;span class=&#34;s1&#34;&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.

telnet localhost &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;5&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11704&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; worked&lt;/span&gt;
Trying 127.0.0.1...
Connected to localhost.
Escape character is &lt;span class=&#34;s1&#34;&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.


&lt;span class=&#34;c1&#34;&gt;# From now on, the backlog got to its maximum, &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# so it won&amp;#39;t accept more connections.&lt;/span&gt;

telnet localhost &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;6&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11707&lt;/span&gt;
Trying 127.0.0.1...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;7&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11709&lt;/span&gt;
Trying 127.0.0.1...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11711&lt;/span&gt;
Trying 127.0.0.1...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;9&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11713&lt;/span&gt;
Trying 127.0.0.1...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;10&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11715&lt;/span&gt;
Trying 127.0.0.1...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What that means is that we can directly affect that rate at which connections get processed by our server without even accepting them in the first place.&lt;/p&gt;
&lt;h3 id=&#34;accepting-connections&#34;&gt;Accepting connections&lt;/h3&gt;
&lt;p&gt;Once a connection lands on the server that has a passive socket for that destination address, it&amp;rsquo;s up to the application to decide to do something with does connections or not.&lt;/p&gt;
&lt;p&gt;As the connections are being established, they float around two queues that are limited by the backlog value:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an incomplete connection queue: keeps track of connections that just arrived and didn&amp;rsquo;t finish the three-way handshake;&lt;/li&gt;
&lt;li&gt;a completed connection queue: keeps track of connections that successfully finished the three-way handshake and can be utilized by the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/tcp-queues.svg&#34;
       alt=&#34;TCP Backlog queues &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;What &lt;code&gt;accept(2)&lt;/code&gt; ends up doing is looking at the completed connections first in first out (FIFO) queue and popping from it, giving to the application a file descriptor that represents that connection (such that it can send data or whatever). If the queue is empty, it just blocks.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ACCEPT(2)    Linux Programmer&#39;s Manual ACCEPT(2)

NAME
       accept, accept4 - accept a connection on a socket

SYNOPSIS
       int accept(int sockfd, 
                  struct sockaddr *addr, 
                  socklen_t *addrlen);

DESCRIPTION
       The  accept()  system  call  is  used  with  connection-based 
       socket types (SOCK_STREAM, SOCK_SEQPACKET).  
       
       It extracts the first connection request on the queue of pending 
       connections for the listening  socket,  sockfd, creates  a  new 
       connected socket, and returns a new file descriptor referring to 
       that socket.  
       
       The newly created socket is not in the listening state.  
       The original socket sockfd is unaffected by this call.

       The argument sockfd is a socket that has been created with socket(2), 
       bound to a local address with  bind(2), and is listening for connections 
       after a listen(2).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With that said, the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;server_accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;server_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;socklen_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
	  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	     &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed accepting connection&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Client connected!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to close connection&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;Now our server can adequately receive connections and act upon them if we want.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I found that going through this rather simple example was great - I took the time to review some concepts and make the whole flow even more concrete in my mind.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re looking for the implementation, make sure you check &lt;code&gt;github.com/cirocosta/hstatic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I plan to make this a simple HTTP server that serves static files, but that&amp;rsquo;ll come next.&lt;/p&gt;
&lt;p&gt;Just in case I got something wrong or you just want to chat about something related, get in touch with me on Twitter! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; there.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;p&gt;Throughout the article, some books were mentioned.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the list of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2zuuMu1&#34;&gt;Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/2QWyXp9&#34;&gt;The Linux Programming Interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
                                <pubDate>Thu, 22 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/a-tcp-server-in-c/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/a-tcp-server-in-c/</guid>

                                
                                        <category>linux</category>
                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Using C to inspect Linux syscalls</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I came through a great article this week (&lt;a href=&#34;https://blog.nelhage.com/2010/08/write-yourself-an-strace-in-70-lines-of-code/&#34;&gt;Write yourself a strace in 70 lines of code&lt;/a&gt;) and decided to give a try, going through every step with a bunch of care such that I&amp;rsquo;d understand each piece.&lt;/p&gt;
&lt;p&gt;While writing the code, I came up with the following schematics of how everything works together:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/ptrace-syscall-flow.svg&#34;
       alt=&#34;Flow of execution of a Linux program that gets traced with PTRACE &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Let&amp;rsquo;s dive into it.&lt;/p&gt;
&lt;h3 id=&#34;executing-a-new-process-with-tracing-enabled&#34;&gt;Executing a new process with tracing enabled&lt;/h3&gt;
&lt;p&gt;By controlling the execution of a new process (being its parent) we can set this new process to have tracing enabled.&lt;/p&gt;
&lt;p&gt;This is possible by how the creation of new processes work in Linux: fork from the parent (in which case there&amp;rsquo;s going to exist two very similar processes - a clone is made), then perform some actions and switch the process image to a new one.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/ptrace-proc-exec.svg&#34;
       alt=&#34;Illustration of the Fork and exec flow for a process that wants to be traced &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;This means that in our main execution we end up with something in the following lines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Main execution - parses CLI arguments forming the runtime_t struct
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * and then starts the tracer by forking the execution and then
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * starting the main routine of the child (tracee) as well as the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * tracing capabilities on the parent.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;setbuf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stdout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;usage: %s prog args&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Initialize the `runtime_t`, a custom structure
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// that takes care of parsing the CLI arguments.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Check the repository to know more.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;runtime_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;runtime_show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Create a new process such that we can spawn a new
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// execution (via `execvp`) via a process that has already
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// declared that it wants to be traced (PTRACE_TRACEME).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// In the other process (parent), we implement the tracing
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// capabilities that will inspect the child&amp;#39;s registers and
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// interrupt its executions.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fork&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;do_child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fork&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;failed to fork process&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;do_trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;runtime_destroy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having &lt;code&gt;do_child&lt;/code&gt; execute the child functionality and &lt;code&gt;do_trace&lt;/code&gt; the tracer (parent), we can see how the child enables tracing and then signals itself a &lt;code&gt;SIGSTOP&lt;/code&gt; to stop its execution:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Main execution of the child process after
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * forking from the parent.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Its `argc` and `argv` are a subset of the parent&amp;#39;s
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * `argv` and `argv`, thus containing only the subprocess
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * arguments (e.g.: tracer myprog arg1 --&amp;gt; myprog arg1).
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;do_child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Explicitly tell that we want to get traced
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_TRACEME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// As a child that gets traced ends up with all the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// signals send to it being sent to the parent, signalling
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// itself will signal the parent.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// To inform the parent then, we send a signal to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// outselves which will also stop us.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kill&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGSTOP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Meanwhile, the parent waits for the child to change its process state (to go from &lt;code&gt;RUNNING&lt;/code&gt; to &lt;code&gt;STOPPED&lt;/code&gt; or &lt;em&gt;vice-versa&lt;/em&gt;) using &lt;code&gt;waitpid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once the child process gets to the paused state (i.e., once the child raises &lt;code&gt;SIGSTOP&lt;/code&gt; to itself), the parent can then resume execution of its main routine to set some &lt;code&gt;ptrace&lt;/code&gt; options before it tells the child to wake up and continue its main routine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;
&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Main execution of the tracer.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;do_trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Wait until the child starts its main execution
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;waitpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Set some options in regards to the child process.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Here we also set ptrace option: PTRACE_O_TRACESYSGOOD.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// This option forces the kernel to set bit 7 in the signal
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// number such that we can know if that was a syscall trap
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// that we caught.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_SETOPTIONS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTRACE_O_TRACESYSGOOD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this moment the child is set to be traced and the parent can allow the child to resume its execution.&lt;/p&gt;
&lt;h3 id=&#34;catching-a-childs-syscalls&#34;&gt;Catching a child&amp;rsquo;s syscalls&lt;/h3&gt;
&lt;p&gt;Once the parent finished setting the options needed to properly analyze the child&amp;rsquo;s behavior, it needs to tell it (the child) to start running again, and then wait on the child&amp;rsquo;s PID so that it can be notified of the syscall execution once it happens (in the child).&lt;/p&gt;
&lt;p&gt;It does so by making use of &lt;code&gt;ptrace(2)&lt;/code&gt; with the flag &lt;code&gt;PTRACE_SYSCALL&lt;/code&gt; set and then using &lt;code&gt;waitpid&lt;/code&gt; to wait for the syscall execution in the child (whenever the child executes a syscall it&amp;rsquo;ll get stopped - changing the process state - which gets noticed by the parent).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/gists/-/images/ptrace-resume.svg&#34;
       alt=&#34;Parent process telling child process to resume using PTRACE_SYSCALL &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Regarding code, we can wrap the logic in a function called &lt;code&gt;wait_for_sycall&lt;/code&gt; which does what&amp;rsquo;s been described and also checks some information carried with the signal that tells the tracer what happened to the child:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Keeps the child running until either entry to
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * or exit from a system call.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;wait_for_syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;c1&#34;&gt;// Calling ptrace with PTRACE_SYSCALL makes
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// the tracee (child) continue its execution
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// and stop whenever there&amp;#39;s a syscall being
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// executed (SIGTRAP is captured).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_SYSCALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Wait until the next signal arrives
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// When the running tracee enters ptrace-stop, it
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// notifies its tracer using waitpid(2)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// (or one of the other &amp;#34;wait&amp;#34; system calls).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;waitpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Ptrace-stopped tracees are reported as returns
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// with pid greater than 0 and WIFSTOPPED(status) true.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// -    WIFSTOPPED(status) returns true if the child
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//      process was stopped by delivery of a signal.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;// -    WSTOPSIG(status) returns the number of the signal
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//      which caused the child to stop - should only be
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//      employed if WIFSTOPPED returned true.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//      by `and`ing with `0x80` we make sure that it was
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//      a stop due to the execution of a syscall (given
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;c1&#34;&gt;//      that we set the PTRACE_O_TRACESYSGOOD option)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WIFSTOPPED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WSTOPSIG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;c1&#34;&gt;// Check whether the child exited normally.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WIFEXITED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, to catch every syscall made in the child, just use it in a loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;	&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wait_for_syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
		  &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_PEEKUSER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ORIG_RAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;syscall(%d) = &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

		&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wait_for_syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

		&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_PEEKUSER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: we use &lt;code&gt;wait_for_syscall&lt;/code&gt; twice as we&amp;rsquo;re being notified regarding the syscall enter (start of the syscall execution) and the syscall exit (termination of the syscall).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;looking-up-syscalls-by-number&#34;&gt;Looking up syscalls by number&lt;/h3&gt;
&lt;p&gt;To test if this is indeed working, I created a simple program that just writes to &lt;code&gt;stdout&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing fancy, just a &lt;code&gt;write(2)&lt;/code&gt; syscall execution.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s run it then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Compile the code we just created&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with `-static` to produce a static binary.&lt;/span&gt;
gcc main.c -O2 -static -o main.out

&lt;span class=&#34;c1&#34;&gt;# Compile the test case (the program that writes&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to stdout&lt;/span&gt;
gcc &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;.c -O2 -static -o &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;.out

&lt;span class=&#34;c1&#34;&gt;# Run the tracer with `case.out` as the tracee&lt;/span&gt;
./main.out ./case.out

syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;59&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;31203328&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;31207872&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;158&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;63&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;89&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;47&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;31343040&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;31346688&lt;/span&gt;
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;21&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; -2
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; hello world11
syscall&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;231&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we wanted, it prints &lt;code&gt;syscall&lt;/code&gt; followed by the number and then after the syscall exits, the exit number from it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Pick the syscall number by inspecting
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the values at the tracee&amp;#39;s registers
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// that were set at the moment that the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// user program was about to perform the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// syscall.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_PEEKUSER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ORIG_RAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;syscall(%d) = &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;wait_for_syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Pick the syscall number by inspecting
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the values at the tracee&amp;#39;s registers
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// once it returned from the syscall
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ptrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PTRACE_PEEKUSER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Those numbers that we see represent the actual syscalls that were performed.&lt;/p&gt;
&lt;p&gt;We can perform a reverse lookup to determine what each number is by looking at &lt;code&gt;/usr/include/x86_64-linux-gnu/asm/unistd_64.h&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_execve 59
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_brk 12
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_arch_prctl 158
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_uname 63
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_readlink 89
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_access 21
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_write 1
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define __NR_exit_group 231
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;meaning that our program started by executing &lt;code&gt;execve&lt;/code&gt; (to get &lt;code&gt;./case.out&lt;/code&gt; program running), then it did some &lt;code&gt;glibc&lt;/code&gt; stuff and then ended with &lt;code&gt;write&lt;/code&gt;, printing our message to &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It seems very useful for me to know that we can fully control the execution of the syscalls that our program performs, eventually injecting faults and tampering results. This seems very useful in the context of chaos engineering.&lt;/p&gt;
&lt;p&gt;One downside of the way we did here is that we&amp;rsquo;re stoping for &lt;strong&gt;every&lt;/strong&gt; single syscall, which might considerably slow down an application. To counterfeit that, I plan to explore the use of SECCOMP together with ptrace which would allow us to get in the middle of specific syscalls based on a filter that we provide.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m very grateful for Nelson who put &lt;a href=&#34;https://blog.nelhage.com/2010/08/write-yourself-an-strace-in-70-lines-of-code/&#34;&gt;Write yourself an strace in 70 lines of code&lt;/a&gt; up. I had a bunch of joy following that article and learning from it. Thanks!&lt;/p&gt;
&lt;p&gt;Please let me know if you have any questions or spot something odd. I&amp;rsquo;d appreciate!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Wed, 21 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/using-c-to-inspect-linux-syscalls/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/using-c-to-inspect-linux-syscalls/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How to set up AWS EFS across multiple availability zones using Terraform</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;this is a quick follow up for the article I wrote about the locks quota of AWS EFS (&lt;a href=&#34;https://ops.tips/blog/limits-aws-efs-nfs-locks/&#34;&gt;The first limit you&amp;rsquo;ll hit on AWS EFS: Locks&lt;/a&gt;) and an article about settings up AWS networking with Terraform (&lt;a href=&#34;https://ops.tips/blog/a-pratical-look-at-basic-aws-networking/&#34;&gt;A practical look at basic AWS Networking with Terraform&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Here I take the concept of creating multiple subnets in a VPC explored in the second article and then tie with the AWS EFS provisioning tips from the first one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-architecture&#34;&gt;The architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-a-multi-az-aws-efs-set-up-with-terraform&#34;&gt;Creating a multi-az AWS EFS set up with Terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-the-aws-efs-terraform-module&#34;&gt;Creating the AWS EFS Terraform module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#making-use-of-aws-efs-in-an-ec2-instance&#34;&gt;Making use of AWS EFS in an EC2 instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-architecture&#34;&gt;The architecture&lt;/h3&gt;
&lt;p&gt;As mentioned in the first article, in AWS EFS you have a file system that is managed by Amazon (per-region) that you can then mount in subnets in a VPC to make use of the filesystem.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/aws-efs-architecture.svg&#34;
       alt=&#34;Illustration of the AWS EFS architecture in a region with an AWS VPC containing subnets already provisioned &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Having the networking set up, it&amp;rsquo;s a matter of iterating over the subnets and creating the mount points.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s check out how that looks like in Terraform terms.&lt;/p&gt;
&lt;h3 id=&#34;creating-a-multi-az-aws-efs-set-up-with-terraform&#34;&gt;Creating a multi-az AWS EFS set up with Terraform&lt;/h3&gt;
&lt;p&gt;First things first, get your VPC ready with at least one subnet for each availability zone you want to cover. In my case, I made use of a module I&amp;rsquo;ve written before (see &lt;a href=&#34;https://ops.tips/blog/a-pratical-look-at-basic-aws-networking/&#34;&gt;how I set up networking with Terraform&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Explicitly maps subnet names to CIDR and&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# availability zone that subnets should live.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This allows us to call the `networking` module&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# once and have all the subnet creation taken&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# care of.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By giving a name to each subnet we&amp;#39;re able to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# get the generated subnet ID after the provisioning&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# is done by looking up for the ID in a map that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# comes as the output of the module.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;az-subnet-mapping&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type = &amp;#34;list&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;us-east-1a&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;az   = &amp;#34;us-east-1a&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr = &amp;#34;10.0.0.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;us-east-1b&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;az   = &amp;#34;us-east-1b&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr = &amp;#34;10.0.1.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Make use of the `networking` module as defined in &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the `./networking` directory of the `cirocosta/sample-aws-networking`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# repository.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;module &amp;#34;networking&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;source = &amp;#34;github.com/cirocosta/sample-aws-networking//networking&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr   = &amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;az-subnet-mapping&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;= &amp;#34;${var.az-subnet-mapping}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That gives us two availability zones covered by two subnets (one for each).&lt;/p&gt;
&lt;p&gt;With the subnets ready, I make use of a custom &lt;code&gt;efs&lt;/code&gt; module (the one we&amp;rsquo;ll create below):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;l&#34;&gt;module &amp;#34;efs&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;source = &amp;#34;./efs&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name          = &amp;#34;shared-fs&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnets-count = &amp;#34;${length(var.az-subnet-mapping)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnets       = &amp;#34;${values(module.networking.az-subnet-id-mapping)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc-id        = &amp;#34;${module.networking.vpc-id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the expectations set, let&amp;rsquo;s write the module.&lt;/p&gt;
&lt;h3 id=&#34;creating-the-aws-efs-terraform-module&#34;&gt;Creating the AWS EFS Terraform module&lt;/h3&gt;
&lt;p&gt;The way we used the EFS module above made explicit what&amp;rsquo;s the interface of it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it takes a name that describes what our elastic file system is about - this can be used for tagging the resource and naming the EFS;&lt;/li&gt;
&lt;li&gt;it takes a list of subnets (and a count because of some Terraform problems with using &lt;code&gt;count&lt;/code&gt; together with a dynamic variable) - these are  the subnets that the AWS EFS will mount to;&lt;/li&gt;
&lt;li&gt;a vpc id that allows us to retrieve information about the VPC that the subnets belong to and then pick the CIDR to allow traffic from and to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that deliniated, I start shaping the module file structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── inputs.tf   &lt;span class=&#34;c1&#34;&gt;# declares the variables that serve as input&lt;/span&gt;
├── main.tf     &lt;span class=&#34;c1&#34;&gt;# defines the main resources and data sources&lt;/span&gt;
└── outputs.tf  &lt;span class=&#34;c1&#34;&gt;# defines the outputs that can be used by other&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;# invocations&lt;/span&gt;

&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;inputs.tf&lt;/code&gt; is fairly simple, so I&amp;rsquo;ll skip (you can look it here: &lt;a href=&#34;https://github.com/cirocosta/aws-efs-sample&#34;&gt;cirocosta/aws-efs-sample&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;main.tf&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Gathers information about the VPC that was provided&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that we can know what CIDR block to allow requests&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from and to the FS.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;data &amp;#34;aws_vpc&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;id = &amp;#34;${var.vpc-id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Creates a new empty file system in EFS.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Although we&amp;#39;re not specifying a VPC_ID here, we can&amp;#39;t have&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# a EFS assigned to subnets in multiple VPCs.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If we wanted to mount in a differente VPC we&amp;#39;d need to first&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# remove all the mount points in subnets of one VPC and only &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# then create the new mountpoints in the other VPC.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_efs_file_system&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;${var.name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Creates a mount target of EFS in a specified subnet&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that our instances can connect to it.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here we iterate over `subnets-count` which indicates&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the length of the `var.subnets` list.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This way we&amp;#39;re able to create a mount target for each&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of the subnets, making it available to instances in all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of the desired subnets.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_efs_mount_target&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;count = &amp;#34;${var.subnets-count}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;file_system_id = &amp;#34;${aws_efs_file_system.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnet_id      = &amp;#34;${element(var.subnets, count.index)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;security_groups = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${aws_security_group.efs.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Allow both ingress and egress for port 2049 (NFS)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that our instances are able to get to the mount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# target in the AZ.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Additionaly, we set the `cidr_blocks` that are allowed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that we restrict the traffic to machines that are&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# within the VPC (and not outside).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_security_group&amp;#34; &amp;#34;efs&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name        = &amp;#34;efs-mnt&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Allows NFS traffic from instances within the VPC.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_id      = &amp;#34;${var.vpc-id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ingress {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;from_port = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to_port   = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;protocol  = &amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_blocks = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${data.aws_vpc.main.cidr_block}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;egress {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;from_port = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to_port   = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;protocol  = &amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_blocks = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${data.aws_vpc.main.cidr_block}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;allow_nfs-ec2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the AWS EFS is properly created, we then care about one thing: the address available for us to perform the NFSv4.1 mounting.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/aws-efs-view.svg&#34;
       alt=&#34;Visualization of the AWS EFS file system provisioned in AWS showing the two different mount points &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;One gotcha is that the VPC must have DNS hostname resolution set.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;l&#34;&gt;output &amp;#34;mount-target-dns&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Address of the mount target provisioned.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;value       = &amp;#34;${aws_efs_mount_target.main.0.dns_name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You might notice that I&amp;rsquo;m taking the address of the first mount target without worrying about the subnet and availability zone that the address comes from. That&amp;rsquo;s because it really doesn&amp;rsquo;t matter - in each subnet the DNS resolution will be performed correctly, returning the address of the mountpoint in that availability zone.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;dns_name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;fs-4b698303.efs.us-east-1.amazonaws.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;file_system_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;fs-4b698303&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;fsmt-7011eb38&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ip_address&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.238&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;network_interface_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;eni-b0388b7c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;security_groups.#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;security_groups.4275814226&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sg-2a644a5d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;subnet_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;subnet-8b4d19a4&amp;#34;&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;dns_name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;fs-4b698303.efs.us-east-1.amazonaws.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;file_system_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;fs-4b698303&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;fsmt-7111eb39&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ip_address&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.1.160&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;network_interface_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;eni-78127885&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;security_groups.#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;security_groups.4275814226&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sg-2a644a5d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;subnet_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;subnet-9b2935d0&amp;#34;&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See? Different IP addresses, subnets and network interfaces, but same address.&lt;/p&gt;
&lt;h3 id=&#34;making-use-of-aws-efs-in-an-ec2-instance&#34;&gt;Making use of AWS EFS in an EC2 instance&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s start by declaring an instance (it could be an autoscaling group with a launch configuration that carries the address of the AWS EFS mount point in that VPC):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Create an EC2 instance that will interact with an EFS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# file system that is mounted in our specific availability&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# zone.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_instance&amp;#34; &amp;#34;inst1&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ami               = &amp;#34;${data.aws_ami.ubuntu.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;instance_type     = &amp;#34;t2.micro&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;key_name          = &amp;#34;${aws_key_pair.main.key_name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;availability_zone = &amp;#34;us-east-1a&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnet_id         = &amp;#34;${module.networking.az-subnet-id-mapping[&amp;#34;us-east-1a&amp;#34;]}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_security_group_ids = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${aws_security_group.allow-ssh-and-egress.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;inst1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once that instance gets up, SSH into it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Lower the permissions of the key &lt;/span&gt;
chmod &lt;span class=&#34;m&#34;&gt;400&lt;/span&gt; ./keys/key.rsa

&lt;span class=&#34;c1&#34;&gt;# Get into the instance by making use of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the private key that corresponds to the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# private side of the key-pair that we generated&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (the instance has the public key in its&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ~/.ssh/authorized_keys).&lt;/span&gt;
ssh -i ./keys/key.rsa ubuntu@inst1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you&amp;rsquo;re there, let&amp;rsquo;s mount EFS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The mount location refers to the destination&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the file system where EFS will be mounted&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;MOUNT_LOCATION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/mnt/efs&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Mount target is the target of the mount - that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# address that we received from the EFS invocation.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Using the EFS module we just created, you could &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# get this address by interpolation:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       ${module.efs.mount-target-dns}&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;MOUNT_TARGET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;fs-4b698303.efs.us-east-1.amazonaws.com&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Retrieve the necessary packages for `mount` to work&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# properly with NFSv4.1&lt;/span&gt;
sudo apt update -y
sudo apt install -y nfs-common

&lt;span class=&#34;c1&#34;&gt;# Create the directory that will hold the mount&lt;/span&gt;
sudo mkdir -p &lt;span class=&#34;nv&#34;&gt;$MOUNT_LOCATION&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Mount the EFS mount point as a NFSv4.1 fs&lt;/span&gt;
sudo mount &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    -t nfs4 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    -o &lt;span class=&#34;nv&#34;&gt;nfsvers&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4.1,rsize&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1048576,wsize&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1048576,hard,timeo&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;600,retrans&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$MOUNT_TARGET&lt;/span&gt;:/ &lt;span class=&#34;nv&#34;&gt;$MOUNT_LOCATION&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check whether it has been successfuly mounted or not:&lt;/span&gt;
df -h &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep efs
fs-8d6d87c5.efs.us-east-1.amazonaws.com:/  8.0E     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  8.0E   0% /mnt/efs

mount &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep nfs
fs-8d6d87c5.efs.us-east-1.amazonaws.com:/ on 
        /mnt/efs &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; nfs4 
        &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;rw,relatime,vers&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4.1,rsize&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1048576,wsize&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1048576,namlen&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;255,
                hard,proto&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;tcp,timeo&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;600,retrans&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;2,sec&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;sys,
                &lt;span class=&#34;nv&#34;&gt;clientaddr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.0.249,local_lock&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;none,
                &lt;span class=&#34;nv&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.0.140&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Mounting an AWS EFS file system into multiple availability zones is not complicated. It has some details here and there but the overall experience is very straightforward.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t forget to have DNS support for your VPC and also have a way of getting the DNS address of the EFS mount, you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;p&gt;In case you have any questions, please let me know!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 19 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/how-aws-efs-multiple-availability-zones-terraform/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/how-aws-efs-multiple-availability-zones-terraform/</guid>

                                
                                        <category>aws</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>A practical look at basic AWS Networking with Terraform</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I noticed that recently a bunch of people has been getting to the website through queries about HAProxy in the context of AWS - mainly how to receive traffic through a set of instances and forward them to another set of machines.&lt;/p&gt;
&lt;p&gt;As I aim at making this blog as much practical as I can, I feel that if I taught the basics around AWS networking first, then I could have the ground set for further discussions about either HAProxy, NGINX or other options out there.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-client-point-of-view&#34;&gt;The client point of view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-components&#34;&gt;The components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-an-aws-vpc-using-terraform&#34;&gt;Creating an AWS VPC using Terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-an-internet-gateway-using-terraform&#34;&gt;Creating an Internet Gateway using Terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-aws-vpc-subnets&#34;&gt;Creating AWS VPC Subnets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#refactoring-making-networking-a-terraform-module&#34;&gt;Refactoring - making networking a Terraform module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#accessing-generated-subnet-ids-via-maps-using-terraform&#34;&gt;Accessing generated subnet IDs via maps using Terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-ec2-instances-in-aws-subnets&#34;&gt;Creating EC2 Instances in AWS Subnets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#accessing-an-aws-ec2-instance-setting-the-security-groups&#34;&gt;Accessing an AWS EC2 Instance - Setting the security groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-client-point-of-view&#34;&gt;The client point of view&lt;/h3&gt;
&lt;p&gt;In the point of view of the client, be it AWS or anywhere else, the lifecycle is the same:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;it makes requests to an endpoint (under a given domain that resolves to an assigned IP);&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;somehow someone processes its request;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it receives a response back.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-highlevel.svg&#34;
       alt=&#34;Client and server communication over the network with hidden application logic &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;That endpoint that takes the request from the client and then calls the application magic behind the scenes could either be a Content Delivery Network (CDN) point of presence (PoP) that would forward the request to another region or be a machine that we own.&lt;/p&gt;
&lt;p&gt;For simplicity, let&amp;rsquo;s assume it&amp;rsquo;s one of our machines.&lt;/p&gt;
&lt;h3 id=&#34;the-components&#34;&gt;The components&lt;/h3&gt;
&lt;p&gt;A very common scenario where many AWS networking concepts can be exercised is the following:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-architecture.svg&#34;
       alt=&#34;Very simplified AWS network infrastructure &#34; &gt;

    
&lt;/figure&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;three machines are meant not to be touched directly by other applications on the internet;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;each of those machines (&lt;code&gt;srv1&lt;/code&gt;, &lt;code&gt;srv2&lt;/code&gt; and &lt;code&gt;srv3&lt;/code&gt;) have application services (maybe just the same application but spread in three machines) which are meant to be accessed publicly via a well-defined URL;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;lb&lt;/code&gt; (our load-balancer machine) has a public interface that is meant to receive traffic from the internet and another interface that can reach the machines in the internal network - this is the machine that should be touched when traffic comes to &lt;code&gt;api.cirocosta.com&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To have these machines communicating with each other, they&amp;rsquo;re put into a common virtual network that we can define - in AWS terms, this big network is the AWS VPC (Virtual Private Cloud).&lt;/p&gt;
&lt;p&gt;These virtual networks (you can have more than your if you wish) are totally separate from each other (so you can have many networks using the same IP address range, for instance) and can be created in a minute.&lt;/p&gt;
&lt;p&gt;Another property of them is that they naturally span across multiple availability zones in a given region.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-intro-multi-az.svg&#34;
       alt=&#34;AWS VPC spanning across multiple availability zones &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;When it comes to provisioning EC2 instances, only having a VPC is not enough. From that big range of IPs that we allocated for our network, it&amp;rsquo;s needed that the user configures subnets too.&lt;/p&gt;
&lt;p&gt;By separating the VPC in subnets we&amp;rsquo;re able to partition that network across the availability zones and configure further properties, including whether it should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;be totally private (i.e, have no default internet gateway assigned to it);&lt;/li&gt;
&lt;li&gt;assign public IPs (even though ephemeral) to the instances when they get into the subnet;&lt;/li&gt;
&lt;li&gt;assign an IPv6 address to the instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I usually think of subnets as a further specification of details about the network that I want to put instances to.&lt;/p&gt;
&lt;p&gt;In the end, we usually have something like this:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-resources.svg&#34;
       alt=&#34;AWS architecture composed of a load-balancer and a set of servers in a private network &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;With the ground set, let&amp;rsquo;s terraform it!&lt;/p&gt;
&lt;h3 id=&#34;creating-an-aws-vpc-using-terraform&#34;&gt;Creating an AWS VPC using Terraform&lt;/h3&gt;
&lt;p&gt;The first resource I start creating is &lt;a href=&#34;https://www.terraform.io/docs/providers/aws/r/vpc.html&#34;&gt;aws_vpc&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# The VPC that spans across multiple availability zones.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Given the CIDR 10.0.0.0/16, we can have IPs from 10.0.0.1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# up to 10.0.255.254. Essentially we can host 65k IPs in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that range. &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_vpc&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_block = &amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The VPC by itself gives us nothing more than that &lt;code&gt;cidr&lt;/code&gt; block that we specified. Creating this resource (&lt;code&gt;terraform apply&lt;/code&gt;) we can see it in &lt;code&gt;describe-vpcs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-vpcs &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PROFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Vpcs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrBlock&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrBlockAssociationSet&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;AssociationId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-cidr-assoc-896491e1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrBlock&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrBlockState&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                        &lt;span class=&#34;nt&#34;&gt;&amp;#34;State&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;associated&amp;#34;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;DhcpOptionsId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;dopt-a20007c7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;InstanceTenancy&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;IsDefault&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;State&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;available&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-76d00d11&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Something I didn&amp;rsquo;t mention before is that there&amp;rsquo;s an extra resource that gets attached to the VPC when you create it: a routing table.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-route-tables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PROFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;RouteTables&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Associations&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Main&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;RouteTableAssociationId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rtbassoc-0f885c69&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;RouteTableId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rtb-852df2e2&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;PropagatingVgws&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;RouteTableId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rtb-852df2e2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Routes&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;DestinationCidrBlock&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;GatewayId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Origin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;CreateRouteTable&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;State&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Tags&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-76d00d11&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each VPC created carries with it an implicit router, coming with a main route table that we can modify. By default, it only comes with a route that determines where traffic should go when packets are sent to internal instances.&lt;/p&gt;
&lt;p&gt;This might look like not much, but it&amp;rsquo;s enough to allow us to create subnets, add instances to them and have these instances communicating with each other. Nevertheless, if we want to download software from the internet to update our instances, we must be able to get traffic sent out to the internet as well.&lt;/p&gt;
&lt;p&gt;To do so, an internet gateway is required.&lt;/p&gt;
&lt;p&gt;The internet gateway is a piece of infrastructure that can be seen as a router that will take packets from instances inside the network and forward them to the outside (as well as receive back packets from the established connection).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-routing-igw.svg&#34;
       alt=&#34;Request going from an EC2 instance inside a VPC to the internet passing by the internet gateway &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The instances that are created within subnets within this VPC use such component as a target in its internal route table and then when it establishes a connection to an outside resource, the gateway takes care of setting up that connection.&lt;/p&gt;
&lt;p&gt;Fortunately, we don&amp;rsquo;t need to take care of this component - you only attach it to your VPC and then AWS takes care of scaling, making it redundant and highly available to all the instances within the VPC.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s now create this internet gateway and add the route to our main route using Terraform then.&lt;/p&gt;
&lt;h3 id=&#34;creating-an-internet-gateway-using-terraform&#34;&gt;Creating an Internet Gateway using Terraform&lt;/h3&gt;
&lt;p&gt;To grant internet access to the VPC we make use of the &lt;a href=&#34;https://www.terraform.io/docs/providers/aws/r/internet_gateway.html&#34;&gt;aws_internet_gateway&lt;/a&gt; resource and &lt;a href=&#34;https://www.terraform.io/docs/providers/aws/r/route.html&#34;&gt;aws_route&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Internet gateway to give our VPC access to the outside world&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_internet_gateway&amp;#34; &amp;#34;default&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_id = &amp;#34;${aws_vpc.default.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Grant the VPC internet access by creating a very generic&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# destination CIDR (&amp;#34;catch all&amp;#34; - the least specific possible) &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that we route traffic to outside as a last resource for &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# any route that the table doesn&amp;#39;t know about.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_route&amp;#34; &amp;#34;internet_access&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;route_table_id         = &amp;#34;${aws_vpc.main.main_route_table_id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;destination_cidr_block = &amp;#34;0.0.0.0/0&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;gateway_id             = &amp;#34;${aws_internet_gateway.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the creation finishes, check out the route table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-route-tables &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PROFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt; {
     &amp;#34;RouteTables&amp;#34;: [
         {
             &amp;#34;Associations&amp;#34;: [
                 {
                     &amp;#34;Main&amp;#34;: true,
                     &amp;#34;RouteTableAssociationId&amp;#34;: &amp;#34;rtbassoc-0f885c69&amp;#34;,
                     &amp;#34;RouteTableId&amp;#34;: &amp;#34;rtb-852df2e2&amp;#34;
                 }
             ],
             &amp;#34;PropagatingVgws&amp;#34;: [],
             &amp;#34;RouteTableId&amp;#34;: &amp;#34;rtb-852df2e2&amp;#34;,
             &amp;#34;Routes&amp;#34;: [
                 {
                     &amp;#34;DestinationCidrBlock&amp;#34;: &amp;#34;10.0.0.0/16&amp;#34;,
                     &amp;#34;GatewayId&amp;#34;: &amp;#34;local&amp;#34;,
                     &amp;#34;Origin&amp;#34;: &amp;#34;CreateRouteTable&amp;#34;,
                     &amp;#34;State&amp;#34;: &amp;#34;active&amp;#34;
&lt;span class=&#34;gd&#34;&gt;-                }
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                },
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                    &amp;#34;DestinationCidrBlock&amp;#34;: &amp;#34;0.0.0.0/0&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                    &amp;#34;GatewayId&amp;#34;: &amp;#34;igw-caa366ae&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                    &amp;#34;Origin&amp;#34;: &amp;#34;CreateRoute&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                    &amp;#34;State&amp;#34;: &amp;#34;active&amp;#34;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;             ],
             &amp;#34;Tags&amp;#34;: [],
             &amp;#34;VpcId&amp;#34;: &amp;#34;vpc-76d00d11&amp;#34;
         }
     ]
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s there!&lt;/p&gt;
&lt;h3 id=&#34;creating-aws-vpc-subnets&#34;&gt;Creating AWS VPC Subnets&lt;/h3&gt;
&lt;p&gt;Differently from a VPC, each subnet is assigned to a specific availability zone, but each availability zone can have more than one subnet (belonging to the same VPC) though.&lt;/p&gt;
&lt;p&gt;This means that if we want to cover two availability zones with instances, we must create two subnets at least.&lt;/p&gt;
&lt;p&gt;With Terraform, I see that the most elegant way of doing so is by using the &lt;a href=&#34;https://www.terraform.io/docs/providers/aws/r/subnet.html&#34;&gt;aws_subnet&lt;/a&gt; resource paired with a list of maps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Creates N subnets according to the subnet mapping described in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the `az-subnet-mapping` variable.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The variable is a list of maps in the following form:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#   [  { name: &amp;#34;crazydog&amp;#34;, az: &amp;#34;name-of-the-az&amp;#34;, cidr: &amp;#34;cidr-range&amp;#34; } , ... ]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# For instance:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#   [ { name =  &amp;#34;sub1&amp;#34;, az = &amp;#34;us-east-1a&amp;#34;, cidr = &amp;#34;192.168.0.0/24&amp;#34;  } ]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_subnet&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;count = &amp;#34;${length(var.az-subnet-mapping)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_block              = &amp;#34;${lookup(var.az-subnet-mapping[count.index], &amp;#34;cidr&amp;#34;)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_id                  = &amp;#34;${aws_vpc.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;map_public_ip_on_launch = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;availability_zone       = &amp;#34;${lookup(var.az-subnet-mapping[count.index], &amp;#34;az&amp;#34;)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags = {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;${lookup(var.az-subnet-mapping[count.index], &amp;#34;name&amp;#34;)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way we&amp;rsquo;re able to be very explicit about which subnets we want in each region and what CIDR they take (we can even vary the size of these subnets without relying on some weird CIDR math).&lt;/p&gt;
&lt;p&gt;To make use of it, just declare the variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;az-subnet-mapping&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type        = &amp;#34;list&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Lists the subnets to be created in their respective AZ.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;subnet1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;az   = &amp;#34;sa-east-1a&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr = &amp;#34;10.0.0.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;subnet1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;az   = &amp;#34;sa-east-1c&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr = &amp;#34;10.0.1.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then, after applying it, see what subnets to we have around:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-subnets &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;beld
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Subnets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;AssignIpv6AddressOnCreation&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;AvailabilityZone&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sa-east-1a&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;AvailableIpAddressCount&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;251&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrBlock&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;DefaultForAz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Ipv6CidrBlockAssociationSet&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;MapPublicIpOnLaunch&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;State&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;available&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;SubnetId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;subnet-936734f4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-76d00d11&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;AssignIpv6AddressOnCreation&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;AvailabilityZone&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sa-east-1c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;AvailableIpAddressCount&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;251&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrBlock&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.1.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;DefaultForAz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Ipv6CidrBlockAssociationSet&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;MapPublicIpOnLaunch&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;State&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;available&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;SubnetId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;subnet-b20122ea&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-76d00d11&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There we go! With the subnets set, we can start creating our instances. Nevertheless, we can take some time to refactor our code a bit.&lt;/p&gt;
&lt;h3 id=&#34;refactoring---making-networking-a-terraform-module&#34;&gt;Refactoring - making networking a Terraform module&lt;/h3&gt;
&lt;p&gt;So far all the code has been thrown out to a &lt;code&gt;main.tf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s perfect if you&amp;rsquo;re dealing with just a pair or two of resources. However, when the infrastructure starts growing, it becomes harder and harder to maintain.&lt;/p&gt;
&lt;p&gt;Here we face one of those situations. We&amp;rsquo;re passing our subnet definitions via a list of maps, but after the subnets get created, it becomes hard for us to retrieve the subnet IDs without passing this complexity to the resource that will need to pick that ID.&lt;/p&gt;
&lt;p&gt;One way of making that whole process easier is to abstract the whole networking set up into a &lt;a href=&#34;https://www.terraform.io/intro/getting-started/modules.html&#34;&gt;Terraform module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To do so, I started by picking all those resources related to networking and put them in a file in a different directory called &lt;code&gt;networking&lt;/code&gt;. The file structure looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── keys                # contains pub and private keys (for this example)
│   ├── key.rsa 
│   └── key.rsa.pub
├── keys.tf             # manages `key` resource
├── main.tf             # top-level tf file - configures providers and vars
├── networking          # networking moduel - sets the whole networking
│   │ 
│   ├── inputs.tf       # declares the variables taken as input
│   ├── main.tf         # main resource creation (vpc, igw, routes, subnets ...)
│   └── outputs.tf      # results from the execution of the module
│     
└── terraform.tfstate  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The rationale behind setting this kind of structure is that we can think of the Terraform modules as functions that take some inputs, creates some resources and then produces some outputs.&lt;/p&gt;
&lt;h3 id=&#34;accessing-generated-subnet-ids-via-maps-using-terraform&#34;&gt;Accessing generated subnet IDs via maps using Terraform&lt;/h3&gt;
&lt;p&gt;Once the subnets have been generated, we&amp;rsquo;ll have their IDs which we can then use to attach instances to (or set as the based subnet to have an autoscaling group placing instances to).&lt;/p&gt;
&lt;p&gt;The problem is that without doing some interpolation trick, we can&amp;rsquo;t access those IDs by name.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;aws_subnet&lt;/code&gt; is executed with the &lt;code&gt;count&lt;/code&gt; set, we end up with a plain list of &lt;code&gt;aws_subnet&lt;/code&gt; resources.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 55rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-tf-subnet.svg&#34;
       alt=&#34;Terraform networking resource transformation using a custom module &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Given that at this point we already separated our networking configuration from the rest, at &lt;code&gt;output.tf&lt;/code&gt; we can make use of &lt;a href=&#34;https://www.terraform.io/docs/configuration/interpolation.html#zipmap-list-list-&#34;&gt;zipmap&lt;/a&gt; to have access to those subnet IDs using plain key-value lookup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Creates a mapping between subnet name and generated subnet ID.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Given an `aws_subnet` resource created with `count`, we can access&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# properties from the list of resources created as a list by using&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the wildcard syntax:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#     &amp;lt;resource&amp;gt;.*.&amp;lt;property&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By making use of `zipmap` we can take two lists and create a map&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that uses the values from the first list as keys and the values&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from the seconds list as values.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Example output:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#     az-subnet-id-mapping = {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       subnet1 = subnet-3b92c15c&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       subnet2 = subnet-a90023f1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#     }&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;output &amp;#34;az-subnet-id-mapping&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;value = &amp;#34;${zipmap(aws_subnet.main.*.tags.Name, aws_subnet.main.*.id)}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having easy access to the subnet IDs, it&amp;rsquo;s time to create the instances.&lt;/p&gt;
&lt;h3 id=&#34;creating-ec2-instances-in-aws-subnets&#34;&gt;Creating EC2 Instances in AWS Subnets&lt;/h3&gt;
&lt;p&gt;As we need an &lt;a href=&#34;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html&#34;&gt;AMI&lt;/a&gt; to create the instances, we start by picking the latest one released by Canonical.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Pick the latest ubuntu artful (17.10) ami released by the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Canonical team.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;data &amp;#34;aws_ami&amp;#34; &amp;#34;ubuntu&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;most_recent = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;filter {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name   = &amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;values = [&amp;#34;ubuntu/images/hvm-ssd/ubuntu-artful-17.10-amd64-server-*&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;filter {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name   = &amp;#34;virtualization-type&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;values = [&amp;#34;hvm&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 099720109477 is the id of the Canonical account&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that releases the official AMIs.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;owners = [&amp;#34;099720109477&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Usually, you&amp;rsquo;d pick an AMI that you prepared yourself already containing the software needed to run your application (maybe it&amp;rsquo;s just &lt;code&gt;docker&lt;/code&gt; and some agent to send metrics / whatever), but for testing, picking a simple base Ubuntu image suffices.&lt;/p&gt;
&lt;p&gt;With the AMI in hands, let&amp;rsquo;s wrap the whole thing with all that&amp;rsquo;s left: making use of the &lt;code&gt;networking&lt;/code&gt; module that we specified, set the desired subnets and specify some instances:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;profile&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Profile with permissions to provision the AWS resources.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;region&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Region to provision the resources into.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default     = &amp;#34;sa-east-1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;provider &amp;#34;aws&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;region  = &amp;#34;${var.region}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;profile = &amp;#34;${var.profile}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By specifying the submodule here we&amp;#39;ll have&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# as an end result 2 subnets created in those&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# two availability zones.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Given that we defined the module&amp;#39;s output, &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# wherever we interpolate with that output,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# terraform will establish the dependency and&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# make sure that the subnets have been properly&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# created.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;module &amp;#34;networking&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;source = &amp;#34;./networking&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr   = &amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;az-subnet-mapping&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;= [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;subnet1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;az   = &amp;#34;sa-east-1a&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr = &amp;#34;10.0.0.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;subnet2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;az   = &amp;#34;sa-east-1c&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr = &amp;#34;10.0.1.0/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Create the first instance in `subnet1`.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here we get the subnet ID to put this instance&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# by performing a simple key-value lookup over&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the map that we created in the output of the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# networking module.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_instance&amp;#34; &amp;#34;inst1&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;instance_type = &amp;#34;t2.micro&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ami           = &amp;#34;${data.aws_ami.ubuntu.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;key_name      = &amp;#34;${aws_key_pair.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnet_id     = &amp;#34;${module.networking.az-subnet-id-mapping[&amp;#34;subnet1&amp;#34;]}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_instance&amp;#34; &amp;#34;inst2&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;instance_type = &amp;#34;t2.micro&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ami           = &amp;#34;${data.aws_ami.ubuntu.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;key_name      = &amp;#34;${aws_key_pair.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnet_id     = &amp;#34;${module.networking.az-subnet-id-mapping[&amp;#34;subnet2&amp;#34;]}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Shoot &lt;code&gt;terraform apply&lt;/code&gt;, and you&amp;rsquo;re good to go!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-instances &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PROFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Reservations&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Instances&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;InstanceId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;i-0394b9700680faf8b&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;InstanceType&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t2.micro&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Placement&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                        &lt;span class=&#34;nt&#34;&gt;&amp;#34;AvailabilityZone&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sa-east-1a&amp;#34;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;PublicIpAddress&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;18.231.174.76&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;PrivateIpAddress&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.191&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-4ff52828&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Instances&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;InstanceId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;i-04714fbbd5df26497&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;InstanceType&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t2.micro&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Placement&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                        &lt;span class=&#34;nt&#34;&gt;&amp;#34;AvailabilityZone&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sa-east-1c&amp;#34;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;PrivateIpAddress&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.1.140&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;PublicIpAddress&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;18.231.163.99&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-4ff52828&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Naturally, we could now try to access the instances via SSH.&lt;/p&gt;
&lt;p&gt;Unfortunatelly, that would not work.&lt;/p&gt;
&lt;h3 id=&#34;accessing-an-aws-ec2-instance---setting-the-security-groups&#34;&gt;Accessing an AWS EC2 Instance - Setting the security groups&lt;/h3&gt;
&lt;p&gt;Whenever traffic comes to our instances, those packets pass by EC2&amp;rsquo;s virtual firewall that filters traffic before it gets to our instances.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-internet-security-groups.svg&#34;
       alt=&#34;AWS Security groups filtering traffic from and to the internet &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;While that&amp;rsquo;s a good analogy that makes sense in the most traditional way of thinking of a centralized firewall, security groups are a bit different.&lt;/p&gt;
&lt;p&gt;They&amp;rsquo;re tied directly to the instances and can also be used to filter internal traffic - you can use it even to decide if two instances within the same network can communicate or not. Even more specifically, these security groups get tied to the virtual network interfaces of the instances.&lt;/p&gt;
&lt;p&gt;A more accurate representation would be one that puts that &amp;ldquo;AWS Firewall&amp;rdquo; more tied to the instance:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/aws-net-intro-internal-sg.svg&#34;
       alt=&#34;Egress and Ingress traffic from EC2 instance being filtered by the AWS security group attached o the instance &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The way AWS EC2 security group works is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a security group is created (at this moment, everything is denied by default);&lt;/li&gt;
&lt;li&gt;rules are specified and attached to a security group (these rules specify which kind of traffic is allowed - either inbound or outbound);&lt;/li&gt;
&lt;li&gt;an instance is raised with a given security group specified.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When we created the instances in the Terraform file above, we didn&amp;rsquo;t specify a security group. In that case, AWS takes the lead and assigns a default security group to our instances.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s check:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-instances &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PROFILE&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.[] | .[] | .Instances | .[] | .SecurityGroups | .[]&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        jq -s &lt;span class=&#34;s1&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sg-948f3ef2&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sg-948f3ef2&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, as we see, both EC2 instances are making use of the default security group.&lt;/p&gt;
&lt;p&gt;We can also check what&amp;rsquo;s defined for this group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;aws ec2 describe-security-groups &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --group-ids sg-948f3ef2 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --profile&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PROFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;SecurityGroups&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Description&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;default VPC security group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sg-948f3ef2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;IpPermissions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;IpProtocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;IpRanges&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Ipv6Ranges&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;PrefixListIds&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;UserIdGroupPairs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                            &lt;span class=&#34;nt&#34;&gt;&amp;#34;GroupId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sg-948f3ef2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                            &lt;span class=&#34;nt&#34;&gt;&amp;#34;UserId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;461528445026&amp;#34;&lt;/span&gt;
                        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;IpPermissionsEgress&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;IpProtocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;IpRanges&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
                        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                            &lt;span class=&#34;nt&#34;&gt;&amp;#34;CidrIp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.0.0.0/0&amp;#34;&lt;/span&gt;
                        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;Ipv6Ranges&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;PrefixListIds&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
                    &lt;span class=&#34;nt&#34;&gt;&amp;#34;UserIdGroupPairs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;OwnerId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;461528445026&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;VpcId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc-bd4e93da&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way, we can adapt our Terraform file to fit our needs - have egress all available and the SSH port open.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Create a security group that will allow us to both&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# SSH into the instance as well as access prometheus&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# publicly (note.: you&amp;#39;d not do this in prod - otherwise&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# you&amp;#39;d have prometheus publicly exposed).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_security_group&amp;#34; &amp;#34;allow-ssh-and-egress&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;main&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Allows SSH traffic into instances as well as all eggress.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_id      = &amp;#34;${module.networking.vpc-id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ingress {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;from_port   = 22&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to_port     = 22&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;protocol    = &amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_blocks = [&amp;#34;0.0.0.0/0&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;egress {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;from_port   = 0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to_port     = 0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;protocol    = &amp;#34;-1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_blocks = [&amp;#34;0.0.0.0/0&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;allow_ssh-all&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then, with that, reference this security group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_instance&amp;#34; &amp;#34;inst1&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;instance_type = &amp;#34;t2.micro&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ami           = &amp;#34;${data.aws_ami.ubuntu.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;key_name      = &amp;#34;${aws_key_pair.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnet_id     = &amp;#34;${module.networking.az-subnet-id-mapping[&amp;#34;subnet1&amp;#34;]}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_security_group_ids = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${aws_security_group.allow-ssh-and-egress.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;With our EC2 instances running, being able to communicate with each other and granting us access to do whatever we want, we&amp;rsquo;re able to move forward with more interesting things.&lt;/p&gt;
&lt;p&gt;To get traffic from the Internet and provide a real service we could either assign an &lt;a href=&#34;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html&#34;&gt;Elastic IP&lt;/a&gt; to an instance (or one for each) and then configure our DNS settings or put a &lt;a href=&#34;https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html&#34;&gt;network load-balancer&lt;/a&gt; in front of them.&lt;/p&gt;
&lt;p&gt;I wanted to share this configuration as this is one of the pieces that when I got started with AWS felt quite hard to understand - as there&amp;rsquo;s a bunch of terminology around it and few gotchas.&lt;/p&gt;
&lt;p&gt;All the code cited here can be found in the &lt;a href=&#34;https://github.com/cirocosta/sample-aws-networking&#34;&gt;cirocosta/sample-aws-networking&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;If you have any questions, make sure to ask me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter. Maybe I wrote something completely wrong here too! I&amp;rsquo;d really appreciate if you let me know.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 18 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/a-pratical-look-at-basic-aws-networking/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/a-pratical-look-at-basic-aws-networking/</guid>

                                
                                        <category>aws</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How to collect Docker Daemon Metrics</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;While people generally know (and agree) that &lt;a href=&#34;https://github.com/google/cadvisor&#34;&gt;cAdvisor&lt;/a&gt; is the guy in the room to keep track of container metrics, there&amp;rsquo;s a sort of hidden feature of the docker daemon that people don&amp;rsquo;t take into account: the daemon by itself can be monitored too - see &lt;a href=&#34;https://docs.docker.com/config/thirdparty/prometheus/&#34;&gt;Collect Docker Metrics with Prometheus&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #f6f7fa; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 80rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/docker-daemon-grafana-metrics.png&#34;
       alt=&#34;Grafana Dashboard configured with Docker Daemon metrics &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;You indeed can determine whether the daemon is running by checking the &lt;a href=&#34;https://www.freedesktop.org/wiki/Software/systemd/&#34;&gt;systemd&lt;/a&gt; metrics via cAdvisor (if you&amp;rsquo;re running the Docker daemon as a systemd service), you can&amp;rsquo;t know much more than that.&lt;/p&gt;
&lt;p&gt;Using the native Docker daemon metrics, you can get much more.&lt;/p&gt;
&lt;p&gt;In this post we go through:&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#how-to-turn-docker-daemon-metrics-on&#34;&gt;How to turn Docker daemon metrics on&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gathering-docker-daemon-metrics-on-macos&#34;&gt;Gatherering Docker daemon metrics on MacOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tailoring-a-docker-metrics-grafana-dashboard&#34;&gt;Tailoring a Docker metrics Grafana Dashboard&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#docker-daemon-cpu-usage&#34;&gt;Docker daemon CPU usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#docker-container-start-times-heatmap&#34;&gt;Docker container start times heatmap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#number-of-running-docker-containers&#34;&gt;Number of running Docker containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;

&lt;h3 id=&#34;how-to-turn-docker-daemon-metrics-on&#34;&gt;How to turn Docker daemon metrics on&lt;/h3&gt;
&lt;p&gt;To turn the feature on, change your &lt;code&gt;daemon.json&lt;/code&gt; (usually at &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;) file to allow experimental features and tell it an address and path to expose the metrics.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;expermental&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;metrics-addr&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.0.0.0:9100&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that done, check out whether it&amp;rsquo;s indeed exporting the metrics:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl localhost:9100/metrics

        &lt;span class=&#34;c1&#34;&gt;# HELP builder_builds_failed_total Number of failed image builds&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# TYPE builder_builds_failed_total counter&lt;/span&gt;
        builder_builds_failed_total&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;reason&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;build_canceled&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
        builder_builds_failed_total&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;reason&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;build_target_not_reachable_error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
        ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the endpoint working, you&amp;rsquo;re now able to have &lt;a href=&#34;https://prometheus.io/&#34;&gt;Prometheus&lt;/a&gt; scraping this endpoint.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/prometheus-scraping-dockerd.svg&#34;
       alt=&#34;Illustration of Prometheus scraping Docker targets &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;gathering-docker-daemon-metrics-on-macos&#34;&gt;Gathering Docker daemon metrics on MacOS&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re a Docker-for-mac user, then there&amp;rsquo;s a little difference.&lt;/p&gt;
&lt;p&gt;First, you&amp;rsquo;ll not have the &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; file - this is all managed by the Docker mac app, which doesn&amp;rsquo;t prevent you from tweaking the daemon configurations though.&lt;/p&gt;
&lt;p&gt;Head over to the preferences pannel:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/gists/-/images/docker-for-mac-preferences.svg&#34;
       alt=&#34;Location of the Docker-for-mac preferences menu &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Once there, head to the Daemon tab and switch to the advanced mode.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/gists/-/images/docker-daemon-settings.svg&#34;
       alt=&#34;Advanced Docker Daemon configuration in Docker for Mac &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;With that configuration set, you&amp;rsquo;re now able to properly reach the docker-for-mac daemon metrics: &lt;code&gt;curl localhost:9100&lt;/code&gt; from your mac terminal.&lt;/p&gt;
&lt;h3 id=&#34;tailoring-a-docker-metrics-grafana-dashboard&#34;&gt;Tailoring a Docker metrics Grafana Dashboard&lt;/h3&gt;
&lt;p&gt;Once our metric collection is set up, we can now start graphing data from our Prometheus instance.&lt;/p&gt;
&lt;p&gt;To demonstrate which kind of metrics we can retrieve, I set up a sample repository (&lt;a href=&#34;https://github.com/cirocosta/sample-collect-docker-metrics&#34;&gt;cirocosta/sample-collect-docker-metrics&lt;/a&gt;) with some preconfigured dashboards that you can use right away.&lt;/p&gt;
&lt;p&gt;There, I configured Prometheus to look for the Docker daemon at &lt;code&gt;host.docker.internal&lt;/code&gt;, a DNS name that in a Docker for Mac installation resolves to the IP of the Xhyve VM that Docker is running on (see &lt;a href=&#34;https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host&#34;&gt;Networking features in Docker for Mac&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;evaluation_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;job_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;static_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;targets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;host.docker.internal:9100&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;instance-1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With Prometheus now scraping my Docker for Mac daemon, we can jump to the Grafana Web UI and start creating some dashboards and graphs.&lt;/p&gt;
&lt;h4 id=&#34;docker-daemon-cpu-usage&#34;&gt;Docker Daemon CPU usage&lt;/h4&gt;
&lt;p&gt;The one I started with was CPU usage to answer the question &lt;em&gt;&amp;ldquo;How much CPU usage is the Docker daemon process taking&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Given that all Prometheus Golang clients report their process CPU usage, we&amp;rsquo;re able to graph that (just like any other process level metric that are also revealed by Prometheus clients).&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics&#34;&gt;Prometheus documentation&lt;/a&gt;, these are:&lt;/p&gt;
&lt;div class=&#34;expanded-container&#34;&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_cpu_seconds_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Total user and system CPU time spent in seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_open_fds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of open file descriptors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_max_fds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Maximum number of open file descriptors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_virtual_memory_bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Virtual memory size in bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_resident_memory_bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resident memory size in bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_heap_bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Process heap size in bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process_start_time_seconds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start time of the process since unix epoch in seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Knowing that, we can then graph the CPU usage of the &lt;code&gt;dockerd&lt;/code&gt; process:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/grafana-docker-daemon-cpu-usage.png&#34;
       alt=&#34;Grafana Dashboard displaying the CPU usage &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;What the query does is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;it grabs the total CPU seconds spent by the Daemon process, then&lt;/li&gt;
&lt;li&gt;calculates the &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/querying/functions&#34;&gt;per-second instantaneous rate&lt;/a&gt; from the five-minutes vector of CPU seconds.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;docker-container-start-times-heatmap&#34;&gt;Docker container start times heatmap&lt;/h4&gt;
&lt;p&gt;A handy type of metric that we can graph from the daemon metrics is heatmaps. With them, we can spot unusual spikes in actions that the Docker daemon performs.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;http://docs.grafana.org/features/panels/heatmap/&#34;&gt;Grafana documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Heatmap panel allows you to view histograms over time&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since Grafana v5.1, we&amp;rsquo;ve been able to make use of Heatmaps when gathering metrics from Prometheus instances (see &lt;a href=&#34;https://github.com/grafana/grafana/issues/10009&#34;&gt;this commit&lt;/a&gt;).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/grafana-docker-daemon-start-times.png&#34;
       alt=&#34;Grafana Dashboard displaying container startup times in a Heatmap &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;All that the query, in this case, is doing is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;gathering all the Prometheus histogram buckets&#39; values for the container action seconds metric labeled with the &amp;ldquo;start&amp;rdquo; action; then&lt;/li&gt;
&lt;li&gt;calculating the rate in a one-minute vector.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The second step is necessary to make the data non-commulative, such that we can see at which point the most significant start time happened.&lt;/p&gt;
&lt;h4 id=&#34;number-of-running-docker-containers&#34;&gt;Number of running Docker containers&lt;/h4&gt;
&lt;p&gt;Another interesting type of metric that we can gather is gauge-like metrics that tell us about how many containers are being supervised by the daemon and in what states they are.&lt;/p&gt;
&lt;p&gt;This can indicate how loaded the machine is. Differently from &lt;code&gt;cAdvisor&lt;/code&gt;, here we can determine how many containers are indeed running, are still in &lt;code&gt;create&lt;/code&gt; state, or even in a &lt;code&gt;pause&lt;/code&gt; state.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/grafana-docker-daemon-container-states.png&#34;
       alt=&#34;Grafana Dashboard configured to show the number of containers in each state &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;By having the Docker daemon exporting its own metrics, we&amp;rsquo;re able to enhance even more the observability of the system when used in conjunction with &lt;code&gt;cAdvisor&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While &lt;code&gt;cAdvisor&lt;/code&gt; gives us the in-depth look of how the containers consume the machine resources, the Daemon metrics tells us how the daemon itself is consuming the machine resources and how well it&amp;rsquo;s performing what it should do - manage containers.&lt;/p&gt;
&lt;p&gt;There are certainly more interesting metrics that you can gather, but I hope these ones will give you an idea of what&amp;rsquo;s possible.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;strong&gt;If you enjoyed the article, please share it!&lt;/strong&gt; I&amp;rsquo;d appreciate a lot!&lt;/p&gt;
&lt;p&gt;You can also get related content by signing up to the newsletter below.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;I&amp;rsquo;m also available for questions and feedback - hit me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; any time.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ciro&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 18 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/how-to-collect-docker-daemon-metrics/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/how-to-collect-docker-daemon-metrics/</guid>

                                
                                        <category>docker</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Nginx HTTP2 Server Push</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;some days ago &lt;a href=&#34;https://hg.nginx.org/nginx/rev/641306096f5b&#34;&gt;HTTP2 server push has been added to Nginx&lt;/a&gt; (at least the open source version).&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s great news since this was one of the most interesting features from HTTP2 that Nginx was lacking.&lt;/p&gt;
&lt;p&gt;Given that I didn&amp;rsquo;t use server push myself so far, I decided to learn a bit more about it and give a try to Nginx&#39; implementation.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/h2-header.svg&#34;
       alt=&#34;Example of an architecture using NGINX HTTP2 Server Push acting as a reverse proxy &#34; &gt;

    
&lt;/figure&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#a-minimal-http2-server-push-example-in-go&#34;&gt;A minimal HTTP2 Server push example in Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#verifying-http2-server-push-with-google-chrome&#34;&gt;Verifying HTTP2 Push with Google Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#inspecting-the-http2-streams-using-wireshark&#34;&gt;Inspecting the HTTP2 streams using Wireshark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#installing-nginx-from-source&#34;&gt;Installing NGINX from source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#configuring-nginx-with-http2&#34;&gt;Configuring NGINX with HTTP2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#http2-server-push-using-nginx-as-a-proxy&#34;&gt;HTTP2 Server push using Nginx as a Proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;a-minimal-http2-server-push-example-in-go&#34;&gt;A minimal HTTP2 Server push example in Go&lt;/h3&gt;
&lt;p&gt;To establish a base around knowing whether the HTTP2 push functionality is indeed working or not, we can implement quick example in Go.&lt;/p&gt;
&lt;p&gt;Following the example of &lt;a href=&#34;https://medium.com/pyspa/how-to-use-golang-1-8s-http-2-server-push-api-4522a45a2eb9&#34;&gt;Yoshiki&lt;/a&gt;, the server serves two endpoints:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;/               --&amp;gt;     index.html   &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt; &amp;lt;img &lt;span class=&#34;nv&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/image.svg&amp;#34;&lt;/span&gt; /&amp;gt;
/image.svg      --&amp;gt;     image.svg itself
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That way we can see whether Chrome would retrieve the image pushed by the &lt;code&gt;/&lt;/code&gt; handler when we request &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I started tailoring &lt;code&gt;main.go&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// handleImage is the handler for serving `/image.svg`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// It does nothing more than taking the byte array that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// defines our SVG image and sending it downstream.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;handleImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;image/svg+xml&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nf&#34;&gt;must&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// main provides the main execution of our server.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// It makes sure that we&amp;#39;re providing the required
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// flags: cert and key.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// These two flags are extremely important because
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// browsers will only communicate via HTTP2 if we
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// serve the content via HTTPS, meaning that we must
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// be able to properly terminate TLS connections, thus,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// need a private key and a certificate.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;flag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;flag: key must be specified&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cert&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;flag: cert must be specified&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;HandleFunc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;HandleFunc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/image.svg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;nf&#34;&gt;must&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ListenAndServeTLS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strconv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Itoa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing fancy there, the big deal comes next: the handler for &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This handler is the one that knows about what are the assets the &lt;code&gt;index.html&lt;/code&gt; have (in our example, &lt;code&gt;image.svg&lt;/code&gt;) such that it can tell the browser to start fetching them ahead of time.&lt;/p&gt;
&lt;p&gt;With Go1.8+ we do that obtaining an &lt;code&gt;http.Pusher&lt;/code&gt; by casting the writer supplied to our handler and then using the &lt;code&gt;Push&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// handleIndex is the handler for serving `/`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// It first checks if it&amp;#39;s possible to push contents via
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the connection. If so, then it pushes `/image.svg` such
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// that at the same moment  that the browser is fetching
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// `index.html` it can also start retrieving `image.svg`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// (even before it knows about the existence in the html).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;handleIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;pusher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Pusher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nf&#34;&gt;must&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pusher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/image.svg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nf&#34;&gt;must&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compile it and let it run.&lt;/p&gt;
&lt;h3 id=&#34;verifying-http2-server-push-with-google-chrome&#34;&gt;Verifying HTTP2 Server Push with Google Chrome&lt;/h3&gt;
&lt;p&gt;Running the application on port &lt;code&gt;443&lt;/code&gt; (requires some privileges), head to Chrome at &lt;code&gt;https://localhost&lt;/code&gt;, open the Networks tab in the developer tools and see the push indication:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/h2-chrome-network.png&#34;
       alt=&#34;Chrome indicating that our image has been retrieved via HTTP2 Server Push &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;ps.: the &lt;code&gt;Not Secure&lt;/code&gt; indication is not a big deal - the browser doesn&amp;rsquo;t trust the certificate we provided. If you wan&amp;rsquo;t to see it green you can either get a real certificate (&lt;code&gt;LetsEncrypt&lt;/code&gt; is very handy for this if you have a domain and a webserver on such domain that you can use to retrieve a cert from them) or, in Mac, use &lt;code&gt;Keychain&lt;/code&gt; to trust your certificate.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To get the details around how that push got initiated, we can use the &lt;code&gt;chrome://net-internals&lt;/code&gt; page to debug the HTTP2 connection that we got established:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/h2-internal-events.png&#34;
       alt=&#34;Chrome network internals showing the http2 server push promise receive event &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Note that we&amp;rsquo;re not pushing contents downstream right from the &lt;code&gt;index.html&lt;/code&gt; handler, but instead in the push functionality we just signalize that the browser should perform another request.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: From the Go&amp;rsquo;s side we can&amp;rsquo;t consume those push frames yet: see &lt;a href=&#34;https://github.com/golang/go/issues/18594&#34;&gt;https://github.com/golang/go/issues/18594&lt;/a&gt; and PR &lt;a href=&#34;https://go-review.googlesource.com/#/c/net/+/85577/&#34;&gt;https://go-review.googlesource.com/#/c/net/+/85577/&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;inspecting-the-http2-streams-using-wireshark&#34;&gt;Inspecting the HTTP2 streams using Wireshark&lt;/h3&gt;
&lt;p&gt;Aside from using &lt;code&gt;chrome://net-internals&lt;/code&gt;, we can use Wireshark.&lt;/p&gt;
&lt;p&gt;Chrome, Firefox and even Go are able to produce NSS-formatted key log files that gives the necessary secrets to Wireshark so it can decrypt the streams and interpret them.&lt;/p&gt;
&lt;p&gt;Using either Chrome of Firefox you can get the file written to our filesystem by initializing them with the environment variable ``SSLKEYLOGFILE` that indicates where this file should live.&lt;/p&gt;
&lt;p&gt;For instance, using &lt;code&gt;MacOS&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SSLKEYLOGFILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;~/tlskey.log &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /Applications/Google&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;Chrome.app/Contents/MacOS/Google&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;Chrome &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the browser is running, open Wireshark, go to preferences, then protocols and then finally reach the SSL configurations. There you set the &lt;code&gt;(Pre)-Master-Secret log filename&lt;/code&gt; to the name you put on &lt;code&gt;SSLKEYLOGFILE&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/h2-wireshark-config.png&#34;
       alt=&#34;Wireshark SSL configuration screen &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Now head to &lt;code&gt;https://localhost&lt;/code&gt; and see the HTTP2-filtered packets flowing on the loopback interface:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/h2-wireshark.png&#34;
       alt=&#34;Wireshark showing HTTP2 Server Push event captured &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Done!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: make sure you&amp;rsquo;re running the application on port &lt;code&gt;443&lt;/code&gt;. For some reason &lt;code&gt;http2&lt;/code&gt; filter won&amp;rsquo;t work on a different port. I guess that&amp;rsquo;s because the &lt;code&gt;http2&lt;/code&gt; filter is probably hardcoded to 443, but who knows?&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;installing-nginx-from-source&#34;&gt;Installing NGINX from source&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m not very sure if there&amp;rsquo;s already a released version of NGINX with the latest commit from some days ago, so I decided to go with a build right from source.&lt;/p&gt;
&lt;p&gt;Here I&amp;rsquo;m using Ubuntu Artful (17.10) on VirtualBox.&lt;/p&gt;
&lt;p&gt;For that I set up a quick Vagrantfile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;Vagrant&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;artful&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu/artful64&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box_check_update&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;network&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;forwarded_port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;guest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;443&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;443&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;virtualbox&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2048&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;synced_folder&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/vagrant&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;disabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the virtual machine up, I get there and start the actual thing process.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Clone the git mirror (the official version control&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# system used by nginx is mercurial)&lt;/span&gt;
git clone https://github.com/nginx/nginx


&lt;span class=&#34;c1&#34;&gt;# Get into the cloned repository&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./nginx


&lt;span class=&#34;c1&#34;&gt;# Run auto configuration to check for dependencies and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# prepare installation files.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Make sure you run this command from the `nginx` directory&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instead of `./auto`. &lt;/span&gt;
./auto/configure


&lt;span class=&#34;c1&#34;&gt;# Here it should probably tell you that you that it &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# didn&amp;#39;t find some dependencies (like `pcre` and others).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Let&amp;#39;s install them&lt;/span&gt;
sudo apt install -y &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libpcre3 libpcre3-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        zlib1g-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libssl-dev


&lt;span class=&#34;c1&#34;&gt;# Configure our build with some modules.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - http_v2_module      provides support for HTTP/2&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# - http_ssl_module     provides the necessary support&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       for dealing with TLS&lt;/span&gt;
./auto/configure &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --with-http_v2_module &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --with-http_ssl_module


&lt;span class=&#34;c1&#34;&gt;# After running the command we should have a Makefile&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the `nginx` directory (current working directory)&lt;/span&gt;
ls &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep Makefile
Makefile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have the &lt;code&gt;Makefile&lt;/code&gt; ready, it&amp;rsquo;s a matter of triggering the build:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the build process with a concurrency of 4&lt;/span&gt;
make -j4


&lt;span class=&#34;c1&#34;&gt;# Check that `nginx` has been produced&lt;/span&gt;
./objs/nginx -v
nginx version: nginx/1.13.9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All set! Time to explore this new NGINX version.&lt;/p&gt;
&lt;h3 id=&#34;configuring-nginx-with-http2&#34;&gt;Configuring NGINX with HTTP2&lt;/h3&gt;
&lt;p&gt;To get started with the most minimal configuration possible, I set up a static website configuration with HTTP2 support with server push configured for our root path:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Do not daemonize - this makes it easier to test&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# new configurations as any stupid error would be&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# more easily caught when developing.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;daemon off;&lt;/span&gt;

&lt;span class=&#34;na&#34;&gt;events {&lt;/span&gt;
        &lt;span class=&#34;na&#34;&gt;worker_connections              1024;&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;na&#34;&gt;http {&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;# Explicitly telling what mime types we&amp;#39;re&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# supporting just for the sake of explicitiness&lt;/span&gt;
        &lt;span class=&#34;na&#34;&gt;types {&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;image/svg+xml           svg svgz;&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;text/html               html;&lt;/span&gt;
        &lt;span class=&#34;na&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;na&#34;&gt;server {&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;# Listen on port 8443 with http2 support on.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;listen                  8443 http2;&lt;/span&gt;


                &lt;span class=&#34;c1&#34;&gt;# Enable TLS such that we can have proper HTTP2&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;# support using browsers&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;ssl on;&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;ssl_certificate         certs/cert_example.com.pem;&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;ssl_certificate_key     certs/key_example.com.pem;&lt;/span&gt;


                &lt;span class=&#34;c1&#34;&gt;# For the root location (`index.html`) we perform&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;# a server push of `/image.svg` when serving the&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;# content to the end user.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;location / {&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;root            www;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;http2_push      &amp;#34;/image.svg&amp;#34;;&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;}&lt;/span&gt;


                &lt;span class=&#34;c1&#34;&gt;# When pushing the asset (`image.svg`) there&amp;#39;s no need&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;# to push additional resurces.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;location /image.svg {&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;root            www;&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;na&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That works exactly as we wanted: if you head over &lt;code&gt;/&lt;/code&gt; (that serves &lt;code&gt;index.html&lt;/code&gt;) you get &lt;code&gt;index.html&lt;/code&gt; and also the &lt;code&gt;PUSH_PROMISE&lt;/code&gt; to retrieve &lt;code&gt;image.svg&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/h2-nginx-push.png&#34;
       alt=&#34;Chrome network tab showing successful NGINX HTTP2 server push &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Unsurprisingly, this is almost identical to the Go example we set up.&lt;/p&gt;
&lt;h3 id=&#34;http2-server-push-using-nginx-as-a-proxy&#34;&gt;HTTP2 Server push using Nginx as a Proxy&lt;/h3&gt;
&lt;p&gt;As it&amp;rsquo;s very common to use NGINX as a reverse proxy, this new feature also supports such mode.&lt;/p&gt;
&lt;p&gt;Although NGINX does not support HTTP2 backends, it can act as an HTTP2 frontend that translates requests back to origin servers as HTTP1.1, letting TLS termination and HTTP2 capabilities to itself.&lt;/p&gt;
&lt;p&gt;The tricky part of server push is knowing what to push - something that a proxy doesn&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;To get over that, NGINX adhered to the spec of using the &lt;code&gt;Link&lt;/code&gt; header as means of informing it what to push.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s go back to Go to implement and HTTP1.1 server that informs NGINX when to push then.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;
&lt;span class=&#34;c1&#34;&gt;// In the case of HTTP1.1 we make use of the `Link` header
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// to indicate that the client (in our case, NGINX) should
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// retrieve a certain URL.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// See more at https://www.w3.org/TR/preload/#server-push-http-2.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;handleIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;pusher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Pusher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nf&#34;&gt;must&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pusher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/image.svg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// This ends up taking the effect of a server push
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// when interacting directly with NGINX.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// Note that I&amp;#39;m returning `/proxy/image.svg` instead
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// of `/image.svg`. 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// This has the effect of NGINX taking this as a normal 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// standard request and processing it through its location
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// pipeline (which ends up in the image Go handler we defined
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// here).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Link&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
			&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;lt;/proxy/image.svg&amp;gt;; rel=preload; as=image&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nf&#34;&gt;must&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In NGINX, not muched changed as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;http {
 
         # Explicitly telling what mime types we&amp;#39;re
&lt;span class=&#34;gu&#34;&gt;@@ -16,6 +18,11 @@ http {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                 text/html               html;
         }
 
&lt;span class=&#34;gi&#34;&gt;+        # Add an upstream server to proxy requests to
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+        upstream sample-http1 {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                server localhost:8080;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+        }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;         server {
                 # Listen on port 8443 with http2 support on.
                 listen                  8443 http2;
&lt;span class=&#34;gu&#34;&gt;@@ -27,6 +34,10 @@ http {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                 ssl_certificate         certs/cert_example.com.pem;
                 ssl_certificate_key     certs/key_example.com.pem;
 
&lt;span class=&#34;gi&#34;&gt;+                # Enable support for using `Link` headers to indicate
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                # origin server push
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                http2_push_preload on;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt; 
                 # For the root location (`index.html`) we perform
                 # a server push of `/image.svg` when serving the
&lt;span class=&#34;gu&#34;&gt;@@ -42,6 +53,15 @@ http {
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                 location /image.svg {
                         root            www;
                 }
&lt;span class=&#34;gi&#34;&gt;+
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                # Act as a reverse proxy for requests going to /proxy/*.
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                # Because we don&amp;#39;t want to rewrite our endpoints in the
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                # Go app, rewrite the path such that `/proxy/lol` ends up
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                # as `/lol`.
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                location /proxy/ {
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                        rewrite         /proxy/(.*) /$1 break;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                        proxy_pass      http://sample-http1;
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                }
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;         }
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I enabled &lt;code&gt;http2_push_preload&lt;/code&gt; for the whole server and then made all request to &lt;code&gt;/proxy/&lt;/code&gt; be proxied to our upstream &lt;code&gt;sample-http1&lt;/code&gt; server.&lt;/p&gt;
&lt;p&gt;The result? The following:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/h2-nginx-proxy.png&#34;
       alt=&#34;Chrome showing both HTTP2 server push from NGINX and the normal request for the sample image &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;At first that didn&amp;rsquo;t make much sense to me: two &lt;code&gt;image.svg&lt;/code&gt;? What?&lt;/p&gt;
&lt;p&gt;However, looking at the paths, it was clear: there was a request being made by the browser (&lt;code&gt;/image.svg&lt;/code&gt;) and another coming from the server push (&lt;code&gt;/proxy/image.svg&lt;/code&gt;). There was that extra one because I didn&amp;rsquo;t change the HTML, thus, Chrome was requesting it (as it should!).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about what goes on at the server host, this is a &lt;code&gt;tcpdump&lt;/code&gt; of what goes on:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Collect some packets within the host.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -i: interface to snoop (loopback)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -A: present body in ASCII format&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# pos&amp;#39; args: only packets destined to 8080&lt;/span&gt;
sudo tcpdump &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -i lo &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -A &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        dst port &lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# When requesting `/proxy/` nginx picks our&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# proxy location and then recreates the request&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as an HTTP1.0 request to `sample-http1` upstream.&lt;/span&gt;
GET / HTTP/1.0
Host: sample-http1
Connection: close


&lt;span class=&#34;c1&#34;&gt;# In consequence of the server-push the browser &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# performs the request (reusing the HTTP2 conenction)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# which ends up rewritten by NGINX as an HTTP1.0 request&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to our origin.&lt;/span&gt;
GET /image.svg HTTP/1.0
Host: sample-http1
Connection: close
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s pretty cool to see that NGINX is integrating server push. While it doesn&amp;rsquo;t support HTTP2 backends, having server push at the proxy level is a very neat way of letting HTTP1 clients take advantage of this functionality.&lt;/p&gt;
&lt;p&gt;I hope HAProxy comes next with an implementation that also makes use of the &lt;code&gt;Link&lt;/code&gt; header (as that seems to be the standard).&lt;/p&gt;
&lt;p&gt;If you have any questions or notice a mistake, please let me know!&lt;/p&gt;
&lt;p&gt;All of the code cited here is aggregated in this repository: &lt;a href=&#34;https://github.com/cirocosta/sample-nginx-http2&#34;&gt;cirocosta/sample-nginx-http2&lt;/a&gt;. Feel free to open issues / PR if you find something to be improved.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, by the way.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 13 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/nginx-http2-server-push/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/nginx-http2-server-push/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>An Example of Go RPC Client and Server</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been exploring the new Go support for AWS Lambda that has been announced by AWS early this year (see &lt;a href=&#34;https://aws.amazon.com/blogs/compute/announcing-go-support-for-aws-lambda/&#34;&gt;Announcing Go Support for AWS Lambda&lt;/a&gt;), and there&amp;rsquo;s a little detail of it that I found very interesting: at its core, it uses Go&amp;rsquo;s &lt;a href=&#34;https://golang.org/pkg/net/rpc&#34;&gt;net/rpc&lt;/a&gt; package as a mean of communication between the AWS infrastructure and your code.&lt;/p&gt;
&lt;p&gt;Having never used &lt;code&gt;net/rpc&lt;/code&gt; myself, I decided to explore it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#architecting-an-rpc-hello-world&#34;&gt;Architecting an RPC hello world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-a-go-rpc-handler&#34;&gt;Creating a Go RPC Handler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-a-go-rpc-server-and-client&#34;&gt;Creating a Go RPC Server and Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#go-rpc-in-practice&#34;&gt;Go RPC in Practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;architecting-an-rpc-hello-world&#34;&gt;Architecting an RPC hello world&lt;/h3&gt;
&lt;p&gt;As &lt;code&gt;net/rpc&lt;/code&gt; gives us ways of making a piece of code communicate with another piece of code over the wire, a natural example is a &amp;ldquo;Hello World&amp;rdquo; in a client-server architecture.&lt;/p&gt;
&lt;p&gt;To achieve that, I created this repository: &lt;a href=&#34;https://github.com/cirocosta/sample-rpc-go&#34;&gt;cirocosta/sample-rpc-go&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The file structure looks like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── Makefile            &lt;span class=&#34;c1&#34;&gt;# instructions for building and running the&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# example&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
├── client              &lt;span class=&#34;c1&#34;&gt;# RPC client&lt;/span&gt;
│   └── client.go       &lt;span class=&#34;c1&#34;&gt;# provides the interface which executes the&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# command remotely.&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
├── core                &lt;span class=&#34;c1&#34;&gt;# Shared functionality.&lt;/span&gt;
│   └── core.go         &lt;span class=&#34;c1&#34;&gt;# - implements the actual handler that gets&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;#   executed in the server;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# - provides the go representation of the &lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;#   messages exchanged between client and server.&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
├── main.go             &lt;span class=&#34;c1&#34;&gt;# CLI&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
└── server              &lt;span class=&#34;c1&#34;&gt;# RPC server - provides the interface which&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;# allows a client to communicate with it&lt;/span&gt;
    └── server.go       &lt;span class=&#34;c1&#34;&gt;# over the wire.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That allow us to keep the project really simple as &lt;code&gt;main&lt;/code&gt; executes either the server or client code based on a flag (&lt;code&gt;-server&lt;/code&gt;) and all the rest of the functionality is implemented independently.&lt;/p&gt;
&lt;p&gt;Create a client and a server, and you&amp;rsquo;ll be able to communicate.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/gists/-/images/go-rpc-architecture.svg&#34;
       alt=&#34;Go RPC (remote procedure call) hello world architecture of a client communicating with the server &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Let&amp;rsquo;s do that, then!&lt;/p&gt;
&lt;h3 id=&#34;creating-a-go-rpc-handler&#34;&gt;Creating a Go RPC Handler&lt;/h3&gt;
&lt;p&gt;The main piece of an RPC server is the methods that get executed when the client makes a call to them, the &lt;strong&gt;p&lt;/strong&gt; part of the name - procedures.&lt;/p&gt;
&lt;p&gt;For those accustomed to HTTP, in RPC land the equivalent of an endpoint (like, &lt;code&gt;POST /say-hello&lt;/code&gt;) is a service/procedure name (&lt;code&gt;HelloSayer.Say&lt;/code&gt;). Go constructs a map of these service endpoints by taking an exported struct that has a set of exported methods and making them available.&lt;/p&gt;
&lt;p&gt;Naturally, these methods must obey to a certain interface so that &lt;code&gt;net/rpc&lt;/code&gt; can properly provide (de)serialization of the request and response objects and perform the right method execution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it must take two arguments and return an error object;&lt;/li&gt;
&lt;li&gt;the first argument is the request and second is the response;&lt;/li&gt;
&lt;li&gt;the second (response) must be a pointer - in case of failure (an error in the service), error is returned, and the response is sent as &lt;code&gt;nil&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking at the Go source code (&lt;a href=&#34;https://golang.org/src/net/rpc/server.go?s=18689:18726#L231&#34;&gt;src/net/rpc/server.go&lt;/a&gt;), we can understand how it&amp;rsquo;s done behind the scenes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Register publishes in the server the set of methods of the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// receiver value that satisfies the following conditions:
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//	- exported method of exported type
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//	- two arguments, both of exported type
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//	- the second argument is a pointer
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//	- one return value, of type error
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// It returns an error if the receiver is not an exported type or has
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// no suitable methods. It also logs the error using package log.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// The client accesses each method using a string of the form &amp;#34;Type.Method&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// where Type is the receiver&amp;#39;s concrete type.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// ciro: `register` does the hard work of taking the struct and then analyzing
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// its methods to register them.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// In the end, `net/rpc` constructs a map that maps endpoint names 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// (`Struct.Method`) to the actual implementations, as well as  
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// performing the (de)serialization accordingly  such that the methods 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// are properly called.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{},&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;useName&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;typ&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reflect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TypeOf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reflect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ValueOf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;reflect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Indirect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rcvr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Install the methods
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// ciro: this inspects the methods and verify (for each) whether they 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// adhere to the &amp;#34;interface&amp;#34; that net/rpc expects - first arg is 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// represents the request and is not a pointer ; second is the response 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and must be  pointer, and then it also has an error return.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;suitableMethods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;typ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// store the service with the given service name
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;dup&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;serviceMap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;LoadOrStore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;dup&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;New&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
                        &lt;span class=&#34;s&#34;&gt;&amp;#34;rpc: service already defined: &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; 
                        &lt;span class=&#34;nx&#34;&gt;sname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, for a Hello World I end up with this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Response&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Handler&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Execute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;New&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;A name must be specified&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Hello &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It adheres to the interface that &lt;code&gt;net/rpc&lt;/code&gt; expects and is simple enough for our example.&lt;/p&gt;
&lt;h3 id=&#34;creating-a-go-rpc-server-and-client&#34;&gt;Creating a Go RPC Server and Client&lt;/h3&gt;
&lt;p&gt;Once the hander has been defined, creating the server is easy if you&amp;rsquo;ve set up an HTTP or TCP server before. The only difference is that before actually listening for incoming connections, you have to call &lt;code&gt;rpc.Register&lt;/code&gt; and pass an instance of the struct that carries the exported methods you define (i.e., your service handlers).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Publish our Handler methods
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rpc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Create a TCP listener that will listen on `Port`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strconv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Itoa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Close the listener whenever we stop
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Wait for incoming connections
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rpc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;on the client side, it&amp;rsquo;s almost the same as establishing a TCP connection:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;127.0.0.1:&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strconv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Itoa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;request&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;// Establish the connection to the adddress of the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// RPC server
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;rpc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Dial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;// Perform a procedure call (core.HandlerName == Handler.Execute)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// with the Request as specified and a pointer to a response
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// to have our response back.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;HandlerName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s see how it works in practice.&lt;/p&gt;
&lt;h3 id=&#34;go-rpc-in-practice&#34;&gt;Go RPC in Practice&lt;/h3&gt;
&lt;p&gt;Given the simplicity of having a client and server, I got curious about how the underlying communication works.&lt;/p&gt;
&lt;p&gt;By default, the Go RPC mechanism uses &lt;a href=&#34;https://golang.org/pkg/encoding/gob/&#34;&gt;&lt;code&gt;encoding/gob&lt;/code&gt;&lt;/a&gt; to (de)serialize the messages that come and go from &lt;code&gt;net/rpc&lt;/code&gt;. This means that we&amp;rsquo;d not have an easy time deciphering what&amp;rsquo;s going on by inspecting the wire.  Nonetheless, &lt;code&gt;net/rpc&lt;/code&gt; is pluggable enough that other encoding mechanisms can be used - for instance, the official &lt;a href=&#34;https://golang.org/pkg/net/rpc/jsonrpc/&#34;&gt;jsonrpc&lt;/a&gt; which is much simpler to inspect.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/go-rpc-wireshark.svg&#34;
       alt=&#34;Go RPC (remote procedure call) hello world architecture of a client communicating with the server &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;First, a connection is established (plain &lt;code&gt;TCP&lt;/code&gt;), and the request is sent:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;method&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Handler.Execute&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;params&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;nt&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ciro&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As no error happens, the response cames back with &lt;code&gt;error: null&lt;/code&gt; and the result (our &lt;code&gt;Response&lt;/code&gt; message):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nt&#34;&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello ciro&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Having never used &lt;code&gt;net/rpc&lt;/code&gt; before, I felt that there&amp;rsquo;s a lot of value having a working RPC system so fast.&lt;/p&gt;
&lt;p&gt;At the same time, it&amp;rsquo;s very hard to find great resources about this package online.&lt;/p&gt;
&lt;p&gt;I started searching why and it turns out that &lt;code&gt;net/rpc&lt;/code&gt; is in a &amp;ldquo;freeze&amp;rdquo; state - no more development is meant to go on in this package - and you can clearly see that: no method of this package takes &lt;code&gt;context&lt;/code&gt;, although it makes a lot of sense for some of them (e.g., the client&amp;rsquo;s &lt;code&gt;.Call&lt;/code&gt; method could easily have request cancellation with a &lt;code&gt;context&lt;/code&gt; just like you have with &lt;code&gt;net/http&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about whether people use &lt;code&gt;net/rpc&lt;/code&gt; out there, the answer is: yes. Most notably, &lt;a href=&#34;https://github.com/minio/minio&#34;&gt;minio&lt;/a&gt;, which saw a decrease in performance when evaluating &lt;code&gt;gRPC&lt;/code&gt;. Pretty interesting.&lt;/p&gt;
&lt;p&gt;What about you? Have you ever used it? Did you, like me, went straight to &lt;code&gt;gRPC&lt;/code&gt; without checking &lt;code&gt;net/rpc&lt;/code&gt;? I&amp;rsquo;d love to know!&lt;/p&gt;
&lt;p&gt;Reach me at Twitter &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; at any time.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 10 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/example-go-rpc-client-and-server/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/example-go-rpc-client-and-server/</guid>

                                
                                        <category>go</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>The first limit you&#39;ll hit on AWS EFS: Locks</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;a month ago I was looking at some issues with a container running a MySQL instance against an NFS-mounted directory on the host (should you do this? maybe not).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/efs-mysql-err.svg&#34;
       alt=&#34;MySQL interacting with AWS EFS showing an error &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The issues seemed pretty weird as I&amp;rsquo;m not a MySQL guy and there were all sorts of errors popping up related to disk quotas.&lt;/p&gt;
&lt;p&gt;Sure, we did have &lt;strong&gt;a bunch&lt;/strong&gt; of space:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;df -h
fs-&amp;lt;...&amp;gt;.amazonaws.com:/  8.0E  1.6G  8.0E   1% /mnt/nfs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem, as the logs revealed, was that &lt;code&gt;InnoDB&lt;/code&gt; wasn&amp;rsquo;t able to grab a lock that it wanted.&lt;/p&gt;
&lt;p&gt;That seemed even weirder to me as I thought we&amp;rsquo;d never hit a limit in this front.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#making-the-case&#34;&gt;Making the case&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#how-does-mysql-behave-on-lock-starvation&#34;&gt;How does MySQL behave on lock starvation?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#messing-up-our-syscalls&#34;&gt;Messing up our syscalls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#terraforming-a-test-scenario-in-aws&#34;&gt;Terraforming a test scenario in AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#exhausting-the-efs-mount-target-locks&#34;&gt;Exhausting the EFS mount target locks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#is-this-a-problem-with-nfs-in-general&#34;&gt;Is this a problem with NFS in general?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;making-the-case&#34;&gt;Making the case&lt;/h3&gt;
&lt;p&gt;My idea to get through this was to try to replicate what the user was facing - he couldn&amp;rsquo;t take his MySQL instance up.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s bring something up and look at some MySQL details:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a container named `inst1` which has&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# two environment variables set which alters&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the behavior of the mysql instance startup.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The code that runs at startup time can be found&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at the repository that holds this image:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# https://hub.docker.com/mysql&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name inst1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;nv&#34;&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;testdb &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;nv&#34;&gt;MYSQL_ALLOW_EMPTY_PASSWORD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        mysql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These two environment variables allow us to have a running MySQL instance with an empty password and a database &lt;code&gt;testdb&lt;/code&gt; created.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about it, this comes from &lt;a href=&#34;https://github.com/docker-library/mysql/blob/6c414e7f38c2079c7193beae5dc7c34ee46cd6e7/5.7/docker-entrypoint.sh#L158&#34;&gt;mysql&amp;rsquo;s image entrypoint&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# If the string `MYSQL_DATABASE` has been&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# specified, then add the database creation&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# string to the list of mysql commands to &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# run after the process has started.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (line 159 of docker-entrypoint.sh)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MYSQL_DATABASE&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;CREATE DATABASE IF NOT EXISTS \`&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MYSQL_DATABASE&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\` ;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;mysql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[@]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;mysql&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+=(&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MYSQL_DATABASE&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this, we can start looking at the structure of the filesystem that MySQL creates.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# get into the container&lt;/span&gt;
docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --interactive &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --tty &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        inst1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /bin/bash


&lt;span class=&#34;c1&#34;&gt;# From within the container, get into the directory &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# where mysql puts our database files and everything &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we should persist&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /var/lib/mysql


&lt;span class=&#34;c1&#34;&gt;# Find all the directories that are out there&lt;/span&gt;
find . -type d

        .
        ./sys
        ./mysql
        ./testdb
        ./performance_schema


&lt;span class=&#34;c1&#34;&gt;# Check that indeed, these are just databases&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;SHOW DATABASES;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; mysql 

        Database
        information_schema
        mysql                   &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;
        performance_schema      &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;
        sys
        testdb                  &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cool, but what about the locks?&lt;/p&gt;
&lt;p&gt;We can count how many are there by either making use of &lt;code&gt;lslocks&lt;/code&gt; or looking at &lt;code&gt;/proc/locks&lt;/code&gt;. The benefit of using &lt;code&gt;lslocks&lt;/code&gt; here is that it&amp;rsquo;ll resolve the paths for us so we can know which files of the MySQL instance that are holding locks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;lslocks
&lt;/span&gt;COMMAND PID  TYPE SIZE MODE  M START END PATH
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  48M WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./ib_logfile0
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  48M WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./ib_logfile1
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  76M WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./ibdata1
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  12M WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./ibtmp1
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/plugin.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/innodb_table_stats.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/innodb_index_stats.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/gtid_executed.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/server_cost.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/engine_cost.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/time_zone_leap_second.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/servers.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX 320K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/time_zone_name.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX 144K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/time_zone.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  12M WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/time_zone_transition.ibd
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX 464K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./mysql/time_zone_transition_type.ibd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, no &lt;code&gt;testdb&lt;/code&gt; there.&lt;/p&gt;
&lt;p&gt;So we know that it&amp;rsquo;s not locking at the database level.&lt;/p&gt;
&lt;p&gt;Maybe it does lock but differently as there is a way of performing a mutually exclusive flush per-database - &lt;code&gt;FLUSh tables WITH read lock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can confirm that it locks at the table-level:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the query that creates a table called &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `example` with just two dummy columns.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;table_creation_query&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;CREATE TABLE example ( 
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        id INT, 
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        data VARCHAR(100) 
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;);&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Execute the query against our database&lt;/span&gt;
mysql --database testdb &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$table_creation_query&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Verify that a lock has been created&lt;/span&gt;
lslocks &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep testdb
mysqld    &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; POSIX  96K WRITE &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ./testdb/example.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cool, we now know that MySQL will hold locks per-table.&lt;/p&gt;
&lt;h3 id=&#34;how-does-mysql-behave-on-lock-starvation&#34;&gt;How does MySQL behave on lock starvation?&lt;/h3&gt;
&lt;p&gt;For someone with close to zero knowledge about MySQL, I thought about forcing the system to fail MySQL when it tried to get a lock by setting limits on the number of locks that the process could take.&lt;/p&gt;
&lt;p&gt;The idea is to make use of the &lt;code&gt;setrlimit&lt;/code&gt; syscall via the &lt;code&gt;ulimit&lt;/code&gt; utility:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GETRLIMIT(2)    Linux Programmer&#39;s Manual         GETRLIMIT(2)

NAME
       getrlimit, setrlimit, prlimit - get/set resource limits

SYNOPSIS
       int setrlimit(int resource, const struct rlimit *rlim);

...

       The  getrlimit()  and  setrlimit()  system  calls  get  
       and set resource limits respectively.  Each resource has 
       an associated soft and hard limit ...


           struct rlimit {
               /* Soft limit */
               rlim_t rlim_cur;  

               /* Hard limit (ceiling for rlim_cur) */
               rlim_t rlim_max;  
           };
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It essentially means that we can put some limits on some resources by specifying some numbers (hard and soft limit). The resource that we want to limit in this case is the number of locks a process can take:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;       RLIMIT_LOCKS
              A limit on the combined number of flock(2) locks 
              and fcntl(2) leases that this process may establish.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That sounds pretty close but we don&amp;rsquo;t know if &lt;code&gt;mysql&lt;/code&gt; is indeed making use of these calls.&lt;/p&gt;
&lt;p&gt;We know that &lt;code&gt;lslocks&lt;/code&gt; does see a new lock when we create a new table but &amp;hellip; does it use one of those syscalls?&lt;/p&gt;
&lt;p&gt;We can check that using &lt;code&gt;strace&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get the PID of the MySQL daemon instance as seen by&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the host.&lt;/span&gt;
docker top inst1
PID          ..   CMD
&lt;span class=&#34;m&#34;&gt;861379&lt;/span&gt;       ..   mysqld
&lt;span class=&#34;m&#34;&gt;861589&lt;/span&gt;       ..   /bin/bash
&lt;span class=&#34;m&#34;&gt;864033&lt;/span&gt;       ..   /bin/bash


&lt;span class=&#34;c1&#34;&gt;# Cool, PID of `mysqld` is 861379.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# From the host we can specify that pid to strace&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and tell it to attach to all the processes raised &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# by it. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This way we can look at every syscall&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# made by them while it runs.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I&amp;#39;m making use of the following arguments:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -f:   Trace  child  processes (and &amp;#34;lightweight processes&amp;#34;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -e:   Filter the calls so that we only get notified when&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       there&amp;#39;s a syscall that matches the term&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# -p:   Pid to attach to (and its children)&lt;/span&gt;

sudo strace -f -e fcntl -p &lt;span class=&#34;m&#34;&gt;861379&lt;/span&gt; 
strace: Process &lt;span class=&#34;m&#34;&gt;861379&lt;/span&gt; attached with &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; threads


&lt;span class=&#34;c1&#34;&gt;# Now that we got attached, in a separate terminal, create a new&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# table by sending the table creation command to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# container&amp;#39;s mysql binary (client) that will get the command&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# sent to the mysql daemon.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;CREATE TABLE example2 ( id INT, data VARCHAR(100) );&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 
        docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; inst1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                mysql --database testdb


&lt;span class=&#34;c1&#34;&gt;# Now look at our strace results!&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We spotted some `fcntl` syscalls with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the lock-related parameters&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;pid 862376&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; fcntl&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;44, F_SETLK, &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;        l_type=F_WRLCK,                 &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;        l_whence=SEEK_SET, 
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;        l_start=0, 
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;        l_len=0}) = 0
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;[pid 862376] fcntl(44, F_SETLK, {       &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;        l_type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;F_WRLCK,                 &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;l_whence&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SEEK_SET, 
        &lt;span class=&#34;nv&#34;&gt;l_start&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0, 
        &lt;span class=&#34;nv&#34;&gt;l_len&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0&lt;span class=&#34;o&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By the declaration of &lt;code&gt;fcntl&lt;/code&gt; we can check what those arguments are about:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fcntl - manipulate file descriptor

int fcntl(int fd, int cmd, ... /* arg */ );

FD:             file descriptor to act upon
CMD:            action to perform
ARG:            well, arguments

fd=44           (acting uppon filedescriptor 44)
cmd=F_SETLK     (acquiring a write - exclusive - lock)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But, how do we know what is that &lt;code&gt;44&lt;/code&gt;? What that file descriptor points to?&lt;/p&gt;
&lt;p&gt;To know that we can look at the table of file descriptors open by a given process.&lt;/p&gt;
&lt;p&gt;From within the container (we could do this from the outside too) we can check that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get inside the container&lt;/span&gt;
docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; -it inst1 /bin/bash

&lt;span class=&#34;c1&#34;&gt;# By looking at the proc virtual filesystem we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# can check what files are open.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Because we&amp;#39;re running a container that runs MYSQL&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as the PID 1, we look at the properties for the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process who&amp;#39;s PID is 1.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
readlink /proc/1/fd/44 
/var/lib/mysql/testdb/example2.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Exactly! Our table &lt;code&gt;example2&lt;/code&gt; has a lock associated with it (as we wanted) which gets set using &lt;code&gt;fcntl&lt;/code&gt;, a syscall that can be blocked by &lt;code&gt;setrlimit&lt;/code&gt; calls.&lt;/p&gt;
&lt;p&gt;So now we know that we can make use of &lt;code&gt;setrlmit&lt;/code&gt; with &lt;code&gt;RLIMIT_LOCKS&lt;/code&gt; and expect that the kernel will limit the process&#39; resources.&lt;/p&gt;
&lt;p&gt;With Docker, we make use of it by specifying an extra argument to the run command: &lt;code&gt;--ulimit&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the same command as before that spawns&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a mysql container but this time with the limit&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of 25 locks. &lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name inst1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --ulimit &lt;span class=&#34;nv&#34;&gt;locks&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;nv&#34;&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;testdb &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;nv&#34;&gt;MYSQL_ALLOW_EMPTY_PASSWORD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        mysql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To see it in action, let&amp;rsquo;s try to create 30 tables.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# exit on any failed execution&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;c1&#34;&gt;# main routine that calls the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# table creation method 30 times&lt;/span&gt;
main &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 30&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
                create_table mytable&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# execute a command within the mysql&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# container to create a table.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# args:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       1) name of the table&lt;/span&gt;
create_table &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;CREATE TABLE &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; ( 
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        id INT, 
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        data VARCHAR(100) 
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;);&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; -i inst1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        mysql --database&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;testdb
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Guess what? It doesn&amp;rsquo;t work! The execution goes past 30 tables without a problem. We&amp;rsquo;re not limiting the locks as we wanted.&lt;/p&gt;
&lt;p&gt;The reason why it&amp;rsquo;s not working is that since Linux 2.4 &lt;code&gt;setrlimit&lt;/code&gt; simply stopped limiting &lt;code&gt;lock&lt;/code&gt;s, meaning that we were relying on a feature that is not even there anymore.&lt;/p&gt;
&lt;p&gt;How can we get get through that?&lt;/p&gt;
&lt;h3 id=&#34;messing-up-our-syscalls&#34;&gt;Messing up our syscalls&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s a Linux &lt;code&gt;syscall&lt;/code&gt; (&lt;code&gt;ptrace&lt;/code&gt;) that can help us.&lt;/p&gt;
&lt;p&gt;Quoting the &lt;a href=&#34;http://man7.org/linux/man-pages/man2/ptrace.2.html&#34;&gt;&lt;code&gt;man&lt;/code&gt; pages&lt;/a&gt;, it provides means by which a trace program may observe &lt;em&gt;and control&lt;/em&gt; the execution of another process, even changing the tracee&amp;rsquo;s memory and registers.&lt;/p&gt;
&lt;p&gt;So, given that we know exactly what syscall brings us the trouble (puts locks), we can get in the way of the syscall invocations for a given process, change it and then mess with it such that the tracee (&lt;code&gt;mysqld&lt;/code&gt; in our case) thinks that it doesn&amp;rsquo;t have enough disk quotas (free locks).&lt;/p&gt;
&lt;p&gt;Given that &lt;code&gt;strace&lt;/code&gt; (the tool) makes use of &lt;code&gt;ptrace&lt;/code&gt; and that it allows us to temper syscalls, we can make use of it to emulate a disk quota issue (after &lt;code&gt;n&lt;/code&gt; &lt;code&gt;fctnl&lt;/code&gt; calls trying to lock, fail with &lt;code&gt;ENOLCK&lt;/code&gt; (&amp;ldquo;Too  many  segment  locks open, lock table is full, or a remote locking protocol failed&amp;rdquo;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run `strace` targetting the process at pid $PID&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as well as it&amp;#39;s children.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Inject an FCNTL error in case the syscall has been&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# executes more than 25 times.&lt;/span&gt;
strace &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -p &lt;span class=&#34;nv&#34;&gt;$PID&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -f &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -e &lt;span class=&#34;nv&#34;&gt;fault&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;fcntl:error&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;ENOLCK:when&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;25+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running the script above (the one that creates 30 tables) runs, we can see the &lt;code&gt;InnoDB&lt;/code&gt; logs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysqld: ready for connections.
Version: &#39;5.7.21&#39;  socket: &#39;/var/run/mysqld/mysqld.sock&#39;  
                   port: 3306  MySQL Community Server (GPL)
[ERROR] InnoDB: Unable to lock ./testdb/mytable22.ibd error: 37
[ERROR] InnoDB: Operating system error number 37 in a file operation.

                                        \/ \/ \/ \/
[ERROR] InnoDB: Error number 37 means &#39;No locks available&#39;
                                        /\ /\ /\ /\

[ERROR] InnoDB: Cannot create file &#39;./testdb/mytable22.ibd&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, we failed the table creation process!&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s time to do it on AWS.&lt;/p&gt;
&lt;h3 id=&#34;terraforming-a-test-scenario-in-aws&#34;&gt;Terraforming a test scenario in AWS&lt;/h3&gt;
&lt;p&gt;The scenario is simple: single machine and an EFS mount in the same AZ (Availability Zone).&lt;/p&gt;
&lt;p&gt;To provision that I made use of Terraform such that I can make it very declarative and reproducible.&lt;/p&gt;
&lt;p&gt;I structured it like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── main.tf             &lt;span class=&#34;c1&#34;&gt;# data retrieval and output&lt;/span&gt;
├── efs.tf              &lt;span class=&#34;c1&#34;&gt;# provisiong the filesystem and a mount target&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# in the specific AZ that our instance is in&lt;/span&gt;
├── instance.tf         &lt;span class=&#34;c1&#34;&gt;# creates an instance in the region and AZ we want&lt;/span&gt;
├── keys.tf             &lt;span class=&#34;c1&#34;&gt;# provisions the key in the region&lt;/span&gt;
├── keys                &lt;span class=&#34;c1&#34;&gt;# dumb keys for this one-off experiment&lt;/span&gt;
│   ├── key.rsa
│   └── key.rsa.pub
└── terraform.tfstate   &lt;span class=&#34;c1&#34;&gt;# state&lt;/span&gt;

&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; directory, &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re curious about the whole Terraform files, check them out at &lt;a href=&#34;https://github.com/cirocosta/efs-locks-sample&#34;&gt;cirocosta/efs-locks-sample&lt;/a&gt;, but I wanted to highlight &lt;code&gt;efs.tf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Whenever you create an EFS filesystem you created it by region (note that not all regions support it - I think it&amp;rsquo;s something like only 5) and then within that region, you create mount points that the EFS attach to within subnets you already provisioned.&lt;/p&gt;
&lt;p&gt;For instance, say you&amp;rsquo;re in &lt;code&gt;us-east-1&lt;/code&gt; and have subnets on &lt;code&gt;us-east-1a&lt;/code&gt; and &lt;code&gt;us-east-1b&lt;/code&gt;. You create two mount points, and then your instances in those two availability zones can connect to it.&lt;/p&gt;
&lt;p&gt;In Terraform terms that would mean that you&amp;rsquo;d have a list of subnets and availability zones that you want your EFS mounts in and then you&amp;rsquo;de iterate over them (using &lt;code&gt;count&lt;/code&gt;) to create the mount points.&lt;/p&gt;
&lt;p&gt;Here I&amp;rsquo;m sticking with a single AZ to make things easier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Creates a new empty file system in EFS.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_efs_file_system&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;locks-test-fs&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Creates a mount target of EFS in a specified subnet&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that our instances can connect to it.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_efs_mount_target&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;file_system_id  = &amp;#34;${aws_efs_file_system.main.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;subnet_id       = &amp;#34;${var.subnet}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;security_groups = [&amp;#34;${aws_security_group.efs.id}&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Allows both ingress and egress for port 2049 (nfs)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# such that our instances can get to the mount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# target in the AZ.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_security_group&amp;#34; &amp;#34;efs&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name        = &amp;#34;efs-mnt&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;Allows NFS traffic from instances within the VPC.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;vpc_id      = &amp;#34;${data.aws_vpc.default.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ingress {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;from_port = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to_port   = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;protocol  = &amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_blocks = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${data.aws_vpc.default.cidr_block}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;egress {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;from_port = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to_port   = 2049&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;protocol  = &amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cidr_blocks = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${data.aws_vpc.default.cidr_block}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tags {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Name = &amp;#34;allow_nfs-ec2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output of that is then an address that we use to mount an NFS partition - which we then use to mount in a directory that we wish the have the file system.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Performs the mounting of an EFS mount target into&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# predefined MOUNT_LOCATION in the filesystem.&lt;/span&gt;


&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;MOUNT_LOCATION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;MOUNT_LOCATION&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;:-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/mnt/efs&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;MOUNT_TARGET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;MOUNT_TARGET&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Main routine - checks for the MOUNT_TARGET variable&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that does not have a default (can be empty) making &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# sure that it gets specified.&lt;/span&gt;
main &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -z &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MOUNT_TARGET&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
                &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;ERROR: 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        MOUNT_TARGET environment variable must be specified.
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;                &amp;#39;&lt;/span&gt;
                &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;INFO:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        Mounting shared filesystem.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        MOUNT_LOCATION  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MOUNT_LOCATION&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        MOUNT_TARGET    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MOUNT_TARGET&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        &amp;#34;&lt;/span&gt;

        mount_nfs
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Performs the actual mounting of the EFS target&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the AZ we specified into a directory we defined&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# via MOUNT_LOCATION.&lt;/span&gt;
mount_nfs&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        sudo mkdir -p &lt;span class=&#34;nv&#34;&gt;$MOUNT_LOCATION&lt;/span&gt;

        sudo mount &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -t nfs4 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -o &lt;span class=&#34;nv&#34;&gt;nfsvers&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4.1,rsize&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1048576,wsize&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1048576,hard,timeo&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;600,retrans&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;nv&#34;&gt;$MOUNT_TARGET&lt;/span&gt;:/ &lt;span class=&#34;nv&#34;&gt;$MOUNT_LOCATION&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the script above executed, we&amp;rsquo;re ready to go (make sure you have &lt;code&gt;nfs-common&lt;/code&gt; installed, by the way).&lt;/p&gt;
&lt;h3 id=&#34;exhausting-the-efs-mount-target-locks&#34;&gt;Exhausting the EFS mount target locks&lt;/h3&gt;
&lt;p&gt;Per the &lt;a href=&#34;https://docs.aws.amazon.com/efs/latest/ug/limits.html&#34;&gt;AWS documentation&lt;/a&gt; we can check how the quotas look like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each unique mount on the instance can acquire up to a total of 8,192 locks across a maximum of 256 unique file/process pairs. For example, a single process can acquire one or more locks on 256 separate files, or 8 processes can each acquire one or more locks on 32 files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;See &lt;a href=&#34;https://docs.aws.amazon.com/efs/latest/ug/limits.html#limits-client-specific&#34;&gt;Limits for Client EC2 Instances&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That means that just to make sure that we&amp;rsquo;ll indeed exhaust it, we can create a single MySQL instance and then make it create some three hundred tables.&lt;/p&gt;
&lt;p&gt;Adopting that script I showed above, this means:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;number_of_tables&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -z &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$number_of_tables&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ERROR:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        An argument (number of tables) must be supplied.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        &amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$number_of_tables&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
        create_table mytable&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then, calling it with &lt;code&gt;300&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;./create-many-tables.sh &lt;span class=&#34;m&#34;&gt;300&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;we can see that after a little while, it breaks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ERROR &lt;span class=&#34;m&#34;&gt;1030&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;HY000&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; at line 1: Got error &lt;span class=&#34;m&#34;&gt;168&lt;/span&gt; from storage engine
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at the number of locks that the system is holding:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Count the number of locks being held from the efs mount
lslocks | grep &#39;efs&#39; | wc -l
256
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can clearly see the quota in place.&lt;/p&gt;
&lt;p&gt;Naturally, InnoDB complained and failed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# docker logs ...&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;Note&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; mysqld: ready &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; connections.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;ERROR&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; InnoDB: Unable to lock ./testdb/mytable241.ibd error: &lt;span class=&#34;m&#34;&gt;122&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;ERROR&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; InnoDB: Operating system error number &lt;span class=&#34;m&#34;&gt;122&lt;/span&gt; in a file operation.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;ERROR&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; InnoDB: Error number &lt;span class=&#34;m&#34;&gt;122&lt;/span&gt; means &lt;span class=&#34;s1&#34;&gt;&amp;#39;Disk quota exceeded&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;ERROR&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; InnoDB: Cannot create file &lt;span class=&#34;s1&#34;&gt;&amp;#39;./testdb/mytable241.ibd&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it, 256 locks in a machine and you&amp;rsquo;re done.&lt;/p&gt;
&lt;h3 id=&#34;is-this-a-problem-with-nfs-in-general&#34;&gt;Is this a problem with NFS in general?&lt;/h3&gt;
&lt;p&gt;I thought this limit that AWS imposes could be a hard limit imposed by the protocol itself (NFSv4.1), but it turns out that this isn&amp;rsquo;t the case.&lt;/p&gt;
&lt;p&gt;If you create yourself an NFS server, mount it and try running a stress test that grabs as many locks as possible, you can go up to the millions (even though that takes some load on the server).&lt;/p&gt;
&lt;p&gt;To make sure that this is indeed the case, I set up a quick &lt;code&gt;c&lt;/code&gt; program that stresses only this piece (checkout at &lt;a href=&#34;https://github.com/cirocosta/efs-locks-sample/blob/master/stress/lock-a-lot.c&#34;&gt;cirocosta/efs-locks-sample/stress&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Struct that keeps track of the runtime arguments
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * that we supply via the CLI.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt; 
&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;number_of_locks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;base_directory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Prints to STODUT the runtime configuration passed.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;runtime_show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// some printf to show the runtime
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Creates a file under a directory (base) with a number (i)
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * and then grabs a write lock to it.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;create_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;base&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flock&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// make the lock exclusive (write lock)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;l_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;F_WRLCK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// .. do some work to have the filename properly set
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// try to acquire the lock
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fcntl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;F_SETLKW&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fcntl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Couldn&amp;#39;t acquire lock on %s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// just write something stupid to the file
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;dummy&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Creates `N` files with write a write lock grabbed for each
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * under a base directory `base`.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;runtime_create_files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Main execution.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Parses the cli arguments (number of locks
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * and base directory) and then starts the creation of the
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * files and locks.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * Once lock creation is done, pauses its execution until
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; * a signal arrives.
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;runtime_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number_of_locks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]),&lt;/span&gt; 
                &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_directory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;runtime_show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;runtime_create_files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
        
        &lt;span class=&#34;c1&#34;&gt;// ... wait for signals
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As expected, we hit the limit pretty fast in AWS while with a regular NFS server we can go to the sky.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;What can you do if you need MySQL on EFS? Well, this is the funny part: not much!&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a limit that you can&amp;rsquo;t tell AWS to raise.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not very sure you&amp;rsquo;d want to run MySQL on EFS (or any other NFS mount) as it&amp;rsquo;s clearly not endorsed by MySQL, but I guess that people using other software might hit problems in scenarios that make sense using EFS (NFS in general).&lt;/p&gt;
&lt;p&gt;I guess the best is to deal with proper MySQL replication on normal EBS disks, SSD on some other machines or go straight with the new NVMe-based instances.&lt;/p&gt;
&lt;p&gt;Have you faced problems like this? Did you spot any error?&lt;/p&gt;
&lt;p&gt;Please let me know!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter and would appreciate knowing what your thoughts are!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 10 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/limits-aws-efs-nfs-locks/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/limits-aws-efs-nfs-locks/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Initializing Grafana with preconfigured dashboards</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;this week the team behind Grafana released a beta release of &lt;a href=&#34;http://docs.grafana.org/guides/whats-new-in-v5/&#34;&gt;Grafana v5&lt;/a&gt; (which is almost there - &lt;a href=&#34;https://github.com/grafana/grafana/milestone/42&#34;&gt;check the milestone&lt;/a&gt;) and I got very happy to know that now it&amp;rsquo;s easier to get an instance from ground up without having to use the UI to configure the dashboards.&lt;/p&gt;
&lt;p&gt;The niceness of that feature is that now you can redeploy a Grafana container that has a bunch of dashboards without needing to go through the UI to configure them.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/grafana-flow.svg&#34;
       alt=&#34;Grafana deploy pipeline using a continuous integration system that ends up in Grafana deployed &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;While previously you&amp;rsquo;d had to manually import dashboards and configure the data sources using the UI, now it&amp;rsquo;s all declarative.&lt;/p&gt;
&lt;p&gt;Here I&amp;rsquo;ll go through an example where I set up Prometheus as Grafana&amp;rsquo;s source such and then perform the dashboard initialization without using the UI.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you&amp;rsquo;re only concerned with the Grafana initialization and want to skip Prometheus, go to the &lt;a href=&#34;#configuring-grafana&#34;&gt;Configuring Grafana&lt;/a&gt; section.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#setting-the-stage&#34;&gt;Setting the stage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#configuring-prometheus&#34;&gt;Configuring Prometheus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#configuring-grafana&#34;&gt;Configuring Grafana&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#example&#34;&gt;Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#updating-dashboards&#34;&gt;Updating dashboards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#scripting-dashboard-retrieval&#34;&gt;Scripting dashboard retrieval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;setting-the-stage&#34;&gt;Setting the stage&lt;/h3&gt;
&lt;p&gt;I created a little repository that contains some source code that can be used to check out the feature: &lt;a href=&#34;https://github.com/cirocosta/sample-grafana&#34;&gt;cirocosta/sample-grafana&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s structured like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── Makefile
├── docker-compose.yml          # docker-compose file that
│                               # aggregates `prometheus`,
│                               # `node_exporter` and `grafana`.
│ 
├── grafana                     # Grafana config
│   ├── Dockerfile              # Dockerfile that adds config to the image
│   ├── config.ini              # Base configuration
│   ├── dashboards              # Pre-made dashboards
│   │   └── mydashboard.json    # Sample dashboard
│   └── provisioning            # Configuration for automatic provisioning at
│       │                       # grafana startup.
│       ├── dashboards          
│       │   └── all.yml         # Configuration about grafana dashboard provisioning
│       └── datasources
│           └── all.yml         # Configuration about grafana data sources provisioning
│ 
└── prometheus                  # Prometheus config
    ├── Dockerfile
    └── config.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;docker-compose.yml&lt;/code&gt; file that aggregates the three containers works like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;3.3&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Prometheus uses the image resulting form the build&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of `./prometheus` which simply packs some configuration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# into the form of an image.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# It could instead, use volume-mounts.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;prometheus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./prometheus&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prometheus&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;9090:9090&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The grafana container uses the image resulting from the build&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of `./grafana` which simply packs some configuration into the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# form of an image.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This could instead be a volume-mounted container.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;grafana&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./grafana&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;grafana&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;3000:3000&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# You&amp;#39;d typically not run `node_exporter` in a container like&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# this.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If so, make sure you&amp;#39;re using `network_mode=host` to give the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# host network namespace to the containers as well as `pid=host`. &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Eventually it would also make sense to extend it with other &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# privileges and mounts. &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# I&amp;#39;ve never run it in a container so I can&amp;#39;t endorse doing so.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;node_exporter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;quay.io/prometheus/node-exporter&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;node_exporter&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that we end up with the following scenario:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/grafana-architecture.svg&#34;
       alt=&#34;Grafana architecture coupled with Prometheus and node_exporter &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Note that there&amp;rsquo;s an extra component: database.&lt;/p&gt;
&lt;p&gt;Grafana records dashboard modifications, alerts, organizations, users, and more (see &lt;a href=&#34;https://github.com/grafana/grafana/tree/master/pkg/services/sqlstore&#34;&gt;grafana/pkg/services/sqlstore&lt;/a&gt;). All of this needs some persistence.&lt;/p&gt;
&lt;p&gt;In the past, Grafana used to use Elasticsearch for that (it was more like a Kibana extension back then). Nowadays, when nothing is configured, a &lt;code&gt;sqlite3&lt;/code&gt; database is created by the Grafana binary, but you&amp;rsquo;re also free to use either &lt;code&gt;mysql&lt;/code&gt; or &lt;code&gt;postgresql&lt;/code&gt; as external databases.&lt;/p&gt;
&lt;h3 id=&#34;configuring-prometheus&#34;&gt;Configuring Prometheus&lt;/h3&gt;
&lt;p&gt;To have a well configured datasource, &lt;code&gt;Prometheus&lt;/code&gt; needs some configuration (checkout the configuration at &lt;code&gt;sample-grafana/prometheus/config.yml&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;evaluation_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `node` takes care of scraping node_exporter instances&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that gives us all sorts of information about the host&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# in which the exporter runs.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;job_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;node&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;static_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Given that we&amp;#39;re only testing a single instance that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# we know the address very well, statically set it here&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# with a custom instance label so that it looks better&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# in the ui (and metrics).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;targets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;node_exporter:9100&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;instance-1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This allows us to query Prometheus and get the metrics from &lt;code&gt;node_exporter&lt;/code&gt; that get the scrape targets registered with the &lt;code&gt;node&lt;/code&gt; job:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl http://localhost:9090/api/v1/query&lt;span class=&#34;se&#34;&gt;\?&lt;/span&gt;query&lt;span class=&#34;se&#34;&gt;\=&lt;/span&gt;node_memory_MemAvailable

&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
            &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;s2&#34;&gt;&amp;#34;metric&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;s2&#34;&gt;&amp;#34;__name__&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_memory_MemAvailable&amp;#34;&lt;/span&gt;,
                    &lt;span class=&#34;s2&#34;&gt;&amp;#34;instance&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;instance-1&amp;#34;&lt;/span&gt;,
                    &lt;span class=&#34;s2&#34;&gt;&amp;#34;job&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;node&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,
                &lt;span class=&#34;s2&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
                    1518184109.51,
                    &lt;span class=&#34;s2&#34;&gt;&amp;#34;7857156096&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;,
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;resultType&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;vector&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;success&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;re new to Prometheus, I highly recommend &lt;a href=&#34;https://amzn.to/2zuQwWz&#34;&gt;Prometheus: Up &amp;amp; Running&lt;/a&gt; from Brian Brazil.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Now we&amp;rsquo;re set to go configure Grafana.&lt;/p&gt;
&lt;h3 id=&#34;configuring-grafana&#34;&gt;Configuring Grafana&lt;/h3&gt;
&lt;p&gt;The new release of Grafana introduced and extra configuration path: &lt;a href=&#34;https://github.com/grafana/grafana/blob/e429cd83336ea3982914d3e401828e3cd0d755c8/conf/defaults.ini#L23-L24&#34;&gt;provisioning&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;c1&#34;&gt;########## Paths ###########&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;[paths]&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# folder that contains provisioning config files &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that grafana will apply on startup and while running.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;provisioning&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;conf/provisioning&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This provisioning directory can have other two directories inside it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;datasources&lt;/code&gt;: holds a list of &lt;code&gt;.yaml&lt;/code&gt; files that configure data sources (e.g, &lt;code&gt;Prometheus&lt;/code&gt; instance &amp;hellip;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dashboards&lt;/code&gt;: holds a list of &lt;code&gt;.yaml&lt;/code&gt; files with configuration files that tell Grafana where to look for dashboards to initialize on startup;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Starting with &lt;code&gt;datasources&lt;/code&gt;, this is where I tell Grafana where it should look for Prometheus:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# provisioning/datasources/all.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# https://github.com/cirocosta/sample-grafana/blob/master/grafana/provisioning/datasources/all.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;datasources&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;access&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;proxy&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                       &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# make grafana perform the requests&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;editable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                        &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# whether it should be editable&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;is_default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# whether this should be the default DS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prom1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                         &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# name of the datasource&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;org_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                             &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# id of the organization to tie this datasource to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prometheus&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# type of the data source&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;http://prometheus:9090&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# url of the prom instance&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                            &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# well, versioning&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that set, whenever Grafana starts up it picks the datasource (see &lt;a href=&#34;https://github.com/grafana/grafana/blob/1c034b7a731cc631b3492f4a9544090549f1c2ca/pkg/services/provisioning/datasources/datasources.go&#34;&gt;pkg/services/provisioning/datasources&lt;/a&gt; if you want to know more by checking the source code) and applies it to its database.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: This &lt;code&gt;datasources&lt;/code&gt; file can also contain a &lt;code&gt;delete_datasources&lt;/code&gt; object which would tell Grafana about datasources to remove from its database (assuming you&amp;rsquo;re not starting from a fresh database).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As just having the data source is not enough, we&amp;rsquo;d then configure the &lt;code&gt;provisioning/dashboards&lt;/code&gt; directory. There you can add a file describing how Grafana can pick dashboards whenever it starts up.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# provisioning/dashboards/all.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# https://github.com/cirocosta/sample-grafana/blob/master/grafana/provisioning/dashboards/all.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# name of this dashboard configuration (not dashboard itself)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;org_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;             &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# id of the org to hold the dashboard&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;folder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# name of the folder to put the dashboard (http://docs.grafana.org/v5.0/reference/dashboard_folders/)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# type of dashboard description (json files)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;options&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;folder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/var/lib/grafana/dashboards&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# where dashboards are&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that configured, make sure your dashboards are in the place they should be (&lt;code&gt;/var/lib/grafana/dashboards&lt;/code&gt; in this example) and you&amp;rsquo;re ready to go.&lt;/p&gt;
&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;Clone the &lt;a href=&#34;https://github.com/cirocosta/sample-grafana&#34;&gt;cirocosta/sample-grafana&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;This repository contains the file structure described above.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;make run&lt;/code&gt; you can take the infrastructure up (&lt;code&gt;node_exporter&lt;/code&gt;, &lt;code&gt;grafana&lt;/code&gt; and &lt;code&gt;prometheus&lt;/code&gt;) if you have &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;docker-compose&lt;/code&gt; installed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# clone the repo and get there&lt;/span&gt;
git clone https://github.com/cirocosta/sample-grafana
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./sample-grafana

&lt;span class=&#34;c1&#34;&gt;# run the infra&lt;/span&gt;
make run

&lt;span class=&#34;c1&#34;&gt;# open the grafana web page&lt;/span&gt;
open http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you should see a &lt;code&gt;login&lt;/code&gt; screen (which you can enter with &lt;code&gt;admin&lt;/code&gt; as user and &lt;code&gt;admin&lt;/code&gt; as password).&lt;/p&gt;
&lt;p&gt;After logged in, &lt;em&gt;voilà&lt;/em&gt;, the datasource has been already configured and you already have a dashboard (&lt;code&gt;mydashboard&lt;/code&gt;) set:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/grafana-provisioned.png&#34;
       alt=&#34;Grafana with datasource and dashboard automatically provisioned at startup time &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Heading towards the dashboard, we can see that our scrape target is really being scraped and that Grafana is properly retrieving the information it needs from Prometheus (as the data source has been properly configured):&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/grafana-instance.png&#34;
       alt=&#34;Grafana dashboard showing Prometheus query working &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;updating-dashboards&#34;&gt;Updating dashboards&lt;/h3&gt;
&lt;p&gt;As the files that represent the dashboards are all JSON files, the easiest way to get them with the modifications you performed is targetting the Grafana API with your credentials and saving the JSON files to the directory.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re managing just one dashboard or another you can do this by hand though - go to settings and retrieve the JSON for the dashboard:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/grafana-json.png&#34;
       alt=&#34;Grafana JSON visualization feature &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;If you&amp;rsquo;re managing some more (which I guess it&amp;rsquo;s the case), there&amp;rsquo;s a better way of doing it.&lt;/p&gt;
&lt;h3 id=&#34;scripting-dashboard-retrieval&#34;&gt;Scripting dashboard retrieval&lt;/h3&gt;
&lt;p&gt;That manual process I described is not all that hard to be scripted.&lt;/p&gt;
&lt;p&gt;By inspecting the network requests issued by the browser, we can notice that Grafana exposes some interesting endpoints via the &lt;code&gt;/api&lt;/code&gt; path:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/api/search             allows us to retrieve different types of objects
                        related to our account / organization, including
                        one that really matters to us: dash-db (dashboards
                        db I guess)

/api/dashboards/db      retrieves the configuration of a dash-db object

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;(the routes are registered under &lt;a href=&#34;https://github.com/grafana/grafana/blob/master/pkg/api/api.go&#34;&gt;grafana/grafana/pkg/api/api.go&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So the idea of the script is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;retrieve a list of dashboard names (get it from &lt;code&gt;dash-db&lt;/code&gt; objects in the list that &lt;code&gt;/api/search&lt;/code&gt; gives us);&lt;/li&gt;
&lt;li&gt;for each dashboard, get its configuration;&lt;/li&gt;
&lt;li&gt;save the configuration to a file in a specific location.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The script looks like this (see &lt;a href=&#34;https://github.com/cirocosta/sample-grafana/blob/master/update-dashboards.sh&#34;&gt;update-dashboards.sh&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Updates local dashboard configurations by retrieving&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the new version from a Grafana instance.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The script assumes that basic authentication is configured&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (change the login credentials with `LOGIN`).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# DASHBOARD_DIRECTORY represents the path to the directory&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# where the JSON files corresponding to the dashboards exist.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The default location is relative to the execution of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# script.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# URL specifies the URL of the Grafana instance.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;URL&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;:-&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;http://localhost:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;LOGIN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOGIN&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;:-&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;admin:admin&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DASHBOARDS_DIRECTORY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;DASHBOARDS_DIRECTORY&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;:-&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;./grafana/dashboards&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;


main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;dashboards&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;list_dashboards&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; dashboard_json

  show_config

  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; dashboard in &lt;span class=&#34;nv&#34;&gt;$dashboards&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;nv&#34;&gt;dashboard_json&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;get_dashboard &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dashboard&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -z &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dashboard_json&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ERROR:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Couldn&amp;#39;t retrieve dashboard &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dashboard&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      &amp;#34;&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dashboard_json&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;nv&#34;&gt;$DASHBOARDS_DIRECTORY&lt;/span&gt;/&lt;span class=&#34;nv&#34;&gt;$dashboard&lt;/span&gt;.json
  &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Shows the global environment variables that have been configured&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# for this run.&lt;/span&gt;
show_config&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;INFO:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Starting dashboard extraction.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  URL:                  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$URL&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  LOGIN:                &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LOGIN&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  DASHBOARDS_DIRECTORY: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DASHBOARDS_DIRECTORY&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Retrieves a dashboard ($1) from the database of dashboards.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As we&amp;#39;re getting it right from the database, it&amp;#39;ll contain an `id`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Given that the ID is potentially different when we import it&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# later, to make this dashboard importable we make the `id`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# field NULL.&lt;/span&gt;
get_dashboard&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;dashboard&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -z &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dashboard&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ERROR:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  A dashboard must be specified.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --user &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LOGIN&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$URL&lt;/span&gt;/api/dashboards/db/&lt;span class=&#34;nv&#34;&gt;$dashboard&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
    jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.dashboard | .id = null&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# lists all the dashboards available.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `/api/search` lists all the dashboards and folders&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that exist in our organization.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here we filter the response (that also contain folders)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to gather only the name of the dashboards.&lt;/span&gt;
list_dashboards&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --user &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LOGIN&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$URL&lt;/span&gt;/api/search &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
    jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.[] | select(.type == &amp;#34;dash-db&amp;#34;) | .uri&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
    cut -d &lt;span class=&#34;s1&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; -f2
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Execute it with the right variables, and you&amp;rsquo;re done!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s very nice to see that Grafana is going.&lt;/p&gt;
&lt;p&gt;As the &lt;em&gt;de facto&lt;/em&gt; tool for graphing I&amp;rsquo;m very happy that Grafana has been improving so much over time. This new version is even more responsive and has this little feature that really helps.&lt;/p&gt;
&lt;p&gt;Congratulations to everybody involved!&lt;/p&gt;
&lt;p&gt;If you have any questions or noticed that I made a mistake somewhere, please let me know!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Fri, 09 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/initialize-grafana-with-preconfigured-dashboards/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/initialize-grafana-with-preconfigured-dashboards/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Simulating AWS tags in local Prometheus</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;some time ago I had the challenge of setting a monitoring system for some machines in AWS.&lt;/p&gt;
&lt;p&gt;I end up taking &lt;a href=&#34;https://prometheus.io&#34;&gt;Prometheus&lt;/a&gt; as the system to retrieve the metrics from the sources and Grafana as the way of graphing them. Nothing fancy, pretty standard.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/prom-aws-overview.svg&#34;
       alt=&#34;Overview of Prometheus pulling metrics &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;After that, I had a problem though. How could I test this setup locally?&lt;/p&gt;
&lt;p&gt;Everything was very much tied to how service discovery worked within an AWS environment. The machines would get fetched from &lt;a href=&#34;https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html&#34;&gt;EC2&amp;rsquo;s DescribeInstances&lt;/a&gt; with all the tags that were set up for them. With the relabelling feature, I was able to make use of those tags to improve the metrics and have a better sense of data. How could I replicate that locally?&lt;/p&gt;
&lt;p&gt;Check out how I end up solving that.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: this is one way - here are undoubtedly many others.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;tailoring-the-aws-prometheus-configuration&#34;&gt;Tailoring the AWS Prometheus configuration&lt;/h3&gt;
&lt;p&gt;As each environment has its specificities regarding how to gather information, about where are the machines and what information can be retrieved from they, I created separate configuration files that achieve the same end goal: expose machine metrics, docker daemon metrics as well as container metrics.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prometheus
    └── config
        ├── aws.yml             # aws-specific configuration
        └── vagrant.yml         # vagrant-specific configuration
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As each machine has (mostly) the same exporters, they&amp;rsquo;re all alike with just a few changes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps: some machines have different exporters, e.g., load-balancer machines have &lt;code&gt;haproxy_exporter&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a Prometheus configuration aiming at getting information about AWS machines that enhance the metrics with custom AWS tags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# AWS configuration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;10s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;evaluation_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;10s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Collect metrics about the node.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# These are plain `node_exporter` metrics that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# are scrapped to reveal all sorts of machine &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# metrics like cpu, inode utilization for each fs, &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# memory, iface statistics ...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# In this example I&amp;#39;m not specifying the AWS access token,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# secret key and regions because the AWS golang client will&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# get it from the environment using the default namings, &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# leaving us only to need to specify the port to scrape.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;job_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;node&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ec2_sd_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;9100&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;relabel_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Because we could have multiple environments running&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# in the same region or some ephemeral machines that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# are not meant to be scrapped, filter out those that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# do not contain a specific tag.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;source_labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;__meta_ec2_tag_tips_ops_environment&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;regex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;dev1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;keep&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Gather the instance id and use it as the name of the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# instance.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This allows us to not use the weird hostname that aws provides&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# but instead, the instance ID that AWS we can gather from the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# service discovery.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;source_labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;__meta_ec2_instance_id&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;target_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;instance&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# To enhance the intel and understand better what&amp;#39;s going on,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# here I also retrieve an extra tag that the machines are &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# supposed to have.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# In this example I set `tips_ops_node_type` to the machine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# tag (e.g., m4.4xlarge) but this could be anything.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Check `local-aws-prom/infrastructure/main.tf` to see the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# tag being set.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;source_labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;__meta_ec2_tag_tips_ops_node_type&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;target_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;tips_ops_node_type&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that there I retrieve a custom tag that I set in the machine and then enhance the metrics with it. That tag, however, comes from &lt;code&gt;ec2_sd&lt;/code&gt; (the EC2 service discovery).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #ffe4e1; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/prom-targets-aws.png&#34;
       alt=&#34;Example of Prometheus monitoring targets in AWS &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Once Prometheus starts with such configuration, we can see our relabelling taking place. Having two instances, one with the proper tags and another without, the first gets accepted and the second, dropped.&lt;/p&gt;
&lt;p&gt;More than that, the first gets some extra labels extracted from the EC2 tags.&lt;/p&gt;
&lt;h3 id=&#34;preparing-the-local-configuration&#34;&gt;Preparing the local configuration&lt;/h3&gt;
&lt;p&gt;To test that locally we can use &lt;code&gt;static_config&lt;/code&gt; labeling for each target.&lt;/p&gt;
&lt;p&gt;For instance, this is how the Vagrant Prometheus configuration would look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# VAGRANT configuration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;evaluation_interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;scrape_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Collect metrics about the node.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# These are plain `node_exporter` metrics that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# are scrapped to reveal all sorts of machine &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# metrics like cpu, inode utilization for each fs, &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# memory, iface statistics ...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;job_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;node&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;relabel_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Gather the instance id and use it as the name of the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# instance.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This allows us to not use `${ADDR}:${PORT}` in the instance&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# names but instead, the instance ID that AWS gives to us.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# In this case, a fake `i-&amp;lt;instance&amp;gt;` identifier.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;source_labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;__meta_ec2_instance_id&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;target_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;instance&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Collect the type of the node and add it as a tag to our&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# metrics. &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This allows us to make use of node types in our&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# queries and dashboards (e.g., if you want to graph the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# average CPU usage of a specific machine type like&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# m4.4xlarge)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;source_labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;__meta_ec2_tag_tips_ops_node_type&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;target_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;opstips_node_type&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Machine configuration acting as if we were in aws.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This has the effect of emulating the AWS labels that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the aws service discovery would give us.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Note that here I&amp;#39;m setting more information&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# than I actually use - not all of these are&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# being used in the relabelling phase so those&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# not used will be dropped and not persisted.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Because I&amp;#39;m simulating a two-node scenario&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# I&amp;#39;m listing only 2 static addresses here with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the desired labels. If you needed to test against more&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# VMs, this would need to be updated. Probably a better&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# way would be setting up DNS service discovery with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# a custom DNS server locally.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;static_configs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;targets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;${MACHINE_IP}:9110&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_tag_tips_ops_environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;dev1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_tag_tips_ops_node_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;opstips-fleet-masters&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_instance_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;t2.medium&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_instance_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;i-inst1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;targets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;${MACHINE_IP}:9120&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_tag_tips_ops_environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;dev1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_tag_tips_ops_node_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;opstips-fleet-slaves&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_instance_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;t2.medium&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;__meta_ec2_instance_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;i-inst2&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To have two machines running with &lt;code&gt;node_exporter&lt;/code&gt; I setup a little &lt;code&gt;Vagrantfile&lt;/code&gt; which would provision them as wanted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Provisioning script that downloads the node_exporter&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# binary from the GitHub releases page and then initiates&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it with a simple `nohup`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.:  for something more robust you&amp;#39;d typically prepare&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       a systemd service and have it enabled to keep it running&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       even between restarts.&lt;/span&gt;
&lt;span class=&#34;vg&#34;&gt;$script&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;SCRIPT
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;github&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prometheus&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node_exporter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;releases&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;download&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node_exporter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;amd64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gz&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;curl&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/tmp/no&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;de_exporter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tgz&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;SL&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;
    &lt;span class=&#34;vg&#34;&gt;$URL&lt;/span&gt;
    
&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;xzf&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/tmp/no&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;de_exporter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tgz&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;C&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/tmp/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;strip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;components&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;nohup&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/tmp/no&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;de_exporter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;SCRIPT&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Prepare the machine configurations.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I&amp;#39;m statically configuring what are the ports&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that will be exposed such that in our prometheus configuration&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can target them directly without needing DNS or any other&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# discovery mechanisms.&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;Vagrant&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu/artful64&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box_check_update&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;synced_folder&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/vagrant&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;disabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provision&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;inline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;vg&#34;&gt;$script&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;machine1&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machine1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;machine1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;network&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;forwarded_port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;guest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9110&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;machine2&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machine2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;machine2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;network&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;forwarded_port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;guest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9120&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;virtualbox&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;512&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After a &lt;code&gt;vagrant up&lt;/code&gt;, we should have both machines running with &lt;code&gt;node_exporter&lt;/code&gt; in the respective ports:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl localhost:9110/metrics
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# HELP go_gc_duration_seconds A summary of the GC invocation durations.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# TYPE go_gc_duration_seconds summary&lt;/span&gt;
go_gc_duration_seconds&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;quantile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
...

&lt;span class=&#34;hl&#34;&gt;curl localhost:9120/metrics
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# HELP go_gc_duration_seconds A summary of the GC invocation durations.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# TYPE go_gc_duration_seconds summary&lt;/span&gt;
go_gc_duration_seconds&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;quantile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now get &lt;code&gt;prometheus&lt;/code&gt; up (in my case I tailored a &lt;code&gt;Dockerfile&lt;/code&gt; that takes care of adding the right configuration depending on the environment - &lt;code&gt;aws&lt;/code&gt; or &lt;code&gt;vagrant&lt;/code&gt;), and we should be able to see the targets:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #faebd7; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/prom-sd-vagrant.png&#34;
       alt=&#34;Example of Prometheus targets using Vagrant &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;And, that&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;With the targets being properly scrapped and with Prometheus performing the right label transformation, we&amp;rsquo;re all set.&lt;/p&gt;
&lt;p&gt;A Grafana dashboard that makes use of those labels would be able to run properly against both AWS and local instances.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #42689a; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/prom-comparison.png&#34;
       alt=&#34;Querying Prometheus Locally and in AWS &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;As it can be seen in the above comparison, the labeling works great.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Even though it&amp;rsquo;s fairly simple to get some instances running in AWS to prepare dashboards and test Prometheus alert rules, I find useful to be able to run it locally. With a set up like this, you can test relabelling easily without the need of any AWS instances.&lt;/p&gt;
&lt;p&gt;Naturally, this technique can be applied to other cloud providers.&lt;/p&gt;
&lt;p&gt;Have you been monitoring instances in AWS with Prometheus? Did you spot a mistake in the article? Please let me know!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter and would be very happy to answer any questions or just hear something about the article.&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Thu, 08 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/simulating-aws-tags-in-local-prometheus/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/simulating-aws-tags-in-local-prometheus/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>What happens when a pipeline is created in Concourse CI?</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;this blog post is the continuation of the previous post (&lt;a href=&#34;https://ops.tips/blog/how-to-run-concourse-ci-locally/&#34;&gt;How to build and run Concourse CI locally&lt;/a&gt;). In this one, I try to understand better how one of its main components works internally to keep track of pipelines and have builds triggered.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dig into what goes on when a pipeline is submitted to Concourse.&lt;/p&gt;
&lt;h3 id=&#34;the-api&#34;&gt;The API&lt;/h3&gt;
&lt;p&gt;As a consumer of the &amp;ldquo;concourse service&amp;rdquo;, the API server is the first point that we touch. The API server in this case is &lt;a href=&#34;http://github.com/concourse/atc&#34;&gt;atc&lt;/a&gt;:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc2-atc.svg&#34;
       alt=&#34;Concourse CI interaction with the Concourse scheduler (ATC) &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;From the words of the &lt;code&gt;atc&lt;/code&gt; repository:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;atc is the brain of Concourse. It&amp;rsquo;s responsible for scheduling builds across the cluster of workers, providing the API for the system, as well as serving the web interface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the &lt;a href=&#34;https://ops.tips/blog/how-to-run-concourse-ci-locally/&#34;&gt;last post&lt;/a&gt;, when we submitted a pipeline to Concourse, &lt;code&gt;atc&lt;/code&gt; was the component that the cli (&lt;a href=&#34;https://github.com/concourse/fly&#34;&gt;fly&lt;/a&gt;) was sending it to.&lt;/p&gt;
&lt;p&gt;To have an example, let&amp;rsquo;s take that very same pipeline:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;jobs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;say-hello&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;platform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;linux&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image_resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker-image&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;nt&#34;&gt;repository&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;alpine&amp;#39;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;echo&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then submit it using &lt;code&gt;fly&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;fly &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        set-pipeline &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --pipeline&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hello-world &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --config&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./hello.yml &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --target&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Fly&lt;/code&gt; is interesting in its own; in summary it does the follow (see &lt;a href=&#34;https://github.com/concourse/fly/blob/master/commands/set_pipeline.go&#34;&gt;commands/set_pipeline&lt;/a&gt; and &lt;a href=&#34;https://github.com/concourse/fly/blob/master/commands/internal/setpipelinehelpers/atc_config.go#L80&#34;&gt;commands/internal/setpipelinehelpers&lt;/a&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;creates an internal representation of the new configuration submitted (parses the &lt;code&gt;yaml&lt;/code&gt; it got from &lt;code&gt;--config&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;loads a possible existing configuration for that pipeline (asks &lt;code&gt;atc&lt;/code&gt; for it based on the pipeline name);&lt;/li&gt;
&lt;li&gt;performs a diff between the existing pipeline and the new one;&lt;/li&gt;
&lt;li&gt;shows a message highlighting these diffs and then asks for confirmation to proceed;&lt;/li&gt;
&lt;li&gt;applies the configuration by making use of the concourse client &lt;a href=&#34;https://github.com/concourse/go-concourse&#34;&gt;go-concourse&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;the configuration save call made from &lt;code&gt;go-concourse&lt;/code&gt; touches the following endpoint in &lt;code&gt;atc&lt;/code&gt;: &lt;code&gt;/api/v1/teams/:team_name/pipelines/:pipeline_name/config&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that the configuration landed in &lt;code&gt;atc&lt;/code&gt;, &lt;a href=&#34;https://github.com/concourse/atc/blob/694a972a34f403982b98811156e36bd254695453/api/configserver/save.go#L52&#34;&gt;api/configserver/save.go#SaveConfig&lt;/a&gt; gets touched.&lt;/p&gt;
&lt;p&gt;This piece does two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;performs a second validation (&lt;code&gt;fly&lt;/code&gt; already validated it, but as this &lt;code&gt;api&lt;/code&gt; might be public it takes the defensive approach);&lt;/li&gt;
&lt;li&gt;saves the configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fair enough, but, what &lt;em&gt;&amp;ldquo;saves the configuration&amp;rdquo;&lt;/em&gt; means?&lt;/p&gt;
&lt;h3 id=&#34;saving-the-pipeline-configuration&#34;&gt;Saving the pipeline configuration&lt;/h3&gt;
&lt;p&gt;Saving such configuration means making the pipeline persistent.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc2-atc-psql.svg&#34;
       alt=&#34;Interaction between Concourse ATC and PostgreSQL &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The process of saving the pipeline is based on two possibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we&amp;rsquo;re creating a plain new pipeline;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s already a pipeline with such name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the first case, it sets a row in the &lt;code&gt;pipelines&lt;/code&gt; table and creates an extra table to keep track of build events for that pipeline (&lt;code&gt;pipeline_build_events_&amp;lt;pipeline_id&amp;gt;d&lt;/code&gt;) - pretty neat. Once that&amp;rsquo;s done, it starts populating the other tables (&lt;code&gt;jobs&lt;/code&gt;, &lt;code&gt;resources&lt;/code&gt;, &lt;code&gt;resource_types&lt;/code&gt;, &amp;hellip;).&lt;/p&gt;
&lt;p&gt;In the case that there&amp;rsquo;s already a pipeline established for that name, an &lt;code&gt;update&lt;/code&gt; is performed, all previous &lt;code&gt;job&lt;/code&gt;s, &lt;code&gt;resource&lt;/code&gt;s and &lt;code&gt;resource_types&lt;/code&gt; are made inactive, and task caches are cleared. Once that&amp;rsquo;s done, now it populates the &lt;code&gt;jobs&lt;/code&gt;, &lt;code&gt;resources&lt;/code&gt;, &amp;hellip; tables with &lt;code&gt;active&lt;/code&gt; entries (such that in the end, it has only the new ones marked as active).&lt;/p&gt;
&lt;h3 id=&#34;whats-in-the-db&#34;&gt;What&amp;rsquo;s in the DB?&lt;/h3&gt;
&lt;p&gt;After we ran &lt;code&gt;set-pipeline&lt;/code&gt;, we should have some stuff filled in our database.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# log in as `postgres` (we know we don&amp;#39;t need password&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# because of the `atc` initialization at `./dev/atc`)&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;psql &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --username&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;postgres &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --no-password
&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# list the databases that we have&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;
&lt;/span&gt;                                 List of databases
   Name    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
-----------+
 atc       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;
 postgres  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
 template0 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
 template1 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; rows&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# connect to the ATC database&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt; atc
&lt;/span&gt;You are now connected to database &lt;span class=&#34;s2&#34;&gt;&amp;#34;atc&amp;#34;&lt;/span&gt; as user &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;.


&lt;span class=&#34;c1&#34;&gt;# list all the tables that are there&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;t                                               
&lt;/span&gt;                                          
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;         Name             &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
+--------------------------+
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; base_resource_types      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; build_events             &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
...
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jobs_serial_groups       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; next_build_inputs        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; pipeline_build_events_2  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; the generated build_events table
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; pipelines                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; our pipeline should be here
...
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; worker_task_caches       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; workers                  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;32&lt;/span&gt; rows&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Retrieve all the pipelines saved&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;SELECT * FROM pipelines&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt; version &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; id &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    name     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; paused &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ordering &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;        last_scheduled         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; team_id &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; public &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; groups 
---------+----+-------------+--------+----------+-------------------------------+---------+--------+--------
       &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; hello-world &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; f      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;        &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 2018-02-05 18:58:00.205094-05 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; f      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; null
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; row&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While that&amp;rsquo;s interesting per se, looking at the table definitions, we can understand a bit more about how data is structured internally by looking at the references.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;by&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;builds&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keeps&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;track&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;executions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;are&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initiated&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;It&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;has&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mark&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;what&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;s the engine that ran the
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    # tasks, if it was manually triggered or not,
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    # which pipeline the build belongs to ...
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    TABLE &amp;#34;builds&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        CONSTRAINT &amp;#34;builds_pipeline_id_fkey&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        FOREIGN KEY (pipeline_id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        REFERENCES pipelines(id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        ON DELETE CASCADE
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    TABLE &amp;#34;jobs&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        CONSTRAINT &amp;#34;jobs_pipeline_id_fkey&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        FOREIGN KEY (pipeline_id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        REFERENCES pipelines(id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        ON DELETE CASCADE
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    TABLE &amp;#34;resource_types&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        CONSTRAINT &amp;#34;resource_types_pipeline_id_fkey&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        FOREIGN KEY (pipeline_id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        REFERENCES pipelines(id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        ON DELETE CASCADE
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    TABLE &amp;#34;resources&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        CONSTRAINT &amp;#34;resources_pipeline_id_fkey&amp;#34; 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        FOREIGN KEY (pipeline_id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        REFERENCES pipelines(id) 
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        ON DELETE CASCADE
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then to understand what are the most critical queries (or at least guess), look at the indices:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Indexes:
    &amp;quot;pipelines_pkey&amp;quot; 
        PRIMARY KEY, btree (id)

    &amp;quot;pipelines_name_team_id&amp;quot; 
        UNIQUE CONSTRAINT, 
        btree (name, team_id)

    &amp;quot;pipelines_team_id&amp;quot; 
        btree (team_id)
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;whats-next&#34;&gt;What&amp;rsquo;s next?&lt;/h3&gt;
&lt;p&gt;The next step is getting to know more about how does a work register itself against &lt;code&gt;tsa&lt;/code&gt;, another component that makes up the architecture.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to dig deep into how that process looks like and what are the components involved.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about it too, check out the next posts!&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions or comments. I probably got something wrong here, and I&amp;rsquo;d really like to know about it - I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, feel free to reach out.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 05 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/what-happens-when-pipeline-is-created-in-concourse-ci/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/what-happens-when-pipeline-is-created-in-concourse-ci/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>How to build and run Concourse CI locally</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;close to a year ago I got in touch with &lt;a href=&#34;https://concourse-ci.org&#34;&gt;concourse.ci&lt;/a&gt; when evaluating a tool to perform builds whenever changes happened in a git repository and even though the team I worked with end up creating a custom tailored system (we needed much less than what concourse - or something like Jenkins - provided) I think Concourse does a lot right.&lt;/p&gt;
&lt;p&gt;This post is not meant to teach you the concepts behind Concourse or provide use cases, but let you know how you can run a development version of it locally if you&amp;rsquo;re willing to contribute to the project.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #293745; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc-head.png&#34;
       alt=&#34;Concourse CI pipeline sample &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;setting-up-the-development-environment&#34;&gt;Setting up the development environment&lt;/h3&gt;
&lt;p&gt;Concourse (and the CloudFoundry project as a whole it seems) performs vendoring using git submodules.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s always a repository somewhere that aggregates dependencies and gives a consistent view of how things group together. In the case of Concourse, it&amp;rsquo;s &lt;a href=&#34;https://github.com/concourse/concourse&#34;&gt;github.com/concourse/concourse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To the extent of this post there&amp;rsquo;s no need to run all the parts of Concourse (as we&amp;rsquo;re only exploring &lt;code&gt;atc&lt;/code&gt; and &lt;code&gt;PostgreSQL&lt;/code&gt;), but before breaking things apart, I think it&amp;rsquo;s good to get an example running.&lt;/p&gt;
&lt;p&gt;Pick that repo and put it somewhere in your FS (doesn&amp;rsquo;t need to be under your current &lt;code&gt;$GOPATH&lt;/code&gt;) and then initialize the submodules (if you have any doubts, check the &lt;a href=&#34;https://github.com/concourse/concourse/blob/master/CONTRIBUTING.md&#34;&gt;CONTRIBUTING.md&lt;/a&gt; file at this repository):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# clone the repository that aggregates the whole&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# project and its dependencies&lt;/span&gt;
git clone https://github.com/concourse/concourse
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; concourse

&lt;span class=&#34;c1&#34;&gt;# initialize the submodules&lt;/span&gt;
git submodule update --init --recursive

&lt;span class=&#34;c1&#34;&gt;# if not using direnv (https://github.com/direnv/direnv),&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# execute the commands described under `.envrc` file in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the current shell session (that `.envrc` is essentially&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# setting the GOPATH go the `./src` directory under &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# concourse/concourse.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; .envrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that set, I update the &lt;code&gt;./dev/Procfile&lt;/code&gt; file which describes how to run the dockerized version of the postgres database and make atc point to the DB instead of a local instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gd&#34;&gt;--- a/dev/Procfile
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/dev/Procfile
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -1,4 +1,4 @@
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;-atc: ./atc
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+atc: ./atc-dockerdb
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt; tsa: ./tsa
 worker: ./worker
&lt;span class=&#34;gd&#34;&gt;-db: ./db
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+db: ./dockerdb
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that set, start:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;./dev/start

Using default tag: latest
latest: Pulling from concourse/con...
Digest: sha256:ac10eadf32798da0567...
Status: Image is up to date &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; co...
10:21:25    atc &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Starting atc on ...
10:21:25    tsa &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Starting tsa on ...
10:21:25     db &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Starting db on p...
10:21:25 worker &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Starting worker ...
10:21:26     db &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 2939be72c6e24ddb...
10:21:26    tsa &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;15...
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;10:21:26     db | Terminating db
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;10:21:26 worker | {&amp;#34;&lt;/span&gt;timestamp&lt;span class=&#34;s2&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;15...
10:21:28    atc &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; creating databas...
10:21:31    atc &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; creating databas...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;using-fly-locally&#34;&gt;Using FLY locally&lt;/h3&gt;
&lt;p&gt;To interact with the Concourse API (provided by &lt;code&gt;atc&lt;/code&gt;) we use the &lt;code&gt;fly&lt;/code&gt; command line interface (CLI). It&amp;rsquo;s the piece that makes use of &lt;a href=&#34;https://github.com/concourse/go-concourse&#34;&gt;go-concourse&lt;/a&gt; to communicate with ATC in a standard fashion.&lt;/p&gt;
&lt;p&gt;Installing it is simple after all submodules have been initialized. Head to &lt;code&gt;concourse/concourse/src/github.com/concourse/fly&lt;/code&gt; and build it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Make sure you have  your `GOPATH` properly set by sourcing &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the `.envrc` file&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; .envrc

&lt;span class=&#34;c1&#34;&gt;# get to the directory where the source of the FLY command&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# line is. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This should be there after you&amp;#39;ve installed the submodules.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./src/github.com/concourse/fly

&lt;span class=&#34;c1&#34;&gt;# By using `go install` we&amp;#39;ll have the final result of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the build in `$GOPATH/bin` which should be in your&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# $PATH after sourcing `.envrc`. &lt;/span&gt;
go install -v

&lt;span class=&#34;c1&#34;&gt;# check if everything is working&lt;/span&gt;
fly --version
0.0.0-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the CLI can now create a target that we&amp;rsquo;ll use to perform the commands against:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Authenticates against a concourse-url (`127.0.0.1:8080`) and &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# saves the auth details under an alias (`local`) in `~/.flyrc`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As we&amp;#39;re not specifying a `team` (`--team-name`) it&amp;#39;ll use the default&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# one (`main`) - a team can be thought as a namespace under which pipelines&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and builds fall into.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# When testing concourse locally (and not dealing with auth) we can stay&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with `main` (which is also an administrator team) and not worry about&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# auth at all (`atc` is being initialized with the `--no-really-i-dont-want-any-auth`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# flag).&lt;/span&gt;
fly &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        login &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --concourse-url http://127.0.0.1:8080 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --target &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; 

&lt;span class=&#34;c1&#34;&gt;# Create a pipeline&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;jobs:
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;- name: hello
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  plan:
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  - task: say-hello
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    config:
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;      platform: linux
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;      image_resource:
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        type: docker-image
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        source: {repository: alpine}
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;      run:
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        path: echo
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        args: [&amp;#34;hello&amp;#34;]
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt; &amp;gt; /tmp/hello.yml

&lt;span class=&#34;c1&#34;&gt;# Submit the pipeline&lt;/span&gt;
 fly &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        set-pipeline &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --pipeline hello-world &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --config ./hello.yml &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --target &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; 

&lt;span class=&#34;c1&#34;&gt;# List the pipelines to make sure it&amp;#39;s there&lt;/span&gt;
fly &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        pipelines &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --target &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt;
name         paused  public
hello-world  yes     no  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ok, everything is set up!&lt;/p&gt;
&lt;h3 id=&#34;running-the-pipeline-from-concourse-web-application&#34;&gt;Running the pipeline from concourse web application&lt;/h3&gt;
&lt;p&gt;At the first time you shoot &lt;code&gt;localhost:8080&lt;/code&gt; on your browser, no pipeline will show:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc-no-pipelines-configured.png&#34;
       alt=&#34;First screen of Concourse CI without pipelines configured &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;That&amp;rsquo;s because our sample pipeline is not public and we&amp;rsquo;re not authenticated.&lt;/p&gt;
&lt;p&gt;Head to &lt;code&gt;login&lt;/code&gt; (&lt;code&gt;http://localhost:8080/login&lt;/code&gt;) and just click right in &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;login&lt;/code&gt;. Because &lt;code&gt;atc&lt;/code&gt; has been put up with &lt;code&gt;--no-really-i-dont-want-any-auth&lt;/code&gt;, no questions will be asked.&lt;/p&gt;
&lt;p&gt;The next step is enabling the pipeline (unpausing it).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc-put-it-to-run.png&#34;
       alt=&#34;Screen showing how to make a Concourse CI pipeline run &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Once that&amp;rsquo;s done, select the pipeline and start a new build:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc-create-new-build.png&#34;
       alt=&#34;Image showing how to create a new Concourse CI build &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;It should now be started:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #293745; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc-pipeline-running.png&#34;
       alt=&#34;Screen showing an ongoing build in yellow &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;m still now very into what&amp;rsquo;s going on at this moment but my guess is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;atc&lt;/code&gt; received a build request&lt;/li&gt;
&lt;li&gt;given that there&amp;rsquo;s a worker that registered itself against &lt;code&gt;tsa&lt;/code&gt;, &lt;code&gt;atc&lt;/code&gt; schedules the build to that worker (as it matches the constraints - &lt;code&gt;platform == linux&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;a container is started at that worker somehow, which then reports back to &lt;code&gt;atc&lt;/code&gt; the progress of the build&lt;/li&gt;
&lt;li&gt;that&amp;rsquo;s all persisted and also reproduced to the &lt;code&gt;ui&lt;/code&gt; something.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;ps.: I might be totally wrong here - check out the next posts to know if that&amp;rsquo;s the case!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some seconds later, we see that it succeeded:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  style=&#34;background-color: #293745; margin-top: 3rem; margin-bottom: 3rem; &#34;
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cc-pipeline-worked.png&#34;
       alt=&#34;Image showing a successful Concourse CI build &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;whats-next&#34;&gt;What&amp;rsquo;s next?&lt;/h3&gt;
&lt;p&gt;The next step is getting into what&amp;rsquo;s going on when we create a new pipeline.&lt;/p&gt;
&lt;p&gt;Concourse is made of a database component - when we create a new pipeline, how does that interaction look like?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s something to be covered next.&lt;/p&gt;
&lt;p&gt;Please let me know what you think about Concourse - have you already used it?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;http://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, let me know if you have any questions!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 04 Feb 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/how-to-run-concourse-ci-locally/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/how-to-run-concourse-ci-locally/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Creating a simple extension to block websites</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;since some months ago I&amp;rsquo;ve been struggling a bit with the amount of information that I consume in a single day.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s just outrageous that sometimes I&amp;rsquo;d put myself in a zombie mode and just keep following news (even if something like HackerNews which, in theory, should be a good source of interesting information) for so long and not really produce much. I decided to try blocking all these sources for a while and see how it goes.&lt;/p&gt;
&lt;p&gt;To do so, I looked for some Chrome extensions that would do the job.&lt;/p&gt;
&lt;p&gt;There are several of them out there, as you might expect, but why not give a try implementing it? I&amp;rsquo;d learn something new (and procrastinate with a &amp;ldquo;reason&amp;rdquo;).&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;td;dr: check out this example: &lt;a href=&#34;https://developer.chrome.com/extensions/webRequest#examples&#34;&gt;https://developer.chrome.com/extensions/webRequest#examples&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;capturing-http-requests&#34;&gt;Capturing HTTP requests&lt;/h3&gt;
&lt;p&gt;Having worked with Firefox extensions before, I knew this couldn&amp;rsquo;t be all that hard.&lt;/p&gt;
&lt;p&gt;From the several Javascript APIs for extensions that are out there, there&amp;rsquo;s one that is very suitable for our needs: &lt;a href=&#34;https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest&#34;&gt;&lt;strong&gt;webRequest&lt;/strong&gt;&lt;/a&gt; (yeah, I&amp;rsquo;m linking to MDN - nowadays the Firefox extension ecosystem uses the same standardized APIs as Chrome does).&lt;/p&gt;
&lt;p&gt;From the description of it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use the chrome.webRequest API to observe and analyze traffic and to intercept, block, or modify requests in-flight.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Exactly what we need.&lt;/p&gt;
&lt;p&gt;Given an HTTP request initiated by the browser we can use this API to mess with it at any point in the request pipeline:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/webrequest-flow.png&#34;
       alt=&#34;Illustration the GRPC service &#34; &gt;

    
&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;image from MDN: &lt;a href=&#34;https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest&#34;&gt;https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Because we&amp;rsquo;re aiming at &lt;strong&gt;blocking&lt;/strong&gt; a specific set of requests we can pick the very first one: &lt;code&gt;onBeforeRequest&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;onBeforeRequest (optionally synchronous) &lt;strong&gt;fires when a request is about to occur&lt;/strong&gt;. This event is sent before any TCP connection is made and can be used to cancel or redirect requests. (&lt;a href=&#34;https://developer.chrome.com/extensions/webRequest&#34;&gt;https://developer.chrome.com/extensions/webRequest&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, that means adding the following to a javascript file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Limit the requests for which events are
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// triggered.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// This allos us to have our code being executed
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// only when the following URLs are matched.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ps.: if we were going to dynamically set the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      URLs to be matched (used a configuration
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      page, for example) we&amp;#39;d then specify the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      wildcard &amp;lt;all_urls&amp;gt; and then do the filtering
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      ourselves.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;filter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;urls&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s1&#34;&gt;&amp;#39;*://news.ycombinator.com/*&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Extra flags for the `onBeforeRequest` event.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Here we&amp;#39;re specifying that we want our callback
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// function to be executed synchronously such that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the request remains blocked until the callback 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// function returns (having our filtering taking 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// effect).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;webRequestFlags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
  &lt;span class=&#34;s1&#34;&gt;&amp;#39;blocking&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Register our function that takes action when a request
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// is initiated and matches the provided filter that we
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// specified in the options.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Because we outsourced the URL filtering to chrome itself
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// all we need to do here is always cancel the request (as
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// it matches the filter of unwanted webpages).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chrome&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;webRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onBeforeRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;page blocked - &amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;nx&#34;&gt;cancel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;nx&#34;&gt;webRequestFlags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The functionality can be illustrated as follows:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/site-blocker.svg&#34;
       alt=&#34;Site blocker &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s pretty evident that this isn&amp;rsquo;t suitable for the case where you want to change the list of URLs to the blacklist regularly. There&amp;rsquo;s a reason why: I don&amp;rsquo;t keep changing the source of my distractions (lol).&lt;/p&gt;
&lt;p&gt;Another point to be made is that it&amp;rsquo;s effortless to get rid of it: just remove the extension. The rationale for not putting much thought into making it hard to remove is that when impulsively visiting a website like Twitter I&amp;rsquo;m not totally freaking out of control of myself - I just got into the habit and by breaking the cycle I can stop it (this comes from the great book &lt;a href=&#34;https://www.amazon.com/Power-Habit-What-Life-Business-ebook/dp/B0055PGUYU&#34;&gt;The Power of Habit&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If you have any questions, just drop by Twitter and let me know - I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; there. You can also subscribe to the mailing list below to receive some up to date content from time to time.&lt;/p&gt;
&lt;p&gt;Have a nice one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Fri, 26 Jan 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/extension-to-block-websites/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/extension-to-block-websites/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Replacing HAProxy ACLs by HAProxy Maps</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;This is a quick tip on how you can switch from using ACLs (access control lists) to use maps for selecting backends based on a request parameter.&lt;/p&gt;
&lt;p&gt;The usefulness of using maps instead of acls is that sometimes it might be easier to update the mappings rather than the ACLs (as well as allowing us to perform mutations on the maps without needing to spawn a new process due to the possibility of using the runtime api via unix sockets).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#overview&#34;&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#selecting-a-backend-using-acls&#34;&gt;Selecting a backend using ACLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#selecting-a-backend-using-maps&#34;&gt;Selecting a backend using Maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;overview&#34;&gt;Overview&lt;/h3&gt;
&lt;p&gt;As an example, consider the job of selecting a backend based on a destination host as advertised by the &lt;code&gt;Host&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;That backend might be configured with a great number of servers that are meant to deal with those requests arriving for that host.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/haproxy-acl-overview.svg&#34;
       alt=&#34;Overview of a client communicating with backends using HAProxy as the HTTP frontend &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;For instance, a client performs a request against our load-balancer (HAProxy) which lives under a known address (&lt;code&gt;test.com&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-http&#34; data-lang=&#34;http&#34;&gt;&lt;span class=&#34;nf&#34;&gt;GET&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;/hello&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;HTTP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1.1&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Host&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;test.com&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;User-Agent&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;Chrome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once that requests lands on HAProxy, that HTTP request is then parsed and we&amp;rsquo;re able to make use of the HTTP headers to determine which set of servers (i.e., which backend) should take care of that request (one possibility is not matching a backend and then sending the traffic to a no-op &amp;ldquo;nomatch&amp;rdquo; backend that just replies back with &lt;code&gt;404&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The usual way of selecting a backend is using ACLs (access control lists) - for a more in-depth documentation of ACLs, see &lt;a href=&#34;http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#7.1&#34;&gt;ACL basics&lt;/a&gt; on the official HAProxy documentation.&lt;/p&gt;
&lt;h3 id=&#34;selecting-a-backend-using-acls&#34;&gt;Selecting a backend using ACLs&lt;/h3&gt;
&lt;p&gt;To get started, let&amp;rsquo;s create a minimal configuration that can handle our example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Apply the `mode http` to every frontend and backend that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# doesn&amp;#39;t specify a mode.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This is useful for us just to don&amp;#39;t repeat ourselves throughout&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the config.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;mode http&lt;/span&gt;



&lt;span class=&#34;c1&#34;&gt;# This main http frontend will be responsible for handling every&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# request that comes to our load-balancer on port 80 (the default&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# http port).&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend        http&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;bind                        *:80 &lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Simple ACL to send traffic to our custom tailored web server.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# It looks at the `Host` header of the request, and if it matches&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `test.com`, then checking that `acl` will evaluate to `true`. &lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;acl                         host_matches hdr_dom(host) test.com&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Make use of the backend `desired_backend` if the acl `host_matches`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# evaluates to `true`.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;use_backend                 desired_backend if host_matches&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By default use the `not_found` no-op backend.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;default_backend             not_found&lt;/span&gt;



&lt;span class=&#34;c1&#34;&gt;# A static backend that will just serve some files from a local server&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;backend         desired_backend&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;server                      myserver localhost:8000&lt;/span&gt;



&lt;span class=&#34;c1&#34;&gt;# A dumb &amp;#34;not-found&amp;#34; auto-responder using HAProxy&amp;#39;s errorfile&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# directive.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As the ACL that send traffic to this backend is the default&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (and least prioritized), when we reach this backend, it means&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we didn&amp;#39;t find a desired backend, thus we should serve&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a 404 instead of the generic 503 that haproxy gives back to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# clients when something goes wrong.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;backend         not_found&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;errorfile                   503 /tmp/sample/errorfiles/404.http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that configuration, you can take HAProxy up and start seeing the requests with &lt;code&gt;Host&lt;/code&gt; set to &lt;code&gt;test.com&lt;/code&gt; succeeding and those with a different &lt;code&gt;Host&lt;/code&gt; (for instance, &lt;code&gt;Host: localhost&lt;/code&gt;) failing (404).&lt;/p&gt;
&lt;p&gt;Looking at what&amp;rsquo;s going on we can see that that&amp;rsquo;s a job that is very well suited for a map lookup.&lt;/p&gt;
&lt;h3 id=&#34;selecting-a-backend-using-maps&#34;&gt;Selecting a backend using Maps&lt;/h3&gt;
&lt;p&gt;Using maps, we can remove &lt;code&gt;acl&lt;/code&gt; completely and just rely on &lt;code&gt;use_backend&lt;/code&gt; with the map lookup syntax.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;mode http&lt;/span&gt;

&lt;span class=&#34;na&#34;&gt;frontend        http&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;bind                        *:80 &lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Use the backend found in the map whose key matches the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `Host` header.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# If nothing is found, use the default `not_found` backend&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (which will 404).&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;use_backend	%[req.hdr(host),lower,map_str(/tmp/sample/maps/map1,not_found)]&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;backend         desired_backend&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;server                      myserver localhost:8000&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;backend         not_found&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;errorfile                   503 /tmp/sample/errorfiles/404.http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, we can simplify the configuration by making use of the map, but we need to know in advance what are the available backends and also have a map file.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/haproxy-backend-lookup.svg&#34;
       alt=&#34;HAProxy performing a map lookup &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The map file is far from complicated though - it&amp;rsquo;s a simple line-by-line key-value file where each key is separated from its value using a space:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;test.com desired_backend
another-host.com another_backend
another-blabla.com haha_backend
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Whenever you spin up HAProxy (or tell it to reload), it looks at this file and then puts that mapping into memory such that it can very quickly perform the lookups.&lt;/p&gt;
&lt;p&gt;One way to make sure that your map has been properly loaded by issuing &lt;a href=&#34;https://cbonte.github.io/haproxy-dconv/1.8/management.html#9.3&#34;&gt;Unix Socket Commands&lt;/a&gt; against the HAProxy runtime API:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt; # Make haproxy create a stats and runtime api socket
 # at `/tmp/haproxy.sock` with admin permissions
&lt;span class=&#34;gi&#34;&gt;+ global
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+                 stats socket /tmp/haproxy.sock mode 666 level admin
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Issuing the `show map` command to the running HAProxy&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instance.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I pipe to a privileged instance of `socat` such&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we can properly access the `/tmp/haproxy.sock`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# unix socket.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# If you didn&amp;#39;t need extra privileges to raise HAProxy,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# then you don&amp;#39;t need `sudo`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# In the output you can see an internal address and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the key-value pair.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;show map /tmp/sample/maps/map1&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        sudo socat stdio /tmp/haproxy.sock          
0x7fbb72d013d0 test.com desired_backend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One of the benefits of using maps is that we can use the Unix sockets API to modify the map without needing to restart the HAProxy process (there&amp;rsquo;s no easy way of changing the ACLs with the unix socket api):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Send the `add map` command through the unix socket so that &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# internally, HAProxy will update the map.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Note that if HAProxy restarts, it won&amp;#39;t know about this&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# newly added domain - it&amp;#39;ll look for the mappings specified&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at the file and that&amp;#39;ll be its source of truth.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# To keep consistency, make sure you also modify the map file.&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;add map /tmp/sample/maps/map1 another-host.com another_backend&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        sudo socat stdio /tmp/haproxy.sock

&lt;span class=&#34;c1&#34;&gt;# Check the newly added domain&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;show map /tmp/sample/maps/map1&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        sudo socat stdio /tmp/haproxy.sock
0x7fbb72d013d0 test.com desired_backend
0x7fbb72d02a30 another-host.com another_backend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;HAProxy maps might offer a great way of reducing (or simplifying) the usage of ACLs in your configuration.&lt;/p&gt;
&lt;p&gt;Here I showed one use of it - one that&amp;rsquo;s actually very common where the name of the backends are well known and updating the map that matches a domain with a backend is needed - but there are certainly many more uses that one can think of.&lt;/p&gt;
&lt;p&gt;Please let me know if you need any help or spotted an error - you can find me on Twitter (&lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Thu, 18 Jan 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/replacing-haproxy-acls-by-haproxy-maps/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/replacing-haproxy-acls-by-haproxy-maps/</guid>

                                
                                        <category>haproxy</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How to publish a blog using AWS</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I just got an idea about a tool, and given that I think it&amp;rsquo;s a type of thing that pairs nicely with a blog to drive people to it, I decided to create one.&lt;/p&gt;
&lt;p&gt;Given that I already have everything set up for this one (&lt;code&gt;ops.tips&lt;/code&gt;, I mean), I thought about sharing my setup with you so that you can also adopt it - if you think it&amp;rsquo;s cool.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: this is not meant to be advertising for AWS. I&amp;rsquo;m just talking about my use-case here.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;update: added a CDN invalidation step to the Travis-CI deployment script - thanks a lot &lt;a href=&#34;https://twitter.com/QuinnyPig/status/956657058698346497&#34;&gt;Corey Quinn&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;how-it-looks&#34;&gt;How it looks&lt;/h3&gt;
&lt;p&gt;The whole process of delivering the content of my blog is based on four steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;create the content (markdown)&lt;/li&gt;
&lt;li&gt;build and publish the content (send generated HTML to somewhere)&lt;/li&gt;
&lt;li&gt;serve the build result (accept connections and serve HTML)&lt;/li&gt;
&lt;li&gt;invalidating old objects in the edge caches&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Naturally, the first case doesn&amp;rsquo;t matter for this blog post.&lt;/p&gt;
&lt;h3 id=&#34;building-and-publishing-the-content&#34;&gt;Building and publishing the content&lt;/h3&gt;
&lt;p&gt;All these blog posts are plain markdown files with some custom templating rules.&lt;/p&gt;
&lt;p&gt;To get markdown processed and HTML generated I make use of &lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You define a theme for your content and then based on the theme and what you write in some markdown files it generates a specific HTML.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/build-process.svg&#34;
       alt=&#34;Illustration of the publishing process &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The code that does so (automatically in &lt;code&gt;travis-ci&lt;/code&gt; after I push to a specific branch) is fairly simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Build the markdown files and output&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (verbosely) information about the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process.&lt;/span&gt;
hugo -v

&lt;span class=&#34;c1&#34;&gt;# Go to the directory where the static&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# files now live&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./public 

&lt;span class=&#34;c1&#34;&gt;# Send the new files to the configured S3 &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (and delete the old ones that are not in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the new desired state) with a special&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# max-age header configuration so that both&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# browsers and CDNs cache it for some time.&lt;/span&gt;
aws s3 sync &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --delete &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --cache-control max-age&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;10800&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./ s3://&lt;span class=&#34;nv&#34;&gt;$BUCKET&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Create a new invalidation that will simply&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# invalidate any objects that we have in our&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# website bucket such that we serve fresh content&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the users that are requests files from the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# edge locations&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: users that already downloaded our &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#      resources will still have then until&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#      the browser cache gets invalidated&lt;/span&gt;
aws cloudfront &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        create-invalidation &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --distribution-id &lt;span class=&#34;nv&#34;&gt;$DISTRIBUTION_ID&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --paths &lt;span class=&#34;s1&#34;&gt;&amp;#39;/*&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the code has been built and sent to S3, it comes the time to post the content to &lt;a href=&#34;https://aws.amazon.com/s3&#34;&gt;S3&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;serving-the-website&#34;&gt;Serving the website&lt;/h3&gt;
&lt;p&gt;As the final &lt;code&gt;html&lt;/code&gt;s lands on S3, it&amp;rsquo;s a matter of serving it.&lt;/p&gt;
&lt;p&gt;S3 allows you to serve your content directly from it (see &lt;a href=&#34;https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html&#34;&gt;Hosting a Static website on S3&lt;/a&gt;). The problem of doing so is that we can&amp;rsquo;t configure it very much. It&amp;rsquo;s not flexible at all.&lt;/p&gt;
&lt;p&gt;Another drawback from serving directly from it is that if we have users from a different continent trying to get content from our website, they&amp;rsquo;ll have to make requests that land in our continent, making their response times not very good.&lt;/p&gt;
&lt;p&gt;A solution to that (which AWS already provides and that integrates very smoothly with S3) is to use a CDN (in this case, &lt;a href=&#34;https://aws.amazon.com/cloudfront&#34;&gt;CloudFront&lt;/a&gt;).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cf-cache.svg&#34;
       alt=&#34;How caching works for requests &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;To make clear why it makes sense to use CloudFront (or any other CDN, to be honest), we can think of how browsers interact with our servers.&lt;/p&gt;
&lt;h3 id=&#34;the-browser-server-interaction&#34;&gt;The browser-server interaction&lt;/h3&gt;
&lt;p&gt;When the user requests our website (say, &lt;code&gt;myblog.com&lt;/code&gt;), it has first to get at least one IP that tells it the location to establish a TCP connection to (so that it can make an HTTP request to request a file).&lt;/p&gt;
&lt;p&gt;This process is called name resolution.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/name-resolution.svg&#34;
       alt=&#34;Illustration of the name resolution process &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Once the browser has the IP of the server to contact, it starts a TCP connection which, in our case, will require negotiating some parameters and exchanging a certificate which the browser decides whether it&amp;rsquo;s trusty or not.&lt;/p&gt;
&lt;p&gt;In the case that the browser trusts the certificate received, it can then start sending application-layer requests (in our case, HTTP2 frames).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/connection-and-request.svg&#34;
       alt=&#34;Illustration of the client establishing a connection &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Having a service like CloudFront makes a huge difference here as this process involves several roundtrips (there&amp;rsquo;s a great article from CloudFlare about this - &lt;a href=&#34;https://blog.cloudflare.com/introducing-0-rtt/&#34;&gt;Introducing Zero Round Trip Time Resumption (0-RTT)&lt;/a&gt;). The less it takes to perform a roundtrip, the better.&lt;/p&gt;
&lt;p&gt;Because a CDN has all these points of presence (PoP) all over the world (and it has our certificate in all of them - at least at some point), the TLS termination happens much closer to the client.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/whole-world.svg&#34;
       alt=&#34;Illustration of CloudFront all over the globe &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In the case that the PoP also has the file you need, it can serve it directly from there without having to have your file coming from a distant location (S3).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/south-america.svg&#34;
       alt=&#34;Illustration of the points of presence at the edges serving the content &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Now you might ask me, does it matter? In a typical scenario where you just launch a blog post, do you have all those cache hits?&lt;/p&gt;
&lt;p&gt;From the CloudFront data I can tell that yeah, it definitely matters:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/cloudfront-statistics.svg&#34;
       alt=&#34;CloudFront statistics when HackerNews starts hitting the blog &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Even though my blog is pretty slim and has not many large images (as I optimize them before publishing), it&amp;rsquo;s still a decent amount of traffic that is not being directed to a far origin.&lt;/p&gt;
&lt;h3 id=&#34;the-actual-thing---terraform-module&#34;&gt;The actual thing - terraform module&lt;/h3&gt;
&lt;p&gt;To put all of this into practice, I make use of Terraform to create the necessary resources in AWS.&lt;/p&gt;
&lt;p&gt;The module is made of three files: &lt;code&gt;outputs.tf&lt;/code&gt;, &lt;code&gt;inputs.tf&lt;/code&gt; and &lt;code&gt;main.tf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;inputs.tf&lt;/code&gt; defines the variables that are required by the module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;domain&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type        = &amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;name of the domain for the distribution and to alias route53 to&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;bucket&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type        = &amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;name of the bucket that will hold the files (access logs goes to {bucket}-log&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;storage-secret&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type        = &amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;a secret user-agent that is sent to all requests from CF to S3&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;variable &amp;#34;acm-certificate-arn&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type        = &amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;description = &amp;#34;the aws resource number of the certificate that has been manually provisioned&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Those variables are used in the &lt;code&gt;main.tf&lt;/code&gt; which manages the resources:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Creates the bucket that will hold logs about&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# access to S3 objects.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The number of access shouldn&amp;#39;t be very big given&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that we&amp;#39;re caching things at the edge.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# In theory, it should have, per day, a maximum of&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# number_of_pops*number_of_objects log lines coming&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from S3.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# As we also log all the requests from CloudFlare, we&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# should have `n` entries for CDN access (as the requests&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# are recorded).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# To not keep all of these log records that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# we will almost never look at we transition&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# these log files to infrequent access storage&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# to reduce costs after 30 days.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_s3_bucket&amp;#34; &amp;#34;website_log_bucket&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;bucket        = &amp;#34;${var.bucket}-logs&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;acl           = &amp;#34;log-delivery-write&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;force_destroy = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;lifecycle_rule {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;enabled = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;transition {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;days          = &amp;#34;30&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;storage_class = &amp;#34;STANDARD_IA&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The main bucket that holds the actual HTML files&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that are generated.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# It defines what&amp;#39;s an error document (404.html) and&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# what&amp;#39;s the `index.html` of it (if we wanted to access&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the website from S3 directly).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# It has versioning enabled such that when we modify&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# or delete files they are not really deleted and then&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# we can go back if we want.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# After 15 days we expire the non-current versions as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# at that point it&amp;#39;s probably all good there.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here we also set the bucket policy so that we only&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# allow the gets from those having a secret user-agent&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# and is a request from aws.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_s3_bucket&amp;#34; &amp;#34;website_bucket&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;bucket = &amp;#34;${var.bucket}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;website {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;index_document = &amp;#34;index.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;error_document = &amp;#34;404.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;versioning {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;enabled = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;lifecycle_rule {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;enabled = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;noncurrent_version_expiration {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;days = &amp;#34;15&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;logging {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;target_bucket = &amp;#34;${aws_s3_bucket.website_log_bucket.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;target_prefix = &amp;#34;website-bucket-logs/&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;policy = &amp;lt;&amp;lt;POLICY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Statement&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Action&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:GetObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Condition&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;StringEquals&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;aws:UserAgent&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.storage-secret}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Effect&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Principal&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;AWS&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Resource&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Sid&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PublicReadAccess&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Version&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;POLICY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# A user that we can use to perform the deployment.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The idea here is that if we want to put the deployment&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# process (i.e., uploading of new contents to S3) in a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# CI system we don&amp;#39;t want to give it many privileges -&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# just the bare minimum which is `put` and `list` for that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# bucket.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_iam_user&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;${var.bucket}-deployer&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Create ACCESS and SECRET keys that we can feed our tools&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_iam_access_key&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;user = &amp;#34;${aws_iam_user.main.name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Assign a policy to the user that restricts its actions.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_iam_user_policy&amp;#34; &amp;#34;main&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name = &amp;#34;${aws_iam_user.main.name}-deploy-policy&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;user = &amp;#34;${aws_iam_user.main.name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;policy = &amp;lt;&amp;lt;POLICY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Statement&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Action&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:ListBucket&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:GetBucketLocation&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:ListBucketMultipartUploads&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:ListBucketVersions&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Effect&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Resource&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Action&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:GetObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:PutObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:DeleteObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:AbortMultipartUpload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;s3:ListMultipartUploadParts&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Effect&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Resource&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;arn:aws:s3:::${var.bucket}/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;Version&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;POLICY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Create the CloudFront distribution that:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - has IPV6 enabled&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - is spread across all the PoPs (PriceClass_All)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - has a default root object for our `/` requests&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - sends requests to the origin with our secret header&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - is tied to the S3 origin&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - has logging configured&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - has caching enabled&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - enforces https&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - sets a minimum TLS version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_cloudfront_distribution&amp;#34; &amp;#34;website_cdn&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;enabled             = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;is_ipv6_enabled     = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;price_class         = &amp;#34;PriceClass_All&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;http_version        = &amp;#34;http2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default_root_object = &amp;#34;index.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;origin&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;origin_id   = &amp;#34;origin-bucket-${aws_s3_bucket.website_bucket.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;domain_name = &amp;#34;${aws_s3_bucket.website_bucket.website_endpoint}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;custom_origin_config {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;origin_protocol_policy = &amp;#34;http-only&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;http_port              = &amp;#34;80&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;https_port             = &amp;#34;443&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;origin_ssl_protocols   = [&amp;#34;TLSv1&amp;#34;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;custom_header {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name  = &amp;#34;User-Agent&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;value = &amp;#34;${var.storage-secret}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;logging_config {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;include_cookies = false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;bucket          = &amp;#34;${aws_s3_bucket.website_log_bucket.bucket_domain_name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;prefix          = &amp;#34;cdn-logs/&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;custom_error_response {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;error_code            = &amp;#34;404&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;error_caching_min_ttl = &amp;#34;360&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;response_code         = &amp;#34;404&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;response_page_path    = &amp;#34;/404.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;default_cache_behavior&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;min_ttl                = &amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default_ttl            = &amp;#34;3600&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;max_ttl                = &amp;#34;3600&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;target_origin_id       = &amp;#34;origin-bucket-${aws_s3_bucket.website_bucket.id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;viewer_protocol_policy = &amp;#34;redirect-to-https&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;compress               = true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;allowed_methods = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HEAD&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;DELETE&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;OPTIONS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PATCH&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PUT&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cached_methods = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HEAD&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;forwarded_values&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;query_string = &amp;#34;false&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cookies {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;forward = &amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;restrictions&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;geo_restriction&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;restriction_type = &amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;viewer_certificate&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;acm_certificate_arn      = &amp;#34;${var.acm-certificate-arn}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ssl_support_method       = &amp;#34;sni-only&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;minimum_protocol_version = &amp;#34;TLSv1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;aliases = [&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.domain}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Retrieve information about the manually configured&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# public hosted zone.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;data &amp;#34;aws_route53_zone&amp;#34; &amp;#34;primary&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name         = &amp;#34;${var.domain}.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;private_zone = false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Creates an ALIAS record that ties our domain to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the CloudFlare distribution.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# We could also have a resource that CNAMEs `www` such&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that we&amp;#39;d have `www` set for our website as well.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;resource &amp;#34;aws_route53_record&amp;#34; &amp;#34;cdn-alias&amp;#34; {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;zone_id = &amp;#34;${data.aws_route53_zone.primary.zone_id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name    = &amp;#34;${var.domain}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;type    = &amp;#34;A&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;alias {&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name                   = &amp;#34;${aws_cloudfront_distribution.website_cdn.domain_name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;zone_id                = &amp;#34;${aws_cloudfront_distribution.website_cdn.hosted_zone_id}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;evaluate_target_health = false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Aside from running a &lt;code&gt;main.tf&lt;/code&gt; that imports the module and creates the resource I just have to do two things manually:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tell GoDaddy to use Route53 as the nameservers for this domain (such that we can make use of &lt;code&gt;ALIAS&lt;/code&gt; records to have the domain tied to CloudFront);&lt;/li&gt;
&lt;li&gt;accept the terms of service for the certificate generation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that&amp;rsquo;s it! Push to &lt;code&gt;git&lt;/code&gt; and everything is live.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;The primary objection to doing things this way is that there are already great players out there to serve static files, and I get the point. For me, however, being able to &lt;strong&gt;guarantee a great performance&lt;/strong&gt;, control each step, get all the metrics I need and still have the same great user experience, makes publishing with AWS great - set it up once (takes 30m) and then never worry again.&lt;/p&gt;
&lt;p&gt;I think now there&amp;rsquo;s only one thing that I&amp;rsquo;d improve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;del&gt;&lt;strong&gt;automatic cache invalidation when publishing&lt;/strong&gt;: would allow me to make sure clients are getting the last published content at the time I post (supposing I want to quickly edit something or make sure that the &lt;code&gt;index.html&lt;/code&gt; that lists all pages is up to date on all locations).&lt;/del&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: this is actually pretty simple and doens&amp;rsquo;t require any Lambda stuff. &lt;a href=&#34;https://twitter.com/QuinnyPig/status/956657058698346497&#34;&gt;Corey Quinn&lt;/a&gt; from &lt;a href=&#34;https://lastweekinaws.com/&#34;&gt;LastWeekInAWS&lt;/a&gt; gave me an excelent idea: use the AWS CLI to perform the invalidations. This way we can tie it to the &lt;code&gt;travis-ci&lt;/code&gt; deployment script and we&amp;rsquo;ll have the invalidations on every push. Pretty neat!&lt;/p&gt;
&lt;p&gt;To achieve that I could have an AWS lambda function that is triggered when I finish pushing to S3.  It hasn&amp;rsquo;t been an issue so far as I&amp;rsquo;ve only needed to expire the cache twice (in those cases I just went to the console and clicked few buttons, no big deal).&lt;/p&gt;
&lt;p&gt;If you liked to post and would want to see more content related to AWS and coding in general, make sure to subscribe to the mailing list below. You can also reach me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;Twitter&lt;/a&gt; at any time.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/publishing-a-blog-with-aws/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/publishing-a-blog-with-aws/</guid>

                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Configuring HAProxy with HTTP2 support</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Recently, &lt;a href=&#34;https://www.mail-archive.com/haproxy@formilux.org/msg28004.html&#34;&gt;HAProxy 1.8 got announced&lt;/a&gt;, and it came with some pretty good news:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP/2 is automatically detected and processed in HTTP frontends negotiating the &amp;ldquo;h2&amp;rdquo; protocol name based on the ALPN or NPN TLS extensions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;At the moment the HTTP/2 frames are converted to HTTP/1.1 requests before processing&lt;/strong&gt;, so they will always appear as 1.1 in the logs (and in server logs).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;No HTTP/2 is supported for now on the backend&lt;/strong&gt;, though this is scheduled for the next steps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;HTTP/2 support is still considered EXPERIMENTAL&lt;/strong&gt;, so just like for multi-threading, in case of problem you may end up having to disable it for the time it takes to solve the issue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re already making use of TLS with HAProxy, HTTP/2 support should be a piece of cake.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-example&#34;&gt;The example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#building-haproxy-from-source&#34;&gt;Building HAProxy from source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#generating-certificates&#34;&gt;Generating certificates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#setting-up-haproxy-with-https-support&#34;&gt;Setting up HAProxy with HTTPS support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-wireshark-to-debug-the-traffic&#34;&gt;Using Wireshark to debug the traffic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#enabling-http2-in-haproxy&#34;&gt;Enabling HTTP2 in HAProxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#inspecting-the-http2-traffic&#34;&gt;Inspecting the HTTP2 traffic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#extra-installing-curl-with-http2-support&#34;&gt;Extra - Installing CURL with HTTP2 support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-example&#34;&gt;The example&lt;/h3&gt;
&lt;p&gt;The whole blog post is centered around the idea of putting HAProxy as a reverse proxy for a service that sits behind the &lt;code&gt;test.com&lt;/code&gt; domain.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/haproxy-http2-overview.svg&#34;
       alt=&#34;Example of HAProxy serving HTTP2 traffic from HTTP1 backends &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;As mentioned in the announcement, all the traffic that flows into HAProxy as HTTP/2 gets translated to HTTP/1.1 requests before processing, meaning that you can put your HTTP/1.1 server as a backend service without any problems.&lt;/p&gt;
&lt;p&gt;Another consequence of the HTTP/2 to HTTP/1.1 translation is that all the &lt;code&gt;http&lt;/code&gt; mode directives that you have in the haproxy configuration are still valid and you don&amp;rsquo;t need to change them.&lt;/p&gt;
&lt;h3 id=&#34;building-haproxy-from-source&#34;&gt;Building HAProxy from source&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re a MacOS user and don&amp;rsquo;t want to wait until the &lt;a href=&#34;https://github.com/Linuxbrew/homebrew-core/blob/master/Formula/haproxy.rb&#34;&gt;HAProxy Brew formula&lt;/a&gt; gets updated, or just don&amp;rsquo;t want to wait for the official &lt;a href=&#34;https://hub.docker.com/_/haproxy/&#34;&gt;HAProxy docker image either&lt;/a&gt;, it&amp;rsquo;s pretty straightforward to build it from source.&lt;/p&gt;
&lt;p&gt;For either macOS or Linux, the first steps are all the same. The only difference comes at the moment of running &lt;code&gt;make&lt;/code&gt; (different flags are needed):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Set the version that we&amp;#39;ll download&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;HAPROXY_BRANCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;1.8&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;HAPROXY_VERSION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;1.8.4&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Retrieve the release of HAProxy&lt;/span&gt;
curl -SOL http://www.haproxy.org/download/&lt;span class=&#34;nv&#34;&gt;$HAPROXY_BRANCH&lt;/span&gt;/src/haproxy-&lt;span class=&#34;nv&#34;&gt;$HAPROXY_VERSION&lt;/span&gt;.tar.gz

&lt;span class=&#34;c1&#34;&gt;# Untar it&lt;/span&gt;
tar xzf ./haproxy-&lt;span class=&#34;nv&#34;&gt;$HAPROXY_VERSION&lt;/span&gt;.tar.gz

&lt;span class=&#34;c1&#34;&gt;# Get into the directory&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./haproxy-&lt;span class=&#34;nv&#34;&gt;$HAPROXY_VERSION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the directory ready, now it&amp;rsquo;s time to run &lt;code&gt;make&lt;/code&gt; with the appropriate flags.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;
&lt;span class=&#34;c1&#34;&gt;# Install (or upgrade) openssl:&lt;/span&gt;
brew upgrade &lt;span class=&#34;nv&#34;&gt;openssl&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; Upgrading openssl 

&lt;span class=&#34;c1&#34;&gt;# Once the install is finished, brew will tell you where to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# look for the openssl headers (include) and the compiled&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# library that you can use with software that requires it&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (in our case, HAPROXY)&lt;/span&gt;
... 
For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/openssl/lib
    CPPFLAGS: -I/usr/local/opt/openssl/include
For pkg-config to find this software you may need to set:
    PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig


&lt;span class=&#34;c1&#34;&gt;# Start the actual compilation.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# These options can be looked up at the Makefile file.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We&amp;#39;re essentially telling it to use some default options for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# OSX as well as specifing that we want a specific regex library&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (pcre), enable use of OpenSSL and zlib support to provide us&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# support for deflate (gives us gzip compression).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# SSL_* options tells the compiler where to look the symbol&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# declarations and definition.&lt;/span&gt;
make -j6 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_ZLIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_PCRE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_OPENSSL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SSL_LIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/opt/openssl/lib &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SSL_INC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/opt/openssl/include &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;osx


&lt;span class=&#34;c1&#34;&gt;# Verify whether the binary has been compiled with  all the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# properties that we need.&lt;/span&gt;
./haproxy -vvvv
HA-Proxy version 1.8.4-1deb90d 2018/02/08
Copyright 2000-2018 Willy Tarreau &amp;lt;willy@haproxy.org&amp;gt;
Build options :
  &lt;span class=&#34;nv&#34;&gt;TARGET&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; osx                                         &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;
  &lt;span class=&#34;nv&#34;&gt;CPU&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; generic
...
Built with OpenSSL version : OpenSSL 1.0.2n  &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; Dec &lt;span class=&#34;m&#34;&gt;2017&lt;/span&gt;
Running on OpenSSL version : OpenSSL 1.0.2n  &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; Dec &lt;span class=&#34;m&#34;&gt;2017&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
OpenSSL library supports TLS extensions : yes           &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
OpenSSL library supports SNI : yes                      &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
OpenSSL library supports : SSLv3 TLSv1.0 TLSv1.1 TLSv1.2 &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;Built with transparent proxy support using:
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;Encrypted password support via crypt(3): yes
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;Built&lt;/span&gt; with PCRE version : 8.41 2017-07-05               &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
Running on PCRE version : 8.41 2017-07-05               &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
PCRE library supports JIT : no &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;USE_PCRE_JIT not &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
Built with zlib version : 1.2.11                        &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
...
Available polling systems :
     kqueue : &lt;span class=&#34;nv&#34;&gt;pref&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;300,  &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; result OK                 &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;&amp;lt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re on Linux, the process is mostly the same. Add some dependencies, switch some parameters when building with &lt;code&gt;make&lt;/code&gt; and you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Update the package information from all the configured&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# sources.&lt;/span&gt;
sudo apt update -y

&lt;span class=&#34;c1&#34;&gt;# Install the dependencies&lt;/span&gt;
sudo apt install -y &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        openssl-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        zlib-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libpcre-dev

&lt;span class=&#34;c1&#34;&gt;# Perform the actual compilation&lt;/span&gt;
make -j6 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;linux2628 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_OPENSSL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_ZLIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_PCRE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: if you also need Lua and is curious to know how to integrate HAProxy with Letsencrypt, make sure you check &lt;a href=&#34;https://ops.tips/blog/tls-certificates-haproxy-letsencrypt/&#34;&gt;how to get TLS certificates with Letsencrypt and HAProxy&lt;/a&gt;. There I build both HAProxy and lua from scratch on an Ubuntu 17.04 box.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;generating-certificates&#34;&gt;Generating certificates&lt;/h3&gt;
&lt;p&gt;As browsers only implement HTTP2 over TLS, we must have some certificates in place if we want to test HAProxy HTTP2 support using a web browser.&lt;/p&gt;
&lt;p&gt;The process of generating self-signed certificates (for tests) is far from difficult though - all we need to do is call &lt;code&gt;openssl&lt;/code&gt; with some arguments:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;openssl req &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -x509 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -sha256 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -newkey rsa:4096 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -keyout &lt;span class=&#34;s2&#34;&gt;&amp;#34;test.com.key&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -out &lt;span class=&#34;s2&#34;&gt;&amp;#34;test.com.pem&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -days &lt;span class=&#34;m&#34;&gt;730&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -nodes &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -subj &lt;span class=&#34;s2&#34;&gt;&amp;#34;/C=BR/ST=SaoPaulo/L=SaoPaulo/O=TestOrg/OU=TestUnit/CN=test.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;Generating a &lt;span class=&#34;m&#34;&gt;4096&lt;/span&gt; bit RSA private key
...............................................................................................................................................................................++
...........................++
writing new private key to &lt;span class=&#34;s1&#34;&gt;&amp;#39;test.com.key&amp;#39;&lt;/span&gt;
-----&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the certificate written to the &lt;code&gt;test.com.pem&lt;/code&gt; file (and the private key to &lt;code&gt;test.com.key&lt;/code&gt;), we inspect the certificate and make sure that what we want is set up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;openssl x509 -in ./test.com.pem -text -noout 

Certificate:
    Data:
        Version: &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
        Serial Number: &lt;span class=&#34;m&#34;&gt;17902607379759041757&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0xf872d68f4fd30cdd&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: &lt;span class=&#34;nv&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;BR, &lt;span class=&#34;nv&#34;&gt;ST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SaoPaulo, &lt;span class=&#34;nv&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SaoPaulo, &lt;span class=&#34;nv&#34;&gt;O&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;TestOrg, &lt;span class=&#34;nv&#34;&gt;OU&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;TestUnit, &lt;span class=&#34;nv&#34;&gt;CN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;test.com
        Validity
            Not Before: Mar  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 13:47:12 &lt;span class=&#34;m&#34;&gt;2018&lt;/span&gt; GMT
            Not After : Feb &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt; 13:47:12 &lt;span class=&#34;m&#34;&gt;2020&lt;/span&gt; GMT
        Subject: &lt;span class=&#34;nv&#34;&gt;C&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;BR, &lt;span class=&#34;nv&#34;&gt;ST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SaoPaulo, &lt;span class=&#34;nv&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;SaoPaulo, &lt;span class=&#34;nv&#34;&gt;O&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;TestOrg, &lt;span class=&#34;nv&#34;&gt;OU&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;TestUnit, &lt;span class=&#34;nv&#34;&gt;CN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;test.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4096&lt;/span&gt; bit&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: I&amp;rsquo;ve created a little script that helps provisioning certificates that bundle multiple domains (via SAN - Subject Alternative Name): &lt;a href=&#34;https://github.com/cirocosta/certgen&#34;&gt;cirocosta/certgen&lt;/a&gt;. It&amp;rsquo;s a one-file bash script that automates the process&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Having the certificate and its associated private key created, we must create the final file that HAProxy uses to terminate the TLS connections. THis file is a combination of both the private key and the certificate. From the &lt;a href=&#34;http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.1-crt&#34;&gt;configuration manual&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[crt&amp;hellip;] designates a PEM file containing both the required certificates and any associated private keys.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This file can be built by concatenating multiple PEM files into one (e.g. cat cert.pem key.pem &amp;gt; combined.pem).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In our case, just concatenate those two:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Concatenate the certificate and the private key&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# such that HAProxy can deal with a single file&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that has both of them.&lt;/span&gt;
cat ./test.com.pem test.com.key &amp;gt; haproxy_test.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the certificates set, let&amp;rsquo;s jump to HAProxy.&lt;/p&gt;
&lt;h3 id=&#34;setting-up-haproxy-with-https-support&#34;&gt;Setting up HAProxy with HTTPS support&lt;/h3&gt;
&lt;p&gt;First, we&amp;rsquo;ll set up HAProxy to route requests from HTTPS to an HTTP backend.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/haproxy-https-request.svg&#34;
       alt=&#34;Example of a request using HTTPS going through HAProxy and ending in a Python simple http server &#34; &gt;

    
&lt;/figure&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;na&#34;&gt;global&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Setting the maximum size of the Diffie-hellman parameters&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# used in the TLS negotiation such that HAProxy won&amp;#39;t warn us &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# about the low default value of 1024.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;tune.ssl.default-dh-param   2048&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As we&amp;#39;re sticking with using HTTP/1.1 all the way&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can set the mode in the `defaults` section and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# have it applied everywhere.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# If you set only in the frontend, then haproxy will&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# complain about letting backend be tcp.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;mode http&lt;/span&gt;


&lt;span class=&#34;na&#34;&gt;frontend        https&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Binding to port 443 forces us to have higher privileges&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# when launching HAProxy, but it allows us not to have to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# set the `:&amp;lt;port&amp;gt;` in the URL when connecting to it using&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a browser (as `https` will imply port 443).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The certificate set here is the one that contains both the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# private key and the actual `.pem` that we generated using&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# openssl.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ps.: if you have *a bunch* of certificates to serve, then &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# you should switch to `crt-list` as HAProxy has a limit on&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the size of each line in this config file.&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;bind                        *:443  ssl crt /tmp/sample/certs/haproxy_test.com&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Simple ACL to send traffic to our custom tailored web server.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This way we can exercise a &amp;#34;not found&amp;#34; when not having `HOST`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# properly set.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This also demonstrates how HAProxy is indeed decyphering the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# traffic (otherwise it wouldn&amp;#39;t catch the Host header).&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;acl                         host_matches hdr_dom(host) test.com&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;use_backend                 desired_backend if host_matches&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;default_backend             not_found&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Our server that serves `/tmp/sample/www` using python&amp;#39;s &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# SimpleHTTPServer module.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;backend         desired_backend&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;server                      myserver localhost:8000&lt;/span&gt;



&lt;span class=&#34;c1&#34;&gt;# A dumb &amp;#34;not-found&amp;#34; auto-responder using HAProxy&amp;#39;s errorfile&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# directive.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As the ACL that send traffic to this backend is the default&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (and least prioritized), when we reach this backend, it means&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we didn&amp;#39;t find a desired backend, thus we should serve&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a 404 instead of the generic 503 that haproxy gives back to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# clients when something goes wrong.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;backend         not_found&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;errorfile                   503 /tmp/sample/errorfiles/404.http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run HAProxy and head over to &lt;code&gt;https://localhost&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At this moment you should see HAProxy serving the HTTP response defined in the errorfile (&lt;code&gt;404.http&lt;/code&gt;).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/haproxy-https-not-found.png&#34;
       alt=&#34;HAProxy showing the Not Found page that we&amp;#39;ve set before &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Now, change your &lt;code&gt;/etc/hosts&lt;/code&gt; (or local DNS) to contain an entry for &lt;code&gt;test.com&lt;/code&gt; and head to &lt;code&gt;https://test.com&lt;/code&gt;: now you should see the page being served.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/haproxy-https-triangles.png&#34;
       alt=&#34;HAProxy showing the triangles page we have set before &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;With TLS termination going on, debugging becomes a bit hard without providing extra help for Wireshark.&lt;/p&gt;
&lt;h3 id=&#34;using-wireshark-to-debug-the-traffic&#34;&gt;Using Wireshark to debug the traffic&lt;/h3&gt;
&lt;p&gt;To have Wireshark being able to interpret the traffic, we must provide it the keys to decrypt the whole traffic.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SSLKEYLOGFILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;~/tlskey.log &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /Applications/Google&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;Chrome.app/Contents/MacOS/Google&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;Chrome &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# go to your website ...&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# check what Chrome put in the file&lt;/span&gt;

cat tlskey.log 
CLIENT_RANDOM d3245ce2f3eabc7895a99c66de03d30be1f8798fe5401dd10dcdf0b2db566e33 2adf73c515bb4fc0171b19f991a6aaecd3899c18fb83f162f926f6239f8e76c431a01d379ede29a4ae31bd37dcb48964
CLIENT_RANDOM 6b8148cc629e9a605f58e13c7a57feaecfb54db2365991c7316cc7705a9fff8b 8c2d1a94f7e8d4b65e115230e725cdda022fda8eefd4f235dde977c3ce7c0b52f95ddd9958193e18ea2b60afb6274a2a
CLIENT_RANDOM 4c6a4da0b4bc5985180c8eb7bc4264d1794a24e4c19c8b1e8bbfe544f737f67d 367b1594d6903a0a93f1b145bf321bb8740df860abdabfd3ef44dce118bed8c92a49a03a1d740f6cd22b4934d1174466
CLIENT_RANDOM d8316ea981c4bf35636c185b186af42dc257ce9b88752f9f9848150298433b9b 1742b4d08c170bf86a70c44130d782db173db32446d5350295395e5ed2c787b5f79772c7f48910b12d0223d85dd5dec0
CLIENT_RANDOM 93ffc7c33a0a38476266961d7eb2c3b7e62ca41db99129f50648779871170feb c8dc729c7f0a3ef195fe856d2fd8f081d0d9519c52ca87eaa9e33c8c77bb8619f691cb99c9ba9ba8ef4968ce97e74d32
CLIENT_RANDOM 27b31452a53d48abfa322f931e0f7a65e5ad846cd682005a9b52a579c03703c1 13121dc8cf9c012f4d5f27a93a2281d3769a3566926ebed7c4fd7ab7d11ae16f210e9268befad340b3d2803f44a5b570
CLIENT_RANDOM 322c12247007fc09a4ddff6ab8c8256b8cb40bc6c82769cde936d28e812c8ced 4455a438772c75fb685418a46801ad63b61459801d217669c7b9ed371ed2959e9da0180dd749496e83f8a78996781b98
CLIENT_RANDOM 3cde72add3576eb96f4cdf7820e2555188a500ea816f835112feb5d195c91c10 34d07cd567fb9287dad18df4c31e3b38f602d8e2ed668942bad45858c76243f4d3f9f0012ca56f1fd5f4fb2ddaafd125
CLIENT_RANDOM 5d6baf61132868f69136415114c9cf2b1134bb509669899cb3ed23610f7d4b5d 1f584a5d6407bc5b2eecef36480af8d4adfb8481cb0e74b8e91f05b3501d4101db34eb47a76edb248b3f73cc1bad005c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this, we&amp;rsquo;re already able to decrypt TLS traffic.&lt;/p&gt;
&lt;p&gt;Open Wireshark&amp;rsquo;s preferences (&lt;code&gt;cmd + , &lt;/code&gt;), head to Protocols &amp;gt; SSL and then change &lt;code&gt;(pre)-Master-Secret log filename&lt;/code&gt; to the filename you specific in &lt;code&gt;SSLKEYLOGFILE&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/h2-wireshark-config.png&#34;
       alt=&#34;Wireshark SSL configuration screen &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Run HAProxy and navigate to the website - you should be able to see the traffic in wireshark:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/wireshark-tls-decrypted.svg&#34;
       alt=&#34;TLS traffic being decrypted by Wireshark &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;enabling-http2-in-haproxy&#34;&gt;Enabling HTTP2 in HAProxy&lt;/h3&gt;
&lt;p&gt;Once HTTPS has been set up, enabling HTTP/2 in HAProxy is a matter of including the &lt;code&gt;alpn h2&lt;/code&gt; directive to the &lt;code&gt;bind&lt;/code&gt; line such that whenever the browser tells HAProxy that it can take HTTP/2 traffic, HAProxy does the job of serving it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt; # ... defaults configuration ...

 # HTTP2 frontend server from https portj
 frontend        https
&lt;span class=&#34;gd&#34;&gt;-     bind  *:443  ssl crt &amp;lt;certificate&amp;gt;                 
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+     bind  *:443  ssl crt &amp;lt;certificate&amp;gt; alpn h2,http/1.1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, reload HAProxy with the new configuration and the traffic should be served via HTTP/2.&lt;/p&gt;
&lt;p&gt;To make sure that that&amp;rsquo;s the case, get to &lt;code&gt;https://test.com&lt;/code&gt; and open the HTTP/2 tab of &lt;code&gt;chrome://net-internals&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/http2-chrome-net-internals.svg&#34;
       alt=&#34;Chrome net internals showing the stream for our example &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;There we should be able to see the HTTP/2 session originated by Chrome to HAProxy which proxies the requests to our HTTP/1.1 server.&lt;/p&gt;
&lt;h3 id=&#34;inspecting-the-http2-traffic&#34;&gt;Inspecting the HTTP2 traffic&lt;/h3&gt;
&lt;p&gt;To have a better view of what goes on, we can make use of Wireshark.&lt;/p&gt;
&lt;p&gt;Unlike with plain HTTPS though, to inspect these HTTP2 streams we must first make sure that our operating system trusts the server certificate.&lt;/p&gt;
&lt;p&gt;Using MacOS and Chrome, you can head to the Security tab in the developer tools and then open &amp;ldquo;view certificate&amp;rdquo; to open the certificate popup.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/chrome-certificate-drag.svg&#34;
       alt=&#34;Example of how to get a certificate right from Google Chrome &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;With that popup open, drag the certificate to your desktop and open it (it&amp;rsquo;ll ask for your password and launch Keychain Access).&lt;/p&gt;
&lt;p&gt;Once keychain is open, perform a right click on the &lt;code&gt;test.com&lt;/code&gt; certificate and then click on &lt;code&gt;get info&lt;/code&gt;. This should open a new popup.&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s a matter of making MacOS trust the cert:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/keychain-trust-cert.svg&#34;
       alt=&#34;How to force MacOS to trust a self-signed certificate &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;With the certificate trusted, now we can go back to Wireshark and see the HTTP/2 streams (notice that Chrome might still tell you that the certificate is not secure as it&amp;rsquo;s a self-signed certificate, but that&amp;rsquo;s ok):&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/wireshark-http2-frames.svg&#34;
       alt=&#34;Wireshark showing decyphered HTTP/2 frames including SNI and ALPN &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;extra---installing-curl-with-http2-support&#34;&gt;Extra - Installing CURL with HTTP2 support&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; by default doesn&amp;rsquo;t come with HTTP/2 support out of the box, and if you&amp;rsquo;re using MacOS and didn&amp;rsquo;t specify an extra flag, that&amp;rsquo;s for sure. As mentioned on the official website:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;libcurl uses this 3rd party library for the low-level protocol handling parts. The reason for this is that HTTP/2 is much more complex at that layer than HTTP/1.1 (which we implement on our own) and that nghttp2 is an already existing and well functional library.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, to have HTTP/2 enabled with Curl, you need to build it with nghttp2 (see &lt;a href=&#34;https://curl.haxx.se/docs/http2.html&#34;&gt;HTTP/2 with curl&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;brew&lt;/code&gt;, it&amp;rsquo;s very simple to have that though.&lt;/p&gt;
&lt;p&gt;The brew formula for &lt;code&gt;curl&lt;/code&gt; supports an &lt;a href=&#34;https://github.com/Homebrew/homebrew-core/blob/master/Formula/curl.rb#L30&#34;&gt;extra flag&lt;/a&gt; that installs it for you:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# some other options ...&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;with-gssapi&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Build with GSSAPI/Kerberos authentication support.&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;with-libmetalink&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Build with libmetalink support.&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;#        \/ \/ what we want!&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;with-nghttp2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Build with HTTP/2 support (requires OpenSSL)&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means that you&amp;rsquo;d go to Terminal and install it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;# install cURL with nghttp2 support
&lt;span class=&#34;hl&#34;&gt;brew install curl --with-nghttp2
&lt;/span&gt;
# link the formula to replace the system cURL
&lt;span class=&#34;hl&#34;&gt;brew link curl --force
&lt;/span&gt;
# reload the shell and then issue a request against
# our `test.com` server specifying the `-k` to allow
# any certificates:
&lt;span class=&#34;hl&#34;&gt;curl -k https://test.com -v
&lt;/span&gt;
* Rebuilt URL to: https://test.com/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to test.com (127.0.0.1) port 443 (#0)
&lt;span class=&#34;hl&#34;&gt;* ALPN, offering h2             &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; negotiating HTTP/2
&lt;/span&gt;* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /usr/local/etc/openssl/cert.pem
  CApath: /usr/local/etc/openssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
...
&lt;span class=&#34;hl&#34;&gt;* Using HTTP2, server supports multi-use                &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HTTP/2
&lt;/span&gt;* Connection state changed (HTTP/2 confirmed)           
&lt;span class=&#34;hl&#34;&gt;* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
&lt;/span&gt;* Using Stream ID: 1 (easy handle 0x7ff354804400)
&lt;span class=&#34;hl&#34;&gt;&amp;gt; GET / HTTP/2
&lt;/span&gt;&amp;gt; Host: test.com
&amp;gt; User-Agent: curl/7.56.1
&amp;gt; Accept: */*
&amp;gt; 
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
&amp;lt; HTTP/2 200 
&amp;lt; server: SimpleHTTP/0.6 Python/2.7.10
&amp;lt; date: Thu, 01 Mar 2018 18:06:30 GMT
&amp;lt; content-type: text/html
&amp;lt; content-length: 423
&amp;lt; last-modified: Thu, 01 Mar 2018 15:31:02 GMT
&amp;lt; 
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s cool to see how easy is to have a basic HTTP/2 setup with HAProxy. Although it&amp;rsquo;s not the new kid on the block, it&amp;rsquo;s catching up regarding features with other more recent load-balancers.&lt;/p&gt;
&lt;p&gt;It still lacks server push and full HTTP/2 support (it can&amp;rsquo;t connect via HTTP/2 with a backend), but it can already deliver great results.&lt;/p&gt;
&lt;p&gt;Please let me know if you spot anything off; I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 08 Jan 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/haproxy-http2/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/haproxy-http2/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Sending files via gRPC</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;some time ago I got curious about whether &lt;a href=&#34;https://grpc.io/&#34;&gt;gRPC&lt;/a&gt; would be something suitable for sending files over the wire.&lt;/p&gt;
&lt;p&gt;One of its goodness is the native support of streams, so, why wouldn&amp;rsquo;t it be?&lt;/p&gt;
&lt;h3 id=&#34;a-service-and-a-message&#34;&gt;A service and a message&lt;/h3&gt;
&lt;p&gt;To get the idea going, I took the approach of defining a minimum viable service, one that takes some chunks and then, once received, counts how many bytes of the actual content has been received.&lt;/p&gt;
&lt;p&gt;These chunks were defined like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Chunk&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;kt&#34;&gt;bytes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As the service takes this as a stream, we can define it like so (see &lt;a href=&#34;https://github.com/cirocosta/gupload/blob/master/messaging/service.proto&#34;&gt;cirocosta/gupload/messaging/service.proto&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;kd&#34;&gt;service&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GuploadService&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Upload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stream&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Chunk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UploadStatus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UploadStatusCode&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;Unknown&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;Ok&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;Failed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;UploadStatus&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Message&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;UploadStatusCode&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To better visualize what&amp;rsquo;s going on, we have the following:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/grpc-stream.png&#34;
       alt=&#34;Illustration the GRPC service &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In essence, this means that we get a file handle and once the connection is started, we start splitting its contents in chunks and sending these fragments as &lt;code&gt;Chunk&lt;/code&gt; messages over the gRPC connection that got established. Once messages arrive at the server, we unpack those messages (which contains the raw bytes in the &lt;code&gt;Content&lt;/code&gt; field. After all the transmission has been finalized, an &lt;code&gt;UploadStatus&lt;/code&gt; message is sent to the client, and the channel is closed.&lt;/p&gt;
&lt;p&gt;You can check the code in &lt;a href=&#34;https://github.com/cirocosta/gupload&#34;&gt;cirocosta/gupload&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The gist of the client is, with some parts removed for brevity, the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ClientGRPC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;UploadFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;f&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stats&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Stats&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Get a file handle for the file we 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// want to upload
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Open a stream-based connection with the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// gRPC server
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Upload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	
        &lt;span class=&#34;c1&#34;&gt;// Start timing the execution
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;stats&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;StartedAt&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Allocate a buffer with `chunkSize` as the capacity
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and length (making a 0 array of the size of `chunkSize`)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chunkSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;writing&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// put as many bytes as `chunkSize` into the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// buf array.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// ... if `eof` --&amp;gt; `writing=false`...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messaging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Chunk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                        &lt;span class=&#34;c1&#34;&gt;// because we might&amp;#39;ve read less than
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;// `chunkSize` we want to only send up to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;// `n` (amount of bytes read).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;// note: slicing (`:n`) won&amp;#39;t copy the 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;// underlying data, so this as fast as taking
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;// a &amp;#34;pointer&amp;#34; to the underlying storage.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;nx&#34;&gt;Content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// keep track of the end time so that we can take the elapsed
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// time later
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;stats&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishedAt&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// close
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CloseAndRecv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the server, almost the same - receive the stream connection and then gather each message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Upload implements the Upload method of the GuploadService
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// interface which is responsible for receiving a stream of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// chunks that form a complete file.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ServerGRPC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Upload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;messaging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GuploadService_UploadServer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// while there are messages coming
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Recv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;EOF&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;END&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

			&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Wrapf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				&lt;span class=&#34;s&#34;&gt;&amp;#34;failed unexpectadely while reading chunks from stream&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;END&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// once the transmission finished, send the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// confirmation if nothign went wrong
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;SendAndClose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messaging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;UploadStatus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Upload received with success&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;messaging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;UploadStatusCode_Ok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that set we can start measuring the transfer time.&lt;/p&gt;
&lt;h3 id=&#34;scenarios&#34;&gt;Scenarios&lt;/h3&gt;
&lt;p&gt;To keep the transmission running for little while I picked a payload of 143M (&lt;code&gt;.git&lt;/code&gt; of &lt;code&gt;github.com/moby/moby&lt;/code&gt; as an uncompressed &lt;code&gt;.tar&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The server and client shared the same host (macOS 16 GB 1600 MHz DDR3, 2.2 GHz Intel Core i7 Retina, 15-inch, Mid 2015) and communicated via loopback.&lt;/p&gt;
&lt;p&gt;Apparently, this is not the best way of testing this kind of stuff, but I think the overall idea is still valid anyway.&lt;/p&gt;
&lt;p&gt;I wanted to understand how changing the size of the chunks would affect the overall transmission time. I hypothesized that there was going to exist a significant number between a big chunk and a small chunk that would be optimal for the transmission.&lt;/p&gt;
&lt;p&gt;With that said, I created the following test script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
main &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# for every chunk size in &lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# &amp;#34;16, 32, 64, 128 ... 2097152 (2MB)&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; k in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; 21&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    
    &lt;span class=&#34;c1&#34;&gt;# run the upload 50 times&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;seq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 50&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      upload_file_via_grpc_tcp_compressed &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$k&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

upload_file_via_grpc_tcp &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;,&amp;#34;&lt;/span&gt;

  gupload upload &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --address localhost:1313 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --chunk-size &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;./shift &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --file ./files.tar 
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;shift&lt;/code&gt; is just a little program that performs the bit shifting of two arguments:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ... validates argc and argv
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;number&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shifts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shifts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which means that our test case would produce a &lt;code&gt;CSV&lt;/code&gt;: &lt;code&gt;&amp;lt;number_of_bitshifts&amp;gt;,&amp;lt;time&amp;gt;&lt;/code&gt;, for instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;4,28418808431
4,31305514409
4,30451840141
...
5,16610844861
5,15894009998
...
6,8175781898
6,8074899000
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Having those two columns, we can then put it in Excel, create a pivot table and then gather insights about the data.&lt;/p&gt;
&lt;h3 id=&#34;results&#34;&gt;Results&lt;/h3&gt;
&lt;p&gt;I let that script run for a while, here are the results:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/grpc-tcp-transmission.png&#34;
       alt=&#34;Illustration the GRPC service &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;From the results, it looks like if we have a tiny chunk size (16, 32, 64 and 128), we can&amp;rsquo;t deliver too much over the network. That&amp;rsquo;s clear via the CPU usage: I was getting close to 200% on each process (client and server), clearly seeing the transfer being bottlenecked by the CPU, which is not the desired.&lt;/p&gt;
&lt;p&gt;As we move to more significant values it becomes evident that the time to transfer the data falls considerably, but we start seeing a big variance in the times - sometimes it was performing pretty well, sometimes it was pretty bad.&lt;/p&gt;
&lt;p&gt;It seems like at 1024bytes (1KB) we have a decent throughput.&lt;/p&gt;
&lt;p&gt;I was expecting something like &lt;code&gt;32KB: (1 &amp;lt;&amp;lt; 15)&lt;/code&gt; to be the most optimal but it looks like it&amp;rsquo;s one of the worst scenarios regarding variance.&lt;/p&gt;
&lt;p&gt;Maybe that&amp;rsquo;s something that&amp;rsquo;s only observed when running both client and server on the same machine &amp;hellip; I&amp;rsquo;m not sure.&lt;/p&gt;
&lt;p&gt;As in this scenario I wasn&amp;rsquo;t making use of TLS I thought that perhaps the underlying gRPC would not be using HTTP2 (I need to confirm this!); thus I could probably get some different results running with TLS enabled.&lt;/p&gt;
&lt;p&gt;That wasn&amp;rsquo;t the case though:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/grpc-tls-transmission.png&#34;
       alt=&#34;Illustration the GRPC service &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The variance is shifted a bit but, still, very close results.&lt;/p&gt;
&lt;h3 id=&#34;comparing-with-plain-http2&#34;&gt;Comparing with plain HTTP2&lt;/h3&gt;
&lt;p&gt;I wanted to have a baseline to compare these results, so I made &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;server&lt;/code&gt; a simple interface that other types of clients and servers could implement.&lt;/p&gt;
&lt;p&gt;With that set I created a HTTP2 client and server that you can check out at the repository - &lt;a href=&#34;http://github.com/cirocosta/gupload&#34;&gt;https://github.com/cirocosta/gupload&lt;/a&gt; under &lt;code&gt;./core/client_h2.go&lt;/code&gt; and &lt;code&gt;./core/server_h2.go&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/http2-vs-grpc.png&#34;
       alt=&#34;Illustration the GRPC service &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;I think it&amp;rsquo;s evident that for this workload a raw transfer of bytes over http2 should be faster than the gRPC one as there&amp;rsquo;s no encoding and decoding of messages - just raw transmission of data.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I didn&amp;rsquo;t want to draw many conclusions from this but just make clear in my head that it&amp;rsquo;s critical to understand what&amp;rsquo;s your workload and how the underlying transport works to get the best results possible. It&amp;rsquo;s common to get caught in &lt;a href=&#34;https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing&#34;&gt;fallacies of distributed computing&lt;/a&gt; and just start assuming things. This week I tried to pretend less and test more.&lt;/p&gt;
&lt;p&gt;If you liked this article, there&amp;rsquo;s &lt;a href=&#34;https://ops.tips/blog/when-to-buffer-writes/&#34;&gt;another blog post I wrote about buffering&lt;/a&gt; where I explore where buffering takes most effect, and it&amp;rsquo;s very interesting to see how different network conditions affect transmission.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;If you&amp;rsquo;ve got interested in this article, you probably should also check out &lt;a href=&#34;https://amzn.to/2NFgJdv&#34;&gt;The Site Reliability Workbook - Practical Ways to Implement SRE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s about practical examples of Google&amp;rsquo;s experience, and the internal gRPC equivalent (Stubby) as well as GRPC itself is part of it.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Again, it was all &amp;ldquo;loopback-based&amp;rdquo; so take it with some salt.&lt;/p&gt;
&lt;p&gt;If you want to get the results, here&amp;rsquo;s the Excel file: &lt;a href=&#34;https://ops.tips/blog/-/general/grpc-uploads.xlsx&#34;&gt;grpc-uploads.xslx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let me know if I got anything wrong; I&amp;rsquo;d love to understand more about it and see what you think.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 02 Jan 2018 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/sending-files-via-grpc/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/sending-files-via-grpc/</guid>

                                
                                        <category>go</category>
                                
                                        <category>networking</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Should you buffer your writes?</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;some weeks ago I wrote a Docker logging plugin that acts as an &lt;code&gt;oklog&lt;/code&gt; forwarder: &lt;a href=&#34;https://github.com/cirocosta/oklog-docker-plugin&#34;&gt;oklog-docker-plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;oklog&lt;/code&gt; makes use of a fairly straightforward format for ingesting logs: send it a line with some predefined fields and &lt;em&gt;ta-da&lt;/em&gt;, it&amp;rsquo;ll be properly ingested.&lt;/p&gt;
&lt;p&gt;While coding the plugin, I remember considering whether I should buffer these stuff or not.&lt;/p&gt;
&lt;p&gt;My &lt;em&gt;rationale&lt;/em&gt; was that I should probably look at the tradeoff of between immediate availability of the logs and some kind of network optimization by reducing the number of writes that I&amp;rsquo;d perform, thus reduce the number of packets inflight in a given time.&lt;/p&gt;
&lt;p&gt;That got me to wonder how much of perceived differences we could find via buffering writes and how does that change as we switch from a given size to another.&lt;/p&gt;
&lt;p&gt;What I expected: in the beginning, the more we cache, the better; we&amp;rsquo;ll achieve some peak, and then after that, we&amp;rsquo;ll start getting worse than not buffering or buffering at a given limit given that the whole write will be broken in parts. Does this hold true for real scenarios? How does it perform?&lt;/p&gt;
&lt;h3 id=&#34;testing-it&#34;&gt;Testing it&lt;/h3&gt;
&lt;p&gt;To test that, I managed to have the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;set a given reasonable amount of data to transfer&lt;/li&gt;
&lt;li&gt;prepare a test executable that would transfer this with the different buffer sizes by passing a different parameter&lt;/li&gt;
&lt;li&gt;run each test execution multiple times; average the results for each.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The easiest way I could find to have buffering set was to make use of &lt;a href=&#34;https://linux.die.net/man/3/setvbuf&#34;&gt;setvbuf(3)&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SETBUF(3)                 Linux Programmer&#39;s Manual                SETBUF(3)

NAME
       setbuf, setbuffer, setlinebuf, setvbuf - stream buffering operations

       ...

       int setvbuf(FILE *stream, char *buf, int mode, size_t size);

       The setvbuf() function may be used on any open stream to  change  its
       buffer.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The coolness of this method is that we can either provide a buffer of our own (and then, say, inspect it at any time we want) or let &lt;code&gt;glibc&lt;/code&gt; take care of that. We can skill all the buffering if desired by setting a flag or make it perform buffering based on newlines. Something to take notice is that &lt;code&gt;setvbuf&lt;/code&gt; is applied to a &lt;code&gt;FILE&lt;/code&gt;, which is not our primary target when making use of sockets.&lt;/p&gt;
&lt;p&gt;This means that to benefit from those methods we have to associate a socket with a &lt;code&gt;FILE&lt;/code&gt; first and just after that set the buffering mode for methods that make use of that stream.&lt;/p&gt;
&lt;h3 id=&#34;establishing-connections-and-associating-sockets-with-file-streams&#34;&gt;Establishing connections and associating sockets with FILE streams&lt;/h3&gt;
&lt;p&gt;To associate a socket with a file stream we have to, right after getting a socket, make use of &lt;a href=&#34;https://linux.die.net/man/3/fdopen&#34;&gt;fdopen(3)&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The fopen() function opens the file whose name is the string pointed to by path and associates a stream with it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given that when we establish a TCP connection, we have both ways (read and write), we can associate the socket with to separate file streams.&lt;/p&gt;
&lt;p&gt;To make that easy to deal with I started by creating a struct (see &lt;a href=&#34;https://github.com/cirocosta/when-to-buf/blob/master/conn.h&#34;&gt;when-to-buf/conn.h&lt;/a&gt;) that would hold these two streams and then deal with establishing the connections.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t_conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The struct gets initialized differently depending on whether we&amp;rsquo;re dealing with a client (active)  or server (passive) connection.&lt;/p&gt;
&lt;p&gt;For instance, on the server side we &lt;code&gt;accept(2)&lt;/code&gt; on the &lt;code&gt;listen_fd&lt;/code&gt; and then prepare the &lt;code&gt;t_conn&lt;/code&gt; struct:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;init_server_conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t_conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;socklen_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// `accept` extracts the first conn request from the queue of 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// pending connections for the listening socket `listen_fd`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and then created a new connected socket.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
	  &lt;span class=&#34;n&#34;&gt;accept&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listen_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sockaddr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to accept connection - accept&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// with `fdopen` we create a FILE stream for the `read`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// side of the socket
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fdopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to associate socket with rx stream - fdopen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// to create the second FILE stream we first duplicate the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// socket file descriptor and then open it with write only
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// capabilities
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fdopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to associate socket with tx stream - fdopen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we have &lt;code&gt;t_conn&lt;/code&gt; set up, writing to it became as simple as writing to a file. Any method that takes a &lt;code&gt;FILE&lt;/code&gt; (like &lt;code&gt;fprintf&lt;/code&gt; or &lt;code&gt;fwrite&lt;/code&gt;&amp;hellip;) could now be an entry point to writing to that connection.&lt;/p&gt;
&lt;h3 id=&#34;writing-to-the-connection&#34;&gt;Writing to the connection&lt;/h3&gt;
&lt;p&gt;To perform the buffered writes, &lt;code&gt;setvbuf&lt;/code&gt; end up looking like the following (see &lt;a href=&#34;https://github.com/cirocosta/when-to-buf/blob/master/client.c&#34;&gt;when-to-buf/client.c#work_on_connection&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;work_on_connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t_conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bufsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to_write&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bufsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;write_buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// ... 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// if we want to buffer our writes, then prepare a 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// buffer that will hold the data prior to pushing it
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// to the real underlying connection via `write(2)`s
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bufsize&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;n&#34;&gt;write_buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bufsize&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write_buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to allocate write_buf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

                &lt;span class=&#34;c1&#34;&gt;// make `glibc` make use of our buffer and always buff
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// up to `bufsize`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setvbuf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;write_buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_IOFBF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bufsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;n&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to set block buffer - setvbuf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// send data to `fwrite` such that it can perform
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// the buffering as performed above and then
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;// end up writing to the connection at some point
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwrite&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SOURCE_BUFFER&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;total_written&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		           &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
		           &lt;span class=&#34;n&#34;&gt;to_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		           &lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that set, it was now time to make sure that our underlying &lt;code&gt;write(2)&lt;/code&gt; calls were being buffered as we intended.&lt;/p&gt;
&lt;p&gt;To test that, the easiest way was to set &lt;code&gt;SOURCE_BUFFER&lt;/code&gt; to something small, like &lt;code&gt;1024&lt;/code&gt; bytes&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gd&#34;&gt;- #define SRC_BUFSIZE (1 &amp;lt;&amp;lt; 25)
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+ #define SRC_BUFSIZE (1 &amp;lt;&amp;lt; 10)
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;  diff client.c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then verify for different &lt;code&gt;bufsize&lt;/code&gt;s how many &lt;code&gt;write(2)&lt;/code&gt; calls are made.&lt;/p&gt;
&lt;p&gt;First we start with a big buffer (&lt;code&gt;bufsize=1024&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run `strace` watching the execution of the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `./client` executable taking the arguments &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `127.0.0.1` (address) and `1024` (bufsize).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#  ps.: -w : summarise time different between executions&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       -c : count the executions&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# In this case, we expect to have a *very*  low number&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of `write(2)`s as we should be able to fill the whole&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# thing in a single `write(2)` call, with no buffering&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at all.&lt;/span&gt;

strace -c -f -w ./client 127.0.0.1 &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;

% &lt;span class=&#34;nb&#34;&gt;time&lt;/span&gt;     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 33.22    0.000288          &lt;span class=&#34;m&#34;&gt;72&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;           close
 18.92    0.000164          &lt;span class=&#34;m&#34;&gt;82&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;           write        &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt;
 13.03    0.000113         &lt;span class=&#34;m&#34;&gt;113&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;           execve
  ...
  0.35    0.000003           &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.000867                    &lt;span class=&#34;m&#34;&gt;36&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; total
                                      /&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;
                                      &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;
                                  low amount &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Y&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, with a very small buffer (&lt;code&gt;bufsize=1&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Now, with a `bufsize` that&amp;#39;s as low as 1 byte, we should&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# expect to have the number of `write(2)`s to be pretty big&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (close to 1024):&lt;/span&gt;
strace -c -f -w ./client 127.0.0.1 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;


% &lt;span class=&#34;nb&#34;&gt;time&lt;/span&gt;     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 94.58    0.011862          &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt;      &lt;span class=&#34;m&#34;&gt;1025&lt;/span&gt;           write        &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
  2.72    0.000341          &lt;span class=&#34;m&#34;&gt;85&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;           close
  ...
  0.02    0.000003           &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.012542                  &lt;span class=&#34;m&#34;&gt;1059&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; total
                                    /&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;
                                    &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;
                            a bunch of syscalls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;cool, so we have what we need setup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;control &lt;code&gt;bufsize&lt;/code&gt; via CLI arguments&lt;/li&gt;
&lt;li&gt;have buffered writes with different buffer sizes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;now it&amp;rsquo;s time to make it run!&lt;/p&gt;
&lt;h3 id=&#34;running-some-scenarios&#34;&gt;Running some scenarios&lt;/h3&gt;
&lt;p&gt;The first scenario I wanted to test was the one that I could predict the outcome pretty well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;communication between client and server via loopback&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the loopback interface isn&amp;rsquo;t more than a virtual NIC and doesn&amp;rsquo;t even makes use of Ethernet, we should be able to transfer these packets as fast as possible regardless of the size (ps.: we&amp;rsquo;d not have everything being sent in a single packet as we still make use of &lt;code&gt;IP&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;That said, the improvements should be seen as we get bigger and bigger buffer sizes.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/perfect-loopback.png&#34;
       alt=&#34;Graph of how perfect loopback performs &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;It really is - overall, increasing the size of the buffers help.&lt;/p&gt;
&lt;p&gt;Is this too far from reality? Well, in some cases. For those deploying Kubeneretes services, it&amp;rsquo;s very common to have sidecars, i.e, collocation of containers. In this case, you&amp;rsquo;re running another container in the same shared namespaces, and you&amp;rsquo;re entirely able to communicate via loopback (e.g, for relaying logs!). It&amp;rsquo;s debatable if you should be using the whole network stack in such case (as opposed to unix sockets), but it&amp;rsquo;s a case.&lt;/p&gt;
&lt;p&gt;Next, I wanted to check how it performs when there are some failures and delays in the communication. In theory, this is where buffers should shine after all.&lt;/p&gt;
&lt;h3 id=&#34;introducing-problems-in-the-network&#34;&gt;Introducing problems in the network&lt;/h3&gt;
&lt;p&gt;To introduce both consistent and eventual delays, as well as the ability to drop packages at a given rate, I made use of &lt;a href=&#34;https://linux.die.net/man/8/tc&#34;&gt;tc(1)&lt;/a&gt;. Change the queueing discipline of the interface, and you&amp;rsquo;ll have a messed up scenario*.&lt;/p&gt;
&lt;p&gt;Keeping the total transfer size constant (1GB), I tried five scenarios. First I started with package loss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Random package loss applied to 0.1% of all packages&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/0-1percent-loss.png&#34;
       alt=&#34;Graph of 0.1% of package loss affects time &#34; &gt;

    
&lt;/figure&gt;

&lt;ul&gt;
&lt;li&gt;Random package loss applied to 1% of all packages&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/1percent-loss.png&#34;
       alt=&#34;Graph of how a consistent 1% package loss affects time &#34; &gt;

    
&lt;/figure&gt;

&lt;ul&gt;
&lt;li&gt;Random package loss applied to 5% of all packages&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/5percent-loss.png&#34;
       alt=&#34;Graph of how 5% package loss affects time &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Nothing too interesting here. The shape of the data looks like the same as in the perfect loopback scenario. It might vary a little bit more but nothing impressive.&lt;/p&gt;
&lt;p&gt;The game changes when it comes to delays though.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistent delay of 5ms to all packages&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/5ms-delay.png&#34;
       alt=&#34;Graph of how a consistent 5ms delay affects time &#34; &gt;

    
&lt;/figure&gt;

&lt;ul&gt;
&lt;li&gt;Consistent 10ms to all packages&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/10ms-delay.png&#34;
       alt=&#34;Graph of how 10ms of delay on all packages affects time &#34; &gt;

    
&lt;/figure&gt;

&lt;ul&gt;
&lt;li&gt;Bursting delay - added delay of 100ms (+/- 10ms) with the next random element depending on 25% on the last one&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/bursting-100ms-delay.png&#34;
       alt=&#34;Graph of how time varies in a bursting delay scenario &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;If you&amp;rsquo;re curious about how to perform the same kind of traffic shaping in your own loopback, these were the rules used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;tc qdisc add dev lo root netem loss 0.1%
tc qdisc change dev lo root netem loss 1%
tc qdisc change dev lo root netem loss 5%
tc qdisc change dev lo root netem delay 100ms 10ms 25%
tc qdisc change dev lo root netem delay 5ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I found pretty surprising how delays introduced a much more diverse result compared to package loss.&lt;/p&gt;
&lt;p&gt;In the future, I might explore this a bit more, but I think this is enough and worth sharing.&lt;/p&gt;
&lt;p&gt;If you spot any mistakes or think that I might have gotten everything wrong, please let me know! I&amp;rsquo;d appreciate a lot perfecting this and understanding better the results.&lt;/p&gt;
&lt;p&gt;You can get the Excel worksheet that I created here: &lt;a href=&#34;https://ops.tips/blog/-/general/when-to-buf.xlsx&#34;&gt;when-to-buf.xslx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, feel free to drop me a message there!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 31 Dec 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/when-to-buffer-writes/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/when-to-buffer-writes/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Writing DNS messages from scratch using Go</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Yesterday I read a pretty interesting article from James Routley with the title &lt;a href=&#34;https://routley.io/tech/2017/12/28/hand-writing-dns-messages.html&#34;&gt;Let&amp;rsquo;s hand write DNS messages&lt;/a&gt;. It goes all the way down to preparing a UDP query by hand and then interpreting it by reading the bytes received back.&lt;/p&gt;
&lt;p&gt;That was cool mainly because it makes clear that DNS messages are not all that complicated.&lt;/p&gt;
&lt;p&gt;It takes some encoding/decoding to create a message and understand its result but, still, not hard.&lt;/p&gt;
&lt;p&gt;I took the opportunity to go through the article and the &lt;a href=&#34;https://tools.ietf.org/html/rfc1035&#34;&gt;DNS RFC&lt;/a&gt; and then implement myself something similar. The result is &lt;a href=&#34;https://github.com/cirocosta/rawdns&#34;&gt;cirocosta/rawdns&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;The post is not intended to explain why DNS exists and what it&amp;rsquo;s meant to do.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to know more about DNS as a whole, make sure you check - &lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Now, to the article.&lt;/p&gt;
&lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;!-- DON&#39;T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#why-recreate-the-wheel&#34;&gt;Why recreate the wheel?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-types&#34;&gt;The types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#a-little-bit-of-digression---getting-and-set-bits-in-a-byte-aligned-language&#34;&gt;A little bit of digression - getting and set bits in a byte-aligned language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#asking-the-questions&#34;&gt;Asking the questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&gt;
&lt;h3 id=&#34;why-recreate-the-wheel&#34;&gt;Why recreate the wheel?&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s pretty evident that the work I did is unnecessary. There are great packages for creating DNS servers/clients (like the excellent &lt;a href=&#34;https://github.com/miekg/dns&#34;&gt;miekg/dns&lt;/a&gt; which I even used in a simple DNS recursive server I wrote (&lt;a href=&#34;https://github.com/cirocosta/sdns&#34;&gt;cirocosta/sdns&lt;/a&gt; some time ago). If all you need is resolving the IP of a host, just use plain &lt;a href=&#34;https://golang.org/pkg/net/#LookupAddr&#34;&gt;&amp;ldquo;net&amp;rdquo;/LookupAddr&lt;/a&gt;, it does the job much better than my tool.&lt;/p&gt;
&lt;p&gt;The good side of doing though is that I had the opportunity to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;review some networking concepts&lt;/li&gt;
&lt;li&gt;check out how to do UDP with Go (I had only dealt with UDP in C before)&lt;/li&gt;
&lt;li&gt;review some bitwise operations&lt;/li&gt;
&lt;li&gt;have a more in-depth view of how the DNS protocol works&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Should you do the same? Well, maybe.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a common practice to do something similar in a networking class, but in my case, we didn&amp;rsquo;t do it (had some other assignments).&lt;/p&gt;
&lt;h3 id=&#34;the-types&#34;&gt;The types&lt;/h3&gt;
&lt;p&gt;I started the project by looking at which types I should deal with.&lt;/p&gt;
&lt;p&gt;Fortunately, there are just a few.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DNS Message&lt;/code&gt;: the piece that goes in both ways (request and response), always contains the header and then other pieces (like question and RR) depending on the message being a request or response;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DNS Message - Header&lt;/code&gt;: this gives general information about what&amp;rsquo;s coming in the message, like, how many queries are there &amp;hellip; how many answers &amp;hellip; what is the ID that identifies this &amp;ldquo;session&amp;rdquo; and some other pieces of information. It&amp;rsquo;s what tells you how to parse what&amp;rsquo;s coming next and give context to the semantics.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DNS Message - Question&lt;/code&gt;: contains the actual query that you want to perform against a nameserver. It can be of many types and classes; here I just carried about one: &lt;code&gt;A&lt;/code&gt; records against recursive servers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DNS Message - RR&lt;/code&gt;: representation of a resource record (in this case, we can treat it as a plain answer). Regardless of the type, this always comes packed with the same format, but it leaves a field (&lt;code&gt;RDATA&lt;/code&gt;) to be parsed after the fact depending on the type.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This translated to the following files in &lt;code&gt;cirocosta/rawdns&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rawdns
└── lib
    ├── header.go               // header
    ├── header_test.go
    ├── message.go              // full DNS msg
    ├── question.go             // question
    ├── question_test.go
    ├── rr.go                   // rr
    └── rr_test.go
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As the whole message (&lt;code&gt;message.go&lt;/code&gt;) is pretty much a composition of &lt;code&gt;Header&lt;/code&gt;, &lt;code&gt;Question&lt;/code&gt;s and &lt;code&gt;Answer&lt;/code&gt;s, I started by making sure that each one of them could be both parsed from a sequence of bytes as well as they could create a sequence of bytes from their definition.&lt;/p&gt;
&lt;p&gt;The tricky part is that all the types we have in Go are byte aligned, while some parts of the header section, for instance, take only 3 bits, or 4 bits &amp;hellip; some others, just 1bit. This means that we have to fit that kind of information in an 8bit type.&lt;/p&gt;
&lt;h3 id=&#34;a-little-bit-of-digression---getting-and-set-bits-in-a-byte-aligned-language&#34;&gt;A little bit of digression - getting and set bits in a byte-aligned language&lt;/h3&gt;
&lt;p&gt;The whole idea of fitting pieces of information in a single byte is very natural to think about as we can easily refer to &amp;ldquo;this bit of this byte&amp;rdquo; but some languages (like Go) gives no native interface to that.&lt;/p&gt;
&lt;p&gt;Looking at the description of the DNS message header, we have the following description:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        FIRST BYTE                SECOND BYTE
   ----------------------- || ---------------------

     0  1  2  3  4  5  6  7  0  1  2  3  4  5  6  7
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The structure can be thought as two bytes which have values placed at different offsets with some maximum values that they can take (given the number of bits that they can hold):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   first_byte:
   {
      QR:      offset=0 , size=1bit
      Opcode:  offset=1 , size=4bit 
      AA:      offset=5 , size=1bit
      TC:      offset=6 , size=1bit
      RD:      offset=7 , size=1bit
   }

   second_byte:
   {
      RA:      offset=0 , size=1bit
      Z:       offset=1 , size=3bit 
      RCODE:   offset=4 , size=4bit
   }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Back in the days in which I used to do some &lt;code&gt;C&lt;/code&gt; I remember there was a pretty good way of dealing with this: bit fields. In Go, however, there are no language features that can help us directly (see &lt;a href=&#34;https://groups.google.com/forum/#!msg/golang-nuts/3TY8jX-iRC8/X2hBGSiv4WoJ&#34;&gt;golang-nuts - Bit fields/binary parsing&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In C this allows us to make use of a &lt;code&gt;struct&lt;/code&gt; to represent a byte and then use field access operators to gather these bit values without having to deal with bitwise operations.&lt;/p&gt;
&lt;p&gt;What I mean is, suppose that you have a multiplayer game where four players are connected and in your loop, you have to evaluate what&amp;rsquo;s the next position of each player based on their directions.&lt;/p&gt;
&lt;p&gt;We could establish that these directions come in the form of an enum which takes 2bits to represent any direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;direction&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;NORTH&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;EAST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;SOUTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;WEST&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;e_direction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being a 4-player game, we can store this information in a single byte:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
     0  1  2  3  4  5  6  7 
   +--+--+--+--+--+--+--+--+
   |DIR1 |DIR2 |DIR3 |DIR4 |
   +--+--+--+--+--+--+--+--+
     /\
   +-------------------------------+
   | direction of the first player |
   +-------------------------------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;such that in &lt;code&gt;C&lt;/code&gt; that would translate two:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;player_directions&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;p1_dir&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;p2_dir&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;p3_dir&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;p4_dir&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t_player_directions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;so in our loop, we could check the directions by accessing the fields of this 1byte struct:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* definitions above ... */&lt;/span&gt;

&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;t_players_directions&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p1_dir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NORTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p2_dir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NORTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p3_dir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SOUTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p4_dir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EAST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sizeof(directions)=%ld&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t_players_directions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;p1_dir=%x&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p1_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;p2_dir=%x&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p2_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;p3_dir=%x&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p3_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;p4_dir=%x&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p4_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   $  gcc -o main ./main.c
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *   $  ./main
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *        sizeof(directions)=1
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *        p1_dir=0
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *        p2_dir=0
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *        p3_dir=2
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *        p4_dir=1
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt; **/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What about Go, then? Bit shifting.&lt;/p&gt;
&lt;p&gt;When setting values: set the bits in the right position and then merge it to the value you want them in.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   given that we want to pack it in
   1 byte:

     0  1  2  3  4  5  6  7   ==&amp;gt;  dirs uint8 = 0
   +--+--+--+--+--+--+--+--+
   |DIR1 |DIR2 |DIR3 |DIR4 |
   +--+--+--+--+--+--+--+--+

   assume that we want the following 
   values packed:
   dir1 = 0     ===&amp;gt; 0 0
   dir2 = 0     ===&amp;gt; 0 0
   dir3 = 2     ===&amp;gt; 1 0
   dir4 = 1     ===&amp;gt; 0 1

   then it means that we need to get
   dir1 shifted all the way to the 
   first position, then dir2 to the
   second, dir3 to the third and dir4
   to the forth.

   dirs = 0             - start with 0 0 0 0 0 0 0 0
                        
   dirs |= 0 &amp;lt;&amp;lt; 6       - move `00` six times and &amp;quot;merge&amp;quot;

   0 0 0 0 0 0 0 0 
   d1  ----------

   dirs |= 0 &amp;lt;&amp;lt; 4       - move `00` four times and &amp;quot;merge&amp;quot;

   0 0 0 0 0 0 0 0 
   d1  d2  -------

   dirs |= 2 &amp;lt;&amp;lt; 2       - move `10` two times and &amp;quot;merge&amp;quot;

   0 0 0 0 1 0 0 0 
   d1  d2  d3  ---

   dirs |= 1 &amp;lt;&amp;lt; 0       - move `01` 0 times and &amp;quot;merge&amp;quot;

   0 0 0 0 1 0 0 1 
   d1  d2  d3  d4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That in Go code turned out to the following (for the case of the header):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//				0  1  2  3  4  5  6  7
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |                      ID                       |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |                    QDCOUNT                    |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Marshal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;       &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;h1_1&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// using `binary.Write` we can take the 16bit
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// int that the ID is made of and have it split
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// in two bytes following big endian order (most
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// significant bit first, less significant second)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BigEndian&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// first 8bit part of the second row
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// QR :		0
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Opcode:	1 2 3 4
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// AA:		5
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// TC:		6
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// RD:		7
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;QR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Opcode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;AA&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;RD&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// second 8bit part of the second row
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// RA:		0
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Z:		1 2 3
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// RCODE:	4 5 6 7
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;h1_1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;RA&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h1_1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Z&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h1_1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;RCODE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;WriteByte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;WriteByte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h1_1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BigEndian&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;QDCOUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ..
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When retrieving though, the idea is the same. The only difference this time is that you shift to the right and apply a mask to the remaining bits:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  0 0 0 0 1 0 0 1   current value    
  d1  d2  d3  d4

  how to know what&#39;s set for `d3`?

  shift the whole thing to the right by
  two places:

  0 0 0 0 0 0 1 0
  --- d1  d2  d3 

  and then mask the remaining (in this case
                               it&#39;s not necessary
                               but I assume we don&#39;t
                               know that in advance)
  0 0 0 0 0 0 1 0
&amp;amp; 0 0 0 0 0 0 1 1 
  ---------------
  0 0 0 0 0 0 1 0

  this way we know that at d3 we have `2` as the value.

  i.e.: d3 = (dirs &amp;gt;&amp;gt; 2) &amp;amp; ((1 &amp;lt;&amp;lt; 2) -1)

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you&amp;rsquo;re wondering why &lt;code&gt;(1 &amp;lt;&amp;lt; 2) - 1&lt;/code&gt;, that&amp;rsquo;s because we want &lt;code&gt;n&lt;/code&gt; places to the right filled with &lt;code&gt;1&lt;/code&gt;s and all the places to the left with &lt;code&gt;0&lt;/code&gt;s such that when we &lt;code&gt;AND&lt;/code&gt; them, only the &lt;code&gt;n&lt;/code&gt; to the right remain.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 0 0 0 0 1     1   = (1 &amp;lt;&amp;lt; 1 ) - 1
0 0 0 0 0 0 1 1     3   = (1 &amp;lt;&amp;lt; 2 ) - 1
0 0 0 0 0 1 1 1     7   = (1 &amp;lt;&amp;lt; 3 ) - 1
0 0 0 0 1 1 1 1     15  = (1 &amp;lt;&amp;lt; 4 ) - 1
0 0 0 1 1 1 1 1     31  = (1 &amp;lt;&amp;lt; 5 ) - 1
0 0 1 1 1 1 1 1     63  = (1 &amp;lt;&amp;lt; 6 ) - 1
0 1 1 1 1 1 1 1     127 = (1 &amp;lt;&amp;lt; 7 ) - 1
1 1 1 1 1 1 1 1     255 = (1 &amp;lt;&amp;lt; 8 ) - 1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you&amp;rsquo;re curious to see how that looks like, check out the method &lt;a href=&#34;https://github.com/cirocosta/rawdns/blob/028e50b601532d5a6221c415383cf291924cfb81/lib/header.go#L116&#34;&gt;lib/header.go#UnmarshalHeader&lt;/a&gt; from &lt;a href=&#34;https://github.com/cirocosta/rawdns&#34;&gt;cirocosta/rawdns&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |                      ID                       |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    |                    QDCOUNT                    |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//    .......
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;UnmarshalHeader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;h1_1&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// ID is formed by the first two bytes such that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// it results in an uint16.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// As this comes from the network in UDP packets we 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// can assume that it comes in BigEndian (network byte 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// order), thus, consider the first byte of each,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the most significant.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ID&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// take the first byte of the second row (QR, Opcode, AA, TC and RD)
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

	&lt;span class=&#34;c1&#34;&gt;// Each value is got from right bitshifting
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// followed by masking such that we end up
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// with only that number.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// Here we&amp;#39;re starting from right to left.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;RD&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;masks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TC&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;masks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;AA&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;masks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Opcode&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Opcode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;masks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;QR&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;h1_0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;masks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you can recreate messages from a sequence of bytes and write bytes from a structure, you&amp;rsquo;re ready to start communicating with a real server.&lt;/p&gt;
&lt;h3 id=&#34;asking-the-questions&#34;&gt;Asking the questions&lt;/h3&gt;
&lt;p&gt;This is the easiest part (&lt;em&gt;ps.: assuming we&amp;rsquo;re not entirely implementing all the details of the protocol, like truncating messages when above 512bytes and making use of some security features&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.ietf.org/rfc/rfc1035.txt&#34;&gt;DNS RFC&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The DNS assumes that messages will be &lt;strong&gt;transmitted as datagrams or in a
byte stream carried by a virtual circuit&lt;/strong&gt;.  While virtual circuits can be
used for any DNS activity, &lt;strong&gt;datagrams are preferred for queries due to
their lower overhead and better performance&lt;/strong&gt;. &amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The Internet supports name server access using TCP [RFC-793] on server
port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
port 53 (decimal).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s essentially meaning that we should make use of UDP when sending queries and that these queries should be performed against port 53 (by default).&lt;/p&gt;
&lt;p&gt;That in Go is translated to a UDP dial:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Dial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Wrapf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;s&#34;&gt;&amp;#34;failed to create connection to address %s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which allows us to &lt;code&gt;write()&lt;/code&gt; a sequence of bytes to it and then wait for responses.&lt;/p&gt;
&lt;p&gt;The fun thing is that UDP is connectionless. That means that we&amp;rsquo;re not setting up a full-fledged connection like with TCP, performing ACKS and NACKS all the way to make sure things go smoothly in the channel.&lt;/p&gt;
&lt;p&gt;Here I didn&amp;rsquo;t make use of timeouts and other mechanisms to control the possible scenario where no message comes back, but in practice, that&amp;rsquo;s totally needed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// LookupAddr queries a DNS server specified in
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the client initialization for A records concerning
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the address `addr`.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;LookupAddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ips&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Construct the query struct which
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// represents the whole message.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Here we&amp;#39;re specifying that we
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// have a single question, that
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// recursion is resired, that the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// message is a query and then in
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the question we specify that we
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// want A records, the type is &amp;#34;internet&amp;#34;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// and the address is &amp;#39;addr&amp;#39;.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;queryMsg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;      &lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;QR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;      &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;Opcode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;OpcodeQuery&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;QDCOUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;RD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;      &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;Questions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Question&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;QNAME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;QTYPE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;QTypeA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
				&lt;span class=&#34;nx&#34;&gt;QCLASS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;QClassIN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Because each piece of the message can be
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// marshalled as a sequence of bytes (`Header`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// implements a `Marshal()` method, as well as
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// `Question` ..), the marshalling of `Message`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// becomes simply a sequence of `Marshall` calls
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// which sum up to a sequence of bytes
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;queryMsg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Marshal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Write the bytes that represent our query to
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the &amp;#34;connection&amp;#34;
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Prepare a buf to receive the response.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// We&amp;#39;re assuming here the best scenario where
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// the response is always less than 512 as, if it
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// was, then we&amp;#39;d need to tie together multiple
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// messages.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;responseMsg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// construct the Message struct from the sequence
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// of bytes.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;UnmarshalMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;responseMsg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// return the IPs (as we asked for IPv4 address,
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// each one will have 4bytes).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;// 3.4.1. A RDATA format
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//     |                    ADDRESS                    |
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// where: 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// ADDRESS         A 32 bit Internet address.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Hosts that have multiple Internet addresses will have multiple A
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// records.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;ips&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;responseMsg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Answers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;answer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;responseMsg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Answers&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;nx&#34;&gt;ips&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;answer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;RDATA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;idx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;idx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that, we&amp;rsquo;re set!&lt;/p&gt;
&lt;p&gt;There are some other details like compression that are implemented in &lt;code&gt;rawdns&lt;/code&gt; that you can check out, but the gist of it is described above.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I found the experiment to be very cool.&lt;/p&gt;
&lt;p&gt;At first I was expecting a tedious task, but in the end, it was fun to look at how well documented the RFC is and how &amp;ldquo;future-proof&amp;rdquo; it was intended to be (even though not everything got really implemented).&lt;/p&gt;
&lt;p&gt;I plan to learn more about DNSSEC soon, so this was a good start.&lt;/p&gt;
&lt;p&gt;If you want to know more or just get in touch, reach me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;Before you go, please make sure you check out &lt;a href=&#34;https://amzn.to/2DEiNOG&#34;&gt;Computer Networking: A top-down approach&lt;/a&gt;; there you can learn more about DNS and other related networking concepts that will help you understand more the whole stack.&lt;/p&gt;

&lt;/div&gt;

</description>
                                <pubDate>Thu, 28 Dec 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/raw-dns-resolver-in-go/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/raw-dns-resolver-in-go/</guid>

                                
                                        <category>networking</category>
                                
                                        <category>go</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Can we manage multiple GitHub repositories in a better way?</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been trying to put myself in the skin of project managers this week and started thinking about some questions related to managing GitHub-based projects. Just trying to grasp what the experience would look like if I needed to gather answers to some very fundamental questions about how my team performs.&lt;/p&gt;
&lt;p&gt;The conclusion that came out from this is that &lt;strong&gt;project managers might be having a hard time with GitHub&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I see that there are all these tools like ZenHub and CodeTree, but I still don&amp;rsquo;t see them as great solutions for reporting team activity.&lt;/p&gt;
&lt;p&gt;They help when it comes to tracking issues and organizing them, but I have the impression that they can&amp;rsquo;t go much farther from that (don&amp;rsquo;t get me wrong, I think it is okay! they do a great job at what they propose).&lt;/p&gt;
&lt;p&gt;To get a sense of what&amp;rsquo;s missing, I started thinking about a project.&lt;/p&gt;
&lt;h3 id=&#34;what-is-the-project&#34;&gt;What is the project?&lt;/h3&gt;
&lt;p&gt;Having a very active GitHub user, I know pretty well that there&amp;rsquo;s a bunch of repositories that, to be honest, I don&amp;rsquo;t even care, they&amp;rsquo;re not meant to be tracked, and their activities don&amp;rsquo;t matter at all.&lt;/p&gt;
&lt;p&gt;It turns out that this is also the same for companies - some repositories that are just &amp;ldquo;lab&amp;rdquo; experiments, others are quick demos, and some forks were used to contribute to other repositories. No big deal.&lt;/p&gt;
&lt;p&gt;Except that it might get in the way when looking for all the  GitHub activity across all the repositories.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can I track just &lt;strong&gt;some&lt;/strong&gt; repositories of all of those that my organization has in GitHub?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s define our project as a set of repositories from all the repositories that our GitHub organization has (it could also aggregate repositories from other organizations).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/gh-myorg.png&#34;
       alt=&#34;Image illustrating the repositories view showing the status and last release tag of the repositories &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Think of our project as the intersection of an open source (OSS) only GitHub organization (which has all the repositories public) and a private organization with only private repositories. As I said, not all of them matter and the same is valid for the public ones.&lt;/p&gt;
&lt;h3 id=&#34;what-is-the-status-of-our-project&#34;&gt;What is the status of our project?&lt;/h3&gt;
&lt;p&gt;As someone who&amp;rsquo;s shipping some binaries and that has continuous integration (CI) systems tied to my repositories, it&amp;rsquo;d be handy to get a sense of how things are going.&lt;/p&gt;
&lt;p&gt;Say that &lt;code&gt;github.com/myorg&lt;/code&gt; has to release &lt;code&gt;github.com/myorg/docker-image&lt;/code&gt; as a Docker image. How can we, in a glance, know whether the current branch is in good shape to be released?  I.e., that all the tests pass and that the image is built just fine?&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve been doing this forever adding to our &lt;code&gt;README.md&lt;/code&gt; a badge that tells people what&amp;rsquo;s the status of all these sorts of things. I discover a repository out there and then boom, it&amp;rsquo;s all there.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re at project management though, that&amp;rsquo;s not how it works (I suppose).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What was the last release of the project repositories?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s easy, you might say. Jump to the repository and go to the releases page.&lt;/p&gt;
&lt;p&gt;For sure, you can do that. What about when you have 13 repositories and need to make sure things are on track?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What&amp;rsquo;s the status? Are we green in all master branches? Are the tests falling all the time?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Could I obtain this information from Travis-CI, or maybe Circle-CI? Well, again, sure! However, it turns out that sometimes there&amp;rsquo;s also Jenkins. Occasionally, other systems advertise their status to commits and pull requests.&lt;/p&gt;
&lt;p&gt;Why should I log into each of them just to get a view of the status of the repositories that they&amp;rsquo;re taking care?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say GitHub suddenly adds &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;release&lt;/code&gt; tags to their repositories visualization.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/gh-repositories.png&#34;
       alt=&#34;Image illustrating the repositories view showing the status and last release tag of the repositories &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Is that better? Maybe. Does it solve the problem? Well, sometimes, but not ours. Having more than a single organization already brakes the flow of &amp;ldquo;knowing how things are across multiple organizations.&amp;rdquo;&lt;/p&gt;
&lt;h3 id=&#34;damn-what-did-i-do-the-whole-week&#34;&gt;Damn, what did I do the whole week?&lt;/h3&gt;
&lt;p&gt;Monday morning and you go to the standup meeting. Now it&amp;rsquo;s your time to tell the team what you&amp;rsquo;ve been working on.&lt;/p&gt;
&lt;p&gt;But, wait.&lt;/p&gt;
&lt;p&gt;What did I do?&lt;/p&gt;
&lt;p&gt;Maybe I&amp;rsquo;m kinda stupid to not remember things, but I guess there are also some other people out there who just forgive what they&amp;rsquo;ve been working on last week like me. Perhaps my head goes blank on a topic when I finish working on it, but, who knows? Maybe people are alike.&lt;/p&gt;
&lt;p&gt;The point here is that even though you have all your work very documented on GitHub (you created issues, your pull requests were very well written and descriptive, you reviewed pull requests &amp;hellip;) there&amp;rsquo;s no easy way to gather that in a concise manner.&lt;/p&gt;
&lt;p&gt;Thinking about the team as a whole we can then multiply that by &lt;code&gt;N&lt;/code&gt;. Maybe the other person is also missing something that (s)he did and it would be pretty important for me to know (or just interesting, anyway).&lt;/p&gt;
&lt;h3 id=&#34;the-contribution-viz&#34;&gt;The contribution viz&lt;/h3&gt;
&lt;p&gt;Looking at what GitHub has we can think about its &amp;ldquo;contribution map&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s interesting for sure but cmon, that does nothing more than should how &lt;em&gt;&amp;ldquo;hard&amp;rdquo;&lt;/em&gt; (focus on the air quotes) you&amp;rsquo;ve been working during some days throughout the year.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/gh-activity.png&#34;
       alt=&#34;Image illustrating the repositories view showing the status and last release tag of the repositories &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Honestly? It doesn&amp;rsquo;t bring much to the table.&lt;/p&gt;
&lt;h3 id=&#34;what-were-my-pull-requests-about&#34;&gt;What were my pull requests about?&lt;/h3&gt;
&lt;p&gt;Next, we have pull request activity. This one is pretty cool, but there&amp;rsquo;s a little detail that bugs me:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/gh-pr-activity.png&#34;
       alt=&#34;Image illustrating the repositories view showing the status and last release tag of the repositories &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;it doesn&amp;rsquo;t allow me to filter the dates.&lt;/p&gt;
&lt;p&gt;What if it&amp;rsquo;s also essential for me to make sure that my team is having all their pull requests peer-reviewed? What if it matters to know that they&amp;rsquo;re only getting merged after test passes?&lt;/p&gt;
&lt;h3 id=&#34;what-was-i-committing&#34;&gt;What was I committing?&lt;/h3&gt;
&lt;p&gt;This topic is a bit controversial in the sense that it might be valid to say that in theory, your commits don&amp;rsquo;t matter when looking at the high level as every meaningful work would get in the form of pull requests which would be peer-reviewed and tested.&lt;/p&gt;
&lt;p&gt;For that reason I think we can come clean out of this.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/gh-commits.png&#34;
       alt=&#34;Image illustrating the repositories view showing the status and last release tag of the repositories &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;GitHub could let us filter the dates and maybe the status of the CI in each commit &amp;hellip; but perhaps it&amp;rsquo;s not very useful.&lt;/p&gt;
&lt;h3 id=&#34;pull-request-reviews&#34;&gt;Pull request reviews&lt;/h3&gt;
&lt;p&gt;From time to time I&amp;rsquo;ve been migrating from just writing code to reviewing a bunch of code.&lt;/p&gt;
&lt;p&gt;Even though I&amp;rsquo;m somewhat new to this, I think this is a place where proper tooling helps.&lt;/p&gt;
&lt;p&gt;Right now it&amp;rsquo;s pretty good to see what you&amp;rsquo;ve done.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/gh-review-activity.png&#34;
       alt=&#34;Image illustrating the repositories view showing the status and last release tag of the repositories &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;But what about what I have to do?&lt;/p&gt;
&lt;p&gt;In some more busier weeks it might happen that I just can&amp;rsquo;t review the code right away as the notification comes, but I don&amp;rsquo;t want to have people pinging me (I wouldn&amp;rsquo;t like to do that to others) and unfortunately GitHub doesn&amp;rsquo;t make easy for you to see what&amp;rsquo;s pending very easily when it comes to reviews.&lt;/p&gt;
&lt;h3 id=&#34;good-good-whatd-be-cool-then&#34;&gt;Good good, what&amp;rsquo;d be cool then?&lt;/h3&gt;
&lt;p&gt;Sincerely? I don&amp;rsquo;t know!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been recentely experimenting with &lt;a href=&#34;https://dgraph.io&#34;&gt;dgraph&lt;/a&gt; and it appears to me that indexing GitHub information in a graph database could lead to great answers.&lt;/p&gt;
&lt;p&gt;Not that it&amp;rsquo;s something that you wouldn&amp;rsquo;t be able to do right now with their REST interface, but it feels like by reducing the difficulty of exploring the relationships between repositories, labels and pull requests, I could maybe ask more interesting questions.&lt;/p&gt;
&lt;p&gt;For instance, consider the following schema:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Id:             int @index(int)         .
Type:           string @index(exact)    .
Name:           string @index(exact)    .
Login:          string @index(exact)    .
ClosedAt:       dateTime @index(hour)   .
Owner:          uid @reverse            .
Repository:     uid @reverse            .
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By indexing the repositories, issues, labels and users that are interacting with a repository (say, &lt;a href=&#34;https://github.com/cirocosta/cr&#34;&gt;cirocosta/cr&lt;/a&gt;), we could quickly see which labels are the most used querying &lt;code&gt;dgraph&lt;/code&gt; with something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  some_query(func: eq(Name, &amp;quot;cr&amp;quot;)) {
    uid
    Name
    Issues: ~Repository {
      Title
      Labels {
        Name
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which gives us back:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/github-labels.png&#34;
       alt=&#34;Image illustrating the relationship of issues and their labels &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Interesting? Well, maybe. I have the impression that the most interesting is the possibility - have better ways of asking those questions and not being bottlenecked at the retrieval.&lt;/p&gt;
&lt;p&gt;My goal is to soon be able to perform some sort of survival analysis on this data.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Survival analysis is a branch of statistics for analyzing the expected duration of time until one or more events happen, such as a death in biological organisms and failure in mechanical systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The survival function is a function that gives the probability that a patient, device, or another object of interest will survive beyond any given specified time.[1]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In theory, we should try to minimize this number for bugs assuming that we keep the good practice of always submitting issues and marking them correctly. We should also see that those issues labeled with higher priorities should get lower values (indicating that they &amp;ldquo;survive&amp;rdquo; less, in the sense that they get closed soon).&lt;/p&gt;
&lt;p&gt;With this kind of calculation we could then estimate the expected amount of time that an issue marked with a given label takes to get into the &amp;ldquo;death state&amp;rdquo; (closed).&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I see that there are many tools that can soon emerge to make querying GitHub data better. The information is there, being produced daily and with great quality. It looks like it&amp;rsquo;s a matter of exploring it better.&lt;/p&gt;
&lt;p&gt;Do share these impressions? Are you using a tool to auxiliate your team gather more insights into how it&amp;rsquo;s operating?&lt;/p&gt;
&lt;p&gt;What would make you improve by knowing data from your development team?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d love to hear from you! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter, feel free to drop a message there!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finnis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 25 Dec 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/managing-multiple-github-repositories/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/managing-multiple-github-repositories/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Creating a hello-world API using Swagger and Go</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been recentely developing, once again, a service that needs to expose an HTTP api which has to be publicly exposed and well documented. Guess what?! That&amp;rsquo;s not new! Write a new service that talks via HTTP and you&amp;rsquo;ll have to document the interface and write, again, all the same boilerplate for dealing with logging requests, handling preflight requests made by browsers, checking parameters and so on and so on.&lt;/p&gt;
&lt;p&gt;The greatness of using swagger is that we can simply skip all of that part and write a &lt;code&gt;swagger.yml&lt;/code&gt; (pretty declarative) which contains the definition of all of our endpoints.&lt;/p&gt;
&lt;p&gt;Given the definition, it generates stub code that we implement in our servers in the language you want (you&amp;rsquo;d probably do this only one time) and then have the client code generated for as many languages as there are swagger generator.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/swagger-declare-implement.svg&#34;
       alt=&#34;Illustration of swagger process &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Aside from that, documentation is all done for you - write a decent &lt;code&gt;swagger.yml&lt;/code&gt; and you can have automatic documentation generated.&lt;/p&gt;
&lt;p&gt;In this tutorial I go through what the process of creating a simple server looks like using &lt;code&gt;go&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;ps.: if you want to check the final result, see &lt;a href=&#34;https://github.com/cirocosta/hello-swagger&#34;&gt;github.com/cirocosta/hello-swagger&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;getting-go-swagger&#34;&gt;Getting go-swagger&lt;/h3&gt;
&lt;p&gt;First step is getting the &lt;code&gt;swagger&lt;/code&gt; command line interface.&lt;/p&gt;
&lt;p&gt;If you already have &lt;code&gt;go&lt;/code&gt;,  use &lt;code&gt;go get&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;go get -u -v github.com/go-swagger/go-swagger/cmd/swagger
&lt;/span&gt;
swagger --help

Usage:
  swagger &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;OPTIONS&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &amp;lt;command&amp;gt;

Swagger tries to support you as best as possible when building APIs.

It aims to represent the contract of your API with a language agnostic description of your application
in json or yaml.

...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The tools gives us a handful of commands aimed at generating and validating configurations as well as producing code according to an API description.&lt;/p&gt;
&lt;h3 id=&#34;initializing-the-golang-project&#34;&gt;Initializing the Golang project&lt;/h3&gt;
&lt;p&gt;To initialize the project, first create a repository in your &lt;code&gt;$GOPATH&lt;/code&gt;. In my case:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; go/src/github.com/cirocosta
mkdir hello-swagger
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./hello-swagger
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step depends on how you manager your project dependencies. I&amp;rsquo;ve been using &lt;a href=&#34;https://github.com/Masterminds/glide&#34;&gt;Masterminds/glide&lt;/a&gt; for a long time so that&amp;rsquo;s what I&amp;rsquo;ll be using (feel free to even not vendor your dependencies if you don&amp;rsquo;t think that&amp;rsquo;s a necessary thing).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;glide init
&lt;/span&gt;
$ tree
.
├── glide.lock
└── glide.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first dependency I&amp;rsquo;ll retrieve is &lt;code&gt;go-arg&lt;/code&gt;, which gives us a simple way of retrieving flags from a CLI application.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;glide get github.com/alexflint/go-arg
&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	Preparing to install &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; package.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	Attempting to get package github.com/alexflint/go-arg
...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	--&amp;gt; Exporting github.com/alexflint/go-arg
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	Replacing existing vendor dependencies
..&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With it we can create &lt;code&gt;main.go&lt;/code&gt;, the entrypoint of our application:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// main declares the CLI that spins up the server of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// our API.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// It takes some arguments, validates if they&amp;#39;re valid
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// and match the expected type and then intiialize the
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// server.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/alexflint/go-arg&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;// cliArgs defines the configuration that the CLI
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// expects. By using a struct we can very easily
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// aggregate them into an object and check what are
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// the expected types.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// If we need to mock this later it&amp;#39;s just a matter
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// of reusing the struct.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cliArgs&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`arg:&amp;#34;-p,help:port to listen to&amp;#34;`&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;c1&#34;&gt;// args is a reference to an instantiation of
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// the configuration that the CLI expects but
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// with some values set.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// By setting some values in advance we provide
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// default values that the user might provide
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;// or not.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cliArgs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8080&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// main parses the arguments from the CLI as specified
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// by our configuration described in `cliArgs` and then
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// populates the `args` reference we defined in the `vars`
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// section above.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;arg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;MustParse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;port=%d\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To install it by running a single command we can tailor a &lt;code&gt;Makefile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;nf&#34;&gt;install&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	go install -v

&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then check if all went well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;make
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;hello-swagger --help
&lt;/span&gt;
Usage: hello-swagger &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--port PORT&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;

Options:
  --port PORT, -p PORT   port to listen to &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;default: 8080&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  --help, -h             display this &lt;span class=&#34;nb&#34;&gt;help&lt;/span&gt; and &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt;

&lt;span class=&#34;hl&#34;&gt;hello-swagger --port &lt;span class=&#34;m&#34;&gt;1337&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1337&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the CLI configured, let&amp;rsquo;s move to the actual API and code generation.&lt;/p&gt;
&lt;h3 id=&#34;define-the-api-and-generate-the-code&#34;&gt;Define the API and generate the code&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── Makefile            &lt;span class=&#34;c1&#34;&gt;# makefile that summarizes the&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# build and code generation procedures&lt;/span&gt;
│       
├── glide.lock          &lt;span class=&#34;c1&#34;&gt;# a lock-file with all the dependencies&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# specified with their respective versions&lt;/span&gt;
│       
├── glide.yaml          &lt;span class=&#34;c1&#34;&gt;# a high-level definition of our directly&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# imported dependencies&lt;/span&gt;
│                       
├── main.go             &lt;span class=&#34;c1&#34;&gt;# our application entrypoint&lt;/span&gt;
│       
├── swagger             &lt;span class=&#34;c1&#34;&gt;# swagger definition and generated code&lt;/span&gt;
│   │       
│   └── swagger.yml
└── vendor              &lt;span class=&#34;c1&#34;&gt;# dependencies&lt;/span&gt;
    ├── github.com
    └── ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;swagger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;0.0.1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;paths&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/hostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;operationId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;getHostname&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;produces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;responses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;returns the hostname of the machine&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;schema&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;the hostname of the machine&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Update the Makefile to properly produce the code that our server will consume and nothing more&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;c&#34;&gt;# The `validate` target checks for errors and inconsistencies in 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# our specification of an API. This target can check if we&amp;#39;re 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# referencing inexistent definitions and gives us hints to where
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# to fix problems with our API in a static manner.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;validate&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	swagger validate ./swagger/swagger.yml


&lt;span class=&#34;c&#34;&gt;# The `gen` target depends on the `validate` target as
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# it will only succesfully generate the code if the specification
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# is valid.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here we&amp;#39;re specifying some flags:
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# --target              the base directory for generating the files;
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# --spec                path to the swagger specification;
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# --exclude-main        generates only the library code and not a 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#                       sample CLI application;
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# --name                the name of the application.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;gen&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;validate&lt;/span&gt;
	swagger generate server &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--target&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./swagger &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--spec&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./swagger/swagger.yml &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--exclude-main &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hello


&lt;span class=&#34;c&#34;&gt;# just added `gen` and `validate`
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gen&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;validate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now generate the swagger code&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;make gen
&lt;/span&gt;swagger generate server &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--target&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./swagger &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--spec&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./swagger/swagger.yml &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--exclude-main &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		--name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hello
2017/10/24 14:57:06 building a plan &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; generation
2017/10/24 14:57:06 planning definitions
2017/10/24 14:57:06 planning operations
2017/10/24 14:57:06 grouping operations into packages
...
  * github.com/jessevdk/go-flags

You can get these now with: go get -u -f swagger/...
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; Check that it has been generated
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ tree -L &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
.
├── Makefile
│   ...
├── main.go
└── swagger
    ├── restapi                 &lt;span class=&#34;c1&#34;&gt;# code generated by&lt;/span&gt;
    │   │                       &lt;span class=&#34;c1&#34;&gt;# go-swagger.&lt;/span&gt;
    │   ├── configure_hello.go
    │   ├── doc.go
    │   ├── embedded_spec.go
    │   ├── operations
    │   └── server.go
    └── swagger.yml             &lt;span class=&#34;c1&#34;&gt;# our definition&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add dependencies to &lt;code&gt;main&lt;/code&gt; and let &lt;code&gt;glide&lt;/code&gt; update your vendor&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/alexflint/go-arg&amp;#34;&lt;/span&gt;

        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cirocosta/hello-swagger/swagger/models&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cirocosta/hello-swagger/swagger/restapi&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cirocosta/hello-swagger/swagger/restapi/operations&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/go-openapi/loads&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/go-openapi/runtime/middleware&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/go-openapi/swag&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ glide up -v
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	Downloading dependencies. Please wait...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	--&amp;gt; Fetching updates &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; github.com/alexflint/go-arg
...
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	--&amp;gt; Fetching updates &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; github.com/go-openapi/validate
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	--&amp;gt; Fetching updates &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; golang.org/x/net
..
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;	Project relies on &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; dependencies.
..

$ tree -L &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
.
├── Makefile
├── glide.lock
├── glide.yaml
├── main.go
├── swagger
│   ├── restapi
│   └── swagger.yml
└── vendor
    ├── github.com      &lt;span class=&#34;c1&#34;&gt;# some new here as well&lt;/span&gt;
    ├── golang.org      &lt;span class=&#34;c1&#34;&gt;# new&lt;/span&gt;
    └── gopkg.in        &lt;span class=&#34;c1&#34;&gt;# new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;implement-the-functionality&#34;&gt;Implement the functionality&lt;/h3&gt;
&lt;p&gt;Now that we have all the dependencies set up we need to create the server and implement the handler functionality.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;

	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/alexflint/go-arg&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cirocosta/hello-swagger/swagger/models&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cirocosta/hello-swagger/swagger/restapi&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cirocosta/hello-swagger/swagger/restapi/operations&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/go-openapi/swag&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/go-openapi/loads&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/go-openapi/runtime/middleware&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cliArgs&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`arg:&amp;#34;-p,help:port to listen to&amp;#34;`&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cliArgs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8080&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;arg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;MustParse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;swaggerSpec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;loads&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Analyzed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;restapi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SwaggerJSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fatalln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;api&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewHelloAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;swaggerSpec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;restapi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewServer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Shutdown&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

	&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Port&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;// Implement the handler functionality.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// As all we need to do is give an implementation to the interface
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// we can just override the `api` method giving it a method with a valid
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// signature (we didn&amp;#39;t need to have this implementation here, it could
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// even come from a different package).
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetHostnameHandler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;GetHostnameHandlerFunc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
		&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;params&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetHostnameParams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;middleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Responder&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
			&lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Hostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
				&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewGetHostnameDefault&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;WithPayload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;models&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
					&lt;span class=&#34;nx&#34;&gt;Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
					&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;swag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to retrieve hostname&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
				&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;operations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewGetHostnameOK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;WithPayload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
		&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;// Start listening using having the handlers and port 
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// already set up.
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Serve&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
		&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fatalln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To verify whether it&amp;rsquo;s all fine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# in one terminal session&lt;/span&gt;
$ hello-swagger          
2017/10/24 15:32:47 Serving hello at http://&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;::&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;:8080

&lt;span class=&#34;c1&#34;&gt;# in another terminal session&lt;/span&gt;
$ hostname
cirocosta.local

$ curl localhost:8080/dadsadas
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;:404,&lt;span class=&#34;s2&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;path /dadsadas was not found&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

$ curl localhost:8080/hostname
cirocosta.local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Done&lt;/p&gt;
</description>
                                <pubDate>Tue, 05 Dec 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/a-swagger-golang-hello-world/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/a-swagger-golang-hello-world/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>A minimal Docker Ansible role</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;there are plenty of Docker Ansible roles out there but it turns out that most of them are overly complex while at the same time it&amp;rsquo;s very simple to install it.&lt;/p&gt;
&lt;p&gt;Actually, most of the times not even Ansible is needed: if you have a single machine and just needs to have it there, Docker already got you covered on how to install Docker:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;head to &lt;a href=&#34;https://get.docker.com&#34;&gt;get.docker.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pick a script that installs it from a specific release channel and done (&lt;em&gt;if you&amp;rsquo;re curious - or worried - about the development of that script, head to &lt;a href=&#34;https://github.com/docker/docker-install&#34;&gt;github.com/docker/docker-install&lt;/a&gt;&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;configure user permissions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you&amp;rsquo;re into Ansible though, maybe because you use it to make a bunch of machines reach a given state or makes use of it to bake machine images, here&amp;rsquo;s my suggestion of minimal Docker role.&lt;/p&gt;
&lt;h3 id=&#34;the-role&#34;&gt;The role&lt;/h3&gt;
&lt;p&gt;The role consists of three directories following Ansible&amp;rsquo;s patterns (see &lt;a href=&#34;http://docs.ansible.com/ansible/latest/playbooks_reuse_roles.html&#34;&gt;Ansible - Roles&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with it, it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker
├── defaults            # Variables used by the docker role.
│   └── main.yml        # Here I place some default variables
│                       # like the `apt` repository and a default
│                       # docker version to be installed.
│
├── files               # static files that we plan to use in the
│   └── daemon.json     # role (i.e, send to the host) but not
│                       # modify (it&#39;s not a template)
│ 
└── tasks               # the actual list of actions to take.
    └── main.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The main part of this role is the &lt;code&gt;tasks/main.yml&lt;/code&gt; file which defines the actions to take:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# As an initial step we make sure that we have our&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# dependencies ready. Here we&amp;#39;re installing just&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# two:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - apt-transport-https makes us be able to use&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#   TLS in the transport of packages coming&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#   from APT repositories&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - ca-certificates gives us a bundle of common&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#   certificate authorities&amp;#39; certificates&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;install docker dependencies&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ item }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with_items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;apt-transport-https&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;ca-certificates&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Because apt makes use of public key crypto to fetch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# packages we must tell it what&amp;#39;s the public key of the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# source that is signing the packages we want to retrieve,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that is, we need to add the repository&amp;#39;s key.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;add docker repo apt key&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;https://download.docker.com/linux/ubuntu/gpg&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;9DC858229FC7DD38854AE2D88D81803C0EBFCD88&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;add_repository_key&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ignore_errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Add the official docker apt repository so that `apt`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# can list packages from it and then fetch them from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# there.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# With `update_cache` we force an `apt update` which&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# would essentially be the equivalent of updating the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# list of packages from a list of source repositories.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;add Docker repository&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt_repository&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ docker_apt_repository }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;update_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# With the list of packages updated we can install&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# a specific version of the `docker-ce` package. This&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# way we can declaratively tell the role which version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of docker we want: a stable (17.09, for instance) or an &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# edge (17.11-rc3)?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;install docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker-ce={{ docker_version }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Once Docker has finished the installation (which involves&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# setting a systemd service) we have the option to either&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# enable that service or not. By enabling it, systemd hooks&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the docker unit into specific places such that whenever the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# machine boots we have this service started.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;enable docker systemd service&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;started&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# As we can configure the docker daemon via the configuration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# file `/etc/docker/daemon.json` here we take the opportunity&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of placing one of our own at the relevant destination.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;prepare default daemon configuration&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;daemon.json&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/etc/docker/daemon.json&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If you use something like `docker swarm mode` it&amp;#39;s&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# very common to have dangling containers around.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By setting a cron job to clean thing ups every N&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# hours we make sure that dangling containers don&amp;#39;t &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# stay around for too long.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;set periodic docker system prune&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;cron&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker-prune&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;minute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hour&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;*/2&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;job&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker container prune -f&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Without adding the unprivileged &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# user to the docker group we can&amp;#39;t &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# make use of the socket that is activated&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# by systemd. Here we take a list of users that&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# we want to make part of the `docker` group and&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# do it.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;add users to docker group&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ item }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;groups&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with_items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{{ docker_group_members }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;when&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;docker_group_members is defined&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file makes use of what&amp;rsquo;s defined under &lt;code&gt;defaults/main.yml&lt;/code&gt;, which looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The specific version that we aim at installing.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If we wanted to get whatever is the latest not &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# marked as a release candidate we could instead&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# not specify a version but simply `docker-ce`.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;docker_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;17.09.0~ce-0~ubuntu&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The release channel to look for packages.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# If your curious about what are the channels and which&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# versions do they have, head to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# https://download.docker.com/linux/ubuntu/dists/zesty/ (or&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# any other distro you want).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;docker_apt_release_channel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;stable&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# The URL of the apt repository.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here we&amp;#39;re picking the values from the knowledge&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that ansible already took from the system. This way&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# we can make fewer changes in this code when changing&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from one distro to another.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Note that there&amp;#39;s a compatibility matrix but in general&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# new versions of Ubuntu are well covered.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;docker_apt_repository&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;deb https://download.docker.com/linux/{{ ansible_distribution|lower }} {{ ansible_distribution_release }} {{ docker_apt_release_channel }}&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# List of users that we want to add to the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `docker` group. As mentioned, by adding them to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the `docker` group they can access the Unix socket&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that Docker places at `/var/run/docker.sock` (by default)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# which the docker CLI uses to communicate with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the docker daemon.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;docker_group_members&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; 
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;ubuntu&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While the Docker daemon configuration looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;experimental&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;icc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;max-concurrent-downloads&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;max-concurrent-uploads&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;metrics-addr&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.0.0.0:9102&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;storage-driver&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;overlay2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;userland-proxy&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re not very sharp about Docker configuration, this is what the last file means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;enabling experimental mode allows us to build images with &lt;code&gt;--squash&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;icc&lt;/code&gt; means that container won&amp;rsquo;t be able to communicate with each others over the &lt;code&gt;bridge&lt;/code&gt; network;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max-concurrent-(downloads|uploads)&lt;/code&gt; increases the number of downloads/uploads (layers) at a given time;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;metrics-addr&lt;/code&gt; makes the daemon expose Prometheus metrics at all interfaces on port &lt;code&gt;9102&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;storage-driver&lt;/code&gt; sets the storage driver to &lt;code&gt;overlay2&lt;/code&gt; (see &lt;a href=&#34;https://docs.docker.com/engine/userguide/storagedriver/selectadriver/&#34;&gt;docs.docker.com - Select a storage driver&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;userland-proxy&lt;/code&gt; deactivates the use of the userland proxy that docker places for each port mapping - this way we rely solely on iptables for the port mapping. I&amp;rsquo;d like to go deeper into this one but I&amp;rsquo;d need to research more first (please send me some articles!).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the role ready we can now prepare a playbook that makes use of it and test it against a real (in this case, virtual) machine.&lt;/p&gt;
&lt;h3 id=&#34;testing-it-with-vagrant&#34;&gt;Testing it with Vagrant&lt;/h3&gt;
&lt;p&gt;The easiest way I can think of testing this is making use of &lt;a href=&#34;https://www.vagrantup.com/&#34;&gt;Vagrant&lt;/a&gt;. I wrote a bit about it when I was setting a VM in an article regarding &lt;a href=&#34;https://ops.tips/blog/augmenting-swap-space/#1-preparing-a-vm&#34;&gt;augmenting swap space in Linux&lt;/a&gt; but the gist of it is that it allows us to create a little piece of code that describes how a VM (or a container) should be prepared.&lt;/p&gt;
&lt;p&gt;Here, just like in the article I mentioned, I&amp;rsquo;ll be creating an Ubuntu 17.04 (zesty) machine with 512MB of RAM and 1 CPU. The difference now is that when the machine gets up we&amp;rsquo;ll be turning ansible against it and executing our role.&lt;/p&gt;
&lt;p&gt;To do so, let&amp;rsquo;s prepare the project directory structure a bit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── ansible             &lt;span class=&#34;c1&#34;&gt;# ansible related configuration&lt;/span&gt;
│   │                   &lt;span class=&#34;c1&#34;&gt;# and execution files&lt;/span&gt;
│   │   
│   ├── ansible.cfg     &lt;span class=&#34;c1&#34;&gt;# general configuration&lt;/span&gt;
│   ├── playbooks       &lt;span class=&#34;c1&#34;&gt;# playbooks that execute the roles&lt;/span&gt;
│   │   │               &lt;span class=&#34;c1&#34;&gt;# and tasks we want&lt;/span&gt;
│   │   └── provision-vagrant.yml
│   └── roles           &lt;span class=&#34;c1&#34;&gt;# the docker role described before&lt;/span&gt;
│       └── docker
│           ├── defaults
│           │   └── main.yml
│           ├── files
│           │   └── daemon.json
│           └── tasks
│               └── main.yml
└── vagrant             &lt;span class=&#34;c1&#34;&gt;# vagrant configuration&lt;/span&gt;
    └── Vagrantfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that structure ready, let&amp;rsquo;s populate the files. The &lt;code&gt;roles/docker/*&lt;/code&gt; ones should already be done given the previous sections, now the &lt;code&gt;Vagrantfile&lt;/code&gt; should look like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;Vagrant&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# - set the image to be used to be ubuntu/zesty64&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# - set the hostname of the machine&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# - do not check for base image updates&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# - do not sync the default vagrant directory&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu/zesty64&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test-machine&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box_check_update&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;synced_folder&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/vagrant&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;disabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;# - configure some parameters from the virtualbox provider&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;virtualbox&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;512&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;


        &lt;span class=&#34;c1&#34;&gt;# hook ansible into the process of provisioning&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# the machine.&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# -     using the ansible configuration file&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;#       located at `../ansible/ansible.cfg`, &lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;#       execute the playbook at `playbooks/provision-vagrant.yml`&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provision&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ansible&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ansible&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;ansible&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;playbook&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;../ansible/playbooks/provision-vagrant.yml&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;ansible&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;../ansible/ansible.cfg&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now moving to the ansible configuration, let&amp;rsquo;s tell it where it should look for the roles. In &lt;code&gt;ansible/ansible.cfg&lt;/code&gt; we can put the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;k&#34;&gt;[defaults]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;roles_path&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;./roles&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now moving to the playbook itself, configure it to target the host that Vagrant will create and make use of the Docker role we just created:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# This is a little role that I always execute at first&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# when I&amp;#39;m provision machines from the ground up. Because&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# some roles might require knowledge about the machine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# (gathered via `gather_facts`) and obtaining such knowledge&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# require python, with this role we can bootstrap the &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# python installation with plain ansible SSH communication.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       -       by not gathering facts and execution &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#               almost manually the `apt install` script&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#               we can install it.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Check the role at https://github.com/cirocosta/example-docker-ansible&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;any_errors_fatal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;become&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;gather_facts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;roles&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;bootstrap&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# * Target whatever is the default group of hosts;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# * If any errors happen in the middle, stop the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# whole execution;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# * Make sure to `become` a privileged user;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# * Gather facts about the machine (requires&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# python);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# * Execute the `docker` role.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;become&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;any_errors_fatal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;roles&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the playbook set up, we can now go back to the root of the repository, enter in the &lt;code&gt;vagrant&lt;/code&gt; directory and execute have the &lt;code&gt;ansible&lt;/code&gt; execution at the launch of the Vagrant machine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./vagrant
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;vagrant up
&lt;/span&gt;
Bringing machine &lt;span class=&#34;s1&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt; up with &lt;span class=&#34;s1&#34;&gt;&amp;#39;virtualbox&amp;#39;&lt;/span&gt; provider...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Importing base box &lt;span class=&#34;s1&#34;&gt;&amp;#39;ubuntu/zesty64&amp;#39;&lt;/span&gt;...
...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Machine booted and ready!
...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Running provisioner: ansible...
    default: Running ansible-playbook...

PLAY &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;default&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; ...........................
TASK &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;bootstrap : bootstrap python&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; ......
changed: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;default&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;

...

TASK &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;docker : install docker dependencies&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; ************************************
ok: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;default&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=[&lt;/span&gt;u&lt;span class=&#34;s1&#34;&gt;&amp;#39;apt-transport-https&amp;#39;&lt;/span&gt;, u&lt;span class=&#34;s1&#34;&gt;&amp;#39;ca-certificates&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;])&lt;/span&gt;

TASK &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;docker : add docker repo apt key&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; ****************************************
ok: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;default&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;can-we-simplify-it-even-more&#34;&gt;Can we simplify it even more?&lt;/h3&gt;
&lt;p&gt;For sure!&lt;/p&gt;
&lt;p&gt;As I mentioned, &lt;a href=&#34;https://get.docker.com&#34;&gt;get.docker.com&lt;/a&gt; already install Docker for you. It won&amp;rsquo;t allow you to specify the version you want but it does the job. As it&amp;rsquo;s a command that you&amp;rsquo;d manually copy and paste into the terminal, we can mimic that with &lt;a href=&#34;http://docs.ansible.com/ansible/latest/command_module.html&#34;&gt;Ansible&amp;rsquo;s command module&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Fetches the docker installation script&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from `get.docker.com` and then pipes the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# script to `sh` so that it gets executed.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;install docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;bash -c &amp;#34;curl -fsSL https://get.docker.com/ | sh&amp;#34;&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;From having this Ansible role to having a process of baking AWS AMIs or images for GCE is just a matter of adding Packer to the mix or even manually just targetting a VM and snapshotting it. I tend to keep using a distribution for a reasonable time so I don&amp;rsquo;t see many reasons to try to make my Ansible roles very complicated with support to a bunch of distros so that&amp;rsquo;s why I wrote this article.&lt;/p&gt;
&lt;p&gt;You can find this example in &lt;a href=&#34;https://github.com/cirocosta/example-docker-ansible&#34;&gt;github.com/cirocosta/example-docker-ansible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Assuming you have Ansbile and Vagrant installed it should be a matter of running &lt;code&gt;make run&lt;/code&gt; from the root of the repository.&lt;/p&gt;
&lt;p&gt;Please let me know if I left something uncovered or if you want to share how you&amp;rsquo;re doing this kind of stuff! I&amp;rsquo;d really like to know.&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;Ciro&lt;/p&gt;
</description>
                                <pubDate>Mon, 04 Dec 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/docker-ansible-role/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/docker-ansible-role/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Incremental backups using GNU Tar and S3</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;a friend of mine recently told me about a way of performing incremental backups making use of the ubiquitous &lt;code&gt;tar&lt;/code&gt; tool.&lt;/p&gt;
&lt;p&gt;I was really impressed that such a useful thing could be hidden there without people talking about it (or is it just me who didn&amp;rsquo;t know? anyway &amp;hellip;)&lt;/p&gt;
&lt;p&gt;Here are my two cents on how you can tailor a script that will backup a directory incrementally sending the snapshots to S3 and then recovering later.&lt;/p&gt;
&lt;p&gt;In the end, I also include &lt;code&gt;restic&lt;/code&gt; as an alternative.&lt;/p&gt;
&lt;h3 id=&#34;goal&#34;&gt;Goal&lt;/h3&gt;
&lt;p&gt;The ultimate goal is pretty simple to describe:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;perform backups that we can go back to if we need and that we can store in a remote location;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With an extra feature that is very nice to have: restore the backups up to a specific date.&lt;/p&gt;
&lt;p&gt;The idea of restoring to a point-in-time snapshot is that if we mess up and backup our mess we want to go back to a previous backup that wasn&amp;rsquo;t messed up.&lt;/p&gt;
&lt;p&gt;Consider the following example: starting at &lt;code&gt;t0&lt;/code&gt; we perform our initial snapshots that corresponds to an addition of all the present files and directories. Next, in &lt;code&gt;t1&lt;/code&gt;, we perform a second snapshot which accounts for only the addition of a new file. In a third time, &lt;code&gt;t2&lt;/code&gt;, we perform another snapshot which differs from the last one by only adding a new file. Now assume that at &lt;code&gt;t3&lt;/code&gt; we perform a new snapshot but we shouldn&amp;rsquo;t have snapshotted as we added a wrong file (e.g, the database was already broken and our snapshotting routine took the snapshot).&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/snapshots.svg&#34;
       alt=&#34;Illustration of a snapshot approach &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;If we can go back in time to any snapshot that we want (instead of relying on a single backup), then we can recover even from a bad snapshot taken at the wrong moment. In our example, that would mean not recovering to &lt;code&gt;t3&lt;/code&gt;, but instead, recover to &lt;code&gt;t2&lt;/code&gt; where we took a good snapshot.&lt;/p&gt;
&lt;p&gt;With that in hands, we can make sure that even if we wrongly backup a directory where things got removed we can still go to a snapshot taken previously and get to that state.&lt;/p&gt;
&lt;h3 id=&#34;install-the-dependencies---gnu-tar-macos&#34;&gt;Install the dependencies - &lt;code&gt;gnu-tar&lt;/code&gt; (macOS)&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re using MacOS you can retrieve &lt;code&gt;gnu-tar&lt;/code&gt; using &lt;code&gt;brew&lt;/code&gt; as it already has a formula (see &lt;a href=&#34;https://github.com/Homebrew/homebrew-core/blob/master/Formula/gnu-tar.rb&#34;&gt;gnu-tar formula&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;brew install gnu-tar
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;gtar --help
&lt;/span&gt;
Usage: gtar &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;OPTION...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;FILE&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;...
GNU &lt;span class=&#34;s1&#34;&gt;&amp;#39;tar&amp;#39;&lt;/span&gt; saves many files together into a single tape or disk archive, and can
restore individual files from the archive.

Examples:
  tar -cf archive.tar foo bar  &lt;span class=&#34;c1&#34;&gt;# Create archive.tar from files foo and bar.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you don&amp;rsquo;t want to have to prefix with &lt;code&gt;g&lt;/code&gt; we can pass an additional argument, &lt;code&gt;--with-default-names&lt;/code&gt; as we can see in the formula (&lt;a href=&#34;https://github.com/Homebrew/homebrew-core/blob/70308b0b33eb6f4a53a06eba1f7ec774382ede84/Formula/gnu-tar.rb#L16&#34;&gt;line 16&lt;/a&gt; from &lt;code&gt;gnu-tar.rb&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;  &lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;with-default-names&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Do not prepend &amp;#39;g&amp;#39; to the binary&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;with?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;default-names&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;?&lt;/span&gt; 
        &lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;tar&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; 
        &lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;gtar&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;so that we install it with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;brew install gnu-tar --with-default-names
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll stick with &lt;code&gt;gtar&lt;/code&gt; (installation with &lt;code&gt;--with-default-names&lt;/code&gt;). You can know whether you&amp;rsquo;re using the BSD or GNU version by looking at &lt;code&gt;help&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;tar --help
&lt;/span&gt;
       ++&lt;span class=&#34;o&#34;&gt;====&lt;/span&gt; BSD
       &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;
       &lt;span class=&#34;se&#34;&gt;\/&lt;/span&gt;
tar&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;bsdtar&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: manipulate archive files
First option must be a mode specifier:
  -c Create  -r Add/Replace  -t List  -u Update  -x Extract
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool, let&amp;rsquo;s jump to the backups.&lt;/p&gt;
&lt;h3 id=&#34;performing-incremental-backups&#34;&gt;Performing incremental backups&lt;/h3&gt;
&lt;p&gt;The manuals of &lt;code&gt;tar&lt;/code&gt; contain a very interesting section &lt;em&gt;Using tar to perform incremental dumps&lt;/em&gt; that states:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The option `--listed-incremental&#39; instructs tar to operate 
on an incremental archive with additional metadata stored in 
a standalone file, called a snapshot file. The purpose of this 
file is to help determine which files have been changed, added 
or deleted since the last backup, so that the next incremental 
backup will contain only modified files. The name of the snapshot 
file is given as an argument to the option:

`--listed-incremental=file&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That essentially means that we can create some various &lt;code&gt;tar&lt;/code&gt; files and keep track of this sequence of files by mutating an index file that we provide to the &lt;code&gt;--listed-incremental&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;So, how to perform incremental backups using Tar?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;create a list that keeps track of all the files that compose the full state of the system up until a given point in time&lt;/li&gt;
&lt;li&gt;create the initial tar with the full current state&lt;/li&gt;
&lt;li&gt;keep creating files with only the difference (increments) and updating the file that lists these snapshots that we take.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As an example, assume we have the following file structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── rootfs
│   └── 1.txt
└── snapshots

2 directories, 1 file
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We want to back up &lt;code&gt;/rootfs&lt;/code&gt; and, which right now contains &lt;code&gt;1.txt&lt;/code&gt;, and send the snapshots to the &lt;code&gt;snapshots&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Starting with the first and second point (creating a list that keeps track of all the files that compose the full state and then creating the first snapshots that contain all the state):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;gtar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --no-check-device &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --file&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./snapshots/1.tar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --listed-incremental&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./snapshots/index &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./rootfs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which leds us to the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;tree
&lt;/span&gt;.
├── rootfs
│   └── 1.txt
└── snapshots
    ├── 1.tar
    └── index

&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; files


&lt;span class=&#34;hl&#34;&gt;cat ./snapshots/index 
&lt;/span&gt;GNU tar-1.29-2
1511892293436890000151189201680544478167772208590981353./rootfsY1.txt%  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now mutate the state of &lt;code&gt;rootfs&lt;/code&gt; directory one more time by adding &lt;code&gt;2.txt&lt;/code&gt; and &lt;code&gt;3.txt&lt;/code&gt; and then perform a second snapshot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# mutate the rootfs directory&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2.txt&amp;#34;&lt;/span&gt; &amp;gt; ./rootfs/2.txt
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3.txt&amp;#34;&lt;/span&gt; &amp;gt; ./rootfs/3.txt
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;tree
&lt;/span&gt;.
├── rootfs
│   ├── 1.txt
│   ├── 2.txt
│   └── 3.txt
└── snapshots
    ├── 1.tar
    └── index

&lt;span class=&#34;c1&#34;&gt;# perform a second snapshot that should&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# contain only the addition of the two files&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt; gtar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --create &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --no-check-device &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --file&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./snapshots/2.tar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --listed-incremental&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./snapshots/index &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./rootfs

&lt;span class=&#34;c1&#34;&gt;# verify that the new snapshot has been created&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# but we still have a single `index` file that&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# lists the contents&lt;/span&gt;
&lt;/span&gt;tree
.
├── rootfs
│   ├── 1.txt
│   ├── 2.txt
│   └── 3.txt
└── snapshots
    ├── 1.tar
    ├── 2.tar
    └── index

&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# check the updated index file&lt;/span&gt;
&lt;/span&gt;cat ./snapshots/index 
GNU tar-1.29-2
151189253560533700001511892488471449116167772208590981353./rootfsN1.txtY2.txtY3.txt

&lt;span class=&#34;c1&#34;&gt;# check the contents of the first snapshot&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# (it should only contain 1.txt)&lt;/span&gt;
&lt;/span&gt;tar -tvf ./snapshots/1.tar 
drwxr-xr-x  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; cirocosta wheel       &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt; Nov &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; 16:00 ./rootfs/
-rw-r--r--  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; cirocosta wheel       &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; Nov &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; 16:00 ./rootfs/1.txt

&lt;span class=&#34;c1&#34;&gt;# check the contents of the first snapshot&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# (it should only contain 2.txt and 3.txt)&lt;/span&gt;
&lt;/span&gt;tar -tvf ./snapshots/2.tar
drwxr-xr-x  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; cirocosta wheel      &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; Nov &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; 16:08 ./rootfs/
-rw-r--r--  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; cirocosta wheel       &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; Nov &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; 16:08 ./rootfs/2.txt
-rw-r--r--  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; cirocosta wheel       &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; Nov &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; 16:08 ./rootfs/3.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool, having that all we need to do is restore to check if it&amp;rsquo;s really working.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# create a separate directory to put the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# restoration files. This is important for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the demo because otherwise `gtar` would&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# remove the files from `rootfs` that were&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# not at the snapshot at that given moment.&lt;/span&gt;
mkdir ./restore
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; restore
&lt;span class=&#34;hl&#34;&gt;gtar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --extract &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --listed-incremental&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;../snapshots/index &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --file&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;../snapshots/1.tar 
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# check if only `1.txt` is there in the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# rootfs from the first moment&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;tree
&lt;/span&gt;.
└── rootfs
    └── 1.txt

&lt;span class=&#34;c1&#34;&gt;# remove the contents so that we start again&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with a clean rootfs&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;rm -rf ./rootfs
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to restore all the files until the last snapshot&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we must perform the extraction of all the snapshots&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# from the first to the last, one after another&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;gtar &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;      
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;        --extract &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --listed-incremental&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;../snapshots/index &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --file&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;../snapshots/1.tar 
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;gtar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --extract &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --listed-incremental&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;../snapshots/index &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --file&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;../snapshots/2.tar 
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# now check that all the files of the last snapshot&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# are there&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;tree
&lt;/span&gt;.
└── rootfs
    ├── 1.txt
    ├── 2.txt
    └── 3.txt

&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; directory, &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;integrating-with-s3&#34;&gt;Integrating with S3&lt;/h3&gt;
&lt;p&gt;Someone who has worked with S3 knows that now syncing this to S3 is not a big deal - make use of the &lt;a href=&#34;https://aws.amazon.com/cli/&#34;&gt;AWS CLI&lt;/a&gt; and then it&amp;rsquo;ll push the new / changed files to a bucket that you want.&lt;/p&gt;
&lt;p&gt;Besides the simplicity of uploading content to S3, I&amp;rsquo;d like to highlight a simple way of testing it locally. The easiest way to do it, in my opinion, is using &lt;a href=&#34;https://www.minio.io/&#34;&gt;minio&lt;/a&gt; which provides us an implementation of the S3 API that we can use locally:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Minio is an open source object storage server with Amazon S3 compatible API. Build cloud-native applications portable across all major public and private clouds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have Docker installed, having &lt;code&gt;minio&lt;/code&gt; running is one command away:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run a container in the background using the image &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `minio/minio` publishing the target port 9000 as 9000 &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# on the host and initialize it with the command `server`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with the argument `/data` (location where minio&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# will save the contents - this is a directory you&amp;#39;d&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# like persisted somehow, here, we don&amp;#39;t care).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# With MINIO_ACCESS_KEY and MINIO_SECRET_KEY we set some&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# testing credentials that we can use with the AWS CLI tool.&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --publish 9000:9000 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name minio &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;s1&#34;&gt;&amp;#39;MINIO_ACCESS_KEY=accesskey&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;s1&#34;&gt;&amp;#39;MINIO_SECRET_KEY=secretkey&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        minio/minio &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        server /data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now to make use of it we can install the AWS CLI and configure it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# install `pip` to fetch python packages (in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# this case, `awscli`)&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;sudo easy_install pip
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# fetch the `awscli` package.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;pip install awscli --upgrade
&lt;/span&gt;
Configure the credentials:

&lt;span class=&#34;hl&#34;&gt;aws configure
&lt;/span&gt;AWS Access Key ID &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;None&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;: accesskey
AWS Secret Access Key &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;None&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;: secretkey
Default region name &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;us-east-1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;: 
Default output format &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;None&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;:

&lt;span class=&#34;c1&#34;&gt;# enable AWS signature V4 for the minio server&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;aws configure &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; default.s3.signature_version s3v4
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# make sure we don&amp;#39;t have previous environment&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# variables set&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;unset&lt;/span&gt; AWS_DEFAULT_REGION    
&lt;span class=&#34;nb&#34;&gt;unset&lt;/span&gt; AWS_ACCESS_KEY_ID
&lt;span class=&#34;nb&#34;&gt;unset&lt;/span&gt; AWS_SECRET_ACCESS_KEY&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With everything configured, we can create a bucket and then sync our snapshots:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;aws &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --endpoint-url&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;http://localhost:9000 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3 mb &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3://backups
&lt;/span&gt;make_bucket: backups

&lt;span class=&#34;c1&#34;&gt;# get into the snapshots directory&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./snapshots
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Sync the current directory (snapshots) with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the S3 bucket.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Only new files will be sent on each new run of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the command. If there are no changes, nothing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is sent. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Because it&amp;#39;s our first run, everything is sent.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;aws &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --endpoint-url&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;http://localhost:9000 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3 sync &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./ s3://backups
&lt;/span&gt;upload: ./2.tar to s3://backups/2.tar                             
upload: ./1.tar to s3://backups/1.tar                           
upload: ./index to s3://backups/index &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, to retrieve all the files from that bucket:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# copy from a remote location (s3 bucket `backups`)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the current location `./` recursively.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;aws &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --endpoint-url&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;http://localhost:9000 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3 cp &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3://backups ./ &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --recursive
&lt;/span&gt;download: s3://backups/index to ./index                           
download: s3://backups/1.tar to ./1.tar                         
download: s3://backups/2.tar to ./2.tar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;alternative---restic&#34;&gt;Alternative - restic&lt;/h3&gt;
&lt;p&gt;In the search of a better UX for performing these incremental backups, I stumbled upon &lt;a href=&#34;https://github.com/restic/restic&#34;&gt;restic&lt;/a&gt;, a backup program in Go that takes care of sending the backups to a remote location and presents a delightful view of the snapshots that have been taken. Besides that, it also takes care of encrypting the contents and performing integrity checks, pretty cool.&lt;/p&gt;
&lt;p&gt;To install it on macOS you can go to the &lt;a href=&#34;https://github.com/restic/restic/releases&#34;&gt;restic/releases&lt;/a&gt; GitHub page and take the latest release (in my case, version 0.8.0) and then fetch the &lt;code&gt;.bz2&lt;/code&gt; file, decompress it and put in your &lt;code&gt;$PATH&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Fetch the .bz2 file with some options:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --show-error  will fail with error messages&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               if something goes wrong&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --remote-name instructs `curl` to save the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               file with the name it receives&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               from the remote&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# --location    follows redirects if there are&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               any&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --show-error &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --remote-name &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --location &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        https://github.com/restic/restic/releases/download/v0.8.0/restic_0.8.0_darwin_amd64.bz2

&lt;span class=&#34;c1&#34;&gt;# Decompress the file&lt;/span&gt;
bzip2 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --decompress &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ./restic_0.8.0_darwin_amd64.bz2

&lt;span class=&#34;c1&#34;&gt;# Move it to somewhere in your $PATH&lt;/span&gt;
sudo mv ./restic_0.8.0_darwin_amd64 /usr/local/bin/restic

&lt;span class=&#34;c1&#34;&gt;# Modify the permission bits (make it executable)&lt;/span&gt;
sudo chmod +x /usr/local/bin/restic

&lt;span class=&#34;c1&#34;&gt;# Check if it worked&lt;/span&gt;
restic --help
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having &lt;code&gt;restic&lt;/code&gt; set up we can perform a local snapshot as we performed before with &lt;code&gt;gtar&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a snapshots directory that will&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# hold the repository structure that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# restic uses to keep track of the changes&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and store the snapshotted content.&lt;/span&gt;
mkdir snapshots

&lt;span class=&#34;c1&#34;&gt;# Create a rootfs that will contain the data&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we plan to backup.&lt;/span&gt;
mkdir rootfs
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; rootfs/1.txt

        tree
        .
        ├── rootfs
        │   └── 1.txt
        └── snapshots


&lt;span class=&#34;c1&#34;&gt;# initialize the restic repository at `./snapshots`&lt;/span&gt;
restic init --repo ./snapshots 

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; new backend: 
        enter password again: 
        created restic backend 100efe3e68 at ./snapshots


&lt;span class=&#34;c1&#34;&gt;# check how the filesystem looks like after &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the initialization&lt;/span&gt;
tree
        .
        ├── rootfs
        │   └── 1.txt
        └── snapshots
            ├── config
            ├── data
            │   ├── &lt;span class=&#34;m&#34;&gt;00&lt;/span&gt;
            │   ├── &lt;span class=&#34;m&#34;&gt;01&lt;/span&gt;
            ...
            │   └── ff
            ├── index
            ├── keys
            │   └── 04b12ce19886a5d25...
            ├── locks
            └── snapshots

&lt;span class=&#34;c1&#34;&gt;# Perform our first snapshot of `rootfs`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# saving it in our repository that we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# initialized before.&lt;/span&gt;
restic --repo ./snapshots backup ./rootfs 

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; repository: 
        password is correct
        scan &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;./rootfs&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        scanned &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; files in 0:00
        &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;0:00&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 100.00%  0B/s  2B / 2B  &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; / &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; items  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; errors  ETA 0:00 
        duration: 0:00, 0.00MiB/s
        snapshot 9171fe56 saved


&lt;span class=&#34;c1&#34;&gt;# With the snapshot creation succeeded, let&amp;#39;s&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# check how the snapshots dir changed.&lt;/span&gt;
tree
        .
        ├── rootfs
        │   └── 1.txt
        └── snapshots
            ├── config
            ├── data
            │   ├── &lt;span class=&#34;m&#34;&gt;00&lt;/span&gt;
            ...
            │   ├── &lt;span class=&#34;m&#34;&gt;06&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;# some new stuff&lt;/span&gt;
            │   │   └── 0623cae88fefc31f07c09a11e8743b9eb94877883d458a6bcc2ec8a870bccf37
            ...
            ├── index           &lt;span class=&#34;c1&#34;&gt;# index dir has some content&lt;/span&gt;
            │   └── 89cbbfae048c49f7abbaa5ac929971550537eb97195039f0a70220890b08d259
            ...
            ...
            └── snapshots       &lt;span class=&#34;c1&#34;&gt;# snapshot!&lt;/span&gt;
                └── 9171fe56882a6ac7d4cc8836ec096dc761698dd2d47bfe8b0f9a6b82c061b7dc


&lt;span class=&#34;c1&#34;&gt;# Having the snapshot created we can&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# now create a `restored` directory where&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we&amp;#39;ll put the results of the restoration&lt;/span&gt;
mkdir restored

&lt;span class=&#34;c1&#34;&gt;# Perform the restoration by pointing restic&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at the snapshots directory and a target&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# directory that will receive the restored files.&lt;/span&gt;
restic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --repo ./snapshots &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        restore &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --target ./restored &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        latest

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; repository: 
        password is correct
        restoring &amp;lt;Snapshot 9171fe56 of &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;./rootfs&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; to ./restored


&lt;span class=&#34;c1&#34;&gt;# Go to the `restored` directory ad check if it worked&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; restored 
tree
        .
        └── rootfs
            └── 1.txt

&lt;span class=&#34;c1&#34;&gt;# We can also check what are the files in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a given snapshot as well as list all the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# snapshots we&amp;#39;ve taken so far.&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Let&amp;#39;s first list the snapshots&lt;/span&gt;
restic --repo ./snapshots snapshots

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; repository:
        password is correct
        ID        Date                 Host             Tags        Directory
        ----------------------------------------------------------------------
        9171fe56  2017-12-01 09:17:51  cirocosta.local              ./rootfs
        ----------------------------------------------------------------------
        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; snapshots

&lt;span class=&#34;c1&#34;&gt;# With the ID of the snapshot we can then&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# inspect the contents of the snapshot&lt;/span&gt;
restic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --repo ./snapshots &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        ls 9171fe56

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; repository:
        password is correct
        snapshot 9171fe56 of &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;:
        /rootfs
        /rootfs/1.txt

&lt;span class=&#34;c1&#34;&gt;# Now, what if we create a new file, snapshot&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it and then check the contents?&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Create a new file:&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt; &amp;gt; ./rootfs/2.txt

&lt;span class=&#34;c1&#34;&gt;# Take the new snapshot&lt;/span&gt;
restic --repo ./snapshots backup ./rootfs
        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; repository: 
        password is correct
        using parent snapshot 9171fe56
        scan &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;./rootfs&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        scanned &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; files in 0:00
        &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;0:00&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 100.00%  0B/s  4B / 4B  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; / &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; items  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; errors  ETA 0:00 
        duration: 0:00, 0.00MiB/s
        snapshot 3b5e8701 saved


&lt;span class=&#34;c1&#34;&gt;# Look at the snapshots that we created&lt;/span&gt;
restic --repo ./snapshots snapshots      
        ID        Date                 Host             Tags        Directory
        ----------------------------------------------------------------------
        9171fe56  2017-12-01 09:17:51  cirocosta.local              /tmp/cc/rootfs
        3b5e8701  2017-12-01 10:38:12  cirocosta.local              /tmp/cc/rootfs
        ----------------------------------------------------------------------
        &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; snapshots


&lt;span class=&#34;c1&#34;&gt;# Check the state of the latest snapshot&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (we `latest` is an alias for the last snapshot)&lt;/span&gt;
restic --repo ./snapshots ls latest      
        /rootfs
        /rootfs/1.txt
        /rootfs/2.txt


&lt;span class=&#34;c1&#34;&gt;# Interesting. Looking at the latest snapshot&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# reveals all the files, not only the addition&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of `2` - it shows us the complete representation&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of the final state.&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# If we look at the first snapshot though,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# then it shows only the final state up to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that point in time.&lt;/span&gt;
 restic --repo ./snapshots ls 9171fe56
        /rootfs
        /rootfs/1.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works! We have our files there.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s important to note that right now &lt;code&gt;restic&lt;/code&gt; does not have support for compression but it performs deduplication across the backups and the backups are all incremental.&lt;/p&gt;
&lt;p&gt;As it already has S3 support we can test it against minio:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# run the minio container just like before&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --publish 9000:9000 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name minio &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;s1&#34;&gt;&amp;#39;MINIO_ACCESS_KEY=accesskey&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --env &lt;span class=&#34;s1&#34;&gt;&amp;#39;MINIO_SECRET_KEY=secretkey&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        minio/minio &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        server /data


&lt;span class=&#34;c1&#34;&gt;# Initialize the S3 (minio) repository passing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the AWS credentials as environment variables&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and the repository pointing to our local minio&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instance&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;accesskey
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;secretkey
restic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --repo s3:http://localhost:9000/restic-test &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        init

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; new backend: 
        enter password again: 
        created restic backend 0871674e7e at s3:http://localhost:9000/restic-test


&lt;span class=&#34;c1&#34;&gt;# now, perform the snapshot:&lt;/span&gt;
restic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --repo s3:http://localhost:9000/restic-test &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        backup ./rootfs 

        enter password &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; repository: 
        password is correct
        scan &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;/tmp/cc/rootfs&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        scanned &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; files in 0:00
        &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;0:00&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 100.00%  0B/s  4B / 4B  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; / &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; items  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; errors  ETA 0:00 
        duration: 0:00, 0.00MiB/s
        snapshot e870fc54 saved


&lt;span class=&#34;c1&#34;&gt;# check that restic created the contents there &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in S3 (minio):&lt;/span&gt;
aws &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --endpoint-url&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;http://localhost:9000 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3 ls --recursive &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        s3://restic-test

        2017-12-01 10:48:41        &lt;span class=&#34;m&#34;&gt;155&lt;/span&gt; config
        2017-12-01 10:49:01        &lt;span class=&#34;m&#34;&gt;178&lt;/span&gt; data/25/25fe4bc29169f29...
        2017-12-01 10:49:01       &lt;span class=&#34;m&#34;&gt;1312&lt;/span&gt; data/5b/5b525003c0450a4...
        2017-12-01 10:49:01        &lt;span class=&#34;m&#34;&gt;661&lt;/span&gt; index/e691cc0bd3ebc2e9c...
        2017-12-01 10:48:41        &lt;span class=&#34;m&#34;&gt;460&lt;/span&gt; keys/50a8c58f10d1c4ae1d...
        2017-12-01 10:49:01        &lt;span class=&#34;m&#34;&gt;247&lt;/span&gt; snapshots/e870fc54bb482...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I was very happy knowing that there&amp;rsquo;s an easy way of creating these incremental snapshots using standard Linux utilities. For sure there are better ways (or more modern at least) but this one described in the article seems to be pretty much enough for various cases.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Restic&lt;/code&gt; reveals to be pretty good for my use case (performing some snapshots and having them sent directly to S3) but it has some limitations like not having compression. As I never used it very extensively, that&amp;rsquo;s the biggest one for me  (ps.: if you want to see a comparison of Restic against some other tools, make sure you check &lt;a href=&#34;https://github.com/gilbertchen/benchmarking&#34;&gt;https://github.com/gilbertchen/benchmarking&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Some resources used for this article are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/tar/manual/tar.html#SEC97&#34;&gt;GNU Tar Manual - Performing incremental dumps&lt;/a&gt; - great section in the &lt;code&gt;man&lt;/code&gt; pages of &lt;code&gt;tar&lt;/code&gt; on how to perform incremental backups;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Homebrew/homebrew-core/tree/master/Formula/gnu-tar.rb&#34;&gt;Source of the GNU-TAR homebrew formula&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.minio.io/&#34;&gt;minio&lt;/a&gt; - the S3-compatible storage used in this article so simulate S3;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/restic/restic&#34;&gt;github.com/restic/restic&lt;/a&gt; - the backup tool to use in comparison with the TAR method.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What about you? Have you been performing incremental backups? What are you using to do it? Please let me know, I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter and would really like to know more about!&lt;/p&gt;
&lt;p&gt;Have a good one,&lt;/p&gt;
&lt;p&gt;Ciro.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 02 Dec 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/incremental-backup-linux/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/incremental-backup-linux/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Updating the Docker version in Travis-CI</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;for some good time, Travis has been allowing anyone to run Docker in their infrastructure - see &lt;a href=&#34;https://docs.travis-ci.com/user/docker/&#34;&gt;Using Docker in Builds&lt;/a&gt; - be it on a paid or free plan.&lt;/p&gt;
&lt;p&gt;Something that is not outlined there is that it&amp;rsquo;s very common to not have the latest version of Docker running in your builds. For some people, that&amp;rsquo;s a problem.&lt;/p&gt;
&lt;h3 id=&#34;updating-the-version&#34;&gt;Updating the version&lt;/h3&gt;
&lt;p&gt;To update the version we must, before using Docker in the build, set a script that will fetch Docker from the official &lt;code&gt;apt&lt;/code&gt; repository and perform the upgrade.&lt;/p&gt;
&lt;p&gt;This script can either be inlined in the &lt;code&gt;.travis.yaml&lt;/code&gt; definition or be called via an extra file.&lt;/p&gt;
&lt;p&gt;Personally, I prefer an extra file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;required&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;generic&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;before_install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;./.travis/main.sh&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;docker version&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;notifications&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the script looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Performs any provisioning needed for a clean build.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This script is meant to be used either directly&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as a `before_install` step such that the next step&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the Travis build have the environment properly &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# setup.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The script is also handy for debugging - SSH into&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the machine and then call `./.travis/main.sh` to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# have all dependencies set.&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  setup_dependencies

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;INFO:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Done! Finished setting up Travis-CI machine.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Takes care of updating any dependencies that the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# machine needs.&lt;/span&gt;
setup_dependencies&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;INFO:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Setting up dependencies.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;

  sudo apt update -y
  sudo apt install --only-upgrade docker-ce -y

  docker info
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let it run and Docker should be updated.&lt;/p&gt;
&lt;p&gt;Looking at &lt;code&gt;build system information&lt;/code&gt; we can see which version Travis used as the Docker version by default:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker version
Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:42:38 2017
 OS/Arch:      linux/amd64
Server:
 Version:      17.09.0-ce
 API version:  1.32 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:41:20 2017
 OS/Arch:      linux/amd64
 Experimental: false
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, verify that our provisioning step got executed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ ./.travis/main.sh
INFO:
  Setting up dependencies.
  
Ign:1 http://us-central1.gce.archive.ubuntu.com/ubuntu trusty InRelease
Hit:2 http://us-central1.gce.archive.ubuntu.com/ubuntu trusty-updates InRelease
....
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And see that we end up with the desired version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ docker version
Client:
 Version:	18.02.0-ce
 API version:	1.36
 Go version:	go1.9.3
 Git commit:	fc4de44
 Built:	Wed Feb  &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; 21:16:47 &lt;span class=&#34;m&#34;&gt;2018&lt;/span&gt;
 OS/Arch:	linux/amd64
 Experimental:	&lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;
 Orchestrator:	swarm
Server:
 Engine:
  Version:	18.02.0-ce
  API version:	1.36 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;minimum version 1.12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
  Go version:	go1.9.3
  Git commit:	fc4de44
  Built:	Wed Feb  &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; 21:15:21 &lt;span class=&#34;m&#34;&gt;2018&lt;/span&gt;
  OS/Arch:	linux/amd64
  Experimental:	&lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In Travis-CI it&amp;rsquo;s almost guaranteed that you&amp;rsquo;ll not have, by default, the latest version of Docker. Nevertheless, it&amp;rsquo;s very easy to update it: just &lt;code&gt;apt update &amp;amp;&amp;amp; apt upgrade &amp;lt;docker&amp;gt;&lt;/code&gt; and you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;p&gt;Just in case you need some guidance, here&amp;rsquo;s an example repository I set up to make this even clearer: &lt;a href=&#34;https://github.com/cirocosta/sample-travis-docker-update&#34;&gt;cirocosta/sample-travis-docker-update&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about the execution, check it out: &lt;a href=&#34;https://travis-ci.org/cirocosta/sample-travis-docker-update&#34;&gt;https://travis-ci.org/cirocosta/sample-travis-docker-update&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Having any questions, make sure you ping me on Twitter! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; there.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 28 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/update-travis-ci-docker/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/update-travis-ci-docker/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Forcing (from inside) the redirection of all outputs of a bash script to a file</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;this is a quick tip that might save you some time if you need to have all the output of a script going out to a file and you don&amp;rsquo;t have control over the execution of it.&lt;/p&gt;
&lt;p&gt;Here I go through two possible ways to tackle the problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using &lt;code&gt;exec&lt;/code&gt; to redirect the &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt; to a specific file;&lt;/li&gt;
&lt;li&gt;using a subprocess and controlling its &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both achieve the same, but are slightly different.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#when-do-you-need-this&#34;&gt;When do you need this?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-exec-to-redirect-stdout-and-stderr&#34;&gt;Using exec to redirect stdout and stderr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#redirecting-subprocess-stdout-and-stderr&#34;&gt;Redirecting subprocess stdout and stderr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;when-do-you-need-this&#34;&gt;When do you need this?&lt;/h3&gt;
&lt;p&gt;The typical case for needing to ensure (from within the script) that the logs end up in a file is when you can&amp;rsquo;t control a shell execution of your script (if you had, then you could simply forward both standard out and standard error to a file without modifying the script).&lt;/p&gt;
&lt;p&gt;Note.: if you&amp;rsquo;re using AWS EC2 AutoScaling groups with a custom script for initializing your instance, you don&amp;rsquo;t necessarily need to use this to get your logs sent to a file - you can already grab them at &lt;code&gt;/var/log/cloud-init-output.log&lt;/code&gt; even if you don&amp;rsquo;t use &lt;code&gt;cloud-init&lt;/code&gt; -, unless you want to change the default file.&lt;/p&gt;
&lt;h3 id=&#34;using-exec-to-redirect-stdout-and-stderr&#34;&gt;Using exec to redirect stdout and stderr&lt;/h3&gt;
&lt;p&gt;The whole thing is rather simple, although it relies on some bash details that most people don&amp;rsquo;t know:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;LOG_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/log/script.log&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Create the destination log file that we can&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# inspect later if something goes wrong with the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# initialization.&lt;/span&gt;
sudo touch &lt;span class=&#34;nv&#34;&gt;$LOG_FILE&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Make sure that the file is accessible by the user&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we want to give permissions to read later&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (maybe this script is executed by some other user)&lt;/span&gt;
sudo chown ubuntu &lt;span class=&#34;nv&#34;&gt;$LOG_FILE&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Open standard out at `$LOG_FILE` for write.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This has the effect &lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; 1&amp;gt;&lt;span class=&#34;nv&#34;&gt;$LOG_FILE&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Redirect standard error to standard out such that &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# standard error ends up going to wherever standard&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# out goes (the file).&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The whole deal is about making use of &lt;code&gt;exec&lt;/code&gt;, which is document in &lt;code&gt;man bash&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      exec [-cl] [-a name] [command [arguments]]
              If command is specified, it replaces the shell.  
              No  new  process  is  created.
              The  arguments  become the arguments to command.  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, nothing fancy, just like a &lt;code&gt;execvp&lt;/code&gt; syscall would do - replace the image of the current process and initialize the program we pass.&lt;/p&gt;
&lt;p&gt;The catch is in the end of the description of the command though:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              ...
              If command is not specified, any redirections  
              take  effect in the current shell, and the return 
              status is 0.  If there is a redirection error, the 
              return status is 1.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It means that by making use of &lt;code&gt;exec&lt;/code&gt; without a program, we can affect the redirection of the current process (the one executing our commands).&lt;/p&gt;
&lt;p&gt;To understand that better, I started pausing the script at several break points to see what&amp;rsquo;s going on under the hood from the perspective of &lt;code&gt;/proc/$PROC/fd&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 70rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/bash-script-redirections.svg&#34;
       alt=&#34;Illustration of the points in the script where we paused to check the proc filesystem &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;At the first moment (I), nothing fancy - the standard redirections to the pseudo terminal are set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ls -lah /proc/&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pgrep script.sh&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/fd
&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;255&lt;/span&gt; -&amp;gt; /tmp/script.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At the second momement though (II), the file has already been open and the standard out got redirected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ls -lah /proc/&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pgrep script.sh&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/fd
&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/1                 &lt;span class=&#34;c1&#34;&gt;# stdin, untouched&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /var/log/script.log        &lt;span class=&#34;c1&#34;&gt;# redirected!&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /dev/pts/1                 &lt;span class=&#34;c1&#34;&gt;# not redirected to the log file&lt;/span&gt;
                                &lt;span class=&#34;c1&#34;&gt;# yet&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;255&lt;/span&gt; -&amp;gt; /tmp/script.sh           
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At the third moment (III - final of the script), as expected, we have everybody redirecting to the log file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/1                 &lt;span class=&#34;c1&#34;&gt;# stdin, untouched&lt;/span&gt;
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /var/log/script.log
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /var/log/script.log
&lt;span class=&#34;m&#34;&gt;255&lt;/span&gt; -&amp;gt; /tmp/script.sh           &lt;span class=&#34;c1&#34;&gt;# other file descriptors - untouched&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re extra curious, take a look at the use of syscalls during the script execution using &lt;code&gt;strace&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Open the log file with 666 permissions, create&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# if it doesn&amp;#39;t exist (`O_CREAT`), start writing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the file from the very beginning if it already&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# exists (O_TRUNC) and open it as write only &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (`O_WRONLY`).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# With the succesfull `openat`, it tells us that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can access it via the file descriptor `3`.&lt;/span&gt;
openat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;AT_FDCWD, 
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/log/script.log&amp;#34;&lt;/span&gt;, 
        O_WRONLY&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_CREAT&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;O_TRUNC, 
        0666&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
...

&lt;span class=&#34;c1&#34;&gt;# dup2 duplicates a file descriptor (first &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# argument) creating a copy of it and giving&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it the number specified in the second &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# argument (1, in this case). &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This comes from `1&amp;gt;$LOG_FILE` where `$LOG_FILE`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is being pointed to as the file descriptor `3`.&lt;/span&gt;
dup2&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3, 1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                              &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Close the first file descriptor associated&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# with out log files as we don&amp;#39;t use it directly&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the rest of the application - it was only&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# openned to be duplicated later.&lt;/span&gt;
close&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                                &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Duplicate the stdout to also be used as the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# stderr (`2&amp;gt;&amp;amp;1`).&lt;/span&gt;
dup2&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1, 2&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                              &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;redirecting-subprocess-stdout-and-stderr&#34;&gt;Redirecting subprocess stdout and stderr&lt;/h3&gt;
&lt;p&gt;Using bash, any command (or series of them) inside a parenthesis group (&lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt;) gets executed in a subshell (a copy of the original shell process but in a &lt;code&gt;fork&lt;/code&gt;ed one).&lt;/p&gt;
&lt;p&gt;From the bash man pages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;       A  compound  &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; is one of the following.  
       In most cases a list in a command&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;s description
       may be separated from the rest of the &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; by 
       one or more newlines, and may be followed  by
       a newline in place of a semicolon.

&lt;span class=&#34;hl&#34;&gt; &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;list&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; list  is  executed in a subshell environment.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s take an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

say_hello&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello! pid=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$BASHPID&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Calls `say hello` from the main&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process&lt;/span&gt;
say_hello

&lt;span class=&#34;c1&#34;&gt;# Creates a subshell (in a sub process)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and then calls `say_hello`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By sleeping we can look at `pstree` and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# figure out how the process tree looks&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# like (the outer process will wait this&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# inner process)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;
  say_hello
  sleep &lt;span class=&#34;m&#34;&gt;3600&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The execution leads to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the script and leave it running in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# background&lt;/span&gt;
./script.sh &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
Hello! &lt;span class=&#34;nv&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;20127&lt;/span&gt;
Hello! &lt;span class=&#34;nv&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;20128&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Check out the process tree of the recently&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# executed script (`./script.sh`)&lt;/span&gt;
pstree -p &lt;span class=&#34;nv&#34;&gt;$!&lt;/span&gt;
script.sh&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;20127&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
        ───script.sh&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;20128&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
                ───sleep&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;20129&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being a compound command, IO redirection can be properly done:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;LOG_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/log/script.log&amp;#34;&lt;/span&gt;

say_hello&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello! pid=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$BASHPID&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Calls `say hello` from the main&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Logs the hello message to the process&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# stdout as no redirection has been&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# performed at this point.&lt;/span&gt;
say_hello

&lt;span class=&#34;c1&#34;&gt;# Creates a subshell (in a sub process)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and then calls `say_hello`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The subshell that gets created has both&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# stdout and stderr redirected to the LOG&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# file `/var/log/script.log`.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;
  say_hello
  sleep &lt;span class=&#34;m&#34;&gt;3600&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&amp;gt;&lt;span class=&#34;nv&#34;&gt;$LOG_FILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Execute the script and then inspect &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/fd&lt;/code&gt; and you should see the redirection taking place:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Look at the file descriptors of the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# parent process&lt;/span&gt;
ls -lah /proc/20370/fd
&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;255&lt;/span&gt; -&amp;gt; /tmp/script.sh

&lt;span class=&#34;c1&#34;&gt;# Look at the file descriptors of the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# child process (subshell) that got&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the redirection:&lt;/span&gt;
ls -lah /proc/20371/fd
&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -&amp;gt; /dev/pts/1
&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -&amp;gt; /var/log/script.log
&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -&amp;gt; /var/log/script.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Maybe you&amp;rsquo;ll never need to do this kind of thing, but now you know how it works haha.&lt;/p&gt;
&lt;p&gt;If you have any questions or just want to chat about something, reach me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twiter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Mon, 27 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/redirect-all-outputs-of-a-bash-script-to-a-file/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/redirect-all-outputs-of-a-bash-script-to-a-file/</guid>

                                
                                        <category>shell</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Inspecting Docker images without pulling them</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;depending on what you&amp;rsquo;re trying to build it might happen that part of it involves inspecting a Docker image from a registry but you can&amp;rsquo;t afford to pull it.&lt;/p&gt;
&lt;p&gt;It turns out that &lt;a href=&#34;https://docs.docker.com/registry/spec/api/&#34;&gt;there&amp;rsquo;s an API&lt;/a&gt; that allows you to perform exactly that - be it DockerHub or a private registry.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Docker Registry HTTP API is the protocol to facilitate distribution of images to the docker engine. It interacts with instances of the docker registry, which is a service to manage information about docker images and enable their distribution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;testing-it-locally&#34;&gt;Testing it locally&lt;/h3&gt;
&lt;p&gt;The first step to test it locally is raising a registry from the &lt;a href=&#34;https://hub.docker.com/_/registry/&#34;&gt;library/registry&lt;/a&gt; image.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run a container named `registry` in the background.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Map the internal port 5000 to the host on port 5000.&lt;/span&gt;
docker run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --detach &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --name registry &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --publish &lt;span class=&#34;s1&#34;&gt;&amp;#39;5000:5000&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        registry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check that it&amp;rsquo;s definitely working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Fetch an image from an external registry.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Because we&amp;#39;re not explicitly specifying a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# registry address it&amp;#39;s going to use dockerhub&amp;#39;s &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# address. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# For instance, we could use registry-1.docker.io/library/registry&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# instead of just `registry` (library repository is also&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# another default value).&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;docker pull busybox
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Tag the image we just fetched to now be named&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `localhost:5000/test`.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;docker tag busybox localhost:5000/test
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Push the image. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Because we have explicitly specified a registry&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the name of the image, it&amp;#39;ll be pushed to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# registry at the given address (localhost:5000)&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;docker push localhost:5000/test
&lt;/span&gt;
The push refers to repository &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;localhost:5000/busybox&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
0271b8eebde3: Pushed 
latest: digest: sha256:91ef6c1c52b166be02645b8efee30d1ee65362024f7da41c404681561734c465 size: &lt;span class=&#34;m&#34;&gt;527&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having the local registry working, we can move to the script that inspects images right from the registry metadata. The following script contains all that it takes to retrieve it and relies only on two dependencies: &lt;code&gt;bash&lt;/code&gt; and &lt;a href=&#34;https://stedolan.github.io/jq/&#34;&gt;jq&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;c1&#34;&gt;# Address of the registry that we&amp;#39;ll be &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# performing the inspections against.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# This is necessary as the arguments we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# supply to the API calls don&amp;#39;t include &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# such address (the address is used in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# url itself).&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;REGISTRY_ADDRESS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;REGISTRY_ADDRESS&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;:-&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;localhost&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;5000&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Entry point of the script.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# If makes sure that the user supplied the right&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# amount of arguments (image_name and image_tag)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and then performs the main workflow:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       1.      retrieve the image digest&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       2.      retrieve the configuration for&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               that digest.&lt;/span&gt;
main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  check_args &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;digest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;get_digest &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;

  get_image_configuration &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$digest&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Makes sure that we provided (from the cli) &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# enough arguments.&lt;/span&gt;
check_args&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; 2&lt;span class=&#34;o&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Error:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Two arguments must be provided - &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; provided.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Usage:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      ./get-image-config.sh &amp;lt;image&amp;gt; &amp;lt;tag&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Aborting.&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Retrieves the digest of a specific image tag,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that is, the address of the uppermost of a specific &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# tag of an image (see more at &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# https://docs.docker.com/registry/spec/api/#content-digests).&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# You can know more about the endpoint used at&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# https://docs.docker.com/registry/spec/api/#pulling-an-image-manifest&lt;/span&gt;
get_digest&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving image digest.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TAG:    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Accept: application/vnd.docker.distribution.manifest.v2+json&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$REGISTRY_ADDRESS&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/v2/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/manifests/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
    jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.config.digest&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Retrieves the image configuration from a given&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# digest.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# See more about the endpoint at:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# https://docs.docker.com/registry/spec/api/#pulling-a-layer&lt;/span&gt;
get_image_configuration&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;digest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving Image Configuration.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    DIGEST: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --location &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$REGISTRY_ADDRESS&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/v2/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/blobs/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
    jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.container_config&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Run the entry point with the CLI arguments&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# as a list of words as supplied.&lt;/span&gt;
main &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;ps.: It&amp;rsquo;s important to note that the API calls need to specify the type of content that it accepts (&lt;code&gt;application/vnd.docker.distribution.manifest.v2+json&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s now check if it&amp;rsquo;s working for real:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;chmod +x ./get-image-config.sh
&lt;span class=&#34;hl&#34;&gt;./get-image-config.sh &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; latest
&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hostname&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;3fbce8bb8947&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Domainname&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
...
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Env&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Cmd&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;/bin/sh&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;-c&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;#(nop) &amp;#34;&lt;/span&gt;,
...
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;OnBuild&amp;#34;&lt;/span&gt;: null,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Labels&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool, it indeed works!&lt;/p&gt;
&lt;p&gt;While that does the job for registries that require no authentication, it&amp;rsquo;s not suitable for DockerHub.  When checking a public image there, we need to perform an extra step before getting the digest of an image - retrieve a token. With such token in hand, we can then inspect either public or private images.&lt;/p&gt;
&lt;p&gt;Going back to scripting, let&amp;rsquo;s create a different one to deal with this case - call it &lt;code&gt;get-public-image-config.sh&lt;/code&gt; (this is for brevity sake, using some other programming language you could place some conditionals and detect each case).&lt;/p&gt;
&lt;p&gt;The additional code can be placed in a method called &lt;code&gt;get_token&lt;/code&gt; which only takes &lt;code&gt;image&lt;/code&gt; as an argument:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Retrieves a token that grants access to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# registry.docker.io (dockerhub registry) access&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to pull a specific image.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# note.:        the token that we retrieve is valid only&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               for that image.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# note.:        we get the token from `auth.docker.io` and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               not `registry.docker.io`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# usage.:       get_token &amp;#34;library/nginx&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
get_token&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving Docker Hub token.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://auth.docker.io/token?scope=repository:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;:pull&amp;amp;service=registry.docker.io&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.token&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the token in hands it&amp;rsquo;s just a matter of making use of it on the other calls.&lt;/p&gt;
&lt;p&gt;If we were targetting private images we&amp;rsquo;d modify &lt;code&gt;get_token&lt;/code&gt; a little bit: on the call to get the token from &lt;code&gt;auth.docker.io&lt;/code&gt; we&amp;rsquo;d need to do it with a DockerHub username and password pair (without authentication we can only have access to public images). To do so, specify in that call an authorization header (&lt;code&gt;--user&lt;/code&gt; flag in &lt;code&gt;curl&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Retrieves a token that grants access to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# a private image named `image` on registry.docker.io.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# note.:        the user identified by `DOCKER_USERNAME`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               and `DOCKER_PASSWORD` must have access&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               to the image.&lt;/span&gt;
get_token&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving Docker Hub token.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;
    --u &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DOCKER_USERNAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DOCKER_PASSWORD&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://auth.docker.io/token?scope=repository:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;:pull&amp;amp;service=registry.docker.io&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.token&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the token in hards we could now retrieve the digest of a given image and tag (pay attention to the extra &lt;code&gt;Authorization: Bearer $token&lt;/code&gt; header that we added):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Retrieve the digest, now specifying in the header&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the token we just received.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# note.:        $token corresponds to the token&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               that we received from the `get_token`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               call.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# note.:        $image must be the full image name without&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               the registry part, e.g.: `nginx` should&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#               be named `library/nginx`.&lt;/span&gt;
get_digest&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$3&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving image digest.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TAG:    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TOKEN:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Accept: application/vnd.docker.distribution.manifest.v2+json&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://registry-1.docker.io/v2/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/manifests/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.config.digest&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that we can have a full script that retrieves public images from Dockerhub (check how in &lt;code&gt;main&lt;/code&gt; we first retrieve a token, then we pass that token to the following methods):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  check_args &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;get_token &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;digest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;get_digest &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;

  get_image_configuration &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$digest&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

get_image_configuration&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;digest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$3&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving Image Configuration.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TOKEN:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    DIGEST: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --location &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://registry-1.docker.io/v2/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/blobs/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.container_config&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

get_token&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving Docker Hub token.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://auth.docker.io/token?scope=repository:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;:pull&amp;amp;service=registry.docker.io&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.token&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Retrieve the digest, now specifying in the header&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that we have a token (so we can pe...&lt;/span&gt;
get_digest&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$3&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving image digest.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TAG:    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TOKEN:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Accept: application/vnd.docker.distribution.manifest.v2+json&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://registry-1.docker.io/v2/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/manifests/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.config.digest&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

check_args&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; 2&lt;span class=&#34;o&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Error:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Two arguments must be provided - &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; provided.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Usage:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      ./get-image-config.sh &amp;lt;image&amp;gt; &amp;lt;tag&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Aborting.&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Note.: again, you must add the full name of the image (official images use the &lt;code&gt;library&lt;/code&gt; repository so &lt;code&gt;nginx&lt;/code&gt; should be referred as &lt;code&gt;library/nginx&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To make sure that it works, run it against an image like &lt;a href=&#34;http://hub.docker.com/_/nginx&#34;&gt;nginx&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# because `nginx` comes from the set of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# official images we must prepend `library/`.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;./get-public-image-config.sh library/nginx latest
&lt;/span&gt;
Retrieving Docker Hub token.
    IMAGE: library/nginx
  
Retrieving image digest.
    IMAGE:  library/nginx
    TAG:    latest
    TOKEN:  eyJhbGciVFER...ZsNw
  
Retrieving Image Configuration.
    IMAGE:  library/nginx
    TOKEN:  eyJhb...ZsNw
    DIGEST: sha256:9e7424e5dbaeb9b28fea44d8c75b41ac6104989b49b2464b7cbbed16ceeccfc3
  
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hostname&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;22e255475f18&amp;#34;&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Domainname&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
  ...
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;Labels&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;maintainer&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;NGINX Docker Maintainers &amp;lt;docker-maint@nginx.com&amp;gt;&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;StopSignal&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;SIGTERM&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&#34;extra---old-images&#34;&gt;Extra - old images&lt;/h4&gt;
&lt;p&gt;If you try to retrieve an image that is not very new (say, that has some 2 years) you&amp;rsquo;ll notice that the script I posted above might not work.&lt;/p&gt;
&lt;p&gt;The reason for that is that images that have been pushed to the docker registry a long time ago won&amp;rsquo;t use the second version of the V2 manifest. However, they still present the image configuration even though in a regular string.&lt;/p&gt;
&lt;p&gt;Bellow is a script that deals with that case:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  check_args &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;get_token &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;old_config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;get_old_config &lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;

  get_image_configuration &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$old_config&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

get_image_configuration &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;old_config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$old_config&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.history[0].v1Compatibility&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.container_config&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

get_token&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving Docker Hub token.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://auth.docker.io/token?scope=repository:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;:pull&amp;amp;service=registry.docker.io&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.token&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

get_old_config&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$3&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Retrieving image digest.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    IMAGE:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TAG:    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    TOKEN:  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt; &amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;

  curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --silent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Accept: application/vnd.docker.distribution.manifest.v2+json&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --header &lt;span class=&#34;s2&#34;&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://registry-1.docker.io/v2/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$image&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/manifests/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tag&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

check_args&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; 2&lt;span class=&#34;o&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Error:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Two arguments must be provided - &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; provided.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Usage:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      ./get-image-config.sh &amp;lt;image&amp;gt; &amp;lt;tag&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Aborting.&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re looking for the difference, look at &lt;code&gt;main&lt;/code&gt;. Essentially we abandon the idea of retrieving a &lt;code&gt;digest&lt;/code&gt; and simply pick the &amp;ldquo;old config&amp;rdquo;. From the old config, we look at the first blob in the list which represents the uppermost layer - the layer that contains all the info altogether. From there we parse that plain-text JSON and then get the config.&lt;/p&gt;
&lt;h3 id=&#34;update&#34;&gt;Update&lt;/h3&gt;
&lt;p&gt;From the feedbacks the article received, two alternatives (that you can use right now) appeared constantly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/GoogleCloudPlatform/container-diff&#34;&gt;github.com/GoogleCloudPlatform/container-diff&lt;/a&gt; - &lt;em&gt;Diff your Docker containers&lt;/em&gt; - it looks pretty interesting but even though you can specify &lt;code&gt;remote://&lt;/code&gt; to an image when analyzing it, it looks like it always pulls the entire image. Maybe I got something wrong?&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/projectatomic/skopeo&#34;&gt;github.com/projectatomic/skopeo&lt;/a&gt; - &lt;em&gt;&amp;ldquo;Work with remote images registries - retrieving information, images, signing content&amp;rdquo;&lt;/em&gt; - well, does exactly what it says! For the scope of retrieving image / repositories configuration before pulling them, totally worth it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By the way, if you wan&amp;rsquo;t to try Skopeo, building it from source is very easy on MacOS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# install gpgme&lt;/span&gt;
brew install gpgme

&lt;span class=&#34;c1&#34;&gt;# clone the repository to the golang-specific directory&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (make sure you have Go installed and GOPATH set &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# before).&lt;/span&gt;
git clone &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        https://github.com/projectatomic/skopeo &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;$GOPATH&lt;/span&gt;/src/github.com/projectatomic/skopeo

&lt;span class=&#34;c1&#34;&gt;# get into the repository you just clones&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$GOPATH&lt;/span&gt;/src/github.com/projectatomic/skopeo 

&lt;span class=&#34;c1&#34;&gt;# run the binary-local target &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (this is a regular `go build` with some&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# tags and flags set.&lt;/span&gt;
make binary-local

&lt;span class=&#34;c1&#34;&gt;# now you should have `skopeo` in the repository&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# directory&lt;/span&gt;
./skopeo --help

NAME:
   skopeo - Various operations with container images and container image registries

USAGE:
   skopeo &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;global options&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; options&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;arguments...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
   
VERSION:
   0.1.28-dev commit: 78b29a5c2f05b4026876728e7651bad31193216c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now inspecting an image or a repository from Dockerhub is one command away:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;./skopeo &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --override-os&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;linux &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        inspect docker://docker.io/fedora
&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker.io/library/fedora&amp;#34;&lt;/span&gt;,
    ...
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;Architecture&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;Os&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;Layers&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;sha256:a8ee583972c2295bb76704d4defe5116d5e4dd7ba3767aaa2cc8fcf71088ee06&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that here I&amp;rsquo;m specifying the &lt;code&gt;--override-os&lt;/code&gt; flag to the command. The reason is that otherwise it&amp;rsquo;ll try to inspect the image or repository filtering by digests marked with &lt;code&gt;OS=darwin&lt;/code&gt;.  If you&amp;rsquo;re using Linux you&amp;rsquo;d not need to use that flag.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Interacting with DockerHub or a private registry is not all that hard, it&amp;rsquo;s just not very documented. Having these scripts it becomes pretty easy to get it working on any language you want - just add some checks, parse the image names and you should be good to go.&lt;/p&gt;
&lt;p&gt;Here are the resources mentioned in the article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/registry/spec/api/#content-digests&#34;&gt;Docker Registry API - Content Digests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/registry/spec/api/#pulling-an-image-manifest&#34;&gt;Docker Registry API - Pulling an Image Manifest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/registry/spec/api/#pulling-a-layer&#34;&gt;Docker Registry API - Pulling a Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/cirocosta/17ea17be7ac11594cb0f290b0a3ac0d1&#34;&gt;Gist: all the scripts created here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please let me know if I got anything wrong and/or if there&amp;rsquo;s an easier way to do it.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 26 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/inspecting-docker-image-without-pull/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/inspecting-docker-image-without-pull/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Getting TLS certificates with Letsencrypt and HAProxy</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;with the upcoming release of HAProxy 1.8 (see the &lt;a href=&#34;https://www.haproxy.com/blog/whats-new-haproxy-1-8/&#34;&gt;blog post at haproxy.com&lt;/a&gt;) it&amp;rsquo;ll be possible to keep your stack behind the goodness of http2 without changing your code at all.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s pretty cool as you can have very perceptive differences under real-life scenarios. One thing to notice is that browsers only establish these connections if you&amp;rsquo;re HTTPS ready, and that means having TLS certificates in your load-balancer (or regular server).&lt;/p&gt;
&lt;p&gt;Here are my 2 cents on how you can have a fully functioning HAProxy set up with certificate generation via &lt;a href=&#34;https://letsencrypt.org/&#34;&gt;Letsencrypt&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;dependencies&#34;&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;There are a handful of dependencies that need to be in place: &lt;code&gt;certbot&lt;/code&gt;, &lt;code&gt;lua&lt;/code&gt;, &lt;code&gt;openssl-dev&lt;/code&gt;,&lt;code&gt;zlib-dev&lt;/code&gt;, &lt;code&gt;libpcre-dev&lt;/code&gt; and &lt;code&gt;haproxy&lt;/code&gt; itself. If you already have all of those set, just skip to the next session: &lt;a href=&#34;#haproxy-configuration&#34;&gt;HAProxy Configuration section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here I&amp;rsquo;m making use of Ubuntu zesty (17.04) so there might be some differences between what I document here and your OS specifics.&lt;/p&gt;
&lt;h4 id=&#34;certbot&#34;&gt;Certbot&lt;/h4&gt;
&lt;p&gt;Start by adding &lt;code&gt;certbot&lt;/code&gt;&amp;rsquo;s &lt;code&gt;apt&lt;/code&gt; repository:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;# after issuing the command press `enter` to accept
&lt;span class=&#34;hl&#34;&gt;sudo add-apt-repository ppa:certbot/certbot
&lt;/span&gt;
 This is the PPA for packages prepared by Debian Let&amp;#39;s Encrypt Team and backported for Ubuntu(s).
 More info: https://launchpad.net/~certbot/+archive/ubuntu/certbot
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keybox &amp;#39;/tmp/tmp028qrfr4/pubring.gpg&amp;#39; created
gpg: /tmp/tmp028qrfr4/trustdb.gpg: trustdb created
gpg: key 8C47BE8E75BCA694: public key &amp;#34;Launchpad PPA for certbot&amp;#34; imported
gpg: Total number processed: 1
gpg:               imported: 1
OK&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;then update:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;hl&#34;&gt;sudo apt update -y
&lt;/span&gt;
Hit:1 http://us-west-2.ec2.archive.ubuntu.com/ubuntu zesty InRelease
Get:2 http://us-west-2.ec2.archive.ubuntu.com/ubuntu zesty-updates InRelease [89.2 kB]  
Get:3 http://us-west-2.ec2.archive.ubuntu.com/ubuntu zesty-backports InRelease [89.2 kB]
Get:4 http://ppa.launchpad.net/certbot/certbot/ubuntu zesty InRelease [21.3 kB]         
Hit:5 http://security.ubuntu.com/ubuntu zesty-security InRelease        
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and now install the desired package, &lt;code&gt;python-certbot&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;hl&#34;&gt;sudo apt install -y python-certbot
&lt;/span&gt;
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  certbot dialog python-acme python-asn1crypto python-certifi python-chardet
  python-configargparse python-configobj python-cryptography python-dialog
...


certbot help

-------------------------------------------------------------

  certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...

Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. The most common SUBCOMMANDS and flags are:

...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once we have that we know that &lt;code&gt;certbot&lt;/code&gt; is ready to request certificates from Letsencrypt for us.&lt;/p&gt;
&lt;h4 id=&#34;haproxy&#34;&gt;HAProxy&lt;/h4&gt;
&lt;p&gt;Before installing HAProxy itself we need to get its dependencies right. HAProxy by itself can&amp;rsquo;t serve content from a directory like a static hosting web server would so to do that we must make use of &lt;a href=&#34;https://www.lua.org/&#34;&gt;lua&lt;/a&gt; which allows us to very easily extend HAProxy functionality. Then, the first dependency we&amp;rsquo;ll get is &lt;code&gt;lua&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# set the version of Lua that we want to install.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# is a variable that we can reference later.&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_VERSION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;5.3.3

&lt;span class=&#34;c1&#34;&gt;# install a development library that lua depends on&lt;/span&gt;
sudo apt install -y &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libreadline-dev

&lt;span class=&#34;c1&#34;&gt;# fetch lua&amp;#39;s source code for the version we want&lt;/span&gt;
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -SOL https://www.lua.org/ftp/lua-&lt;span class=&#34;nv&#34;&gt;$LUA_VERSION&lt;/span&gt;.tar.gz

&lt;span class=&#34;c1&#34;&gt;# create a directory to hold that source code&lt;/span&gt;
sudo mkdir &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -p /usr/src/lua 

&lt;span class=&#34;c1&#34;&gt;# extract the source code to the directory we want&lt;/span&gt;
sudo tar &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -xzf lua-&lt;span class=&#34;nv&#34;&gt;$LUA_VERSION&lt;/span&gt;.tar.gz &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -C /usr/src/lua --strip-components&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 

&lt;span class=&#34;c1&#34;&gt;# build Lua using a concurrency equivalent to the number&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of processors we have (and targetting Linux)&lt;/span&gt;
sudo make &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -C /usr/src/lua &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -j &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;getconf _NPROCESSORS_ONLN&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        linux 

&lt;span class=&#34;c1&#34;&gt;# install it so that it&amp;#39;s widely accessible&lt;/span&gt;
sudo make &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -C /usr/src/lua &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        install 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To proceed with the HAProxy installation we need to know where the lua headers and compiled library are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# search for the headers&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;find /usr/local/include -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*lua*&amp;#34;&lt;/span&gt;
&lt;/span&gt;/usr/local/include/lua.h
/usr/local/include/lualib.h
/usr/local/include/lua.hpp
/usr/local/include/luaconf.h

&lt;span class=&#34;c1&#34;&gt;# search for the lib&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;find /usr/local/lib -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*lua*&amp;#34;&lt;/span&gt;
&lt;/span&gt;/usr/local/lib/liblua.a
/usr/local/lib/lua&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The next dependencies can all be fetched from &lt;code&gt;apt&lt;/code&gt; though. We need three:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OpenSSL&lt;/code&gt;: for full TLS support (e.g, &lt;code&gt;SNI&lt;/code&gt; extension);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PCRE&lt;/code&gt;: to not rely on libc&amp;rsquo;s regex support but the more common Perl regex&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ZLIB&lt;/code&gt;: for providing &lt;code&gt;deflate&lt;/code&gt; and &lt;code&gt;gzip&lt;/code&gt; compression algorithms&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;sudo apt install -y &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libpcre3-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        libssl-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        zlib1g-dev
&lt;/span&gt;Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that our dependencies are all ready to be used we can proceed with HAProxy itself.&lt;/p&gt;
&lt;p&gt;For obtaining the source code we can head to the downloads page (&lt;a href=&#34;http://www.haproxy.org/download/1.8/src/&#34;&gt;haproxy.org/download/1.8/src/&lt;/a&gt;) and fetch the latest version (I&amp;rsquo;m getting the last release candidate of 1.8 because this version gives us HTTP2 support, which is something I plan to write about soon).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# fetch the .tar.gz of the source code of haproxy &lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;curl -SOL http://www.haproxy.org/download/1.8/src/haproxy-1.8-rc3.tar.gz
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# decompress it to the current directory&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;tar xzf ./haproxy-1.8-rc3.tar.gz &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once everything is in place it&amp;rsquo;s just a matter of compiling it with some flags that signalize the build process what is our environment and where it can find the Lua dependency:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# get into the source code directory&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./haproxy-1.8-rc3/
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# build the code with Lua, gzip compression, PCRE regex&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# targetting a recent kernel.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;make &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;TARGET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;linux2628 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;USE_OPENSSL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;USE_ZLIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;USE_PCRE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;USE_LUA&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;LUA_LIB_NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;lua &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;LUA_LIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/lib/ &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;LUA_INC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/include
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# make it available from `$PATH` so that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# we can call `haproxy` from anywhere and&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# also have `man` pages set&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;sudo make install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you wonder why &lt;code&gt;TARGET=linux2628&lt;/code&gt;, head to the &lt;code&gt;Makefile&lt;/code&gt; at &lt;code&gt;haproxy&lt;/code&gt;&amp;rsquo;s source and check this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGET&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,linux2628)&lt;/span&gt;
  &lt;span class=&#34;c&#34;&gt;# This is for standard Linux &amp;gt;= 2.6.28 with 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# netfilter, epoll, tproxy and splice.&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;USE_NETFILTER&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_POLL&lt;/span&gt;              &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_EPOLL&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_TPROXY&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_LIBCRYPT&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_LINUX_SPLICE&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_LINUX_TPROXY&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_ACCEPT4&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_FUTEX&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_CPU_AFFINITY&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;ASSUME_SPLICE_WORKS&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_DL&lt;/span&gt;                &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
  &lt;span class=&#34;nv&#34;&gt;USE_THREAD&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; implicit
&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In summary, it means that it&amp;rsquo;ll use some recent kernel capabilities to improve our performance.&lt;/p&gt;
&lt;p&gt;After the compilation finishes you should have something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;hl&#34;&gt;./haproxy -vvvv
&lt;/span&gt;HA-Proxy version 1.8-rc3-34650d5 2017/11/11
Copyright 2000-2017 Willy Tarreau &amp;lt;willy@haproxy.org&amp;gt;

Build options :
&lt;span class=&#34;hl&#34;&gt;  TARGET  = linux2628
&lt;/span&gt;  CPU     = generic
  CC      = gcc
  CFLAGS  = -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-null-dereference -Wno-unused-label
&lt;span class=&#34;hl&#34;&gt;  OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1
&lt;/span&gt;
Default settings :
  maxconn = 2000, bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with OpenSSL version : OpenSSL 1.0.2g  1 Mar 2016
&lt;span class=&#34;hl&#34;&gt;Running on OpenSSL version : OpenSSL 1.0.2g  1 Mar 2016
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;OpenSSL library supports TLS extensions : yes
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;OpenSSL library supports SNI : yes
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;Built with Lua version : Lua 5.3.3
&lt;/span&gt;Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built with network namespace support.
&lt;span class=&#34;hl&#34;&gt;Built with zlib version : 1.2.11
&lt;/span&gt;Running on zlib version : 1.2.11
&lt;span class=&#34;hl&#34;&gt;Compression algorithms supported : identity(&amp;#34;identity&amp;#34;), deflate(&amp;#34;deflate&amp;#34;), raw-deflate(&amp;#34;deflate&amp;#34;), gzip(&amp;#34;gzip&amp;#34;)
&lt;/span&gt;Encrypted password support via crypt(3): yes
&lt;span class=&#34;hl&#34;&gt;Built with PCRE version : 8.39 2016-06-14
&lt;/span&gt;Running on PCRE version : 8.39 2016-06-14
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Built with multi-threading support.

Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use epoll.

Available filters :
	[SPOE] spoe
	[COMP] compression
	[TRACE] trace&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the output, we can make sure that what we wanted has been properly compiled. Now we can move to the HAProxy configuration.&lt;/p&gt;
&lt;h3 id=&#34;haproxy-configuration&#34;&gt;HAProxy Configuration&lt;/h3&gt;
&lt;p&gt;With all the dependencies installed we can proceed with the actual HAProxy configuration.&lt;/p&gt;
&lt;p&gt;Because we need to have HAProxy performing something that it can&amp;rsquo;t do by default as mentioned - serve static files from a directory - we need to add a Lua plugin that does the job. That&amp;rsquo;s needed to serve the challenge that letsencrypt gives us when checking if we can serve content from a given domain (&lt;a href=&#34;https://certbot.eff.org/docs/using.html#webroot&#34;&gt;webroot&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Thanks to Jan (&lt;a href=&#34;https://github.com/janeczku&#34;&gt;github.com/janeczku&lt;/a&gt;), we don&amp;rsquo;t have to write our own:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# get out of the haproxy directory&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ../

&lt;span class=&#34;c1&#34;&gt;# fetch the lua script code that will serve the challenges&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# placed by certbot at a specific directory (webroot)&lt;/span&gt;
git clone https://github.com/janeczku/haproxy-acme-validation-plugin

&lt;span class=&#34;c1&#34;&gt;# go to the repository directory and check what are the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# files that we have there&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ./haproxy-acme-validation-plugin
tree
.
├── LICENSE
├── README.md
├── acme-http01-webroot.lua
├── cert-renewal-haproxy.sh
└── haproxy.cfg.example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;acme-http01-webroot.lua&lt;/code&gt; make sure you set the &lt;code&gt;non_chroot_webroot&lt;/code&gt; variable to a location where we&amp;rsquo;ll set &lt;code&gt;certbot&lt;/code&gt; to put challenges on:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span class=&#34;c1&#34;&gt;--&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- Configuration&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;--&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- When HAProxy is *not* configured with the &amp;#39;chroot&amp;#39; option you must set an absolute path here and pass &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- that as &amp;#39;webroot-path&amp;#39; to the letsencrypt client&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;acme.conf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;non_chroot_webroot&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/tmp/webroot&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the Lua plugin in place all we need to do next is specify that path to the plugin in our &lt;code&gt;haproxy.cfg&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# notice that we&amp;#39;re specifying in &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `lua-load` the location of the Lua&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# script. Make sure you reference it&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# according to your configuration.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;global&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;maxconn                   8192&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;log                       127.0.0.1  local0&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;tune.maxrewrite           16384&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;tune.bufsize              32768&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;tune.ssl.default-dh-param 2048&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;max-spread-checks         200&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;spread-checks             5&lt;/span&gt;
		&lt;span class=&#34;na&#34;&gt;lua-load                  /home/ubuntu/haproxy-acme-validation-plugin/acme-http01-webroot.lua&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Configure some default values that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# frontends and backends can inherit&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I&amp;#39;m setting some dummy timeouts.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# In another blog post we can go through&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# some real values there.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;log       global&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;retries   3&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;option    redispatch&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;option    dontlog-normal&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;mode      http&lt;/span&gt;

                &lt;span class=&#34;na&#34;&gt;timeout   http-request 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   client 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   connect 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   server 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   http-keep-alive 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   tunnel 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   client-fin 10m&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;timeout   server-fin 10m&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# The HTTP frontend serving only as a way of redirecting traffic&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to port :443 where it can serve the real content via HTTPS&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and also accept the requests from letsencrypt.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The big thing here is `use-service` which essentially means that&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# when the `url_acme_http01` ACL is `true` it&amp;#39;ll execute the lua &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# script that we registered.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The name `lua.acme-http01` comes from the lua script itself:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       core.register_service(&amp;#34;acme-http01&amp;#34;, &amp;#34;http&amp;#34;, acme.http01)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend        http&lt;/span&gt;
		&lt;span class=&#34;na&#34;&gt;bind		*:80&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;acl		url_acme_http01 path_beg /.well-known/acme-challenge/&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;http-request	use-service lua.acme-http01 if METH_GET url_acme_http01&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;redirect	scheme https if METH_GET !url_acme_http01&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Serve the HTTPS traffic.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# For each request that comes it takes the server name indicated &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in SNI (the TLS extension that gives to an encrypted connection the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# equivalent of a Host header) it looks on the list of certificates&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that it loaded from the `crt-list` file and then uses that certificate.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# As we&amp;#39;re offloading the TLS resolution from the backend to the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# frontend, `backend_test` will receive unencrypted content as&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# if there was a plain TCP connection coming (no need to deal with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# certificates there - only HAProxy has to care about it).&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend        https&lt;/span&gt;
		&lt;span class=&#34;na&#34;&gt;bind		*:443&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;default_backend backend_test&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Dummy backend connecting haproxy to a server on the same machine.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# The server at `localhost:8080` is a simple HTTP server expecting&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# regular non-encrypted connections.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;backend         backend_test&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;server test-server localhost:8080&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To make sure we got our configuration right we can make use of the &lt;code&gt;-c&lt;/code&gt; flag of HAProxy to perform some sort of &amp;ldquo;dry run&amp;rdquo; and only check the config. Assuming we have the configuration at &lt;code&gt;~/haproxy.cfg&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;haproxy --help 
&lt;/span&gt;...
Usage : haproxy -f &amp;lt;cfgfile&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;cfgdir&amp;gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;opt&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
        ...
        -c check mode : only check config files and &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt;
        ...

&lt;span class=&#34;hl&#34;&gt;haproxy -c -f ~/haproxy.cfg
&lt;/span&gt;Configuration file is valid&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As the configuration is valid we can start &lt;code&gt;HAProxy&lt;/code&gt; with a privileged user (as it&amp;rsquo;s going to bind on ports 80 and 443):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;sudo haproxy -f ./haproxy.cfg
&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;info&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/123916 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;acme&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; http-01 plugin v0.1.1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we got HAProxy working we can check if the &lt;code&gt;lua&lt;/code&gt; plugin is really receiving the requests when we hit port 80 on the expected path:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# in a separate terminal, make a request to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# haproxy instance on the path which should respond&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to letsencrypt requests&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;curl localhost:80/.well-known/acme-challenge/aa
&lt;/span&gt;resource not found

&lt;span class=&#34;c1&#34;&gt;# on the HAProxy terminal, check the logs&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;warning&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/124202 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;acme&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; http-01 token not found: aa &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;client-ip: 127.0.0.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As it&amp;rsquo;s all working as expected we can request a certificate to letsencrypt.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the directory where challenges will&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# be placed. This is the directory that you have&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to be set earlier in the lua script in the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# `acme.conf` field.&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;mkdir /tmp/webroot
&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# make certbot initiate the certificate generation&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# process using the webroot method, placing challenges&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# at the directory /tmp/webroot and creating the certificate&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# for the domain `cirocosta.com`&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;sudo certbot certonly --webroot -w /tmp/webroot -d cirocosta.com
&lt;/span&gt;
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
...
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/cirocosta.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/cirocosta.com/privkey.pem
   Your cert will expire on 2018-02-23. To obtain a new or tweaked
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the certificates in hand now we have to create a new file that HAProxy can use to terminate the TLS connections. This new file is a concatenation of the private key and the certificate we received from letsencrypt:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# concatenate those files (as I used the root user to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# provision them - via certbot - they were created as&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# root, so I must be `root` to see them).&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;sudo cat &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /etc/letsencrypt/live/cirocosta.com/privkey.pem &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        /etc/letsencrypt/live/cirocosta.com/fullchain.pem &amp;gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                ~/cirocosta.com&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then update the &lt;code&gt;haproxy.cfg&lt;/code&gt; file to make use of the certificate when &lt;code&gt;bind&lt;/code&gt;ing to port &lt;code&gt;443&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt; &lt;span class=&#34;na&#34;&gt;frontend        https&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                bind		*:443   (before)&lt;/span&gt;
                 &lt;span class=&#34;na&#34;&gt;bind		*:443   ssl crt /home/ubuntu/cirocosta.com&lt;/span&gt;
                 &lt;span class=&#34;na&#34;&gt;default_backend backend_test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then perform a soft-reload HAProxy after checking if the configuration is fine (it checks the cert):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# check the configuration&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;haproxy -c -f ~/haproxy.cfg 
&lt;/span&gt;Configuration file is valid

&lt;span class=&#34;c1&#34;&gt;# soft-reload the current instance by creating a new&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# one passing the pid of the old instance via the `-sf`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# flag&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;sudo haproxy &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -f ./haproxy.cfg &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -sf &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;pidof haproxy&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;info&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;376196&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;acme&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; http-01 plugin v0.1.1

&lt;span class=&#34;c1&#34;&gt;# in the terminal where the old HAProxy was running&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# you should see the following (perfectly fine) messages:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WARNING&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : Stopping frontend http in &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ms.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WARNING&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : Stopping frontend https in &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ms.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WARNING&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : Stopping backend backend_test in &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ms.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WARNING&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : Proxy http stopped &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;FE: &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; conns, BE: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; conns&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WARNING&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : Proxy https stopped &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;FE: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; conns, BE: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; conns&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.
&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WARNING&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 328/131241 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;374961&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; : Proxy backend_test stopped &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;FE: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; conns, BE: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; conns&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;Even without a properly configured server, we should already be able to see that the HTTPS setup is fine:&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/haproxy-https-503.png&#34;
       alt=&#34;Image of Google Chrome with HTTPS working &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Even though the guide is quite extensive if you consider the process of building HAProxy and Lua from scratch, there&amp;rsquo;s not much going on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make HAProxy serve the challenges at port 80 on a specific path that letsencrypt expects&lt;/li&gt;
&lt;li&gt;Concatenate certificates and private keys&lt;/li&gt;
&lt;li&gt;Update the HAProxy configuration&lt;/li&gt;
&lt;li&gt;Reload HAProxy&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once that&amp;rsquo;s automated you&amp;rsquo;re ready to serve your customers with HTTPS / TLS without dropping connections and having to pay for certificates.&lt;/p&gt;
&lt;p&gt;Even if the part of setting up the dependencies seem like too much you can tailor a Dockerfile that does all of that and you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;p&gt;If you enjoyed the guide and are willing to learn more about related content, make sure you subscribe to the newsletter. In case you find mistakes I made or think there&amp;rsquo;s something to improve, just let me know, I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;update-13-feb-2018&#34;&gt;Update (13 Feb, 2018)&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re interested in provisioning TLS certificates, you&amp;rsquo;re probably also interested in HTTP/2.&lt;/p&gt;
&lt;p&gt;I just finished writing a blog post on &lt;a href=&#34;https://ops.tips/blog/nginx-http2-server-push/&#34;&gt;how to make use of HTTP/2 Server Push with NGINX&lt;/a&gt; for those out there making use of NGINX.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
</description>
                                <pubDate>Sat, 25 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/tls-certificates-haproxy-letsencrypt/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/tls-certificates-haproxy-letsencrypt/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Pushing Docker images right from Travis-CI</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;oftentimes I have some code that ends up in a Docker image which I want to have pushed to Dockerhub. Docker itself is capable of automatically building images from git repositories but it has the restriction that I can&amp;rsquo;t specify a certain Docker daemon version to run the build. This &lt;em&gt;used&lt;/em&gt; to be important (not sure if it still is) as in the stable version of Docker we already have been using &lt;a href=&#34;https://docs.docker.com/engine/userguide/eng-image/multistage-build/&#34;&gt;multi-stage builds&lt;/a&gt; but the Dockerhub builder didn&amp;rsquo;t allow us to use it.&lt;/p&gt;
&lt;p&gt;As I already make use of Travis to run my tests I think it&amp;rsquo;s a no-brainer to tie the image building to Travis as well - if tests pass and we&amp;rsquo;re on the &lt;code&gt;master&lt;/code&gt; branch, build the image and push to docker hub.&lt;/p&gt;
&lt;h3 id=&#34;updating-the-docker-daemon&#34;&gt;Updating the docker daemon&lt;/h3&gt;
&lt;p&gt;As I mentioned, I like to force Travis to use a newer Docker than they use by default. To speed some things I also like to configure &lt;code&gt;/etc/docker.json&lt;/code&gt; so that we can increase the concurrency of downloads and uploads (it really matters depending on how many images you have and whether you build them in parallel).&lt;/p&gt;
&lt;p&gt;To achieve that I use the following structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .travis
│   └── main.sh
├── .travis.yml
├── README.md
├── Dockerfile
└── Makefile
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;.travis&lt;/code&gt; is a directory that holds scripts to update the Travis machine. This way if I need to use the &lt;code&gt;debug&lt;/code&gt; feature of Travis I don&amp;rsquo;t have to follow the entire &lt;code&gt;.travis.yml&lt;/code&gt; recipe and instead just run &lt;code&gt;./.travis/main.sh&lt;/code&gt; from there to have the dependencies set.&lt;/p&gt;
&lt;p&gt;The file looks like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Set an option to exit immediately if any error appears&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit

&lt;span class=&#34;c1&#34;&gt;# Main function that describes the behavior of the &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# script. &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# By making it a function we can place our methods&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# below and have the main execution described in a&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# concise way via function invocations.&lt;/span&gt;
main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  setup_dependencies
  update_docker_configuration

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;SUCCESS:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Done! Finished setting up Travis machine.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Prepare the dependencies that the machine need.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Here I&amp;#39;m just updating the apt references and then&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# installing both python and python-pip. This allows&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# us to make use of `pip` to fetch the latest `docker-compose`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# later.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# We also upgrade `docker-ce` so that we can get the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# latest docker version which allows us to perform&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# image squashing as well as multi-stage builds.&lt;/span&gt;
setup_dependencies&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;INFO:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Setting up dependencies.
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;

  sudo apt update -y
  sudo apt install realpath python python-pip -y
  sudo apt install --only-upgrade docker-ce -y

  sudo pip install docker-compose &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;

  docker info
  docker-compose --version
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Tweak the daemon configuration so that we&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# can make use of experimental features (like image&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# squashing) as well as have a bigger amount of&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# concurrent downloads and uploads.&lt;/span&gt;
update_docker_configuration&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;INFO:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  Updating docker configuration
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;#34;&lt;/span&gt;

  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;{
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  &amp;#34;experimental&amp;#34;: true,
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  &amp;#34;storage-driver&amp;#34;: &amp;#34;overlay2&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  &amp;#34;max-concurrent-downloads&amp;#34;: 50,
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  &amp;#34;max-concurrent-uploads&amp;#34;: 50
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;}&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee /etc/docker/daemon.json
  sudo service docker restart
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that set, we can move on to the Travis configuration file (&lt;code&gt;.travis.yml&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# make use of vm&amp;#39;s &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;required&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# have the docker service set up (we&amp;#39;ll&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# update it later)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# prepare the machine before any code&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# installation scripts&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;before_install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;./.travis/main.sh&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# first execute the test suite.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# after the test execution is done and didn&amp;#39;t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# fail, build the images (if this step fails&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the whole Travis build is considered a failure).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;make test&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;make image&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# only execute the following instructions in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the case of a success (failing at this point&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# won&amp;#39;t mark the build as a failure).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# To have `DOCKER_USERNAME` and `DOCKER_PASSWORD`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# filled you need to either use `travis`&amp;#39; cli &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# and then `travis set ..` or go to the travis&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# page of your repository and then change the &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# environment in the settings pannel.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;after_success&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;if [[ &amp;#34;$TRAVIS_BRANCH&amp;#34; == &amp;#34;master&amp;#34; ]]; then&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD ;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;make push-image ;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;fi&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# don&amp;#39;t notify me when things fail&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;notifications&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you might have noticed the whole functionality is behind a &lt;code&gt;Makefile&lt;/code&gt; (from the &lt;code&gt;make&lt;/code&gt; commands). That&amp;rsquo;s on purpose to facilitate possible debugging sessions (you&amp;rsquo;d SSH into the Travis machine and just &lt;code&gt;./.travis/main.sh&lt;/code&gt;, &lt;code&gt;make test&lt;/code&gt; to run the whole thing).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Makefile&lt;/code&gt; can be as simple as something like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;nv&#34;&gt;IMAGE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; cirocosta/dind

&lt;span class=&#34;nf&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;

&lt;span class=&#34;nf&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	docker build -t &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;IMAGE&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; .

&lt;span class=&#34;nf&#34;&gt;push-image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	docker push &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;IMAGE&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;push&lt;/span&gt;-&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want an example to check out, see &lt;a href=&#34;https://github.com/cirocosta/dind&#34;&gt;cirocosta/dind&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s no need to complicate a lot the process of automatically pushing images after a successful test run using &lt;a href=&#34;https://travis-ci.org&#34;&gt;travis-ci&lt;/a&gt;. I really enjoy the idea of only pushing an image when things are fine as it gives a good guarantee that the code that is being packed as the image will run.&lt;/p&gt;
&lt;p&gt;To be even more sure about the wellness of the image you could add an extra suit of integration tests that creates docker containers using the image and then asserts that it works as expected.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to have a container-based environment that runs your unit tests and on the side (concurrently) run a build in a VM that prepares your docker images and run integration tests, you can totally do that with Travis-ci - it&amp;rsquo;s a matter of adapting a previous article I wrote: &lt;a href=&#34;https://ops.tips/blog/parallel-container-vms-travis-ci/&#34;&gt;Concurrently running container-based and VM tests in Travis-CI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to learn more about integrating Travis-ci into your projects or automation in general, make sure you subscribe to the mailing list.&lt;/p&gt;
&lt;p&gt;Here are some resources related to the article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.travis-ci.com/user/docker/&#34;&gt;Travis-CI: Using Docker in Builds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.travis-ci.com/user/customizing-the-build/&#34;&gt;Travis-CI: Customizing the build&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/reference/commandline/login/&#34;&gt;docker login&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/reference/commandline/push/&#34;&gt;docker push&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/reference/commandline/build/&#34;&gt;docker build&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Fri, 24 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/travis-ci-push-docker-image/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/travis-ci-push-docker-image/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Changing the name of an index in Elasticsearch</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;today I happened to write a script to solve a specific problem that it looks like a good deal of people face: rename a Elasticsearch index.&lt;/p&gt;
&lt;p&gt;Naturally, there are documented solutions but I didn&amp;rsquo;t find quickly a script that would get me where I wanted - all the data from an index named &lt;code&gt;a&lt;/code&gt; now being queryable in an index named &lt;code&gt;b&lt;/code&gt; with all the properties set.&lt;/p&gt;
&lt;p&gt;Note.: the following code is aimed at Elasticsearch 2.4.6.&lt;/p&gt;
&lt;p&gt;Here it comes then.&lt;/p&gt;
&lt;h3 id=&#34;reindexing-step-by-step&#34;&gt;Reindexing step by step&lt;/h3&gt;
&lt;p&gt;There are four steps to get towards our goal:&lt;/p&gt;
&lt;ol start=&#34;0&#34;&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; Create an Elasticsearch index and populate it with some data;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; Get the configurations of the original index;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; Create the new index with the desired configuration;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; Run `_reindex` action;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; Drop the old index.
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;0-create-an-elasticsearch-index-and-populate-it-with-some-data&#34;&gt;0. Create an Elasticsearch index and populate it with some data&lt;/h4&gt;
&lt;p&gt;To create an index using the default parameters (e.g, number of shards and replicas) we can issue a &lt;code&gt;POST&lt;/code&gt; against the Elasticsearch HTTP endpoint specifying the desired index (in this case, &lt;code&gt;acme-production&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPOST &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/acme-production
&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;acknowledged&amp;#34;&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which, naturally, has no data indexed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl localhost:9200/_cat/indices&lt;span class=&#34;se&#34;&gt;\?&lt;/span&gt;v
&lt;/span&gt;
health status index           pri rep docs.count docs.deleted store.size pri.store.size 
green  open   acme-production   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;            &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       130b           130b &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we populate it with some data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPOST &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -d &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;title&amp;#34;:&amp;#34;Hello world&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/acme-production/test/hello
&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;_index&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;_shards&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;failed&amp;#34;&lt;/span&gt;: 0,
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;successful&amp;#34;&lt;/span&gt;: 1,
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;total&amp;#34;&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;_type&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;_version&amp;#34;&lt;/span&gt;: 1,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;created&amp;#34;&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which we can verify by looking again at the &lt;code&gt;/_cat/indices&lt;/code&gt; endpoint:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl localhost:9200/_cat/indices&lt;span class=&#34;se&#34;&gt;\?&lt;/span&gt;v
&lt;/span&gt;
health status index           pri rep docs.count docs.deleted store.size pri.store.size 
green  open   acme-production   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;            &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      2.9kb          2.9kb &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&#34;1------get-the-configurations-of-the-original-index&#34;&gt;1.      Get the configurations of the original index&lt;/h4&gt;
&lt;p&gt;Because the renaming is nothing more than &amp;ldquo;create, copy and delete&amp;rdquo; we need to create a new index with the properties from the old one. To properly achieve that we must then copy the old configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;index_config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        localhost:9200/acme-production/_settings,_mappings &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.[]&amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index_config&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;mappings&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;s2&#34;&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;s2&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;string&amp;#34;&lt;/span&gt;
                &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
            &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;s2&#34;&gt;&amp;#34;creation_date&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;1511285883996&amp;#34;&lt;/span&gt;,
            &lt;span class=&#34;s2&#34;&gt;&amp;#34;number_of_replicas&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;,
            &lt;span class=&#34;s2&#34;&gt;&amp;#34;number_of_shards&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;,
            &lt;span class=&#34;s2&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;h3z8Hq_5SKuu7MwEJZYcVQ&amp;#34;&lt;/span&gt;,
            &lt;span class=&#34;s2&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
                &lt;span class=&#34;s2&#34;&gt;&amp;#34;created&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;2040699&amp;#34;&lt;/span&gt;
            &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ps.: here I&amp;rsquo;m making use of &lt;a href=&#34;https://stedolan.github.io/jq/&#34;&gt;jq&lt;/a&gt;, the lightweight command-line JSON processor, in order to get the mappings and settings objects from within the bigger object returned by the call to &lt;code&gt;/&amp;lt;index&amp;gt;/_settings,_mappings&lt;/code&gt;. This way we&amp;rsquo;re able to assign that to a variable and then utilize directly later.&lt;/p&gt;
&lt;h4 id=&#34;2------create-the-new-index-with-the-desired-configuration&#34;&gt;2.      Create the new index with the desired configuration&lt;/h4&gt;
&lt;p&gt;Using the old configuration (stored in the &lt;code&gt;index_config&lt;/code&gt; variable) we&amp;rsquo;re able to create the the index based on it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPUT &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -d &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index_config&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/acme-staging
&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;acknowledged&amp;#34;&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ps.: even though there&amp;rsquo;s an &lt;code&gt;uuid&lt;/code&gt; in the &lt;code&gt;$index_config&lt;/code&gt; object there, it doesn&amp;rsquo;t matter - it&amp;rsquo;ll get replaced by a new &lt;code&gt;uuid&lt;/code&gt; in the new index.&lt;/p&gt;
&lt;h4 id=&#34;3------run-_reindex-action&#34;&gt;3.      Run &lt;code&gt;_reindex&lt;/code&gt; action&lt;/h4&gt;
&lt;p&gt;Having both indices properly configured we&amp;rsquo;re ready to have the data from the old index in the new one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;acme-production
&lt;span class=&#34;nv&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;acme-staging
&lt;span class=&#34;nv&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  \&amp;#34;source\&amp;#34;: {
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    \&amp;#34;index\&amp;#34;: \&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$source&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  },
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  \&amp;#34;dest\&amp;#34;: {
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    \&amp;#34;index\&amp;#34;: \&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dest&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    \&amp;#34;version_type\&amp;#34;: \&amp;#34;internal\&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  }
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;}&amp;#34;&lt;/span&gt;

&lt;span class=&#34;hl&#34;&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPOST &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -d &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$payload&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/_reindex
&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;batches&amp;#34;&lt;/span&gt;: 1,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;created&amp;#34;&lt;/span&gt;: 1,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;failures&amp;#34;&lt;/span&gt;: &lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;noops&amp;#34;&lt;/span&gt;: 0,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;requests_per_second&amp;#34;&lt;/span&gt;: &lt;span class=&#34;s2&#34;&gt;&amp;#34;unlimited&amp;#34;&lt;/span&gt;,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;retries&amp;#34;&lt;/span&gt;: 0,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;throttled_millis&amp;#34;&lt;/span&gt;: 0,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;throttled_until_millis&amp;#34;&lt;/span&gt;: 0,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;timed_out&amp;#34;&lt;/span&gt;: false,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;took&amp;#34;&lt;/span&gt;: 48,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;total&amp;#34;&lt;/span&gt;: 1,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;updated&amp;#34;&lt;/span&gt;: 0,
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;version_conflicts&amp;#34;&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By this time you should already have your new index populated. Now it&amp;rsquo;s a matter of deleting the old index:&lt;/p&gt;
&lt;h4 id=&#34;4------drop-the-old-index&#34;&gt;4.      Drop the old index&lt;/h4&gt;
&lt;p&gt;If you have no intention of making use of the old index, now it&amp;rsquo;s time to drop it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XDELETE &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/acme-production
&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;acknowledged&amp;#34;&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&#34;update---using-aliases-and-avoiding-complete-index-copies&#34;&gt;Update - Using aliases and avoiding complete index copies&lt;/h4&gt;
&lt;p&gt;I received some pretty interesting feedback on Reddit that I&amp;rsquo;d like to share here.&lt;/p&gt;
&lt;p&gt;It turns out that sometimes we can avoid &lt;code&gt;reindex&lt;/code&gt;ing by making use of aliases (see &lt;a href=&#34;https://www.elastic.co/guide/en/elasticsearch/reference/2.0/indices-aliases.html&#34;&gt;Elasticsearch Indices Aliases&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The idea is that when we need to reference what&amp;rsquo;s covered by an index by using another name we can create some kind of &amp;ldquo;pointer&amp;rdquo; to the real index and perform all the normal operations against this pointer (alias). The API that allows doing that allows us to essentially &lt;code&gt;CRUD&lt;/code&gt; (create, remove, update and delete) aliases, making it totally possible for us to perform what we want: achieve a &amp;ldquo;renaming&amp;rdquo; of an index, even if only virtually.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s do it then.&lt;/p&gt;
&lt;p&gt;First, create an &lt;code&gt;acme-production&lt;/code&gt; index just like before and add some data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPOST &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/acme-production
curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPOST &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -d &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;title&amp;#34;:&amp;#34;Hello world&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/acme-production/test/hello

health status index           pri rep docs.count docs.deleted store.size pri.store.size 
yellow open   acme-production   &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;            &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      3.4kb          3.4kb 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then create an &lt;code&gt;alias&lt;/code&gt; named &lt;code&gt;acme-staging&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    &amp;#34;actions&amp;#34;: [
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        {
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;            &amp;#34;add&amp;#34;: {
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;                &amp;#34;alias&amp;#34;: &amp;#34;acme-staging&amp;#34;,
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;                &amp;#34;index&amp;#34;: &amp;#34;acme-production&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;            }
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;        }
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;    ]
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;}&amp;#39;&lt;/span&gt;

curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -XPOST &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -d &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$payload&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        http://localhost:9200/_aliases 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;if we check the indices we&amp;rsquo;ll see that we don&amp;rsquo;t have any new index though:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl localhost:9200/_cat/indices&lt;span class=&#34;se&#34;&gt;\?&lt;/span&gt;v
health status index           pri rep docs.count docs.deleted store.size pri.store.size 
yellow open   acme-production   &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;          &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;            &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;      3.4kb          3.4kb 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But that we do have aliases:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl localhost:9200/_cat/aliases&lt;span class=&#34;se&#34;&gt;\?&lt;/span&gt;v
&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt;        index           filter routing.index routing.search 
acme-staging acme-production -      -             -              
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which allows us to perform queries against &lt;code&gt;acme-staging&lt;/code&gt; and retrieve data from &lt;code&gt;acme-production&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# request against the index&lt;/span&gt;
curl http://localhost:9200/acme-production/test/hello
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;_index&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_type&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_version&amp;#34;&lt;/span&gt;:1,&lt;span class=&#34;s2&#34;&gt;&amp;#34;found&amp;#34;&lt;/span&gt;:true,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_source&amp;#34;&lt;/span&gt;:&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello world&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# now against the alias&lt;/span&gt;
curl http://localhost:9200/acme-staging/test/hello
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;_index&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_type&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_version&amp;#34;&lt;/span&gt;:1,&lt;span class=&#34;s2&#34;&gt;&amp;#34;found&amp;#34;&lt;/span&gt;:true,&lt;span class=&#34;s2&#34;&gt;&amp;#34;_source&amp;#34;&lt;/span&gt;:&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello world&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, what if we want to disallow requests to the old index? As if we had really renamed it and not duplicated? Then we need to close the old index using the &lt;a href=&#34;https://www.elastic.co/guide/en/elasticsearch/reference/2.0/indices-open-close.html&#34;&gt;open/close index api&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl -XPOST http://localhost:9200/acme-production/_close
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then we can try to get from &lt;code&gt;acme-production&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt; curl http://localhost:9200/acme-production/test/hello   

&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;:&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;root_cause&amp;#34;&lt;/span&gt;:&lt;span class=&#34;o&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;index_closed_exception&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;reason&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;closed&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}]&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;index_closed_exception&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;reason&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;closed&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;:403&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cool, what we wanted, huh? Now, if we try to get from &lt;code&gt;acme-staging&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;curl http://localhost:9200/acme-staging/test/hello
&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;:&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;root_cause&amp;#34;&lt;/span&gt;:&lt;span class=&#34;o&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;index_closed_exception&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;reason&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;closed&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}]&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;index_closed_exception&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;reason&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;closed&amp;#34;&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;:&lt;span class=&#34;s2&#34;&gt;&amp;#34;acme-production&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;,&lt;span class=&#34;s2&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;:403&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;we can&amp;rsquo;t retrieve either.&lt;/p&gt;
&lt;p&gt;It sounds logical to me that we can&amp;rsquo;t as the alias is just a pointer to the other index (which was closed).&lt;/p&gt;
&lt;p&gt;So, to sum up, if you want to have new indices to point to an existing one (as if you were renaming), aliases will save you and you&amp;rsquo;ll need to perform 0 copying of data.&lt;/p&gt;
&lt;p&gt;If you need to have something like &amp;ldquo;rename&amp;rdquo; and disallow access to the old index, then &lt;code&gt;alias&lt;/code&gt; won&amp;rsquo;t help you (will have to use the &lt;code&gt;reindex + delete&lt;/code&gt; strategy.&lt;/p&gt;
&lt;p&gt;I never used aliases before and it&amp;rsquo;s pretty good to know that they exist! It can definitely be very useful some times.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts-and-resources&#34;&gt;Closing thoughts and resources&lt;/h3&gt;
&lt;p&gt;As someone who never really dug deep into how Elasticsearch works, I found very easy the whole concept of reindexing. The official documentation is pretty good and with it, I was able to quickly solve the problem. Kudos Elasticsearch team!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.elastic.co/guide/en/elasticsearch/reference/2.4/docs-reindex.html&#34;&gt;Elasticsearch Reindex API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.elastic.co/guide/en/elasticsearch/reference/2.4/_list_all_indices.html&#34;&gt;Elasticsearch List all indices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.elastic.co/guide/en/elasticsearch/reference/2.0/indices-aliases.html&#34;&gt;Elasticsearch Indices Aliases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.elastic.co/guide/en/elasticsearch/reference/2.0/indices-open-close.html&#34;&gt;Elasticsearch Open/Close Index API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I plan to do some more posts regarding Elasticsearch in the future. If you want to come along and learn together, make sure you subscribe to the mailing list.&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Tue, 21 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/change-name-of-index-elasticsearch/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/change-name-of-index-elasticsearch/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Executing multiple commands in SSH session against multiple machines</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;it&amp;rsquo;s not uncommon for me to have to execute a quick command against a set of machines. Naturally, the easiest way of performing that against a single machine is using &lt;code&gt;ssh&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;private_key&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./key.rsa&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;echo test&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;10.0.0.2&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ubuntu&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;22&amp;#39;&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$command&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ssh &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -i &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;private_key&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -p &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;:&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the command properly wrapped in terms of variables now it&amp;rsquo;s just a matter making it a method, looping through a list of machines and executing the command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Executes a given command via SSH&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $1:             IP of the machine;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $2:             port of the machine to &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       connect to.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $USER:          user to use when executing&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       the commands.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $SCRIPT:        global variable with the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       full multiline script to&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       execute.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#       $PRIVATE_KEY:   global variable with the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       full path to a private&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       key that is authorized by&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#                       the machines.&lt;/span&gt;
execute_script_in_machine &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;

        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$SCRIPT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ssh &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -o &lt;span class=&#34;s2&#34;&gt;&amp;#34;StrictHostKeyChecking=no&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -i &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PRIVATE_KEY&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -p &lt;span class=&#34;nv&#34;&gt;$port&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;nv&#34;&gt;$USER&lt;/span&gt;@&lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The list of machines might be an array that we just iterate through:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TARGETS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=(&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1:2200&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1:2201&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1:2202&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we provide the &lt;code&gt;port&lt;/code&gt; argument separated from the &lt;code&gt;ip&lt;/code&gt; argument we must split the strings during the iteration. Thankfully to &lt;code&gt;bash&lt;/code&gt; we are covered by some internal operators. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-ssh&#34; data-lang=&#34;ssh&#34;&gt;#!/bin/bash

readonly TARGETS=(
        &amp;quot;firstIP:firstPORT&amp;quot;
        &amp;quot;secondIP:secondPORT&amp;quot;
)

# when iterating over an array we must 
# get each element from the array accessor
# `VARIABLE[@]` and not only `VARIABLE`.
main () {
        local ip
        local port

        for target in &amp;quot;${TARGETS[@]}&amp;quot;; do
                ip=${target%:*}
                port=${target#*:}

                printf &amp;quot;ip=$ip\tport=$port\n&amp;quot;
        done
}

main
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;leads to the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;bash test.sh 
&lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;firstIP      &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;firstPORT
&lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;secondIP     &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;secondPORT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which essentially means that now we need to plumb these two pieces (the parsing of the target list and the command execution) and have the full working script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;./key.rsa&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;SCRIPT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;echo -----STARTING;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  echo &amp;#34;WhoAmI? $(whoami)&amp;#34;;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;  echo -----DONE;
&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TARGETS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=(&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1:2020&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1:2021&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1:2022&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;

main &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; ip
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; port

        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; target in &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGETS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[@]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
                &lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%:*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
                &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#*:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

execute_script_in_machine &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;

        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$SCRIPT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ssh &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -o &lt;span class=&#34;nv&#34;&gt;StrictHostKeyChecking&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;no &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -i &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PRIVATE_KEY&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                -p &lt;span class=&#34;nv&#34;&gt;$port&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;nv&#34;&gt;$USER&lt;/span&gt;@&lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;I included an extra section after some feedback. It describes an alternative called &lt;code&gt;mpssh&lt;/code&gt; that does the job of executing commands over SSH across many machines. Make sure you check it out!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;This is just a quick script that might be handy if you want to inspect the state of something across many machines. I really don&amp;rsquo;t advise to make use of this as a way of provisioning machines as there are much better solutions out there (like &lt;code&gt;ansible&lt;/code&gt;) which take a more declarative approach, are less distribution-specific and provides the great benefit of idempotence.&lt;/p&gt;
&lt;p&gt;Having some bash skills are nice and can really save some time if need to get something done quickly using standard Unix tools. If you&amp;rsquo;re interested in knowing more about some bash/shell stuff, make sure you subscribe to the mailing list.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have many resources to share regarding this article but I always end up reading something here and there from the &lt;a href=&#34;http://tldp.org/LDP/abs/html/&#34;&gt;advanced bash-scripting guide on TLDP&lt;/a&gt;. I&amp;rsquo;d not stress too much on a guide as at least in my case most of what I know comes from solving stuff when needed. After a while, you get the gotchas and become good enough to get to the goal.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;update---mpssh-as-an-alternative&#34;&gt;Update - &lt;code&gt;mpssh&lt;/code&gt; as an alternative&lt;/h3&gt;
&lt;p&gt;Hey, a reader pointed out that there are some other very lightweight solutions that do the job very well. The alternative I liked the most is &lt;code&gt;mpssh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a MacOS user and uses &lt;a href=&#34;https://brew.sh/&#34;&gt;brew&lt;/a&gt;: &lt;code&gt;brew install mpssh&lt;/code&gt;.
Under Linux, clone the repository &lt;a href=&#34;https://github.com/ndenev/mpssh&#34;&gt;ndenev/mpssh&lt;/a&gt; and then run &lt;code&gt;make&lt;/code&gt; from the root (assuming you have at least &lt;code&gt;gcc&lt;/code&gt; and &lt;code&gt;make&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SYNOPSIS
        mpssh \
                [-besvV] \
                [-o directory] \
                [-u username] \
                [-f hosts] \
                [-p procs] \
                &amp;lt;command&amp;gt;

   The mpssh utility executes multiple parallel ssh binary 
   instances in order to connect to a list of hosts (specified 
   in the hosts file) and execute the given &amp;lt;command&amp;gt; on each 
   of them.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, first thing to do is create a &lt;code&gt;hosts&lt;/code&gt; file. There you can specify in each line the &lt;code&gt;ip&lt;/code&gt; that you want to connect to. For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.1
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;10.0.0.2
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;10.0.0.3&amp;#34;&lt;/span&gt;  &amp;gt; /tmp/hosts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next step is configuring &lt;code&gt;~/.ssh/config&lt;/code&gt;: &lt;code&gt;mpssh&lt;/code&gt; seems to now have an easy way of specifying a private key to use so you have to specify an &lt;code&gt;IdentityFile&lt;/code&gt; in the &lt;code&gt;~/.ssh/config&lt;/code&gt; file. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host *
    IdentityFile /tmp/key.rsa
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With that we can already execute a command across those machines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;hl&#34;&gt;mpssh --user ubuntu --nokeychk --file /tmp/hosts &lt;span class=&#34;s1&#34;&gt;&amp;#39;echo &amp;#34;test&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;
MPSSH - Mass Parallel Ssh Ver.1.3.3
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;c&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;2005-2013 Nikolay Denev &amp;lt;ndenev@gmail.com&amp;gt;

  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;*&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; hosts from the list
  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;*&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; executing &lt;span class=&#34;s2&#34;&gt;&amp;#34;echo &amp;#34;&lt;/span&gt;test&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; as user &lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;*&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; strict host key check disabled
  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;*&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; spawning &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; parallel ssh sessions

10.0.0.1 -&amp;gt; &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
10.0.0.2 -&amp;gt; &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
10.0.0.3 -&amp;gt; &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;

  Done. &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; hosts processed.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Aside from just executing the commands in all of them, it can have a ratelimit in terms of parallelization (e.g, given a list of 100 machines, execute in parallel 3 at a time). It&amp;rsquo;s also possible to output the result of the execution of each machine in a separate file. Pretty good!&lt;/p&gt;
</description>
                                <pubDate>Mon, 20 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/multiple-commands-in-ssh-session/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/multiple-commands-in-ssh-session/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Concurrently running container-based and VM tests in Travis-CI</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;oftentimes I see myself having to run two types of tests in &lt;a href=&#34;https://travis-ci.com&#34;&gt;travis-ci&lt;/a&gt;: unitary and integration tests.&lt;/p&gt;
&lt;p&gt;For the first category, that usually means running some plain Golang code that interacts with no other services (e.g, it uses a mocked database or it mocks HTTP requests). In the other scenario, spawning Docker containers which end up creating a database that is used in the test - requiring docker to be present, thus, VM-based builds.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/travis-concurrent.svg&#34;
       alt=&#34;Illustration of concurrently running VM and container-based builds &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;Using the &lt;code&gt;matrix&lt;/code&gt; property we can tailor our build matrix and make use of both types of build infrastructures: container-based (pretty fast, super good for unit tests) and VM-based (pretty good for raising services and Docker containers).&lt;/p&gt;
&lt;h3 id=&#34;snippet&#34;&gt;Snippet&lt;/h3&gt;
&lt;p&gt;Below is a very commented snippet (&lt;code&gt;.travis.yml&lt;/code&gt;) detailing how to run more than one type of build infrastructure. Note that here I&amp;rsquo;m making use of &lt;code&gt;language: go&lt;/code&gt; but that works just fine for anything else.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;go&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.9.1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `matrix` allows us to include or exclude environments&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# specifying properties for each of them.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# As `sudo` is a property like any other, we can change&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# it in `matrix` such that we can have one build environment&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# running in a container - useful for very quick unit tests - and &lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# another build running in a Travis VM - where we can make&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# use of `docker` and create many containers, very suitable&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# for integration testing.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matrix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;include&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# mark via environment-variables that we&amp;#39;re in a unit-test&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;TEST_SUITE=unit&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# sudo-enabled specific configuration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;TEST_SUITE=integration&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# most of the times I set a `setup.sh` script that updates&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the image dependencies so that if I want to debug the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# build later it&amp;#39;s very easy to run all the setup by just&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# running a single command.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;before_install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; 
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;./.travis/setup.sh&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;before_script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;make image&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# These properties that are not in `include` will be run for both&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# environments.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;make&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Having `test-&amp;lt;TEST_SUITE&amp;gt;` different in each environment we can&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# then run different types of tests in different environments.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;make test-${TEST_SUITE}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Evict sending notifications when things fail.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# I&amp;#39;m definitely not a fan of being alerted by&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# this when developing.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;notifications&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it! Let&amp;rsquo;s create a test project and check how that works.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; create a new GitHub repository (in this case I&#39;m creating [cirocosta/travis-multiinfra](https://github.com/cirocosta/travis-multiinfra));
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; sync your account in `travis-ci.org` or `travis-ci.com` (works for both offerings);
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; enable builds for that repository
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; populate the repo with some code and a `yaml` file like the above
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; push to git and check the build at Travis-ci.
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In &lt;a href=&#34;https://github.com/cirocosta/travis-multiinfra/blob/master/.travis.yml&#34;&gt;cirocosta/travis-multiinfra&amp;rsquo;s .travis.yml&lt;/a&gt; I have a simplified &lt;code&gt;.travis.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;nt&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;go&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.9.1&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matrix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;include&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;TEST_SUITE=unit&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;TEST_SUITE=integration&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;true&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s1&#34;&gt;&amp;#39;true&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;notifications&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When your build starts you should see two instantiations: one for the container-based build and another for the VM-based.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: the amount of parallelization depends on your plan. If you&amp;rsquo;re on the free plan on &lt;code&gt;travis.org&lt;/code&gt; or you&amp;rsquo;re already running other builds you won&amp;rsquo;t be able to execute multiple builds in parallel. You&amp;rsquo;ll still have the multiple infrastructures though.&lt;/em&gt;&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       
       src=&#34;https://ops.tips/blog/-/images/travis-jobs.png&#34;
       alt=&#34;Image of the Travis jobs console &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;To check configuration was used for each job, head to one of them and then click on &lt;code&gt;view config&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the unitary (container) looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;dist&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;trusty&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;TEST_SUITE=unit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;go&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1.9.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;stable&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;install&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;language&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;go&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;script&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;sudo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and the integration (VM):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;dist&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;trusty&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;TEST_SUITE=integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;go&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1.9.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;stable&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;install&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;language&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;go&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;script&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;services&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;&amp;#34;sudo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the &lt;code&gt;vm&lt;/code&gt;-based contains the service as we want but the first (container-based) doesn&amp;rsquo;t.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Being a long time Travis-ci user I really enjoy the flexibility that it brings as well as the peace of mind that having a CI infrastructure setup brings. I got very excited when Travis announced container-based build and migrated some projects right away (it was mostly a matter of putting &lt;code&gt;sudo: false&lt;/code&gt; and replacing the &lt;code&gt;apt get ...&lt;/code&gt; calls). Their container-based builds are pretty fast and can do a bunch for sure but not everything is doable there. For these other situations, the VM-based runtime is needed and being able to run both of them without changing a lot the configuration (or worse, imagine if I had to create a separate repository?) is pretty good.&lt;/p&gt;
&lt;p&gt;If you want to know more, make sure you look at their official docs on build customization: &lt;a href=&#34;https://docs.travis-ci.com/user/customizing-the-build/&#34;&gt;docs.travis-ci: customizing the build&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be following up soon on how I publish this blog. As a heads up, I use Travis to build the static files and sync with an S3 bucket that serves the content to CloudFront. If you want to know more, make sure you subscribe to the mailing list 👌&lt;/p&gt;
&lt;p&gt;Please let me know if I got something wrong.&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 18 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/parallel-container-vms-travis-ci/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/parallel-container-vms-travis-ci/</guid>

                                
                        </item>
                        
                

                        
                        <item>
                                <title>Why my Ubuntu container doesn&#39;t execute profile scripts?</title>
                                <description>&lt;blockquote&gt;
&lt;p&gt;tl;dr: you&amp;rsquo;re missing the &lt;code&gt;--login&lt;/code&gt; flag in your &lt;code&gt;bash&lt;/code&gt; execution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;yesterday I was trying to test some ansible roles I had written and to do so I was using a containerized version of Ubuntu that I tailored for doing the job - &lt;a href=&#34;https://github.com/cirocosta/docker-ubuntu&#34;&gt;cirocosta/ubuntu&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The image does its job pretty well: it can run with &lt;code&gt;systemd&lt;/code&gt; as the PID 1, it has SSH and I can mess around with systemd services, units .. etc etc as if I had a working &amp;ldquo;VM&amp;rdquo; (given the set of boundaries of how far we can simulate a VM). Anyway &amp;hellip; I faced an issue: my ansible roles were setting some scripts at &lt;code&gt;/etc/profile.d/&lt;/code&gt; but they were not being executed! How dare they?&lt;/p&gt;
&lt;p&gt;It turns out that something pretty simple was going on - the default shell (bash in that case) wasn&amp;rsquo;t being executed as &amp;ldquo;login shell&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Looking at &lt;a href=&#34;https://linux.die.net/man/1/bash&#34;&gt;bash(1)&amp;rsquo;s man page&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;--noprofile
	Do not &lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt; either the system-wide startup file 
	/etc/profile or any of the personal initialization 
	files ~/.bash_profile, ~/.bash_login, or ~/.profile. 
	By default, bash reads these files when it is invoked 
	as a login shell &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;see INVOCATION below&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.

Invocation

	A login shell is one whose first character of argument 
	zero is a -, or one started with the --login option.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;i.e, when we run &lt;code&gt;bash &amp;lt;blabla&amp;gt;&lt;/code&gt; by default, it won&amp;rsquo;t run as a login shell and it turns out that &lt;code&gt;profile&lt;/code&gt; files are only read when running it as &lt;code&gt;login&lt;/code&gt;. Does it? We can easily check that with &lt;code&gt;strace&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;# create a script to be sourced by bash on startup
echo &amp;#34;export FOO=bar&amp;#34; &amp;gt; /etc/profile.d/my-script.sh

# create a simplistic exec file
echo &amp;#34;echo hey!&amp;#34; &amp;gt; ./exec.sh

# execute it without &amp;#39;--login&amp;#39; 
&lt;span class=&#34;hl&#34;&gt;strace -e open bash exec.sh 
&lt;/span&gt;open(&amp;#34;/etc/ld.so.cache&amp;#34;, O_RDONLY|O_CLOEXEC) = 3
...
open(&amp;#34;/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache&amp;#34;, O_RDONLY) = 3
open(&amp;#34;exec.sh&amp;#34;, O_RDONLY)               = 3
hey!
+++ exited with 0 +++

# execute it with &amp;#39;--login&amp;#39; 
&lt;span class=&#34;hl&#34;&gt;strace -e open bash --login exec.sh 
&lt;/span&gt;open(&amp;#34;/etc/ld.so.cache&amp;#34;, O_RDONLY|O_CLOEXEC) = 3
..
open(&amp;#34;/dev/tty&amp;#34;, O_RDWR|O_NONBLOCK)     = 3
open(&amp;#34;/usr/lib/locale/locale-archive&amp;#34;, O_RDONLY|O_CLOEXEC) = 3
open(&amp;#34;/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache&amp;#34;, O_RDONLY) = 3
open(&amp;#34;/etc/profile&amp;#34;, O_RDONLY)          = 3
open(&amp;#34;/etc/profile.d/&amp;#34;, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
&lt;span class=&#34;hl&#34;&gt;open(&amp;#34;/etc/profile.d/my-script.sh&amp;#34;, O_RDONLY) = 3
&lt;/span&gt;open(&amp;#34;exec.sh&amp;#34;, O_RDONLY)               = 3
hey!
+++ exited with 0 +++&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Do you need a full ubuntu container? Should you care about &lt;code&gt;/etc/profile.d&lt;/code&gt; in a container? Probably not. Honestly, aside from testing &lt;code&gt;ansible&lt;/code&gt; roles, I never needed.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s pretty cool how we can super easily verify a behavior making use of a combination of &lt;code&gt;man&lt;/code&gt; to check the docs and &lt;code&gt;strace&lt;/code&gt; to check the syscalls involved. Very handy.&lt;/p&gt;
&lt;p&gt;If you have any questions or just noticed that I wrote something that&amp;rsquo;s totally wrong or that could be made better, reach out! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter. You can also subscribe to the newsletter to keep up with some stuff that I find very useful.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;
</description>
                                <pubDate>Mon, 13 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/why-ubuntu-doesnt-execute-profile-scripts/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/why-ubuntu-doesnt-execute-profile-scripts/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>A Dockerfile tailored for Golang applications</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;The first time I got involved with &lt;a href=&#34;https://docs.docker.com/&#34;&gt;Docker&lt;/a&gt; was three and a half years ago while I was still an undergraduate student.&lt;/p&gt;
&lt;p&gt;By that time, the only thing that used to matter to me in regards to Docker was the fact that I was able to run &amp;ldquo;a minimalistic VM&amp;rdquo; (which is almost an absurd way of referring to Docker or Linux containers in general).&lt;/p&gt;
&lt;p&gt;Remember the time when the blogs were all about &lt;em&gt;&amp;ldquo;how a container compares to a VM&amp;rdquo;&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Some years later (having dealt with Docker in production a lot), the most interesting piece for me (and others it seems) became the container image - this immutable thing that carries all of your dependencies - create a little recipe specifying the steps to reach the final desired state and ship that packed filesystem. A &lt;em&gt;&amp;ldquo;Tarball++&amp;quot;&lt;/em&gt;.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/visualization-of-a-docker-image.svg&#34;
       alt=&#34;Visualization of a Docker image &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;In regards to &lt;a href=&#34;https://golang.org&#34;&gt;Golang&lt;/a&gt;, do we need much effort to create a working image? &lt;strong&gt;Totally not&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Here in this blog post, we go through:&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#the-file-structure-of-a-common-golang-project&#34;&gt;The file structure of a common Golang project&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#an-initial-approach-to-a-golang-docker-image&#34;&gt;An initial approach to a Golang Docker Image&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#improving-the-golang-dockerfile-using-multi-stage-builds&#34;&gt;Improving the Golang Dockerfile using multi-stage builds&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-minimal-golang-dockerfile&#34;&gt;The minimal Golang Dockerfile&lt;/a&gt;; and&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#some-remarks&#34;&gt;Some remarks&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;/div&gt;

&lt;h3 id=&#34;the-file-structure-of-a-common-golang-project&#34;&gt;The file structure of a common Golang project&lt;/h3&gt;
&lt;p&gt;For almost every Go project, I tend to always structure my Golang application in the same way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── .editorconfig
├── Dockerfile          &lt;span class=&#34;c1&#34;&gt;# By placing the Dockerfile on the root&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# we can make it very simple - when executing&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# the `docker build` command from the root&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# the context of the build will carry all the&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# relevant Go files and dependencies (assuming &lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# you have a `vendor` directory at least).&lt;/span&gt;
├── Makefile
├── vendor
├── lib                 &lt;span class=&#34;c1&#34;&gt;# A sample Golang package (you&amp;#39;d probably not call&lt;/span&gt;
│   ├── foo.go          &lt;span class=&#34;c1&#34;&gt;# it `lib`, but something more meaningful).&lt;/span&gt;
│   ├── foo_test.go
│   ├── something.go
│   └── something_test.go
├── anotherpackage      &lt;span class=&#34;c1&#34;&gt;# Another go package.&lt;/span&gt;
│   ├── bar.go
│   └── bar_test.go
├── main.go             &lt;span class=&#34;c1&#34;&gt;# The `main` package.&lt;/span&gt;
└── VERSION
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way, I have to make minimal changes to this &lt;code&gt;Dockerfile&lt;/code&gt; and the &lt;code&gt;Makefile&lt;/code&gt; that I use (check the &lt;code&gt;Makefile&lt;/code&gt; at &lt;a href=&#34;https://ops.tips/blog/minimal-golang-makefile&#34;&gt;Minimal Golang Makefile&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;By keeping it simple like that we can build almost any kind of Docker images for all sorts of Golang projects without having to learn weird &lt;code&gt;Makefile&lt;/code&gt; syntax or something complex for such a simple task.&lt;/p&gt;
&lt;h3 id=&#34;an-initial-approach-to-a-golang-docker-image&#34;&gt;An initial approach to a Golang Docker Image&lt;/h3&gt;
&lt;p&gt;If we take a multi-step approach to reach a very minimal Go Dockerfile, we can start with a path where we pack all the Golang source into it, build the code and then we&amp;rsquo;re done with it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Retrieve the `golang:alpine` image to provide us the &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# necessary Golang tooling for building Go binaries.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here I retrieve the `alpine`-based just for the &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# convenience of using a tiny image.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; golang:alpine&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Add the `main` file that is really the only Golang &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# file under the root directory that matters for the &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# build &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./main.go /go/src/github.com/cirocosta/l7/main.go&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Add all the files from the packages that I own&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./lib /go/src/github.com/cirocosta/l7/lib&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Add vendor dependencies (committed or not)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# I typically commit the vendor dependencies as it&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# makes the final build more reproducible and less&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# dependant on dependency managers.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./vendor /go/src/github.com/cirocosta/l7/vendor&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 0.    Set some shell flags like `-e` to abort the &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       execution in case of any failure (useful if we &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       have many &amp;#39;;&amp;#39; commands) and also `-x` to print to &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       stderr each command already expanded.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 1.    Get into the directory with the golang source code&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 2.    Perform the go build with some flags to make our&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       build produce a static binary (CGO_ENABLED=0 and &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       the `netgo` tag).&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 3.    copy the final binary to a suitable location that&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#       is easy to reference in the next stage&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -ex &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /go/src/github.com/cirocosta/l7 &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;      &lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nv&#34;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; go build &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -tags netgo &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -v -a &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -ldflags &lt;span class=&#34;s1&#34;&gt;&amp;#39;-extldflags &amp;#34;-static&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  mv ./l7 /usr/bin/l7&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Set the binary as the entrypoint of the container&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ENTRYPOINT&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;l7&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While this is an approach that indeed works, it has two drawbacks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;it makes you have to update the Dockerfile whenever a new package is created, or the filestructure changes, and&lt;/li&gt;
&lt;li&gt;it ends up in an image that contains the entire Go compiler, Make and other tools that are not needed for the consumer of this image.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can make it better.&lt;/p&gt;
&lt;h3 id=&#34;improving-the-golang-dockerfile-using-multi-stage-builds&#34;&gt;Improving the Golang Dockerfile using multi-stage builds&lt;/h3&gt;
&lt;p&gt;One improvement that we can perform is making use of &lt;a href=&#34;https://docs.docker.com/develop/develop-images/multistage-build/&#34;&gt;multi-stage builds&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This tackles the second drawback outlines in the last section.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/golang-minimal-dockerfile.svg&#34;
       alt=&#34;Illustration of the multi-stage Dockerfile build process &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;The whole idea is that you can separate your build process into stages such that each stage marks an entirely new base image which can &lt;code&gt;COPY&lt;/code&gt; files from previous stages.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Dockerfile&#34; data-lang=&#34;Dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; golang:alpine AS builder&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./main.go /go/src/github.com/cirocosta/l7/main.go&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./lib /go/src/github.com/cirocosta/l7/lib&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./vendor /go/src/github.com/cirocosta/l7/vendor&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -ex &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /go/src/github.com/cirocosta/l7 &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;      &lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nv&#34;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; go build &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -tags netgo &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -v -a &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -ldflags &lt;span class=&#34;s1&#34;&gt;&amp;#39;-extldflags &amp;#34;-static&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  mv ./l7 /usr/bin/l7&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Create the second stage with the most basic that we need - a &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# busybox which contains some tiny utilities like `ls`, `cp`, &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# etc. When we do this we&amp;#39;ll end up dropping any previous &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# stages (defined as `FROM &amp;lt;some_image&amp;gt; as &amp;lt;some_name&amp;gt;`) &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# allowing us to start with a fat build image and end up with &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# a very small runtime image. Another common option is using &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `alpine` so that the end image also has a package manager.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; busybox&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Retrieve the binary from the previous stage&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COPY&lt;/span&gt; --from&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;builder /usr/bin/l7 /usr/local/bin/l7&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Set the binary as the entrypoint of the container&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ENTRYPOINT&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;l7&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just by adding this extra stage you can see the differences in practice.&lt;/p&gt;
&lt;p&gt;At least the size of the Go toolchain will be reduced (that&amp;rsquo;s &lt;em&gt;at least&lt;/em&gt; 30MB).&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;ps.: it&amp;rsquo;s not everytime that 30MB makes a difference. I&amp;rsquo;m sure that early optimization is a problem, but this is such a straightforward optimization that everyone can take it without much thought.&lt;/em&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;h3 id=&#34;the-minimal-golang-dockerfile&#34;&gt;The minimal Golang Dockerfile&lt;/h3&gt;
&lt;p&gt;The final optimization missing is reducing those lines that add specific directories to the builder stage.&lt;/p&gt;
&lt;p&gt;While that&amp;rsquo;s something useful to be done when you have &lt;code&gt;RUN&lt;/code&gt; steps in between (it can let you cache directories and avoid re-running build steps all the time), in this case, it&amp;rsquo;s not very useful if you only have a handful of dependencies and no big files in the repository.&lt;/p&gt;
&lt;p&gt;To have an even simple &lt;code&gt;Dockerfile&lt;/code&gt;, we can then replace those adds by a wildcard &lt;code&gt;ADD ./&lt;/code&gt; that simply puts everything we have into the image build context:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Dockerfile&#34; data-lang=&#34;Dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; golang:alpine AS builder&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Add all the source code (except what&amp;#39;s ignored&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# under `.dockerignore`) to the build context.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./ /go/src/github.com/cirocosta/l7/&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -ex &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /go/src/github.com/cirocosta/l7 &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;      &lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nv&#34;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; go build &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -tags netgo &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -v -a &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -ldflags &lt;span class=&#34;s1&#34;&gt;&amp;#39;-extldflags &amp;#34;-static&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  mv ./l7 /usr/bin/l7&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; busybox&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Retrieve the binary from the previous stage&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COPY&lt;/span&gt; --from&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;builder /usr/bin/l7 /usr/local/bin/l7&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Set the binary as the entrypoint of the container&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ENTRYPOINT&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;l7&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;some-remarks&#34;&gt;Some remarks&lt;/h3&gt;
&lt;p&gt;You might want to end up with a &lt;code&gt;FROM alpine&lt;/code&gt; instead of &lt;code&gt;FROM busybox&lt;/code&gt; and then run &lt;code&gt;apk add --update ca-certificates&lt;/code&gt; if your binary needs to perform requests to HTTPS endpoints - just using &lt;code&gt;busybox&lt;/code&gt; will lead to an image that doesn&amp;rsquo;t contain root CA certificates which would make HTTPS requests fail.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in learning how to deal with Docker, Golang or just wanting to learn more about software engineering in general, make sure you subscribe to the mailing list!&lt;/p&gt;
&lt;p&gt;In case of questions or if you spot something odd, please get in touch with me at &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 12 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/dockerfile-golang/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/dockerfile-golang/</guid>

                                
                                        <category>go</category>
                                
                                        <category>docker</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>LVM on loopback devices</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;I remember back when I was introduced to &lt;a href=&#34;https://www.archlinux.org/&#34;&gt;Arch Linux&lt;/a&gt; this thing called &lt;a href=&#34;https://wiki.archlinux.org/index.php/LVM&#34;&gt;LVM&lt;/a&gt; but I never really used it and knew what were its capabilities.&lt;/p&gt;
&lt;p&gt;I simply couldn&amp;rsquo;t understand why someone would want to resize a partition on the fly (guess what, I&amp;rsquo;ve done that so many times in AWS nowadays). Why would someone want to snapshot? Why LVM?&lt;/p&gt;
&lt;p&gt;Now many years after my first Arch Linux installation I understand what are its benefits but I&amp;rsquo;ve never really set up on a Linux machine myself though. Here in this article, I go through the process of how one can play around with LVM without needing to have an extra disk or format anything.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: If you&amp;rsquo;re looking for high-level concepts of LVM, this is not really the place you&amp;rsquo;re looking for. This is just hands-on on how to get it running with a loopback device (&lt;code&gt;/dev/loop*&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: in all of the code below the &amp;ldquo;hashtags&amp;rdquo; before the command (&lt;code&gt;#&lt;/code&gt;) indicates that we&amp;rsquo;re executing it with a privileged user.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ps.: this is an area I&amp;rsquo;m not expert at all! Please be kind of pointing to me the places I got stuff wrong and I&amp;rsquo;ll update right away!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;getting-real&#34;&gt;Getting real&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s verify that we have some loopback devices&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# ls /dev | grep loop&lt;/span&gt;
loop0
loop1
loop2
loop3
loop4
loop5
loop6
loop7
loop-control
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now create a file to hold the data that will be written to the first loopback device.
This is important because we&amp;rsquo;re wanting to simulate a real disk so we have to reserve some space for it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# dd if=/dev/zero of=./lvm0.img bs=50 count=1M&lt;/span&gt;
1048576+0 records in
1048576+0 records out
&lt;span class=&#34;m&#34;&gt;52428800&lt;/span&gt; bytes &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;52&lt;/span&gt; MB, &lt;span class=&#34;m&#34;&gt;50&lt;/span&gt; MiB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; copied, 1.06171 s, 49.4 MB/s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step is linking the loopback devices with the file we just created.
This is important because the file itself is just another regular file in the OS. LVM can&amp;rsquo;t get set up on a regular file though - it demands a special block device (like those you have under &lt;code&gt;/dev&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# losetup /dev/loop0 ./lvm0.img&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that the loopback device has been recognized
as an actual disk&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# fdisk -l&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;Disk /dev/loop0: &lt;span class=&#34;m&#34;&gt;50&lt;/span&gt; MiB, &lt;span class=&#34;m&#34;&gt;52428800&lt;/span&gt; bytes, &lt;span class=&#34;m&#34;&gt;102400&lt;/span&gt; sectors &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
&lt;/span&gt;Units: sectors of &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; * &lt;span class=&#34;nv&#34;&gt;512&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
Sector size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;logical/physical&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes / &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
I/O size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;minimum/optimal&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes / &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes


Disk /dev/sda: &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; GiB, &lt;span class=&#34;m&#34;&gt;10737418240&lt;/span&gt; bytes, &lt;span class=&#34;m&#34;&gt;20971520&lt;/span&gt; sectors
Units: sectors of &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; * &lt;span class=&#34;nv&#34;&gt;512&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
Sector size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;logical/physical&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes / &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
I/O size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;minimum/optimal&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes / &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
Disklabel type: dos
Disk identifier: 0x14f750bf

&lt;span class=&#34;c1&#34;&gt;# lsblk&lt;/span&gt;
lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
&lt;span class=&#34;hl&#34;&gt;loop0    7:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  50M  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; loop          &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;not mounted yet&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;sda      8:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  10G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk 
└─sda1   8:1    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  10G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; part /
sdb      8:16   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  10M  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Check all the partitions that we have in our disks - we should see &lt;code&gt;0&lt;/code&gt; partitions in &lt;code&gt;/dev/loop0&lt;/code&gt;. For doing so we can use &lt;code&gt;GNU parted&lt;/code&gt; (&lt;code&gt;parted&lt;/code&gt; command in ubuntu zesty).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# man parted&lt;/span&gt;

NAME
       GNU Parted - a partition manipulation program

SYNOPSIS
       parted &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;options&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;device &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;options...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;...&lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;

...
      -l, --list
              lists partition layout on all block devices
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s execute it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# parted -l&lt;/span&gt;

Model: VBOX HARDDISK &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;scsi&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;hl&#34;&gt;Disk /dev/sda: 10.7GB                           &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&amp;lt; NOT THE LOOPBACK
&lt;/span&gt;Sector size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;logical/physical&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;      1049kB  10.7GB  10.7GB  primary  ext4         boot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So now what we need to do is format the device and set it to use LVM.
For doing so we can make use of &lt;code&gt;fdisk&lt;/code&gt;. As we don&amp;rsquo;t want to go
through the process using the interactive section we can make use of &lt;code&gt;sfdisk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From &lt;code&gt;man sfdisk&lt;/code&gt; you can see that it&amp;rsquo;s a &amp;ldquo;script-oriented tool for partitioning any block device&amp;rdquo;. Here we only have to submit the same inputs we&amp;rsquo;d use with &lt;code&gt;fdisk&lt;/code&gt; but in the &lt;code&gt;stdin&lt;/code&gt; of the executable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# echo &amp;#34;,,8e,,&amp;#34; | sfdisk /dev/loop0&lt;/span&gt;
Checking that no-one is using this disk right now ... OK

Disk /dev/loop0: &lt;span class=&#34;m&#34;&gt;50&lt;/span&gt; MiB, &lt;span class=&#34;m&#34;&gt;52428800&lt;/span&gt; bytes, &lt;span class=&#34;m&#34;&gt;102400&lt;/span&gt; sectors
Units: sectors of &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; * &lt;span class=&#34;nv&#34;&gt;512&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
Sector size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;logical/physical&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes / &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes
I/O size &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;minimum/optimal&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes / &lt;span class=&#34;m&#34;&gt;512&lt;/span&gt; bytes

&amp;gt;&amp;gt;&amp;gt; Created a new DOS disklabel with disk identifier 0x9f5773d1.
&lt;span class=&#34;hl&#34;&gt;/dev/loop0p1: Created a new partition &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; of &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Linux LVM&amp;#39;&lt;/span&gt; and of size &lt;span class=&#34;m&#34;&gt;49&lt;/span&gt; MiB.
&lt;/span&gt;/dev/loop0p2: Done.

New situation:

Device       Boot Start    End Sectors Size Id Type
&lt;span class=&#34;hl&#34;&gt;/dev/loop0p1       &lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;102399&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;100352&lt;/span&gt;  49M 8e Linux LVM
&lt;/span&gt;
The partition table has been altered.
Calling ioctl&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; to re-read partition table.
Re-reading the partition table failed.: Invalid argument
&lt;span class=&#34;hl&#34;&gt;The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; or kpartx&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.
&lt;/span&gt;Syncing disks.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What does &lt;code&gt;,,8e,,&lt;/code&gt; means? It&amp;rsquo;s the same as &amp;ldquo;create a partition starting at the default start, with the default size, being LVM and using the default value for the bootable property&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;We can understand that better by looking at &lt;code&gt;man sfdisk&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# man sfdisk.8&lt;/span&gt;
...
       Unnamed-fields format

&lt;span class=&#34;hl&#34;&gt;                     start size &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; bootable
&lt;/span&gt;
LIKE WHAT WE DID
           &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;         ,     , 8e ,       ,

              where each line fills one partition descriptor.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can check that &lt;code&gt;8e&lt;/code&gt; is the type of LVM by using &lt;code&gt;fdisk&lt;/code&gt; manually, typing &lt;code&gt;m&lt;/code&gt; to look for help, and then &lt;code&gt;l&lt;/code&gt; to list known partition types:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#fdisk&lt;/span&gt;

press m
press l

Command &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;m &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;help&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: l

 ...
 &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt;  HPFS/NTFS/exFAT 4d  QNX4.x          &lt;span class=&#34;m&#34;&gt;88&lt;/span&gt;  Linux plaintext de  Dell Utility   
                                        ++++++++++++++
&lt;span class=&#34;hl&#34;&gt; &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;  AIX             4e  QNX4.x 2nd part 8e  Linux LVM&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      df  BootIt         
&lt;/span&gt;                                        /&lt;span class=&#34;se&#34;&gt;\+&lt;/span&gt;+++++++++++
                                        &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; 
                                        the 8e we used!
 ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool, we have our &lt;code&gt;/dev/loop0&lt;/code&gt; device partitioned with LVM. Using the same commands we used before we can make sure that the statement is true:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# fdisk -l&lt;/span&gt;

fdisk -l
Disk /dev/loop0: &lt;span class=&#34;m&#34;&gt;50&lt;/span&gt; MiB, &lt;span class=&#34;m&#34;&gt;52428800&lt;/span&gt; bytes, &lt;span class=&#34;m&#34;&gt;102400&lt;/span&gt; sectors
...

Device       Boot Start    End Sectors Size Id Type
&lt;span class=&#34;hl&#34;&gt;/dev/loop0p1       &lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;102399&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;100352&lt;/span&gt;  49M 8e Linux LVM&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But if you go back to the output of the &lt;code&gt;sfdisk&lt;/code&gt; command you can see there was an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;The kernel still uses the old table. 
The new table will be used at the next reboot or 
after you run partprobe&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; or kpartx&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can confirm that indeed there&amp;rsquo;s something wrong if we make use of a command that relies on the mentioned table.&lt;/p&gt;
&lt;p&gt;We can be faced with such problem by using our first LVM command: &lt;code&gt;lvmdiskscan&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# lvmdiskscan &lt;/span&gt;
  /dev/loop0 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      50.00 MiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
  /dev/sda1  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      10.00 GiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
  /dev/sdb   &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      10.00 MiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; disk
  &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; partitions
  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; LVM physical volume whole disks
  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; LVM physical volumes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What? We just created an LVM partition on a disk (on the loopback device) and it says that there&amp;rsquo;s no LVM devices? That&amp;rsquo;s the mentioned problem in place.&lt;/p&gt;
&lt;p&gt;To fix it we can make use of &lt;code&gt;partx&lt;/code&gt; to force an update in the kernel table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# partx --update /dev/loop0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then see the new output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# lvmdiskscan&lt;/span&gt;

&lt;span class=&#34;hl&#34;&gt;  /dev/loop0p1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      49.00 MiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;  /dev/loop0   &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      50.00 MiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
  /dev/sda1    &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      10.00 GiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
  /dev/sdb     &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;      10.00 MiB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 
  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; disk
&lt;span class=&#34;hl&#34;&gt;  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; partitions
&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; LVM physical volume whole disks
  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; LVM physical volumes&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But we still don&amp;rsquo;t have a physical volume that LVM can use.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# lvmdiskscan -l&lt;/span&gt;
  WARNING: only considering LVM devices
  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; LVM physical volume whole disks
  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; LVM physical volumes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To create that we now make use of &lt;code&gt;pvcreate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;PVCREATE(8)                     System Manager&amp;#39;s Manual                    PVCREATE(8)

NAME
&lt;span class=&#34;hl&#34;&gt;       pvcreate — initialize a disk or partition for use by LVM
&lt;/span&gt;
...

Examples
       Initialize  partition  #4 on the third SCSI disk and the entire fifth SCSI disk
       for later use by LVM:

       pvcreate /dev/sdc4 /dev/sde&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So that&amp;rsquo;s cool, we can just follow the example provided and do ourselves:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;# lvmdiskscan -l
  WARNING: only considering LVM devices
  0 LVM physical volume whole disks
  0 LVM physical volumes

&lt;span class=&#34;hl&#34;&gt;# pvcreate /dev/loop0
&lt;/span&gt;WARNING: dos signature detected on /dev/loop0 at offset 510. Wipe it? [y/n]: y
  Wiping dos signature on /dev/loop0.
  Physical volume &amp;#34;/dev/loop0&amp;#34; successfully created.

# lvmdiskscan  -l
  WARNING: only considering LVM devices
  /dev/loop0   [      50.00 MiB] LVM physical volume
  0 LVM physical volume whole disks
  1 LVM physical volume&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So now we have our first physical volume. Next step is creating a volume group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;VGCREATE&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;                     System Manager&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;s Manual                    VGCREATE&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;

NAME
       vgcreate — create a volume group

SYNOPSIS
&lt;span class=&#34;hl&#34;&gt;       vgcreate &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;opts...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; VolumeGroupName PhysicalDevicePath
&lt;/span&gt;
DESCRIPTION
       vgcreate creates a new volume group called VolumeGroupName using the block spe‐
       cial device PhysicalDevicePath.


&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# vgcreate myvg /dev/loop0&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;  Volume group &lt;span class=&#34;s2&#34;&gt;&amp;#34;myvg&amp;#34;&lt;/span&gt; successfully created&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With &lt;code&gt;vgdisplay&lt;/code&gt; we can then check that everything went fine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# vgdisplay &lt;/span&gt;
  --- Volume group ---
&lt;span class=&#34;hl&#34;&gt;  VG Name               myvg
&lt;/span&gt;  System ID             
  Format                lvm2
  Metadata Areas        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  Metadata Sequence No  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
  VG Access             read/write
  VG Status             resizable
  ...
  VG Size               48.00 MiB
  ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have a volume group we can create a logical volume using a desired amount of size from the volume group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# lvcreate --size 10M --name lv1 myvg&lt;/span&gt;
 Rounding up size to full physical extent 12.00 MiB
  Logical volume &lt;span class=&#34;s2&#34;&gt;&amp;#34;lv1&amp;#34;&lt;/span&gt; created.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the logical volume created we can inspect the before and after of &lt;code&gt;vgdisplay&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gd&#34;&gt;--- initial	2017-11-11 18:54:11.000000000 -0200
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ after	2017-11-11 18:54:23.000000000 -0200
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -3,11 +3,11 @@
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;   System ID             
   Format                lvm2
   Metadata Areas        1
&lt;span class=&#34;gd&#34;&gt;-  Metadata Sequence No  1
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+  Metadata Sequence No  2
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;   VG Access             read/write
   VG Status             resizable
   MAX LV                0
&lt;span class=&#34;gd&#34;&gt;-  Cur LV                0
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+  Cur LV                1
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;   Open LV               0
   Max PV                0
   Cur PV                1
&lt;span class=&#34;gu&#34;&gt;@@ -15,6 +15,6 @@
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;   VG Size               48.00 MiB
   PE Size               4.00 MiB
   Total PE              12
&lt;span class=&#34;gd&#34;&gt;-  Alloc PE / Size       0 / 0   
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;-  Free  PE / Size       12 / 48.00 MiB
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+  Alloc PE / Size       3 / 12.00 MiB
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+  Free  PE / Size       9 / 36.00 MiB
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;   VG UUID               TmGsRi-3SZg-kU9Q-FTOI-72rG-XaYB-xkxXYB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clearly, we can see that we took some space from the pool of all available space of the volume group (as it was allocated to the logical volume).&lt;/p&gt;
&lt;p&gt;To finish, just see that our logical volume is not listed under &lt;code&gt;lsblk&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# lsblk&lt;/span&gt;
NAME       MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0        7:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  50M  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; loop 
├─myvg-lv1 253:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  12M  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; lvm  
&lt;span class=&#34;hl&#34;&gt;└─loop0p1  259:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  49M  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; loop 
&lt;/span&gt;sda          8:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  10G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk 
└─sda1       8:1    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  10G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; part /
sdb          8:16   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  10M  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having that we&amp;rsquo;re set to use the partition for anything we want - mounting XFS, EXT4 .. any filesystem you want there and have all the benefits that LVM gives us (which is not the focus of this article).&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Compared to just set up up a block device with a different filesystem, setting up LVM takes a big number of steps. Besides this, it&amp;rsquo;s pretty cool to see that because the interface (a special block device) is so simple we can totally skip the need for a real device and work in the same manner. Once meet the needs of the interface we&amp;rsquo;re done. That&amp;rsquo;s pretty cool IMHO.&lt;/p&gt;
&lt;p&gt;What I plan to do next is script that process and set up multiple loopback devices so that I can experiment with the concept of having multiple volumegroups together with docker volumes.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see if that works out well 🙌.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re struggling with a concept related to this or do something related to your work, your side project .. make sure you subscribe to the newsletter - you&amp;rsquo;ll be interested in other content similar to this.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;h3 id=&#34;resources&#34;&gt;Resources&lt;/h3&gt;
&lt;p&gt;I used two resources (beside &lt;code&gt;man&lt;/code&gt; pages) that really helped me along the way. I want to thank these two for the great resources they provided:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.anthonyldechiaro.com/blog/2010/12/19/lvm-loopback-how-to/&#34;&gt;Anothony&amp;rsquo;s blog: LVM Loopbackv HOW-TO&lt;/a&gt; - this is what I used the most to write the article. It goes through almost the same as I do here but I think I explained more some pieces that he just passed by.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-use-lvm-to-manage-storage-devices-on-ubuntu-16-04&#34;&gt;Digital Ocean: How to use LVM To Manage storage devices on Ubuntu 16.04&lt;/a&gt;: another pretty great article that covers the process of using LVM on Ubuntu but not really focused on loopback devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 11 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/lvm-on-loopback-devices/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/lvm-on-loopback-devices/</guid>

                                
                                        <category>programming</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Minimal Golang Makefile</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Most of the time I see myself creating a &lt;a href=&#34;https://golang.org/&#34;&gt;Golang&lt;/a&gt; project: be it a one-file single-purpose thing or a more complex project.&lt;/p&gt;
&lt;p&gt;To facilitate that process, I try always to keep the structure the same such that there&amp;rsquo;s no need to put much thought into the process of bootstrapping a new project - for me, the less friction to get started, the better.&lt;/p&gt;
&lt;p&gt;The file structure usually looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── .editorconfig       &lt;span class=&#34;c1&#34;&gt;# Allows you to define and maintain &lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# a consistent editor configuration&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# for your project.&lt;/span&gt;
│ 
├── Dockerfile          &lt;span class=&#34;c1&#34;&gt;# Define the steps to build a Docker&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# image that contains just the software&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# I&amp;#39;m building and nothing more.&lt;/span&gt;
│                        
│                       &lt;span class=&#34;c1&#34;&gt;# The benefits that I see here is that &lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# it makes explicit for anyone what are&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# the dependencies. It also provides a&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# reproducible way for people to build&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# your software without worrying about&lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# external dependencies, like, the &lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# compiler toolchain or some shared &lt;/span&gt;
│                       &lt;span class=&#34;c1&#34;&gt;# libraries.&lt;/span&gt;
│                       
├── Makefile    
├── lib                 &lt;span class=&#34;c1&#34;&gt;# A package that we might use in `main`&lt;/span&gt;
│   ├── foo.go
│   ├── foo_test.go
│   ├── something.go
│   └── something_test.go
├── main.go             &lt;span class=&#34;c1&#34;&gt;# `main` package.&lt;/span&gt;
└── VERSION     
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Some things to pay attention:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; [`editorconfig`](https://editorconfig.org/) is a real deal
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use vim with &lt;code&gt;set shiftwidth=2; set tabstop=2&lt;/code&gt; set by default, meaning that I always have two spaces set for identation.&lt;/p&gt;
&lt;p&gt;Go, on the other hand, is all about tabs.&lt;/p&gt;
&lt;p&gt;The standard formatting tool doesn&amp;rsquo;t even allow you to use spaces - see &lt;a href=&#34;https://github.com/golang/go/issues/7101&#34;&gt;cmd/gofmt: remove -tabs and -tabwidth flags&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; People tend to expect a [Dockerfile](https://docs.docker.com/engine/reference/builder/) nowadays
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I get it!&lt;/p&gt;
&lt;p&gt;Because with a standard Docker builder we&amp;rsquo;re able to do the equivalent of vendoring the whole filesystem, it allows the developer to set the versions for all the toolchain around building the code, and that&amp;rsquo;s very convenient for someone who&amp;rsquo;s wanting to consume the software from your repository.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s get to the point - the Golang Makefile.&lt;/p&gt;
&lt;h3 id=&#34;the-annotated-minimal-makefile-for-go&#34;&gt;The (annotated) minimal makefile for Go&lt;/h3&gt;
&lt;p&gt;In this case, I extracted the &lt;code&gt;Makefile&lt;/code&gt; from a test project I started some time ago (a &amp;ldquo;load-balancer&amp;rdquo; that makes use of &lt;code&gt;fasthttp&lt;/code&gt;: &lt;a href=&#34;https://github.com/cirocosta/l7&#34;&gt;cirocosta/l7&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve never used &lt;code&gt;make&lt;/code&gt; before (or if you don&amp;rsquo;t remember the syntax), there&amp;rsquo;s &lt;a href=&#34;https://gist.github.com/isaacs/62a2d1825d04437c6f08&#34;&gt;this &lt;strong&gt;awesome&lt;/strong&gt; Gist from Isaacs&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;ps.: the snippet below is scrollable - if you&amp;rsquo;re seeing the text cut, perform a horizontal scroll.&lt;/em&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;c&#34;&gt;# I usually keep a `VERSION` file in the root so that anyone
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# can clearly check what&amp;#39;s the VERSION of `master` or any
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# branch at any time by checking the `VERSION` in that git
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# revision.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Another benefit is that we can pass this file to our Docker 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# build context and have the version set in the binary that ends
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# up inside the Docker image too.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;VERSION&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell cat ./VERSION&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;IMAGE_NAME&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;      cirocosta/l7


&lt;span class=&#34;c&#34;&gt;# As a call to `make` without any arguments leads to the execution
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# of the first target found I really prefer to make sure that this
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# first one is a non-destructive one that does the most simple 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# desired installation. 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# It&amp;#39;s very common to people set it as `all` but it could be anything 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# like `a`.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt;


&lt;span class=&#34;c&#34;&gt;# Install just performs a normal `go install` which builds the source
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# files from the package at `./` (I like to keep a `main.go` in the root
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that imports other subpackages). 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# As I always commit `vendor` to `git`, a `go install` will typically 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# always work - except if there&amp;#39;s an OS limitation in the build flags 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# (e.g, a linux-only project).
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;install&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	go install -v


&lt;span class=&#34;c&#34;&gt;# Keeping `./main.go` with just a `cli` and `./lib/*.go` with actual 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# logic, `tests` usually reside under `./lib` (or some other subdirectories).
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By using the `./...` notation, all the non-vendor packages are going
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# to be tested if they have test files.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; ./... -v


&lt;span class=&#34;c&#34;&gt;# Just like `test`, formatting what matters. As `main.go` is in the root,
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `go fmt` the root package. Then just `cd` to what matters to you (`vendor`
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# doesn&amp;#39;t matter).
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By using the `./...` notation, all the non-vendor packages are going
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# to be formatted (including test files).
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
        go fmt ./... -v


&lt;span class=&#34;c&#34;&gt;# This target is only useful if you plan to also create a Docker image at
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# the end. 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# I really like publishing a Docker image together with the GitHub release
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# because Docker makes it very simple to someone run your binary without
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# having to worry about the retrieval of the binary and execution of it
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# - docker already provides the necessary boundaries.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	docker build -t cirocosta/l7 .


&lt;span class=&#34;c&#34;&gt;# This is pretty much an optional thing that I tend always to include.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Goreleaser is a tool that allows anyone to integrate a binary releasing
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# process to their pipelines. 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Here in this target With just a simple `make release` you can have a 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# `tag` created in GitHub with multiple builds if you wish. 
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# See more at `gorelease` github repo.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;release&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	git tag -a &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;VERSION&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -m &lt;span class=&#34;s2&#34;&gt;&amp;#34;Release&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
	git push origin &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;VERSION&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
	goreleaser --rm-dist

&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;test&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fmt&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save that content in the &lt;code&gt;Makefile&lt;/code&gt; file in root directory of the project, create a &lt;code&gt;VERSION&lt;/code&gt; file with something like &lt;code&gt;0.0.1&lt;/code&gt; (semver) and you&amp;rsquo;re ready to go.&lt;/p&gt;
&lt;p&gt;Naturally, vendor directories and all of that is already covered.&lt;/p&gt;
&lt;h3 id=&#34;projects-with-many-packages-and-vendor-dependencies&#34;&gt;Projects with many packages and vendor dependencies&lt;/h3&gt;
&lt;p&gt;In bigger projects, you might have a bunch of packages and they&amp;rsquo;re not as flat as I described here.&lt;/p&gt;
&lt;p&gt;Regardless of how big it is, given that in our targets we&amp;rsquo;ve been specifying to the tools that the paths should be recursively traversed (&lt;code&gt;./...&lt;/code&gt;), we don&amp;rsquo;t need to keep updating the Makefile.&lt;/p&gt;
&lt;p&gt;Although this one I supplied is minimal, it stays minimal even if your project grows.&lt;/p&gt;
&lt;p&gt;It might happen though, that you want to include an extra tool that requires exact paths to directories where Golang files live. Maybe your static analyser doesn&amp;rsquo;t have the equivalent of &lt;code&gt;./...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In that case, we can still keep our Makefile minimal.&lt;/p&gt;
&lt;p&gt;One way is adapting the Makefile to handle both nesting and multiple packages &amp;ldquo;intelligently&amp;rdquo; by finding them ahead of time and then suppliying these to your targets.&lt;/p&gt;
&lt;p&gt;First things first, we can combine &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;xargs&lt;/code&gt; utilities to gather the directories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;nv&#34;&gt;GO_SRC_DIRS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	find . -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.go&amp;#34;&lt;/span&gt; -not -path &lt;span class=&#34;s2&#34;&gt;&amp;#34;./vendor/*&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	xargs -I &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt; dirname &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	uniq&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;nv&#34;&gt;GO_TEST_DIRS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	find . -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*_test.go&amp;#34;&lt;/span&gt; -not -path &lt;span class=&#34;s2&#34;&gt;&amp;#34;./vendor/*&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	xargs -I &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt; dirname &lt;span class=&#34;o&#34;&gt;{}&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	uniq&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c&#34;&gt;# Shows the variables we just set.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# By prepending `@` we prevent Make
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# from printing the command before the
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# stdout of the execution.
&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
	@echo &lt;span class=&#34;s2&#34;&gt;&amp;#34;SRC  = &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;GO_SRC_DIRS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
	@echo &lt;span class=&#34;s2&#34;&gt;&amp;#34;TEST = &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;GO_TEST_DIRS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, testing it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make show

&lt;span class=&#34;nv&#34;&gt;SRC&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; ./lib ./lib/sub ./lib .
&lt;span class=&#34;nv&#34;&gt;TEST&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; ./lib
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With those lists as variables, we can make use of them as dependencies for our new &lt;code&gt;fmt&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; targets:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;nf&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;GO_TEST_DIRS&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
	@for dir in $^&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nb&#34;&gt;pushd&lt;/span&gt; ./&lt;span class=&#34;nv&#34;&gt;$$&lt;/span&gt;dir &amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; -v &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nb&#34;&gt;popd&lt;/span&gt; &amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;nf&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;GO_SRC_DIRS&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
	@for dir in $^&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nb&#34;&gt;pushd&lt;/span&gt; ./&lt;span class=&#34;nv&#34;&gt;$$&lt;/span&gt;dir &amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		go fmt &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nb&#34;&gt;popd&lt;/span&gt; &amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As &lt;code&gt;$^&lt;/code&gt; targets all the dependencies, on both targets we&amp;rsquo;re able to use the &lt;code&gt;$ˆ&lt;/code&gt; selector to iterate over the directories of each.&lt;/p&gt;
&lt;p&gt;Note that I&amp;rsquo;m not using &lt;code&gt;cd&lt;/code&gt; to get into the directories. That&amp;rsquo;s because not knowing how deep in the file structure we&amp;rsquo;ll go, just stacking the directory changes with &lt;code&gt;pushd&lt;/code&gt; is easier as to get back to the original place we just need to &lt;code&gt;popd&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;I think it&amp;rsquo;s very handy to keep a standard way of performing basic operations across multiple repositories. In my experience this reduces the friction of moving from one project to another. Having a common flow of how to build, create an image and publish a project using a Makefile has helped me in such area.&lt;/p&gt;
&lt;p&gt;Do you think the same? What are your thoughts?&lt;/p&gt;
&lt;p&gt;Reach me on Twitter at any time &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; and subscribe to the list if you&amp;rsquo;re a Golang developer or simply likes software stuff!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sat, 11 Nov 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/minimal-golang-makefile/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/minimal-golang-makefile/</guid>

                                
                                        <category>programming</category>
                                
                                        <category>go</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>How to install HAProxy with Lua support on MacOS</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;Since 2016, a great &lt;a href=&#34;https://www.lua.org/&#34;&gt;Lua&lt;/a&gt; script has been used by many people deploying &lt;a href=&#34;http://haproxy.org/&#34;&gt;HAProxy&lt;/a&gt; instances that need to allow LetsEncrypt certificates generation: &lt;a href=&#34;https://github.com/janeczku/haproxy-acme-validation-plugin&#34;&gt;haproxy-acme-validation-plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve even written about how to respond to HTTP requests right from HAProxy: &lt;a href=&#34;https://ops.tips/gists/making-haproxy-respond-200ok-to-health-checks/&#34;&gt;Making HAProxy respond 200 OK to health checks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Many other scripts that extend HAProxy&amp;rsquo;s functionality have been made, but that&amp;rsquo;s not the point of this post.&lt;/p&gt;
&lt;p&gt;If you ever need (or want) to test this script in a MacOS machine (or any other Lua script that enhances HAProxy), you&amp;rsquo;d need a special build of it: one that comes with Lua support.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt; users have an easy time with this - since &lt;a href=&#34;https://github.com/Homebrew/homebrew-core/commit/457a23b628d647998687f0a60655173da088ebcc#diff-0cdde0d904aae65215a93b022234123b&#34;&gt;this commit&lt;/a&gt;, an extra option has been added: &lt;code&gt;--lua&lt;/code&gt;, making the how installation a breeze:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Install the `HAPROXY` brew formula with&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the extra `lua` option.&lt;/span&gt;
brew install haproxy &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        --with-lua
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, &lt;em&gt;what if you want to install the very latest HAProxy version from source?&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;installing-haproxy-from-source-with-lua-support&#34;&gt;Installing HAProxy from source with Lua support&lt;/h3&gt;
&lt;p&gt;To install HAProxy from source on a Mac, we need to follow some steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;install HAProxy dependencies (you can discover these using &lt;code&gt;brew info haproxy&lt;/code&gt; if you have &lt;code&gt;brew&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;gather the source code from the official website;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;untar&amp;rdquo; it; and&lt;/li&gt;
&lt;li&gt;compile the code using a set of flags that will allow us to build with the proper Lua support.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Aiming at Lua 5.3, it&amp;rsquo;s required that you first install it (you can use &lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt; for this):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;brew install lua@5.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To properly satisfy the first step though, it&amp;rsquo;s also important that you have the other dependencies as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Discover what are the dependencies&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# that have been set for HAProxy&lt;/span&gt;
brew info &lt;span class=&#34;nv&#34;&gt;haproxy&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; Dependencies
Required: openssl ✔, pcre ✔
Optional: lua ✘

&lt;span class=&#34;c1&#34;&gt;# Install the dependencies&lt;/span&gt;
brew install openssl
brew install pcre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having that done, proceed with the download of the version you want (at this time, &lt;code&gt;1.9-dev0&lt;/code&gt; is the very latest release):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Set the version that we want to get the source&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;VERSION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1.9-dev0

&lt;span class=&#34;c1&#34;&gt;# Grab the haproxy source from their website.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Note that differently from the stable releases,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the development version sits under `devel`.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Make sure you properly modify the URL when you&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# use the stable versions.&lt;/span&gt;
wget http://www.haproxy.org/download/1.9/src/devel/haproxy-&lt;span class=&#34;nv&#34;&gt;$VERSION&lt;/span&gt;.tar.gz
tar xzf haproxy-&lt;span class=&#34;nv&#34;&gt;$VERSION&lt;/span&gt;.tar.gz
&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; haproxy-&lt;span class=&#34;nv&#34;&gt;$VERSION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being in the source directory of the HAProxy version, make sure that there&amp;rsquo;s no &lt;code&gt;--export-dynamic&lt;/code&gt; property set in the &lt;code&gt;LUA_LD_FLAGS&lt;/code&gt; line of the &lt;code&gt;Makefile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Such flag is not available in the MacOS linker, so, with it, your build will fail.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/Makefile b/Makefile
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;index 26b55db..d02c858 100644
&lt;/span&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/Makefile
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/Makefile
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -629,7 +629,7 @@ check_lua_inc = $(shell if [ -d $(2)$(1) ]; then echo $(2)$(1); fi;)
&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt; 
 BUILD_OPTIONS   += $(call ignore_implicit,USE_LUA)
 OPTIONS_CFLAGS  += -DUSE_LUA $(if $(LUA_INC),-I$(LUA_INC))
&lt;span class=&#34;gd&#34;&gt;-LUA_LD_FLAGS := -Wl,--export-dynamic $(if $(LUA_LIB),-L$(LUA_LIB))
&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+LUA_LD_FLAGS := -Wl $(if $(LUA_LIB),-L$(LUA_LIB))
&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt; ifeq ($(LUA_LIB_NAME),)
 # Try to automatically detect the Lua library
 LUA_LIB_NAME := $(firstword $(foreach lib,lua5.3 lua53 lua,$(call check_lua_lib,$(lib),$(LUA_LD_FLAGS))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the &lt;code&gt;Makefile&lt;/code&gt; fixed, proceed with the compilation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# build the source code.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# for doing this you must at least have a recent C compiler&lt;/span&gt;

make -j6 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGET&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;osx &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_KQUEUE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_POLL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_PCRE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_THREAD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_OPENSSL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_ZLIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;USE_LUA&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_LIB_NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;lua &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_LIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/lib/ &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_INC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/include &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SSL_LIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/opt/openssl/lib &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SSL_INC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/opt/openssl/include &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ADDLIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;-lcrypto

&lt;span class=&#34;c1&#34;&gt;# Check if everything was correctly installed.&lt;/span&gt;
./haproxy -vvvv
HA-Proxy version 1.9-dev0-b306650 2017/11/26
Copyright 2000-2017 Willy Tarreau &amp;lt;willy@haproxy.org&amp;gt;


..
  &lt;span class=&#34;nv&#34;&gt;OPTIONS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USE_ZLIB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USE_POLL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USE_KQUEUE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USE_OPENSSL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USE_LUA&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;USE_PCRE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
...
Built with Lua version : Lua 5.3.4
...

&lt;span class=&#34;c1&#34;&gt;# link it to `/usr/local/bin/haproxy` (which is in my $PATH) so I&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# can access it directly from `cli`&lt;/span&gt;
ln -s &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;realpath haproxy&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; /usr/local/bin/haproxy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;Now you should have the binary ready to be used.&lt;/p&gt;
&lt;p&gt;If you want to know how to get TLS certificates with LetsEncrypt and HAProxy, make sure you check a blog post I wrote about the topic: &lt;a href=&#34;https://ops.tips/blog/tls-certificates-haproxy-letsencrypt/&#34;&gt;Getting TLS certificates with Letsencrypt and HAProxy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In case you have any questions, please let me know! I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter and would love your feedback.&lt;/p&gt;
&lt;p&gt;Also, make sure you subscribe to the mailing list if you like the topic!&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Fri, 27 Oct 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/installing-haproxy-lua-macos/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/installing-haproxy-lua-macos/</guid>

                                
                                        <category>haproxy</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>HAProxy Docker Container Logs</title>
                                <description>&lt;p&gt;If you simply take the official HAProxy docker image, you&amp;rsquo;ll quickly see that your logs will not show.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because by default, HAProxy won&amp;rsquo;t log to stdout - you need to have a facility (rsyslog) that will take those logs and ship it to somewhere.&lt;/p&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 60rem; &#34;
       src=&#34;https://ops.tips/gists/-/images/haproxy-rsyslog-architecture.svg&#34;
       alt=&#34;Location of the Docker-for-mac preferences menu &#34; &gt;

    
&lt;/figure&gt;

&lt;h3 id=&#34;a-dockerfile-with-rsyslog-for-haproxy-logging&#34;&gt;A Dockerfile with RSYSLOG for HAProxy logging&lt;/h3&gt;
&lt;p&gt;Although adding rsyslog is straightforward with the alpine-based image, we can go further with linking the generated &lt;code&gt;haproxy.log&lt;/code&gt; from &lt;code&gt;rsyslog&lt;/code&gt; to &lt;code&gt;/dev/stdout&lt;/code&gt; such that whenever rsyslog writes HAProxy logs, it goes directly to stdout (such that any log aggregation driver from Docker can pick).&lt;/p&gt;
&lt;p&gt;Given that we need to have some configuration files and a custom entrypoint, I created the following file structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;.
├── Dockerfile          &lt;span class=&#34;c1&#34;&gt;# image description&lt;/span&gt;
├── entrypoint.sh       &lt;span class=&#34;c1&#34;&gt;# executable script to launch both&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;# haproxy and rsyslog.&lt;/span&gt;
└── etc                 &lt;span class=&#34;c1&#34;&gt;# configuration files&lt;/span&gt;
    ├── haproxy.cfg     &lt;span class=&#34;c1&#34;&gt;# haproxy config&lt;/span&gt;
    └── rsyslog.conf    &lt;span class=&#34;c1&#34;&gt;# rsyslog config&lt;/span&gt;

&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; directory, &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Dockerfile doesn&amp;rsquo;t do much:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;starts from the &lt;a href=&#34;http://hub.docker.com/_/haproxy&#34;&gt;official HAProxy image&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;adds rsyslog;&lt;/li&gt;
&lt;li&gt;creates the file that rsyslog will log contents to;&lt;/li&gt;
&lt;li&gt;links the haproxy log with the stdout device.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Dockerfile&#34; data-lang=&#34;Dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; haproxy:1.8-alpine&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -x	&lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	apk upgrade --update					&lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;	apk add bash ca-certificates rsyslog	                &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class=&#34;err&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;	mkdir -p /etc/rsyslog.d/				&lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class=&#34;err&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;	touch /var/log/haproxy.log				&lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class=&#34;err&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;# here&amp;#39;s the catch: by creating a soft-link that &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;# links /var/log/haproxy.log to /dev/stdout whatever &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;# rsyslogd writes to the file will endup being&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;# propagated to the standard output of the container&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;	ln -sf /dev/stdout /var/log/haproxy.log&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Include our configurations (`./etc` contains the files that we&amp;#39;d&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# need to have in the `/etc` of the container).&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./etc/ /etc/&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Include our custom entrypoint that will the the job of lifting&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# rsyslog alongside haproxy.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; ./entrypoint.sh /usr/local/bin/entrypoint&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Set our custom entrypoint as the image&amp;#39;s default entrypoint&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ENTRYPOINT&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;entrypoint&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Make haproxy use the default configuration file&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CMD&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-f&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/etc/haproxy.cfg&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now looking at the configuration files, we have two: the rsyslog configuration and the haproxy configuration.&lt;/p&gt;
&lt;p&gt;The rsyslog is tailored with a facility (&lt;code&gt;local0&lt;/code&gt;) to be used solely by haproxy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Loads the imudp into rsyslog address space&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and activates it.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# IMUDP provides the ability to receive syslog&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# messages via UDP.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;$ModLoad imudp&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Address to listen for syslog messages to be &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# received.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;$UDPServerAddress 0.0.0.0&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Port to listen for the messages&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;$UDPServerRun 514&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Take the messages of any priority sent to the&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# local0 facility (which we reference in the haproxy&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# configuration) and send to the haproxy.log &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# file.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;local0.* -/var/log/haproxy.log&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Discard the rest&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;&amp;amp; ~&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The HAProxy configuration then, with &lt;code&gt;local0&lt;/code&gt; as the target for the logs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Setting `log` here with the address of 127.0.0.1 will have the effect&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# of haproxy sending the udp log messages to its own rsyslog instance&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# (which sits at `127.0.0.1`) at the `local0` facility including all&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# logs that have a priority greater or equal than debug&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;global&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;maxconn                   2046&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;log                       127.0.0.1       local0  debug&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# By default we want to use the same logging parameters as defined&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# in the global section.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;defaults&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;log                       global&lt;/span&gt;


&lt;span class=&#34;c1&#34;&gt;# Simple frontend that will take some HTTP requests from port :80&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# and then always pick the `backend_default` default backend.&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Naturally, this configuration you&amp;#39;d replace by whatever makes more&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# sense to your application.&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;frontend        http&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;bind                      :80&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;default_backend           backend_default&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# A non-existent backend that would never return - again, this would&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# be replaced by something that makes sense to your application, maybe&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# something that gets generated whenever a new container goes up or&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# it could be picked via DNS (as HAProxy now supports SRV records).&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;backend         backend_default&lt;/span&gt;
                &lt;span class=&#34;na&#34;&gt;server                    local-server 127.0.0.1:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can then raise those two components (HAProxy and RSYSLOG) by making the entrypoint do so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o errexit
&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -o nounset

&lt;span class=&#34;nb&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;RSYSLOG_PID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/run/rsyslogd.pid&amp;#34;&lt;/span&gt;

main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  start_rsyslogd
  start_lb &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# make sure we have rsyslogd&amp;#39;s pid file not&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# created before&lt;/span&gt;
start_rsyslogd&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  rm -f &lt;span class=&#34;nv&#34;&gt;$RSYSLOG_PID&lt;/span&gt;
  rsyslogd -n
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Starts the load-balancer (haproxy) with &lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# whatever arguments we pass to it (&amp;#34;$@&amp;#34;)&lt;/span&gt;
start_lb&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; haproxy &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;

main &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create the image and you&amp;rsquo;re good to go!&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;Redirecting all the logs from rsyslog to the standard out device makes haproxy logs play nice with docker default logging. It also has the upside of allowing us to not be concerned about log rotation from within the load-balancer container - either the log aggregation platform that takes the HAProxy logs would take care of it or even the standard &lt;code&gt;json-file&lt;/code&gt; driver would do the log rotation.&lt;/p&gt;
&lt;p&gt;This configuration is fairly simplistic - it doesn&amp;rsquo;t account the eventual failure of rsyslog that might occur. In that case, I&amp;rsquo;d say the best would be to kill the container and let it be recreated (although I never saw rsyslog diying like that).&lt;/p&gt;
&lt;p&gt;Please let me know if you have any questions or if you have any suggestions.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; and would appreciate!&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Fri, 20 Oct 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/gists/haproxy-docker-container-logs/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/gists/haproxy-docker-container-logs/</guid>

                                
                                        <category>haproxy</category>
                                
                        </item>
                        
                

                        
                        <item>
                                <title>Augmenting Linux Swap Space</title>
                                <description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;the first time I had a machine provisioned using a set of scripts I noticed that I had a hardcoded value for the amount of swap space that it could handle.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Damn! All my machines are using the same amount of swap! Can I fix that?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&#34;expanded-container&#34;
  
  &gt;
    &lt;img
        width=&#34;100%&#34; height=&#34;100%&#34;
       style=&#34;max-width: 65rem; &#34;
       src=&#34;https://ops.tips/blog/-/images/linux-swap-increase.svg&#34;
       alt=&#34;illustration of an increase in the size of the swap in a Linux system &#34; &gt;

    
&lt;/figure&gt;

&lt;p&gt;It turns out that increasing the swap space is pretty straightforward.&lt;/p&gt;
&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;: just create an extra file and activate it - Linux will add it to the count of available swap space.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;If you&amp;rsquo;ve ever needed to extend the amount of swap space that you have in your Linux machine, be it Ubuntu, CentOS or any other distribution, this blog post is for you.&lt;/p&gt;
&lt;h3 id=&#34;simulating&#34;&gt;Simulating&lt;/h3&gt;
&lt;p&gt;To simulate the action, we can follow some steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Prepare a virtual machine where we can mess with swap space.&lt;/li&gt;
&lt;li&gt;Set up a single swap area and activate it&lt;/li&gt;
&lt;li&gt;Expand the total amount of swap by creating an extra file, setting it as a swap area and enabling it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the simulation is done, we can verify that we can end up with a system that has more swap space than before.&lt;/p&gt;
&lt;h3 id=&#34;1-preparing-a-vm&#34;&gt;1. Preparing a VM&lt;/h3&gt;
&lt;p&gt;The easiest way of creating a VM that I know is making use of the excellent &lt;a href=&#34;https://vagrantup.com&#34;&gt;Vagrant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It allows you to prepare a &lt;code&gt;ruby&lt;/code&gt; file that tells it how to create a set of machines given a spec that you define.&lt;/p&gt;
&lt;p&gt;What I like the most of it is that even though it&amp;rsquo;s &lt;code&gt;ruby&lt;/code&gt; (and not something like &lt;code&gt;yaml&lt;/code&gt;) it&amp;rsquo;s very declarative (I know nothing about &lt;code&gt;ruby&lt;/code&gt; and can go with it pretty well).&lt;/p&gt;
&lt;p&gt;Having &lt;code&gt;vagrant&lt;/code&gt; properly installed we need to create a &lt;code&gt;Vagrantfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# -*- mode: ruby -*-&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# vi: set ft=ruby :&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# run this little script that changes&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the password of the ubuntu user after&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# the machine gets booted up&lt;/span&gt;
&lt;span class=&#34;vg&#34;&gt;$script&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;SCRIPT
&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu:admin&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chpasswd&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;SCRIPT&lt;/span&gt;

&lt;span class=&#34;no&#34;&gt;Vagrant&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# set the image to be used to be ubuntu/zesty64&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ubuntu/zesty64&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# set the hostname of the machine&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test-machine&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# do not check for base image updates&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;box_check_update&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# do not sync the default vagrant directory&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;synced_folder&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/vagrant&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;disabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# provision the machine with a custom script&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provision&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;inline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;vg&#34;&gt;$script&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# configure some parameters from the virtualbox provider&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;virtualbox&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;512&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;vagrant up&lt;/code&gt; gives us a virtual machine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;vagrant up
Bringing machine &lt;span class=&#34;s1&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt; up with &lt;span class=&#34;s1&#34;&gt;&amp;#39;virtualbox&amp;#39;&lt;/span&gt; provider...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Importing base box &lt;span class=&#34;s1&#34;&gt;&amp;#39;ubuntu/zesty64&amp;#39;&lt;/span&gt;...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Matching MAC address &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; NAT networking...
...
    default: &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;guest&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&#34;m&#34;&gt;2200&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;host&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;adapter 1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Setting hostname...
&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&amp;gt; default: Running provisioner: shell...
    default: Running: inline script
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can &lt;code&gt;SSH&lt;/code&gt; into the machine at any time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;vagrant ssh default

&lt;span class=&#34;c1&#34;&gt;# or&lt;/span&gt;

ssh ubuntu@localhost -p &lt;span class=&#34;m&#34;&gt;2200&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# password is `admin` as set by the provisioning&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# script that we defined in the Vagrantfile&lt;/span&gt;

Welcome to Ubuntu 17.04 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;GNU/Linux 4.10.0-26-generic x86_64&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;

 * Documentation:  https://help.ubuntu.com
 ...

ubuntu@test-machine:~$ 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have a VM running we can give it some swap space. All the following commands are meant to be executed inside the VM.&lt;/p&gt;
&lt;h3 id=&#34;2-activating-some-wrong-swap-space&#34;&gt;2. Activating some wrong swap space&lt;/h3&gt;
&lt;p&gt;The first thing to do is allocate some space on a disk that Linux can refer to when swapping. Here we can choose two approaches: &lt;code&gt;fallocate&lt;/code&gt; or &lt;code&gt;dd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fallocate&lt;/code&gt; is used to manipulate the allocated disk space for a file, either to deallocate or preallocate it. For filesystems which support the &lt;code&gt;fallocate&lt;/code&gt; system call, preallocation is done quickly by allocating blocks and marking them as uninitialized, requiring no &lt;code&gt;IO&lt;/code&gt; to the data blocks.&lt;/p&gt;
&lt;p&gt;This is much faster than creating a file by filling it with zeroes as one would do with &lt;code&gt;dd&lt;/code&gt;. You can check it with the following snippet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;swap_file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/mnt/1g.swap
&lt;span class=&#34;nb&#34;&gt;time&lt;/span&gt; dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1M &lt;span class=&#34;nv&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;

1024+0 records in
1024+0 records out
&lt;span class=&#34;m&#34;&gt;1073741824&lt;/span&gt; bytes &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.1 GB, 1.0 GiB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; copied, 1.51977 s, &lt;span class=&#34;m&#34;&gt;707&lt;/span&gt; MB/s

real	0m1.534s
user	0m0.008s
sys	0m0.756s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now comparing to the &lt;code&gt;fallocate&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;rm -rf &lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;time&lt;/span&gt; fallocate --length 1g &lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

real	0m0.022s
user	0m0.000s
sys	0m0.000s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;ps&#34;&gt;

&lt;p&gt;&lt;em&gt;ps.: this amount of time might not matter much if we&amp;rsquo;re allocating just a small amount like 1g and it&amp;rsquo;s not at instance-startup time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;However, having something like 64G could take some unnecessary time from the instance startup.&lt;/em&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;After space on disk has been reserved for &lt;code&gt;swap&lt;/code&gt; we need now to
make it so that Linux understands that file as a linux swap area
designed for such purpose - &lt;code&gt;mkswap&lt;/code&gt; is the command to do the job.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkswap &lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt;

mkswap: /mnt/1g.swap: insecure permissions 0644, &lt;span class=&#34;m&#34;&gt;0600&lt;/span&gt; suggested.
Setting up swapspace version 1, &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; MiB &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1073737728&lt;/span&gt; bytes&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
no label, &lt;span class=&#34;nv&#34;&gt;UUID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0ef91bd0-3691-4dde-848c-44699289d733
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the operation succeeds, we need to activate the swap area. &lt;code&gt;swapon&lt;/code&gt;
is the command that does so. You just need to specify the file and Linux
will keep a reference to it to swap in when needed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;free -h
              total        used        free      shared  buff/cache   available
Mem:           486M         62M        361M        1.8M         62M        406M
&lt;span class=&#34;hl&#34;&gt;Swap:            0B          0B          0B
&lt;/span&gt;                /&lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; NO SWAP

&lt;span class=&#34;hl&#34;&gt;swapon &lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt;
&lt;/span&gt;
free -h
              total        used        free      shared  buff/cache   available
Mem:           486M         62M        360M        1.8M         62M        406M
&lt;span class=&#34;hl&#34;&gt;Swap:          1.0G          0B        1.0G
&lt;/span&gt;                /&lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;                &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; SWAP ACTIVATED&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ok, we got some swap space! Now, can we make it bigger?&lt;/p&gt;
&lt;h3 id=&#34;3-extending-it&#34;&gt;3. Extending it&lt;/h3&gt;
&lt;p&gt;Sure, making it bigger is just a matter of adding an extra file where we can submit swap memory to it and making sure that Linux keeps track of it.&lt;/p&gt;
&lt;p&gt;Just execute the same commands as before but targetting a new file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;nv&#34;&gt;swap_file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/mnt/2g.swap
dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1M &lt;span class=&#34;nv&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt;
mkswap &lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt;
swapon &lt;span class=&#34;nv&#34;&gt;$swap_file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After all, we should now have 3G of swap space:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;free -h
              total        used        free      shared  buff/cache   available
Mem:           486M         62M        7.1M        1.8M        416M        406M
Swap:          3.0G          0B        3.0G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id=&#34;gotchas&#34;&gt;Gotchas&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q&lt;/strong&gt;: Can you allocate as much space as you want?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, there&amp;rsquo;s an amount in the number of pages that Linux will allow to be
addressed by swap area headers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q&lt;/strong&gt;: Can you create as many swap areas as you want?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, there&amp;rsquo;s a limit on that amount as well and each allocated swap area
can be found in &lt;code&gt;/proc/swaps&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;This was one of those simple little things that you learn by doing and really has no secrets.&lt;/p&gt;
&lt;p&gt;I already knew how to increase swap because I had previously hardcoded things before and wanted to change later but this one I also faced in the middle of a call when a machine was literally close to getting OOM triggered because all the RAM had been taken and swap space was almost done.&lt;/p&gt;
&lt;p&gt;To have just a little bit more of time to investigate the leak I just had to increase the swap space and then let it crash after the investigation. These steps did the job.&lt;/p&gt;
&lt;p&gt;By the way, if you want to know more about Linux in general, some tips regarding on-call stuff, operations, and software engineering you should definitely subscribe to the newsletter - I occasionally send some links and content that I&amp;rsquo;d really like to receive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you have any questions or just want to chat a little bit, let me know!&lt;/strong&gt; I&amp;rsquo;m &lt;a href=&#34;https://twitter.com/cirowrc&#34;&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;p&gt;Have a good one!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;finis&lt;/em&gt;&lt;/p&gt;
</description>
                                <pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate>
                                <link>https://ops.tips/blog/augmenting-swap-space/</link>
                                <author>Ciro S. Costa</author>
                                <guid isPermaLink="true">https://ops.tips/blog/augmenting-swap-space/</guid>

                                
                                        <category>linux</category>
                                
                        </item>
                        
                
        </channel>
</rss>
