<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://ibnusani.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ibnusani.com/" rel="alternate" type="text/html" /><updated>2025-11-20T10:38:11+00:00</updated><id>https://ibnusani.com/feed.xml</id><title type="html">Mind dump</title><subtitle>Manifesting thoughts.</subtitle><author><name>Ahmad Syazwan</name></author><entry><title type="html">Easy Makefile self-documentation</title><link href="https://ibnusani.com/article/easy-makefile-self-documentation/" rel="alternate" type="text/html" title="Easy Makefile self-documentation" /><published>2020-05-20T00:00:00+00:00</published><updated>2020-05-20T00:00:00+00:00</updated><id>https://ibnusani.com/article/easy-makefile-self-documentation</id><content type="html" xml:base="https://ibnusani.com/article/easy-makefile-self-documentation/"><![CDATA[<p>Here’s an easy way to generate makefile help command from its comments that I saw some time ago somewhere.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.DEFAULT_GOAL := help

help:
	@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'

command1: command2 ## Alias of command2
	echo 'Done!'

command2: ## run command2
	echo 'Running command2'

command3: # Unlisted command
	@echo "I'm private"
</code></pre></div></div>

<h2 id="explanation">Explanation</h2>

<ol>
  <li><code class="language-plaintext highlighter-rouge">.DEFAULT_GOAL</code> will run provided make command if none is specified, so by doing <code class="language-plaintext highlighter-rouge">make</code> it will execute <code class="language-plaintext highlighter-rouge">make help</code></li>
  <li><code class="language-plaintext highlighter-rouge">@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST)</code>:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">@</code> will suppress output because by default make will print out the command it’s executing</li>
      <li><code class="language-plaintext highlighter-rouge">grep ...</code> will look for lines that have commands with comments separated by <code class="language-plaintext highlighter-rouge">##</code></li>
      <li><code class="language-plaintext highlighter-rouge">'^[a-zA-Z0-9_-]+:.*?## .*$$'</code> means search from start of line, any alphanumeric, <code class="language-plaintext highlighter-rouge">_</code> and <code class="language-plaintext highlighter-rouge">-</code> command names followed by <code class="language-plaintext highlighter-rouge">:</code> and any character until <code class="language-plaintext highlighter-rouge">##</code> to end of line (since <code class="language-plaintext highlighter-rouge">$</code> has special meaning in make, we have to escape it so end of line becomes <code class="language-plaintext highlighter-rouge">$$</code>)</li>
      <li><a href="https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html"><code class="language-plaintext highlighter-rouge">MAKEFILE_LIST</code></a> is make variable that refers to the makefile name in this case</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">sort</code> to get alphabetically sorted output</li>
  <li><code class="language-plaintext highlighter-rouge">awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'</code>:
    <ul>
      <li>pipe the lines through <code class="language-plaintext highlighter-rouge">awk</code> and set the <a href="https://www.gnu.org/software/gawk/manual/html_node/Field-Separators.html"><code class="language-plaintext highlighter-rouge">FS</code></a> field separator to be whatever between the command and help text (modify <code class="language-plaintext highlighter-rouge">##</code> if you want different separator)</li>
      <li>for each match print with <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">color</a>: <code class="language-plaintext highlighter-rouge">\033[36m%-15s\033[0m %s\n</code> so we will get command, <a href="https://www.gnu.org/software/gawk/manual/html_node/Format-Modifiers.html">padded</a> with 15 spaces, followed by the help text</li>
      <li>again since we’re inside make escape <code class="language-plaintext highlighter-rouge">$1</code> &amp; <code class="language-plaintext highlighter-rouge">$2</code> for column number with <code class="language-plaintext highlighter-rouge">$$1</code> &amp; <code class="language-plaintext highlighter-rouge">$$2</code></li>
    </ul>
  </li>
  <li>For commands you don’t want to be listed as <code class="language-plaintext highlighter-rouge">help</code> output, simply don’t comment or use single <code class="language-plaintext highlighter-rouge">#</code> like <code class="language-plaintext highlighter-rouge">command3</code> example</li>
</ol>

<h2 id="output">Output</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>make
command1        Alias of command2
command2        run command2
</code></pre></div></div>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="makefile" /><summary type="html"><![CDATA[Here’s an easy way to generate makefile help command from its comments that I saw some time ago somewhere.]]></summary></entry><entry><title type="html">Mojave + VirtualBox</title><link href="https://ibnusani.com/article/mojave-virtualbox/" rel="alternate" type="text/html" title="Mojave + VirtualBox" /><published>2019-05-22T00:00:00+00:00</published><updated>2019-05-22T00:00:00+00:00</updated><id>https://ibnusani.com/article/mojave-virtualbox</id><content type="html" xml:base="https://ibnusani.com/article/mojave-virtualbox/"><![CDATA[<p>I have finally decided to upgrade my macs to Mojave from High Sierra. For my work machine however, VirtualBox simply stopped working and throwing <code class="language-plaintext highlighter-rouge">NS_ERROR_FAILURE</code> on startup. Similar to <a href="https://stackoverflow.com/questions/52689672/virtualbox-ns-error-failure-0x80004005-macos">this</a>. Trying to reinstall won’t work because the installer will fail at the last step.</p>

<p>I have tried <em>everything</em> suggested from disabling Gatekeeper to many many iterations of uninstall/reinstall. Almost every solution suggested clicking <code class="language-plaintext highlighter-rouge">Allow</code> on the Security &amp; Privacy tab but it never appeared.</p>

<p>What worked for me finally was: <a href="https://apple.stackexchange.com/a/360123/332949">macos - VirtualBox 5.2 Won’t Install on Mac OS 10.13 - Ask Different</a> which boils down to:</p>

<p>Go into recovery mode (reboot with Cmd + R during loading screen) and open the terminal:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>spctl kext-consent disable
spctl kext-consent add VB5E2TV963
spctl kext-consent enable 
reboot
</code></pre></div></div>

<p>That is basically the <code class="language-plaintext highlighter-rouge">Allow</code> part which will finally make the install successful. <code class="language-plaintext highlighter-rouge">VB5E2TV963</code> is the Oracle id that we are allowing.</p>

<p>If you are in similar situation, I hope this will help.</p>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="virtualbox" /><category term="mojave" /><summary type="html"><![CDATA[I have finally decided to upgrade my macs to Mojave from High Sierra. For my work machine however, VirtualBox simply stopped working and throwing NS_ERROR_FAILURE on startup. Similar to this. Trying to reinstall won’t work because the installer will fail at the last step.]]></summary></entry><entry><title type="html">Moving away from Alpine</title><link href="https://ibnusani.com/article/moving-away-from-alpine/" rel="alternate" type="text/html" title="Moving away from Alpine" /><published>2019-02-14T00:00:00+00:00</published><updated>2019-02-14T00:00:00+00:00</updated><id>https://ibnusani.com/article/moving-away-from-alpine</id><content type="html" xml:base="https://ibnusani.com/article/moving-away-from-alpine/"><![CDATA[<p>When container movement started getting a lot of traction thanks to docker, there was a real demand for lightweight base image that is optimized for single process, unlike your typical OS. Enter Alpine, a lightweight linux distribution as small as 3MB! It also came with good enough <a href="https://pkgs.alpinelinux.org/packages">package repository</a> which helped a lot with adoption. Unfortunately we have stopped adopting Alpine when possible, due to reasons I will outline.</p>

<h2 id="adopting-alpine">Adopting Alpine</h2>
<p>At work, we started adopting Alpine pretty early on for development, CI, and even production. All is well, except when it’s not. Turns out it’s a lot of work to get packages that are not readily available in Alpine repository. You see, Alpine uses <a href="http://www.musl-libc.org/">musl</a> libc instead of <a href="https://www.gnu.org/software/libc/">glibc</a> and most popular distros use the latter. So things compiled in Alpine won’t be usable on Ubuntu, for example, and vice versa. It’s great when all packages you need are there in the <code class="language-plaintext highlighter-rouge">main</code> &amp; <code class="language-plaintext highlighter-rouge">community</code> alpine repositories. When that is not the case, you have to build it on your own and <em>hope</em> that the dependencies are available or at least easy to build as well (against musl).</p>

<h2 id="missing-package">Missing package</h2>
<p>One day our CI started failing during docker image build phase. <code class="language-plaintext highlighter-rouge">mysql</code> package (which is just a compatibility package pointing to mariadb) suddenly went missing. We issued the bug report: <a href="https://bugs.alpinelinux.org/issues/8030">Bug #8030: Missing x86_64 architecture for mysql and mysql-client packages in Alpine v3.3 - Alpine Linux - Alpine Linux Development</a>. To Natanael’s credit, the issue was resolved within the day, but this issue got us to start questioning things.</p>

<h2 id="losing-version">Losing version</h2>
<p>I covered this in a <a href="https://ibnusani.com/article/php-curl-segfault/">previous post</a>, it’s basically about the difficulty in pinning package versions in Alpine. I would continue but I think <a href="https://medium.com/@stschindler/the-problem-with-docker-and-alpines-package-pinning-18346593e891">this guy</a> got through the same situation and has the same thoughts. Recommended read.</p>

<h2 id="when-a-package-is-not-available">When a package is not available</h2>
<p>Developers at work needed to use PHP <a href="http://php.net/manual/en/book.v8js.php">V8js</a> for our experimental branch so I had to get the extension for our alpine-based images. Someone got through most of the trouble for me as he detailed the findings in this Github <a href="https://gist.github.com/tylerchr/15a74b05944cfb90729db6a51265b6c9">gist</a>. Basically we had to compile <a href="https://gn.googlesource.com/gn/">GN</a>, download v8 source, and then build it against musl. Even with the steps laid out, it wasn’t a smooth experience. This method is not sustainable for us, considering future updates and patches.</p>

<h2 id="syslog-limit">Syslog limit</h2>
<p>Developers rely heavily on app logs via syslog (mounted <code class="language-plaintext highlighter-rouge">/dev/log</code>) and Alpine uses busybox <a href="https://wiki.alpinelinux.org/wiki/Syslog">syslog</a> by default. The problem is, messages are truncated at 1024-character limit, which is very small. The root issue is musl has hardcoded limit of 1024 syslog buffer, which is a generous increase from the initial <a href="https://git.musl-libc.org/cgit/musl/commit/src/misc/syslog.c?id=3f65494a4cb2544eb16af3fa64a161bd8142f487">256</a>(!) limit but still not enough. This doesn’t make sense as a default, and I could not find a way to configure this <em>easily</em>.</p>

<h2 id="final-straw">Final straw</h2>
<p>Ubuntu officially launched minimal ubuntu images for cloud / container use around <a href="https://blog.ubuntu.com/2018/07/09/minimal-ubuntu-released">July</a> last year.</p>

<blockquote>
  <p>These images are less than 50% the size of the standard Ubuntu server image, and boot up to 40% faster.</p>
</blockquote>

<p>Not only the base image just 29MB in size, but you also get to use all apt packages! All our previous problems with Alpine made it very easy to switch to ubuntu as our base image and we have been satisfied with the switch so far. This in not to say Alpine is not good. It’s just not a fit for us.</p>

<h3 id="edit-i-need-to-clarify-that-this-post-is-not-about-whats-the-better-alternative-rather-its-about-ditching-alpine-there-are-definitely-few-good-alternatives-to-ubuntu-minimal-">Edit: I need to clarify that this post is not about what’s the better alternative. Rather, it’s about ditching Alpine. There are definitely few good alternatives to ubuntu-minimal. :)</h3>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="docker" /><category term="alpine" /><category term="ubuntu" /><summary type="html"><![CDATA[When container movement started getting a lot of traction thanks to docker, there was a real demand for lightweight base image that is optimized for single process, unlike your typical OS. Enter Alpine, a lightweight linux distribution as small as 3MB! It also came with good enough package repository which helped a lot with adoption. Unfortunately we have stopped adopting Alpine when possible, due to reasons I will outline.]]></summary></entry><entry><title type="html">PHP cURL segfault</title><link href="https://ibnusani.com/article/php-curl-segfault/" rel="alternate" type="text/html" title="PHP cURL segfault" /><published>2019-01-25T00:00:00+00:00</published><updated>2019-01-25T00:00:00+00:00</updated><id>https://ibnusani.com/article/php-curl-segfault</id><content type="html" xml:base="https://ibnusani.com/article/php-curl-segfault/"><![CDATA[<p>Around August 2018, my colleague started to have breaking tests involving curl functions. Few days later, the problem infected our CI. Upon further debugging, we confirmed that it was related to segfaults with curl/libcurl 7.60.0. We didn’t pin our curl version so it got upgraded from 7.59 -&gt; 7.60 during docker image build. Apparently, around June 2018 there were <a href="https://github.com/curl/curl/pull/2669">quite</a> <a href="https://github.com/curl/curl/issues/2688">a</a> <a href="https://github.com/curl/curl/issues/2674">few</a> issues reported related to segfaulting and 7.60.0.</p>

