<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jun Lin</title>
    <description>The latest articles on DEV Community by Jun Lin (@linjunpop).</description>
    <link>https://dev.to/linjunpop</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1564%2F214616.png</url>
      <title>DEV Community: Jun Lin</title>
      <link>https://dev.to/linjunpop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/linjunpop"/>
    <language>en</language>
    <item>
      <title>Using Docker with Phoenix Umbrella App</title>
      <dc:creator>Jun Lin</dc:creator>
      <pubDate>Sun, 30 Apr 2023 22:25:51 +0000</pubDate>
      <link>https://dev.to/linjunpop/using-docker-with-phoenix-umbrella-app-4192</link>
      <guid>https://dev.to/linjunpop/using-docker-with-phoenix-umbrella-app-4192</guid>
      <description>&lt;p&gt;First, config the distillery with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rel/config.exs&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="ss"&gt;:void&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;applications:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;:runtime_tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;void:&lt;/span&gt; &lt;span class="ss"&gt;:permanent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;commands:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"migrate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"rel/commands/migrate.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"seed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"rel/commands/seed.sh"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="ss"&gt;:void_web&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;applications:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;:runtime_tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;void:&lt;/span&gt; &lt;span class="ss"&gt;:permanent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;void_web:&lt;/span&gt; &lt;span class="ss"&gt;:permanent&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use the following &lt;code&gt;Dockerfile&lt;/code&gt; which take an arg &lt;code&gt;app_name&lt;/code&gt;, then build the specific umbrella app for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dockerfile&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; elixir:1.4&lt;/span&gt;

&lt;span class="c"&gt;# fixes bad trap when running release in foreground, built with distillery&lt;/span&gt;
&lt;span class="c"&gt;# https://github.com/bitwalker/distillery/issues/18&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'dash dash/sh boolean false'&lt;/span&gt; | debconf-set-selections
&lt;span class="k"&gt;RUN &lt;/span&gt;dpkg-reconfigure &lt;span class="nt"&gt;-phigh&lt;/span&gt; dash

&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_6.x | bash - &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential

&lt;span class="c"&gt;# ENVs&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; MIX_ENV=prod&lt;/span&gt;

&lt;span class="c"&gt;# Define path ENVs&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; BUILD_DIR /build&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nv"&gt;$BUILD_DIR&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; APP_HOME /app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nv"&gt;$APP_HOME&lt;/span&gt;

&lt;span class="c"&gt;## Build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; $BUILD_DIR&lt;/span&gt;

&lt;span class="c"&gt;# Install Elixir Deps&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix local.hex &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mix local.rebar &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="c"&gt;# Copying mix.exs&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; mix.exs mix.lock ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; apps/void/mix.exs apps/void/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; apps/void_web/mix.exs apps/void_web/&lt;/span&gt;

&lt;span class="c"&gt;# Fetch deps&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; deps deps&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix deps.get