<p>This is the minimal test that could reproduce the problem:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nv">$ch</span> <span class="o">=</span> <span class="nb">curl_init</span><span class="p">();</span>
<span class="nb">curl_setopt</span><span class="p">(</span><span class="nv">$ch</span><span class="p">,</span> <span class="no">CURLOPT_URL</span><span class="p">,</span> <span class="s2">"https://www.google.com"</span><span class="p">);</span>
<span class="nb">curl_exec</span><span class="p">(</span><span class="nv">$ch</span><span class="p">);</span>
<span class="nb">curl_close</span><span class="p">(</span><span class="nv">$ch</span><span class="p">);</span>
</code></pre></div></div>

<p>Which would get you some variation of this coredump:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thread 1 "php" received signal SIGSEGV, Segmentation fault.
0x00007ffff540dfc3 in ?? () from /lib/libssl.so.43
(gdb) bt
#0  0x00007ffff540dfc3 in ?? () from /lib/libssl.so.43
#1  0x00007ffff6545eac in ssl_create_cipher_list () from /lib/libssl.so.1.0.0
#2  0x00007ffff653faf4 in SSL_CTX_new () from /lib/libssl.so.1.0.0
#3  0x00007ffff58a495a in ?? () from /usr/lib/libcurl.so.4
#4  0x00007ffff58a59b9 in ?? () from /usr/lib/libcurl.so.4
#5  0x00007ffff58a6553 in ?? () from /usr/lib/libcurl.so.4
#6  0x00007ffff5867b3c in ?? () from /usr/lib/libcurl.so.4
#7  0x00007ffff5868e7f in ?? () from /usr/lib/libcurl.so.4
#8  0x00007ffff5872030 in ?? () from /usr/lib/libcurl.so.4
#9  0x00007ffff5882810 in ?? () from /usr/lib/libcurl.so.4
#10 0x00007ffff5883470 in curl_multi_perform () from /usr/lib/libcurl.so.4
#11 0x00007ffff5acd1ba in ?? () from /usr/lib/php7/modules/curl.so
</code></pre></div></div>

<p>Ok what the heck, let’s just downgrade, right? That’s what we did via:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.4/main" &gt;&gt; /etc/apk/repositories \
    &amp;&amp; apk update \
    &amp;&amp; apk add --no-cache \
                ...
                curl=7.59.0-r0 \
                libcurl=7.59.0-r0 \
</code></pre></div></div>

<p>That solved it… until a month later when build failed again because the pinned version has gone missing from alpine 3.4 repository. I’ve experienced this a few times, and I’m not <a href="https://medium.com/@stschindler/the-problem-with-docker-and-alpines-package-pinning-18346593e891">alone</a>.</p>

<p>Our solution then is to just upgrade to alpine 3.8 with fixed version of curl and unpinned them. As of this moment of writing, we have migrated away from Alpine, which I will cover in future post.</p>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="curl" /><category term="php" /><summary type="html"><![CDATA[Around August 2018, my colleague started to have breaking tests involving curl functions. Few days later, the problem infected our CI. Upon further debugging, we confirmed that it was related to segfaults with curl/libcurl 7.60.0. We didn’t pin our curl version so it got upgraded from 7.59 -&gt; 7.60 during docker image build. Apparently, around June 2018 there were quite a few issues reported related to segfaulting and 7.60.0.]]></summary></entry><entry><title type="html">docker-compose new naming scheme</title><link href="https://ibnusani.com/article/docker-compose-new-naming-scheme/" rel="alternate" type="text/html" title="docker-compose new naming scheme" /><published>2019-01-21T00:00:00+00:00</published><updated>2019-01-21T00:00:00+00:00</updated><id>https://ibnusani.com/article/docker-compose-new-naming-scheme</id><content type="html" xml:base="https://ibnusani.com/article/docker-compose-new-naming-scheme/"><![CDATA[<p>On 30 October 2018, docker-compose released version <a href="https://docs.docker.com/release-notes/docker-compose/#1230-2018-10-30">1.23.0 (2018-10-30)</a> with a very notable change that would likely break many scripts out there, including mine:</p>

<blockquote>
  <p>The default naming scheme for containers created by Compose in this version has changed from &lt;project&gt;_&lt;service&gt;_&lt;index&gt; to &lt;project&gt;_&lt;service&gt;_&lt;index&gt;_&lt;slug&gt; where &lt;slug&gt; is a randomly-generated hexadecimal string.</p>
</blockquote>

<p>The “warning” came only about 1 month prior, hidden in 1.23.0-rc1 (2018-09-26) <a href="https://github.com/docker/compose/releases/tag/1.23.0-rc1">release note</a>. So previously your <code class="language-plaintext highlighter-rouge">project_app_1</code> will now be <code class="language-plaintext highlighter-rouge">project_app_1_abc123</code>! Unsurprisingly this caused a lot of <a href="https://github.com/docker/compose/issues/6316">breakage and rage</a>.</p>

<p>It was promptly reverted a month later in <a href="https://github.com/docker/compose/blob/master/CHANGELOG.md#1232-2018-11-28">1.23.2 (2018-11-28)</a>.</p>