&lt;span class="c"&gt;# Copying Config files&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; config ./config&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; apps/void/config
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; apps/void/config/* apps/void/config/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; apps/void_web/config
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; apps/void_web/config/* apps/void_web/config/&lt;/span&gt;

&lt;span class="c"&gt;# Compile everything&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix compile

&lt;span class="c"&gt;# Web Assets&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; apps/void_web/assets apps/void_web/assets&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apps/void_web/assets/ &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./node_modules/brunch/bin/brunch build &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apps/void_web &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mix phx.digest

&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;## - Release tasks, build the $app_name application.&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; app_name&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;mix release &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$app_name&lt;/span&gt; &lt;span class="nt"&gt;--env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prod &lt;span class="nt"&gt;--executable&lt;/span&gt;

&lt;span class="c"&gt;# Copy releases&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; ./_build/prod/rel/&lt;span class="nv"&gt;$app_name&lt;/span&gt;/bin/&lt;span class="nv"&gt;$app_name&lt;/span&gt;.run &lt;span class="nv"&gt;$APP_HOME&lt;/span&gt;/ &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$BUILD_DIR&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; $APP_HOME&lt;/span&gt;

&lt;span class="c"&gt;# Set entry point&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="nv"&gt;$app_name&lt;/span&gt;&lt;span class="s2"&gt;.run &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; entrypoint.sh
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["sh", "entrypoint.sh"]&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; foreground&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using with docker-compose&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db-volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgres:9.4"&lt;/span&gt;
    &lt;span class="na"&gt;expose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;civic&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;civic&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;civic_prod&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db-volume:/var/lib/postgresql&lt;/span&gt;

  &lt;span class="na"&gt;migrator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;void&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod"&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres://civic:civic@db/civic_prod&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;migrate&lt;/span&gt;

  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;void_web&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod"&lt;/span&gt;
      &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4000&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres://civic:civic@db/civic_prod&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;migrator&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foreground&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4000:4000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>docker</category>
      <category>phoenix</category>
    </item>
    <item>
      <title>A step to step guide to set up Dev Container</title>
      <dc:creator>Jun Lin</dc:creator>
      <pubDate>Sun, 30 Apr 2023 22:24:57 +0000</pubDate>
      <link>https://dev.to/linjunpop/a-step-to-step-guide-to-set-up-dev-container-id1</link>
      <guid>https://dev.to/linjunpop/a-step-to-step-guide-to-set-up-dev-container-id1</guid>
      <description>&lt;h2&gt;
  
  
  A brief on Dev Container
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://code.visualstudio.com/docs/remote/create-dev-container"&gt;Dev Container&lt;/a&gt; is a mechanism to set up a full-featured local development environment. By using VSCode as the editor, remote connecting to a Docker container (which running a fully functional development environment), developers can enjoy a great local development experience, while taking full advantage of the container technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To make the Dev Contaienr works, the following software are required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/products/docker-desktop"&gt;Docker Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com"&gt;VSCode&lt;/a&gt; with &lt;a href="https://github.com/Microsoft/vscode-remote-release"&gt;Remote-Container extension&lt;/a&gt; installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A step-by-step guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A minimal Dev Container definition
&lt;/h3&gt;

&lt;p&gt;Now, let's take the &lt;a href="https://github.com/linjunpop/transhook"&gt;Transhook&lt;/a&gt; project as an example, set up the Dev Container step by step.&lt;/p&gt;

&lt;p&gt;The first step is to create a new directory &lt;code&gt;.devcontainer&lt;/code&gt; in your project's root directory, this directory will be the single place for the Dev Container definitions and some related files.&lt;/p&gt;

&lt;p&gt;Now let's add the definition file &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; for this project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hexpm/elixir:1.12.2-erlang-24.0.4-ubuntu-focal-20210325"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"transhook-devcontainer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"onCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"elixir --version"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then try "Open Folder in Container..."&lt;/p&gt;

&lt;p&gt;![[Pasted image 20210725095039.png]]&lt;/p&gt;

&lt;p&gt;The VSCode window will restart and connect to the container. After the container successfully running, you can see the result of &lt;code&gt;onCreateCommand&lt;/code&gt; which show the elixir version here:&lt;/p&gt;

&lt;p&gt;![[Pasted image 20210724195814.png]]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@aa36190d0d2f:/workspaces/transhook# elixir &lt;span class="nt"&gt;--version&lt;/span&gt;
Erlang/OTP 24 &lt;span class="o"&gt;[&lt;/span&gt;erts-12.0.3] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;64-bit] &lt;span class="o"&gt;[&lt;/span&gt;smp:4:4] &lt;span class="o"&gt;[&lt;/span&gt;ds:4:4:10] &lt;span class="o"&gt;[&lt;/span&gt;async-threads:1]

Elixir 1.12.2 &lt;span class="o"&gt;(&lt;/span&gt;compiled with Erlang/OTP 24&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let's open the &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;![[Pasted image 20210724195824.png]]&lt;/p&gt;

&lt;p&gt;As you can see, there are no syntax highlights for the Elixir files. Let move to the next step to make the syntax highlighting work.&lt;/p&gt;

&lt;h3&gt;
  
  
  VSCode extensions
&lt;/h3&gt;

&lt;p&gt;Dev Container also can bundle the VSCode extensions for the project. Let's go ahead and add the &lt;code&gt;extensions&lt;/code&gt; section to the &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hexpm/elixir:1.12.2-erlang-24.0.4-ubuntu-focal-20210325"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"transhook-devcontainer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"onCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"elixir --version"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jakebecker.elixir-ls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"eamodio.gitlens"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you reopen the project in Container, VSCode will detect there's a change, then ask you to rebuild the container.&lt;/p&gt;

&lt;p&gt;![[Pasted image 20210724200346.png]]&lt;/p&gt;

&lt;p&gt;After the rebuild is finished, VSCode will get the ElixirLS and GitLens extension installed. Now the Elixir files got syntax highlighting:&lt;/p&gt;

&lt;p&gt;![[Pasted image 20210724195903.png]]&lt;/p&gt;

&lt;p&gt;But as you can see, VSCode complains that the Git is missing, that's because there's the only Elixir installed in the image: &lt;code&gt;hexpm/elixir:1.12.2-erlang-24.0.4-ubuntu-focal-20210325&lt;/code&gt;. But Git is required for our development, can we find a way to add it to the Dev Container? Let's move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Docker Compose approach
&lt;/h3&gt;

&lt;p&gt;How can we add extra software and configuration to an existing Docker image? Use &lt;a href="https://docs.docker.com/engine/reference/builder/"&gt;Dockerfile&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The Dev Container also supports building from a &lt;code&gt;Dockerfile&lt;/code&gt; or even &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;, here I will take the second one, I'll show you why in the following content.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/linjunpop/transhook"&gt;Transhook&lt;/a&gt; project, I'm using &lt;a href="https://asdf-vm.com"&gt;asdf&lt;/a&gt; to manage tool versions, so Instead of build upon the &lt;code&gt;hexpm/elixir&lt;/code&gt;, I will use the &lt;code&gt;ubuntu&lt;/code&gt; as the base image, then add essential tools (Elixir, Erlang, Node.js) to the dev environment.&lt;/p&gt;

&lt;p&gt;What we need to do is to modify the &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file, and add two extra new files: &lt;code&gt;.devcontainer/Dockerfile&lt;/code&gt; and &lt;code&gt;.devcontainer/docker-compose.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Dockerfile&lt;/code&gt;, we installed &lt;a href="https://asdf-vm.com"&gt;asdf&lt;/a&gt;, and Elixir, Erlang, Nodejs based on the versions defined in the project's &lt;code&gt;.tool-versions&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;dev&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="nt"&gt;-qq&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-qq&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  curl &lt;span class="se"&gt;\
&lt;/span&gt;  git &lt;span class="se"&gt;\
&lt;/span&gt;  dirmngr &lt;span class="se"&gt;\
&lt;/span&gt;  gpg &lt;span class="se"&gt;\
&lt;/span&gt;  gawk &lt;span class="se"&gt;\
&lt;/span&gt;  unzip &lt;span class="se"&gt;\
&lt;/span&gt;  build-essential &lt;span class="se"&gt;\
&lt;/span&gt;  autoconf &lt;span class="se"&gt;\
&lt;/span&gt;  libssl-dev &lt;span class="se"&gt;\
&lt;/span&gt;  libncurses5-dev &lt;span class="se"&gt;\
&lt;/span&gt;  m4 &lt;span class="se"&gt;\
&lt;/span&gt;  libssh-dev

&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-ms&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;which bash&lt;span class="si"&gt;)&lt;/span&gt; asdf

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; asdf&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;git clone https://github.com/asdf-vm/asdf.git &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.asdf &lt;span class="nt"&gt;--branch&lt;/span&gt; v0.8.1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'. $HOME/.asdf/asdf.sh'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.bashrc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'. $HOME/.asdf/asdf.sh'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.profile

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH /home/asdf/.asdf/bin:/home/asdf/.asdf/shims:$PATH&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s2"&gt;  asdf plugin-add elixir &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s2"&gt;  asdf plugin-add erlang &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s2"&gt;  asdf plugin-add nodejs &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s2"&gt;  "&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; .tool-versions /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"ls -la &amp;amp;&amp;amp; asdf install"&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; LANG C.UTF-8&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /workspace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, the service &lt;code&gt;app_dev&lt;/code&gt; will be defined to build the image and mount the project into the container's &lt;code&gt;/workspace/transhook&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.6"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app_dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;# Set the context to the parent directory, so we can add `.tool-versions` to the container&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.devcontainer/Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../:/workspace/transhook&lt;/span&gt;

    &lt;span class="c1"&gt;# Overrides default command so things don't shut down after the process ends.&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash -c "sleep infinity"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we will modify the &lt;code&gt;devcontainer.json&lt;/code&gt; to tell VSCode we need to build the Dev Container from a Docker Compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dockerComposeFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"docker-compose.yml"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"workspaceFolder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/workspace/transhook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app_dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jakebecker.elixir-ls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"eamodio.gitlens"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"streetsidesoftware.code-spell-checker"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a rebuild, everything should up and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;asdf@bcdc19f598ee:/workspace/transhook&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .tool-versions 
erlang 24.0.2
elixir 1.12.1-otp-24
nodejs 16.5.0
asdf@bcdc19f598ee:/workspace/transhook&lt;span class="nv"&gt;$ &lt;/span&gt;elixir &lt;span class="nt"&gt;--version&lt;/span&gt;
warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is &lt;span class="nb"&gt;set &lt;/span&gt;to UTF-8 &lt;span class="o"&gt;(&lt;/span&gt;which can be verified by running &lt;span class="s2"&gt;"locale"&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;your shell&lt;span class="o"&gt;)&lt;/span&gt;
Erlang/OTP 24 &lt;span class="o"&gt;[&lt;/span&gt;erts-12.0.2] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;64-bit] &lt;span class="o"&gt;[&lt;/span&gt;smp:4:4] &lt;span class="o"&gt;[&lt;/span&gt;ds:4:4:10] &lt;span class="o"&gt;[&lt;/span&gt;async-threads:1]

Elixir 1.12.1 &lt;span class="o"&gt;(&lt;/span&gt;compiled with Erlang/OTP 24&lt;span class="o"&gt;)&lt;/span&gt;
asdf@bcdc19f598ee:/workspace/transhook&lt;span class="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
v16.5.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Till now, we've set up a Dev Container with a fully functional Elixir development environment, we can start coding. &lt;/p&gt;

&lt;p&gt;![[Pasted image 20210724223138.png]]&lt;/p&gt;

&lt;p&gt;Can we?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;asdf@cde62f300dea:/workspace/transhook$ iex -S mix phx.server
Erlang/OTP 24 [erts-12.0.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]

Compiling 33 files (.ex)

Generated transhook app
[error] Postgrex.Protocol (#PID&amp;lt;0.623.0&amp;gt;) failed to connect: ** (DBConnection.ConnectionError) tcp connect (localhost:5432): connection refused - :econnrefused
...
[info] Running TranshookWeb.Endpoint with cowboy 2.9.0 at 0.0.0.0:4000 (http)
[info] Access TranshookWeb.Endpoint at http://localhost:4000
Interactive Elixir (1.12.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The webserver failed to start because the application is failed to connect to the Postgres database. This is the last issue we need to resolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Postgres as a part of the Dev Container
&lt;/h3&gt;

&lt;p&gt;In the previous steps, we did successfully set up the Elixir development environment. But in practice, a complicated production application will rely on many third-party tools, can we bundle them into the Dev Container system too? The answer is definitely yes. Take Transhook as an example, it's built with the Phoenix framework, so Postgres will be an underlying dependency as the data storage system.&lt;/p&gt;

&lt;p&gt;Now let's add Postgres to the &lt;code&gt;docker-compose.yml&lt;/code&gt; as the &lt;code&gt;db&lt;/code&gt; service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.6"

services:
  app_dev:
    build:
      # Set the context to the parent directory, so we can add `.tool-versions` to the container
      context: ../
      dockerfile: .devcontainer/Dockerfile
    environment:
      MIX_ENV: dev
    volumes:
      - ../:/workspace/transhook

    # Overrides default command so things don't shut down after the process ends.
    command: sleep infinity
    depends_on:
      - db
  db:
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_HOST_AUTH_METHOD: trust
    image: 'postgres:11-alpine'
    restart: always
    volumes:
      - 'pgdata:/var/lib/postgresql/data'
volumes:
  pgdata:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now change the database hostname to &lt;code&gt;db&lt;/code&gt; in &lt;code&gt;config/dev.exs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Configure your database
config :transhook, Transhook.Repo,
  username: "postgres",
  password: "postgres",
  database: "transhook_dev",
  hostname: "db",
  show_sensitive_data_on_connection_error: true,
  pool_size: 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then another rebuild, Postgres will be up and running, and we can successfully connect to it and bootstrap the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;asdf@61d774e9052e:/workspace/transhook&lt;span class="nv"&gt;$ &lt;/span&gt;mix ecto.setup
The database &lt;span class="k"&gt;for &lt;/span&gt;Transhook.Repo has been created

14:56:08.298 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Running 20200429042810 Transhook.Repo.Migrations.CreateHooks.change/0 forward

14:56:08.342 &lt;span class="o"&gt;[&lt;/span&gt;info]  create table hooks

14:56:08.443 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Migrated 20200429042810 &lt;span class="k"&gt;in &lt;/span&gt;0.0s

14:56:08.601 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Running 20210401074039 Transhook.Repo.Migrations.AddFiltersToHooks.change/0 forward

14:56:08.601 &lt;span class="o"&gt;[&lt;/span&gt;info]  alter table hooks

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

&lt;/div&gt;



&lt;p&gt;And the web server can be successfully started now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;asdf@61d774e9052e:/workspace/transhook$ iex -S mix phx.server
Erlang/OTP 24 [erts-12.0.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]

[info] Running TranshookWeb.Endpoint with cowboy 2.9.0 at 0.0.0.0:4000 (http)
[info] Access TranshookWeb.Endpoint at http://localhost:4000
Interactive Elixir (1.12.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can visit the server from the host machine, on the forwarded port &lt;code&gt;4000&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;![[Pasted image 20210724230119.png]]&lt;/p&gt;

&lt;h3&gt;
  
  
  We did it!
&lt;/h3&gt;

&lt;p&gt;With the Dev Container mechanism, we've turned VSCode into a full-featured development environment.&lt;/p&gt;

&lt;p&gt;You can refer to this Pull Request &lt;a href="https://github.com/linjunpop/transhook/pull/1"&gt;# Add Dev Container support&lt;/a&gt; for a reference of files described in this blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;If you read through the above content, you might be wondering why would we spend time to set up such an environment, here I'll put in my two cents, and you are welcome to share yours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Dev Container can provide a clean dev environment, which can keep the same language &amp;amp; tools as production runtime environment&lt;/li&gt;
&lt;li&gt;New contributors can easily set up the dev environment, especially when the project is complex and relying on many 3rd party tools/services.&lt;/li&gt;
&lt;li&gt;The VSCode extensions can be also included in the Dev Container definition, so every contributor of the project can enjoy the same editing 环境. Also, new useful plugins can quickly sync to developers.&lt;/li&gt;
&lt;li&gt;As &lt;a href="https://github.com/features/codespaces"&gt;GitHub Codespaces&lt;/a&gt; support Dev Container too, so a project hosted on GitHub might provide a cloud editing environment, which could allow you to edit and ship projects on an iPad. (I will try this later for the Transhook project)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;As the Dev Container relies on Docker, it might consume more resources than a well-setup local dev environment. It's a trade-off, on my MacBook Air with 8G memory, sometimes I'll receive memory out warnings, and it seems the virtual machine uses around 5G of my memory)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>devcontainer</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