<p>There’s a lot of lesson to learn here from the perspectives of both maintainer and user of project, as evident by going through the comments in the <a href="https://github.com/docker/compose/issues/6316">issue</a>.</p>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="docker-compose" /><category term="docker" /><summary type="html"><![CDATA[On 30 October 2018, docker-compose released version 1.23.0 (2018-10-30) with a very notable change that would likely break many scripts out there, including mine:]]></summary></entry><entry><title type="html">Dockerizing vim</title><link href="https://ibnusani.com/article/dockerizing-vim/" rel="alternate" type="text/html" title="Dockerizing vim" /><published>2018-08-10T00:00:00+00:00</published><updated>2018-08-10T00:00:00+00:00</updated><id>https://ibnusani.com/article/dockerizing-vim</id><content type="html" xml:base="https://ibnusani.com/article/dockerizing-vim/"><![CDATA[<p>I have dockerized my vim so that I can pull the image and get my familiar vim setup within minutes from any machine (with docker).</p>

<p>I was heavily inspired by <a href="https://github.com/JAremko/alpine-vim">this</a> dockerized vim project. Check it out if you think that’s enough for you. Or you can use the <a href="https://hub.docker.com/r/asyazwan/vim/tags/">images</a> I have prepared:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">asyazwan/vim:tiny</code>   - 24MB compressed / 61MB uncompressed</li>
  <li><code class="language-plaintext highlighter-rouge">asyazwan/vim:small</code>  - 24MB compressed / 61MB uncompressed</li>
  <li><code class="language-plaintext highlighter-rouge">asyazwan/vim:normal</code> - 25MB compressed / 62MB uncompressed</li>
  <li><code class="language-plaintext highlighter-rouge">asyazwan/vim:big</code>    - 25MB compressed / 62MB uncompressed</li>
  <li><code class="language-plaintext highlighter-rouge">asyazwan/vim:huge</code>   - 25MB compressed / 62MB uncompressed</li>
</ul>

<p class="notice--info">Check out <a href="http://www.drchip.org/astronaut/vim/vimfeat.html">this</a> table of comparison for the differences between features</p>

<p>But if you want to make your own image, here’s how I did it.</p>

<p>I have pushed the Dockerfiles used into <a href="https://github.com/asyazwan/docker-vim">this</a> repository. Check out the main Dockerfile:</p>

<div class="language-Dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="w"> </span><span class="s">alpine:3.8</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="s">builder</span>

<span class="k">WORKDIR</span><span class="s"> /tmp</span>

<span class="k">RUN </span>apk add <span class="nt">--no-cache</span> <span class="se">\
</span>  build-base <span class="se">\
</span>  ctags <span class="se">\
</span>  git <span class="se">\
</span>  libx11-dev <span class="se">\
</span>  libxpm-dev <span class="se">\
</span>  libxt-dev <span class="se">\
</span>  make <span class="se">\
</span>  ncurses-dev <span class="se">\
</span>  python3 <span class="se">\
</span>  python3-dev <span class="se">\
</span>  perl-dev <span class="se">\
</span>  ruby-dev

<span class="k">RUN </span>git clone https://github.com/vim/vim <span class="o">&amp;&amp;</span> <span class="nb">cd </span>vim <span class="se">\
</span>  <span class="o">&amp;&amp;</span> ./configure <span class="se">\
</span>  <span class="nt">--disable-gui</span> <span class="se">\
</span>  <span class="nt">--disable-netbeans</span> <span class="se">\
</span>  <span class="nt">--enable-multibyte</span> <span class="se">\
</span>  <span class="nt">--enable-perlinterp</span> <span class="se">\
</span>  <span class="nt">--enable-rubyinterp</span> <span class="se">\
</span>  <span class="nt">--enable-python3interp</span> <span class="se">\
</span>  <span class="nt">--with-features</span><span class="o">=</span>huge <span class="se">\
</span>  <span class="nt">--with-python3-config-dir</span><span class="o">=</span>/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu/ <span class="se">\
</span>  <span class="nt">--with-compiledby</span><span class="o">=</span>asyazwan@gmail.com <span class="se">\
</span>  <span class="o">&amp;&amp;</span> make <span class="nb">install</span>


<span class="k">FROM</span><span class="s"> alpine:3.8</span>

<span class="k">COPY</span><span class="s"> --from=builder /usr/local/bin /usr/local/bin</span>
<span class="k">COPY</span><span class="s"> --from=builder /usr/local/share/vim  /usr/local/share/vim</span>
<span class="k">RUN </span>apk add <span class="nt">--update</span> <span class="nt">--no-cache</span> <span class="se">\
</span>  libice <span class="se">\
</span>  libsm <span class="se">\
</span>  libx11 <span class="se">\
</span>  libxt <span class="se">\
</span>  ncurses <span class="se">\
</span>  python3 <span class="se">\
</span>  ruby <span class="se">\
</span>  perl <span class="se">\
</span>  php7

<span class="k">RUN </span>apk add <span class="nt">--update</span> <span class="nt">--no-cache</span> <span class="se">\
</span>  git <span class="se">\
</span>  bash <span class="se">\
</span>  fish <span class="se">\
</span>  ctags <span class="se">\
</span>  fzf <span class="se">\
</span>  the_silver_searcher

<span class="k">RUN </span>git clone <span class="nt">--depth</span> 1 https://github.com/junegunn/fzf.git ~/.fzf <span class="o">&amp;&amp;</span> ~/.fzf/install


<span class="k">ENTRYPOINT</span><span class="s"> ["vim"]</span>
</code></pre></div></div>

<p>I am utilizing <a href="https://docs.docker.com/develop/develop-images/multistage-build/">multi-stage</a> build for this. It’s to reduce the size of final image since it won’t have all the packages required for building vim like <code class="language-plaintext highlighter-rouge">gcc</code> and various libraries and their headers. Also, if you take out the last 2 <code class="language-plaintext highlighter-rouge">RUN</code> statements and also remove <code class="language-plaintext highlighter-rouge">ruby</code>, <code class="language-plaintext highlighter-rouge">perl</code> and <code class="language-plaintext highlighter-rouge">php7</code> packages, your vim image (uncompressed) will only be around 30MB!</p>

<p>Remove <code class="language-plaintext highlighter-rouge">--enable-&lt;language&gt;interp</code> from the build stage and the language package from the last stage if you don’t want them. Chances are you won’t need them if you don’t already know what they are for.</p>

<p>The second-last <code class="language-plaintext highlighter-rouge">RUN</code> will install additional stuff that I need. <code class="language-plaintext highlighter-rouge">the_silver_searcher</code> is for using <code class="language-plaintext highlighter-rouge">:Ag</code> in vim and <code class="language-plaintext highlighter-rouge">fzf</code> is for lots of useful commands that I use many times a day.
The last <code class="language-plaintext highlighter-rouge">RUN</code> will clone <code class="language-plaintext highlighter-rouge">fzf</code> vim plugin and run the install script.</p>

<p>Use <code class="language-plaintext highlighter-rouge">docker build -t vim-base .</code> to build and you will have a pretty capable vim. Run <code class="language-plaintext highlighter-rouge">docker run --rm vim-base "--version"</code> to see what features have been compiled with vim.</p>

<p>Now that I have base vim, it’s time to bake in some plugins. I’ve been using the same plugins for some time now and I don’t think they’re going to change anytime soon, so I decided to put the plugins into my final vim image. Check out <code class="language-plaintext highlighter-rouge">Dockerfile.plugins</code>:</p>

<div class="language-Dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> asyazwan/vim</span>

<span class="k">ARG</span><span class="s"> USERNAME=syazwan</span>
<span class="k">ARG</span><span class="s"> GROUPNAME=syazwan</span>
<span class="k">ARG</span><span class="s"> WORKSPACE=/home/syazwan</span>
<span class="k">ARG</span><span class="s"> UID=1000</span>
<span class="k">ARG</span><span class="s"> GID=1000</span>
<span class="k">ARG</span><span class="s"> SHELL=/bin/sh</span>

<span class="k">RUN </span>apk add <span class="nt">--no-cache</span> <span class="nb">sudo</span> <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="k">${</span><span class="nv">WORKSPACE</span><span class="k">}</span><span class="s2">"</span> <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2">:x:</span><span class="k">${</span><span class="nv">UID</span><span class="k">}</span><span class="s2">:</span><span class="k">${</span><span class="nv">GID</span><span class="k">}</span><span class="s2">:</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2">,,,:</span><span class="k">${</span><span class="nv">WORKSPACE</span><span class="k">}</span><span class="s2">:</span><span class="k">${</span><span class="nv">SHELL</span><span class="k">}</span><span class="s2">"</span> <span class="se">\
</span>  <span class="o">&gt;&gt;</span> /etc/passwd <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2">::17032:0:99999:7:::"</span> <span class="se">\
</span>  <span class="o">&gt;&gt;</span> /etc/shadow <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2"> ALL=(ALL) NOPASSWD: ALL"</span> <span class="se">\
</span>  <span class="o">&gt;</span> <span class="s2">"/etc/sudoers.d/</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2">"</span> <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">chmod </span>0440 <span class="s2">"/etc/sudoers.d/</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2">"</span> <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">GROUPNAME</span><span class="k">}</span><span class="s2">:x:</span><span class="k">${</span><span class="nv">GID</span><span class="k">}</span><span class="s2">:</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">}</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> /etc/group <span class="se">\
</span>  <span class="o">&amp;&amp;</span> <span class="nb">chown</span> <span class="s2">"</span><span class="k">${</span><span class="nv">UID</span><span class="k">}</span><span class="s2">"</span>:<span class="s2">"</span><span class="k">${</span><span class="nv">GID</span><span class="k">}</span><span class="s2">"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">WORKSPACE</span><span class="k">}</span><span class="s2">"</span>

<span class="k">WORKDIR</span><span class="s"> $WORKSPACE</span>

<span class="k">USER</span><span class="s"> $USERNAME</span>

<span class="k">COPY</span><span class="s"> plug.vim ${WORKSPACE}/.vim/autoload/plug.vim</span>
<span class="k">COPY</span><span class="s"> plugged ${WORKSPACE}/.vim/plugged/</span>
<span class="k">COPY</span><span class="s"> vimrc ${WORKSPACE}/.vimrc</span>
<span class="k">COPY</span><span class="s"> fzf-default.sh ${WORKSPACE}/.vim/fzf-default</span>
<span class="k">RUN </span><span class="nb">sudo mv</span> /root/.fzf <span class="k">${</span><span class="nv">WORKSPACE</span><span class="k">}</span>/.vim/

<span class="k">RUN </span><span class="nb">sudo chown</span> <span class="nt">-R</span> <span class="s2">"</span><span class="k">${</span><span class="nv">UID</span><span class="k">}</span><span class="s2">"</span>:<span class="s2">"</span><span class="k">${</span><span class="nv">GID</span><span class="k">}</span><span class="s2">"</span> .vimrc .vim/
<span class="k">RUN </span>~/.vim/.fzf/install
<span class="k">RUN </span><span class="nb">mkdir</span> <span class="nt">-p</span> .vim/backups .vim/undo
<span class="k">ENV</span><span class="s"> FZF_DEFAULT_COMMAND ~/.vim/fzf-default</span>

<span class="k">ENTRYPOINT</span><span class="s"> ["/usr/bin/fish"]</span>
</code></pre></div></div>

<p>Let’s break down what is going on here. From the base vim image, I create user account the same as I have on the current machine, which can be overriden via <code class="language-plaintext highlighter-rouge">--build-arg</code>. This is to avoid possible file permission/ownership issues. Then I copy my plugin manager <a href="https://github.com/junegunn/vim-plug">Plug</a>, the plugins, vimrc file, and  <a href="https://github.com/junegunn/fzf">fzf</a> files. Entrypoint is set to my current favorite terminal.</p>

<p>To build:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-f</span> Dockerfile.plugins <span class="nt">-t</span> vim <span class="se">\</span>
  <span class="nt">--build-arg</span> <span class="nv">USERNAME</span><span class="o">=</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-un</span><span class="si">)</span> <span class="se">\</span>
  <span class="nt">--build-arg</span> <span class="nv">GROUPNAME</span><span class="o">=</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-gn</span><span class="si">)</span> <span class="se">\</span>
  <span class="nt">--build-arg</span> <span class="nv">UID</span><span class="o">=</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-u</span><span class="si">)</span> <span class="se">\</span>
  <span class="nt">--build-arg</span> <span class="nv">GID</span><span class="o">=</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-g</span><span class="si">)</span> <span class="se">\</span>
  <span class="nt">--build-arg</span> <span class="nv">WORKSPACE</span><span class="o">=</span><span class="nv">$$</span>HOME <span class="se">\</span>
  <span class="nt">--build-arg</span> <span class="nv">SHELL</span><span class="o">=</span>/usr/bin/fish <span class="nb">.</span>
</code></pre></div></div>

<p>Then to run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--rm</span> <span class="nt">-it</span> <span class="nt">--hostname</span> vim <span class="nt">-v</span> <span class="s2">"</span><span class="nv">$PWD</span><span class="s2">"</span>:<span class="nv">$HOME</span>/dev/ vim
</code></pre></div></div>

<p>Which will bring you into fish terminal and <code class="language-plaintext highlighter-rouge">$HOME/dev/</code> workspace. Invoke vim with <code class="language-plaintext highlighter-rouge">vim .</code>.</p>

<p>That’s the idea, basically. From any machine with docker I can just clone the repo and build <code class="language-plaintext highlighter-rouge">Dockerfile.plugins</code> to get my familiar development environment.</p>

<p>Please share if you have suggestions on how to improve it.</p>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="vim" /><category term="docker" /><summary type="html"><![CDATA[I have dockerized my vim so that I can pull the image and get my familiar vim setup within minutes from any machine (with docker).]]></summary></entry><entry><title type="html">Migrating with Postgres FDW</title><link href="https://ibnusani.com/article/migrating-with-postgres-fdw/" rel="alternate" type="text/html" title="Migrating with Postgres FDW" /><published>2018-05-27T00:00:00+00:00</published><updated>2018-05-27T00:00:00+00:00</updated><id>https://ibnusani.com/article/migrating-with-postgres-fdw</id><content type="html" xml:base="https://ibnusani.com/article/migrating-with-postgres-fdw/"><![CDATA[<p>In a situation where you are migrating data from one provider to another and do not want to use intermediate node, foreign data wrapper helps. Foreign data wrapper / FDW allows us to connect to remote data sources from another data source giving the illusion it’s local to us.</p>

<figure class="">
  <img src="/assets/images/2018/fdw-migration.svg" alt="migration illustration" />
  
    <figcaption>
      Migration with &amp; without intermediary

    </figcaption>
  
</figure>

<p class="notice--warning">Earlier versions of Postgres only allows read-only data. As of Postgres 9.3, writing is available so if you are doing write operations take note of that.</p>

<p>My use case was this: I wanted to transfer gigabytes of data from provider A in Singapore region to another provider B in EU region. These providers provide DB access only, no OS-level access. So it wasn’t possible to dump as usual and there’s the issue of size too. To make my workstation the intermediate node (import from A - export to B) would also be a huge waste of bandwidth and space (about 400 GB total). I also don’t have the best internet connection. Enter FDW.</p>

<p>First create the extension:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="n">EXTENSION</span> <span class="n">postgres_fdw</span><span class="p">;</span>
</code></pre></div></div>

<p>Then create the connection:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="n">SERVER</span> <span class="n">myremotedb</span>
<span class="k">FOREIGN</span> <span class="k">DATA</span> <span class="n">WRAPPER</span> <span class="n">postgres_fdw</span>
<span class="k">OPTIONS</span> <span class="p">(</span><span class="k">host</span> <span class="s1">'myremotedb.providera.com'</span><span class="p">,</span> <span class="n">port</span> <span class="s1">'5432'</span><span class="p">,</span> <span class="n">dbname</span> <span class="s1">'mydb'</span><span class="p">,</span> <span class="n">sslmode</span> <span class="s1">'require'</span><span class="p">,</span> <span class="n">fetch_size</span> <span class="s1">'250000'</span><span class="p">);</span>
</code></pre></div></div>

<p class="notice--warning">Important gotcha: find the right <code class="language-plaintext highlighter-rouge">fetch_size</code> for you. The default is 100 rows and extremely small for tables with millions of rows thus can cause big overhead depending on latency between the two servers.</p>

<p>You may exclude or include any server options as you require.</p>

<p>Now that we have the server, next we declare the user mapping:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">USER</span> <span class="n">MAPPING</span> <span class="k">FOR</span> <span class="n">newuser1</span>
<span class="n">SERVER</span> <span class="n">myremotedb</span>
<span class="k">OPTIONS</span> <span class="p">(</span><span class="k">user</span> <span class="s1">'olduser1'</span><span class="p">,</span> <span class="n">password</span> <span class="s1">'password1'</span><span class="p">);</span>
</code></pre></div></div>

<p>Lastly, the schema:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">SCHEMA</span> <span class="n">oldschema</span><span class="p">;</span>

<span class="n">IMPORT</span> <span class="k">FOREIGN</span> <span class="k">SCHEMA</span> <span class="k">public</span> <span class="k">FROM</span> <span class="n">SERVER</span> <span class="n">myremotedb</span> <span class="k">INTO</span> <span class="n">oldschema</span><span class="p">;</span>
</code></pre></div></div>

<p>Now you can query the remote database from the new one as if it’s a local db:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">oldschema</span><span class="p">.</span><span class="n">table1</span><span class="p">;</span>

<span class="c1">-- Migrate: (obviously their structure must be the same)</span>
<span class="k">INSERT</span> <span class="k">INTO</span> <span class="k">public</span><span class="p">.</span><span class="n">table1</span> <span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">oldschema</span><span class="p">.</span><span class="n">table1</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="results">Results</h2>

<p>FDW is usually not the most performant way to do things so it’s rarely the first thing I look at. But here it proved to be useful since my migration wasn’t so time-critical. With this setup I was able to move over 500k rows, 250 MB data in 30s (as opposed to 20m with default <code class="language-plaintext highlighter-rouge">fetch_size</code>!). Moving 2.7m rows, 8 GB data took 80 minutes, which is not so bad.</p>

<p>However, if intermediate node is a non-issue for you, it’s better to use it. In my initial tests using <code class="language-plaintext highlighter-rouge">\copy</code> to dump CSV did over 1k rows/s on average, which is much faster than FDW. But of course that’s exluding importing the dump to the new db.</p>

<p>Recommended reads:</p>
<ul>
  <li><a href="https://wiki.postgresql.org/wiki/Foreign_data_wrappers">List of FDW</a> (More on <a href="https://pgxn.org/tag/fdw/">PGXN</a>)</li>
  <li><a href="http://www.craigkerstiens.com/2016/09/11/a-tour-of-fdws/">Intro to Postgres FDW</a></li>
</ul>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="postgresql" /><category term="postgres-fdw" /><summary type="html"><![CDATA[In a situation where you are migrating data from one provider to another and do not want to use intermediate node, foreign data wrapper helps. Foreign data wrapper / FDW allows us to connect to remote data sources from another data source giving the illusion it’s local to us.]]></summary></entry><entry><title type="html">Docker for Mac logs (updated)</title><link href="https://ibnusani.com/article/docker-for-mac-logs-updated/" rel="alternate" type="text/html" title="Docker for Mac logs (updated)" /><published>2018-02-03T00:00:00+00:00</published><updated>2018-02-03T00:00:00+00:00</updated><id>https://ibnusani.com/article/docker-for-mac-logs-updated</id><content type="html" xml:base="https://ibnusani.com/article/docker-for-mac-logs-updated/"><![CDATA[<p>Some time last month new docker for mac <a href="https://docs.docker.com/docker-for-mac/release-notes/#docker-community-edition-17120-ce-mac46-2018-01-09-stable">shipped with LinuxKit</a>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
linuxkit-025000000001:~# <span class="nb">uname</span> <span class="nt">-a</span>
Linux linuxkit-025000000001 4.9.75-linuxkit-aufs <span class="c">#1 SMP Tue Jan 9 10:58:17 UTC 2018 x86_64 Linux</span>
</code></pre></div></div>

<p>But eventually you’ll discover <code class="language-plaintext highlighter-rouge">/dev/log</code> is missing. Apparently <code class="language-plaintext highlighter-rouge">syslog</code> is not running too.</p>

<p>So <a href="https://github.com/docker/for-mac/issues/2465#issuecomment-359111018">one way</a> to get the log working again is to run syslog:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>linuxkit-025000000001:~# syslogd
</code></pre></div></div>

<p>Which will create <code class="language-plaintext highlighter-rouge">/dev/log</code> socket and write to <code class="language-plaintext highlighter-rouge">/var/log/messages</code> by default and you can continue tailing that log file like before.</p>

<p>Happy logging!</p>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="docker" /><category term="linuxkit" /><summary type="html"><![CDATA[Some time last month new docker for mac shipped with LinuxKit:]]></summary></entry><entry><title type="html">Attaching to another container</title><link href="https://ibnusani.com/article/attaching-to-another-container/" rel="alternate" type="text/html" title="Attaching to another container" /><published>2017-12-02T00:00:00+00:00</published><updated>2017-12-02T00:00:00+00:00</updated><id>https://ibnusani.com/article/attaching-to-another-container</id><content type="html" xml:base="https://ibnusani.com/article/attaching-to-another-container/"><![CDATA[<p>Sometimes you have to debug a running container and you cannot modify the container (without much hassle). For example, you’re running a container that you don’t want to modify, probably because everybody in your office is using the image and you’d want to run the exact same image. Or it could be that the container is highly dependent on by other containers (service containers) and bringing it down to add debug tools will mean restarting the whole stack, which could be very trivial or very involved. Or maybe you started the container with <code class="language-plaintext highlighter-rouge">--rm</code> or <code class="language-plaintext highlighter-rouge">-t</code> options which will make <code class="language-plaintext highlighter-rouge">docker attach</code> tricky or impossible. Or you’re running a redis container and would like to <code class="language-plaintext highlighter-rouge">strace</code> why it seems stuck. Or you’re running a python container and would like to use <code class="language-plaintext highlighter-rouge">ipython</code> inside the container which is not available so you’d have to install, commit and rebuild the image (or ephemerally install on the running container). Or you have a Go standalone binary container and just want to poke around inside.</p>

<p>There could be a lot of reasons. Use docker enough and eventually you’ll bump into situation where <code class="language-plaintext highlighter-rouge">docker exec</code> isn’t sufficient. This is just a cool trick to add to your docker swiss army knife collection.</p>

<p>The tool we will be using is called <a href="https://github.com/jpetazzo/nsenter">nsenter</a> (<strong>N</strong>ame<strong>S</strong>pace<strong>ENTER</strong>). The original docker image uses <code class="language-plaintext highlighter-rouge">debian:jessie</code> which is over 300 MB in size.
If you don’t mind using someone’s binary, <a href="https://github.com/walkerlee/docker-nsenter">there</a> is a standalone binary with statically compiled <code class="language-plaintext highlighter-rouge">musl</code> as the dependency and the whole thing is only 500 KB.</p>

<h2 id="get-into-container">Get into container</h2>

<p>Suppose you need to use a container’s network (eg. to access non-exposed services) or debug the process itself (PID: 1):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># enter by container name</span>
<span class="nv">$ </span>docker run <span class="nt">--rm</span> <span class="nt">-it</span> <span class="nt">--privileged</span> <span class="nt">--net</span><span class="o">=</span>container:mycontainer <span class="nt">--pid</span><span class="o">=</span>container:mycontainer  jpetazzo/nsenter <span class="nt">-t</span> 1 <span class="nt">-m</span> <span class="nt">-u</span> <span class="nt">-i</span> <span class="nt">-n</span> sh
<span class="c"># enter by container id</span>
<span class="nv">$ </span>docker run <span class="nt">--rm</span> <span class="nt">-it</span> <span class="nt">--privileged</span> <span class="nt">--net</span><span class="o">=</span>container:21ee7ab8ddd7 <span class="nt">--pid</span><span class="o">=</span>container:21ee7ab8ddd7  jpetazzo/nsenter <span class="nt">-t</span> 1 <span class="nt">-m</span> <span class="nt">-u</span> <span class="nt">-i</span> <span class="nt">-n</span> sh
</code></pre></div></div>

<p>The equivalent* with official ways <code class="language-plaintext highlighter-rouge">docker exec</code> / <code class="language-plaintext highlighter-rouge">docker run</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>docker <span class="nb">exec</span> <span class="nt">-it</span> <span class="nt">--privileged</span> <span class="nt">--net</span><span class="o">=</span>container:mycontainer <span class="nt">--pid</span><span class="o">=</span>container:mycontainer bash
<span class="c"># use minimal privelege instead of --privileged because strace only need these 2</span>
<span class="nv">$ </span>docker run <span class="nt">--rm</span> <span class="nt">-it</span> <span class="nt">--cap-add</span> sys_admin <span class="nt">--cap-add</span> sys_ptrace <span class="nt">--net</span><span class="o">=</span>container:mycontainer <span class="nt">--pid</span><span class="o">=</span>container:mycontainer myimage/strace strace
</code></pre></div></div>

<div class="notice--info">
*It's not technically the same. As stated <a href="https://github.com/jpetazzo/nsenter#looking-to-start-a-shell-inside-a-docker-container">here</a>:

<blockquote>
There are differences between nsenter and docker exec; namely, nsenter doesn't enter the cgroups, and therefore evades resource limitations. The potential benefit of this would be debugging and external audit, but for remote access, docker exec is the current recommended approach.
</blockquote>
</div>

<h2 id="get-into-docker-host--docker-for-mac">Get into docker host / Docker for Mac</h2>

<p>Suppose you want to see docker’s syslog or debug docker host itself:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>docker run <span class="nt">--rm</span> <span class="nt">-it</span> <span class="nt">--privileged</span> <span class="nt">--pid</span><span class="o">=</span>host <span class="nt">--net</span><span class="o">=</span>host jpetazzo/nsenter <span class="nt">-t</span> 1 <span class="nt">-m</span> <span class="nt">-u</span> <span class="nt">-i</span> <span class="nt">-n</span> sh
</code></pre></div></div>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="docker" /><category term="nsenter" /><summary type="html"><![CDATA[Sometimes you have to debug a running container and you cannot modify the container (without much hassle). For example, you’re running a container that you don’t want to modify, probably because everybody in your office is using the image and you’d want to run the exact same image. Or it could be that the container is highly dependent on by other containers (service containers) and bringing it down to add debug tools will mean restarting the whole stack, which could be very trivial or very involved. Or maybe you started the container with --rm or -t options which will make docker attach tricky or impossible. Or you’re running a redis container and would like to strace why it seems stuck. Or you’re running a python container and would like to use ipython inside the container which is not available so you’d have to install, commit and rebuild the image (or ephemerally install on the running container). Or you have a Go standalone binary container and just want to poke around inside.]]></summary></entry><entry><title type="html">Docker for Mac logs</title><link href="https://ibnusani.com/article/docker-for-mac-logs/" rel="alternate" type="text/html" title="Docker for Mac logs" /><published>2017-09-30T00:00:00+00:00</published><updated>2017-09-30T00:00:00+00:00</updated><id>https://ibnusani.com/article/docker-for-mac-logs</id><content type="html" xml:base="https://ibnusani.com/article/docker-for-mac-logs/"><![CDATA[<p class="notice--warning">Edit Feb 2018: New docker for mac uses LinuxKit doesn’t have syslogd running by default (as of this time of writing). More info <a href="/article/docker-for-mac-logs-updated/">here</a>.</p>

<p>When docker <a href="https://blog.docker.com/2016/05/docker-unikernels-open-source/">ditched</a> Alpine for <a href="https://github.com/mist64/xhyve">xhyve</a>, I didn’t know how to get into docker itself to eg. see logs.</p>

<blockquote>
  <p>The xhyve hypervisor is a port of bhyve to OS X. It is built on top of Hypervisor.framework in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies.</p>
</blockquote>

<p>So it’s a lightweight hypervisor that runs Linux with Docker Engine inside. If you can’t find your logs you need via <code class="language-plaintext highlighter-rouge">docker logs</code> (what’s sent to <code class="language-plaintext highlighter-rouge">STDOUT</code>), chances are it’s in the docker daemon logs (sent for example via syslog facilities).</p>

<p>This is the magic:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
</code></pre></div></div>

<p>I will spare the explanation of what <code class="language-plaintext highlighter-rouge">screen</code> is but it comes bundled with OSX. The trick is just knowing where the tty to attach to is at.</p>

<p>Sometimes you might have been disconnected or you exit the terminal using <code class="language-plaintext highlighter-rouge">^d</code>.
This actually <em>detach</em> from the terminal.
What this means is that the next time you run the command again, you will see weird artifacts like crazy text indentation and gibberish characters.
Restarting docker will of course fix this as the Linux effectively reboots.</p>

<p>Or you can be civilized and just reattach (assuming you only have one session running):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ screen -R
</code></pre></div></div>

<p>If you have multiple sessions, find your docker session:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ screen -ls
There is a screen on:
	48617.ttys019.syazwan	(Detached)
1 Socket in /var/folders/_4/gl_zvn7x4y7g8m66vwwvz4nr0000gn/T/.screen.
</code></pre></div></div>
<p>Then reattach with the correct <code class="language-plaintext highlighter-rouge">&lt;pid&gt;.&lt;tty&gt;.&lt;host&gt;</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ screen -r 48617.ttys019.syazwan
</code></pre></div></div>

<p>Happy logging!</p>]]></content><author><name>Ahmad Syazwan</name></author><category term="article" /><category term="dev" /><category term="docker" /><category term="xhyve" /><summary type="html"><![CDATA[Edit Feb 2018: New docker for mac uses LinuxKit doesn’t have syslogd running by default (as of this time of writing). More info here.]]></summary></entry></feed>